官方文档:mongoosejs.net/docs/
安装 mongoose
项目中我们会用到 Mongoose 来操作我们的数据库,Nest 官方为我们提供了一个 Mongoose 的封装,我们需要安装 mongoose 和 @nestjs/mongoose:
npm install mongoose @nestjs/mongoose --save
创建user依赖的几个文件
# 创建模块
nest g module user server
# 创建控制器
nest g controller user server
# 创建 Provider 服务
nest g service user server
连接数据库引入 根模块Mongoose
连接数据之前,我们要先在根模块,也就是 app.module.ts 中引入 Mongoose 的连接模块:
// app.module.ts
//MongooseModule.forRoot("mongodb://user:pass@ip:port/database");
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './server/user/user.module';
@Module({ imports: [MongooseModule.forRoot('mongodb://localhost:27017/Users'), UserModule],
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}
error:如果这里运行后端文件是又可能会报错,如果报错就添加:
npm install @types/mongoose --dev
引入 分模块Mongoose
这里我们先要创建一个数据表的格式,在 src/server/user 文件夹下创建一个 user.schema.ts 文件,定义一个数据表的格式:
// user.schema.ts
import { Schema } from 'mongoose';
export const userSchema = new Schema({
// _id: { type: String, required: true }, // 覆盖 Mongoose 生成的默认 _id
user_name: { type: String, required: true },
password: { type: String, required: true }
});
然后将我们的 user.module.ts 文件修改成这样:
// user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserController } from './user.controller';
import { userSchema } from './user.schema';
import { UserService } from './user.service';
@Module({
imports: [MongooseModule.forFeature([{ name: 'Users', schema: userSchema }])],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
CRUD
创建两个文件做数据类型的定义:
// user.interface.ts
import { Document } from 'mongoose';
export interface User extends Document {
// readonly _id: string;
readonly user_name: string;
readonly password: string;
}
//////////////////////////////////////////////////////////
// user.dto.ts
export class CreateUserDTO {
readonly user_name: string;
readonly password: string;
}
export class EditUserDTO {
readonly user_name: string;
readonly password: string;
}
修改 user.service.ts 文件,为 UserService 类添加一个构造函数,让其在实例化的时候能够接收到数据库 Model,这样才能在类中的方法里操作数据库。
因为 mongoose 操作数据库其实是异步的,所以这里我们使用 async 函数来处理异步的过程。
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateUserDTO, EditUserDTO } from './user.dto';
import { User } from './user.interface';
@Injectable()
export class UserService {
constructor(@InjectModel('Users') private readonly userModel: Model<User>) { }
// 查找所有用户
async findAll(): Promise<User[]> {
const users = await this.userModel.find();
return users;
}
// 查找单个用户
async findOne(user_name: string): Promise<User> {
return await this.userModel.findOne({user_name});
}
// 添加单个用户
async addOne(body: CreateUserDTO): Promise<void> {
await this.userModel.create(body);
}
// 编辑单个用户
async updateOne(user_name: string, newPassword: string): Promise<void> {
await this.userModel.updateOne({user_name},{password: newPassword});
}
// 删除单个用户
async deleteOne(user_name: string): Promise<void> {
await this.userModel.deleteOne({user_name});
}
}
修改 user.controller.ts 设置路由了,将客户端的请求进行处理,调用相应的服务实现相应的功能:
import {
Controller,
Body,
// Delete,
Get,
Param,
Post,
Put
} from '@nestjs/common';
import { CreateUserDTO, EditUserDTO } from './user.dto';
import { User } from './user.interface';
import { UserService } from './user.service';
interface UserResponse<T = unknown> {
//这是一个 TypeScript 接口定义,用于描述用户响应的数据结构。它包含一个泛型参数 T,默认值为 unknown,其中包含 code(响应码)、data(响应数据,可选)和 message(响应消息)三个属性。
code: number;
data?: T;
message: string;
}
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) { }
// GET /user/users
@Get('/users')
async findAll(): Promise<UserResponse<User[]>> {
return {
code: 200,
data: await this.userService.findAll(),
message: '查询成功.'
};
}
// POST /user/find_one
@Post('/find_one')
async findOne(@Body() userData: { user_name: string }): Promise<UserResponse> {
await this.userService.findOne(userData.user_name); // 使用传入的 user_name 参数
return {
code: 200,
data: await this.userService.findOne(userData.user_name),
message: '查询成功.'
};
}
// POST /user/user
@Post('/user')
async addOne(@Body() body: CreateUserDTO): Promise<UserResponse> {
await this.userService.addOne(body);
return {
code: 200,
message: '添加成功.'
};
}
// POST /user/upd
@Post('/upd')
async updateOne(@Body() userData: { user_name: string, newPassword: string }): Promise<UserResponse> {
await this.userService.updateOne(userData.user_name, userData.newPassword); // 使用传入的 user_name 参数
return {
code: 200,
message: '修改成功.'
};
}
// Post /user/deluser
@Post('/deluser')
async deleteOne(@Body() userData: { user_name: string }): Promise<UserResponse> {
await this.userService.deleteOne(userData.user_name); // 使用传入的 user_name 参数
return {
code: 200,
message: '删除成功.'
};
}
}
nest.js调用mongoose来操作mongoDB数据库的后端程序就已经写好了。
小程序端调用
这里只包含了与后端交互的部分代码
Page({
...
tijiao(){
wx.request({
url: 'http://localhost:3000/user/user',
method:'POST',
data:{
user_name:this.data.inputValue1,
password:this.data.inputValue2
},
})
},
// 删除
shanchu() {
wx.request({
url: 'http://localhost:3000/user/deluser',
method: 'POST',
data: {
user_name: this.data.inputValue_del,
},
success: (res) => {
// 处理成功的情况
console.log(res.data); // 可以打印后端返回的数据
},
fail: (error) => {
// 处理失败的情况
console.error(error);
}
})
},
// 修改
xiugai(){
wx.request({
url: 'http://localhost:3000/user/upd',
method:'POST',
data:{
// 名字
user_name:this.data.inputValue1_upda,
// 修改后的年龄
newPassword:this.data.inputValue2_upda,
},
})
},
// 查询
find(){
wx.request({
url: 'http://localhost:3000/user/find_one',
method: 'POST',
data:{
user_name:this.data.inputValue1_find,
},
success: function(res) {
console.log('服务器返回的数据:', res.data);
if (res.data && res.data.length > 0) {
const records = res.data;
records.forEach(record => {
console.log('记录:', record);
});
} else {
console.log('未找到匹配的记录');
}
},
fail: function(error) {
console.error('请求失败:', error);
}
});
},
find_all(){
wx.request({
url: 'http://localhost:3000/user/users',
method: 'GET',
success: function(res) {
// 请求成功,处理从服务器返回的数据
console.log('服务器返回的数据:', res.data);
// 检查是否找到匹配的记录
if (res.data && res.data.length > 0) {
// 处理返回的记录数据
const records = res.data;
records.forEach(record => {
console.log('记录:', record);
// 在这里进行您的处理逻辑,例如显示在界面上
});
}
},
fail: function(error) {
// 请求失败,处理错误
console.error('请求失败:', error);
// 在界面上显示错误信息,告知用户请求失败
}
});
}
})
多数据库
有的项目需要多数据库连接,可以在这个模块中实现。要使用多连接,首先要创建连接,在这种情况下,连接必须**要有名称。
//app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/test', {
connectionName: 'cats',
}),
MongooseModule.forRoot('mongodb://localhost/users', {
connectionName: 'users',
}),
],
})
export class AppModule {}
在设置中,要告诉MongooseModule.forFeature()方法应该使用哪个连接。
// cat/cat.module.ts
@Module({
imports: [MongooseModule.forFeature([{ name: 'Cat', schema: CatSchema }], 'cats')],
})
export class CatModule {}
分页
// cats.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Cat } from './cat.schema';
@Injectable()
export class CatsService {
constructor(@InjectModel(Cat.name) private readonly catModel: Model<Cat>,) {}
async findAll(page: number, limit: number): Promise<Cat[]> {
return this.catModel.find().skip((page - 1) * limit).limit(limit).exec();
}
}
CURD
数据库的基本操作包括四个,增加(create),删除(delete),修改(update),查(read)
// 插入一条
SongModel.create({
title:'给我一首歌的时间',
author: 'Jay'
},
function(err, data){
//错误
console.log(err);
//插入后的数据对象
console.log(data);
});
// 批量插入
PhoneModel.insertMany([
{
brand:'华为',
color:'灰色',
price:2399,
tags:['电量大','屏幕大','信号好']
},
{
brand:'小米',
color:'白色',
price:2099,
tags:['电量大','屏幕大','信号好']
}],
(err,data)=>{
if(err) throw err;
console.log('写入成功');
mongoose.connection.close();
})
// 删除一条数据
SongModel.deleteOne(
{_id:'5dd65f32be6401035cb5b1ed'},
function(err){
if(err) throw err;
console.log('删除成功');
mongoose.connection.close();
}
)
// 批量删除
SongModel.deleteMany({author:'Jay'},
function(err){
if(err) throw err;
console.log('删除成功');
mongoose.connection.close();
})
// 更新一条数据
SongModel.updateOne({author: 'JJ Lin'}, {author: '林俊杰'},
function (err) {
if(err) throw err;
mongoose.connection.close();
})
// 批量更新数据
SongModel.updateMany({author: 'Leehom Wang'}, {author: '王力宏'}, function (err) {
if(err) throw err;
mongoose.connection.close();
})
// 查询一条数据
SongModel.findOne({author: '王力宏'},
function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
})
//根据 id 查询数据
SongModel.findById('5dd662b5381fc316b44ce167',
function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
})
//不加条件查询
SongModel.find(function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
//加条件查询
SongModel.find({author: '王力宏'},
function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据处理
返回指定字段
//0:不要的字段
//1:要的字段
SongModel.find()
.select({_id:0,title:1})
.exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据排序
//sort 排序
//1:升序
//-1:倒序
SongModel.find()
.sort({hot:1})
.exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据截取
//skip 跳过 limit 限定
SongModel.find()
.skip(10)
.limit(10)
.exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
})
连表操作
// 定义User模型
const UserSchema = new mongoose.Schema({
name: String,
email: String
});
const User = mongoose.model('User', UserSchema);
// 定义Post模型
const PostSchema = new mongoose.Schema({
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
const Post = mongoose.model('Post', PostSchema);
// 现在我们要获取一个帖子并且包含作者信息
Post.findOne({ _id: postId }).populate('author').exec((err, post) => {
if (err) {
// 处理错误
console.error(err);
} else {
// 获取到的帖子,包含作者信息
console.log(post);
}
});
创建、查询
const studentSchema = Schema({
name: String,
age: Number,
xuexiao: {
type: mongoose.Schema.Types.ObjectId,
ref: 'School' //这里要写你指向的数据库表名字
}
});
const schoolSchemal = Schema({
name: String,
});
const studentModel = mongoose.model('Student', studentSchema);
const schoolModel = mongoose.model('School', schoolSchemal);
//创建学校
const school = schoolModel({
name: '第一高中'
});
school.save(function(err) {
if (err) {
console.log(err);
return;
}
//创建了学生1
const student = studentModel({
name: '小红',
age: 16,
xuexiao: school._id //把学校的唯一id给绑定到学生身上。
});
student.save(function(err) {
if (err) console.log(err);
});
//创建了学生2
const student2 = studentModel({
name: '小明',
age: 16,
xuexiao: school._id //把学校的唯一id给绑定到学生身上。
});
student2.save(function(err) {
if (err) console.log(err);
});
});
//查询//////////////////////////
studentModel
.findOne({
name: '小红'
})
.exec(function(err, student) {
console.log('id: ', student.xuexiao, 'name: ', student.xuexiao.name);
//id: 58ddd5db6216a905ce973de4 name: undefined
//这里打印只有id,并没有属性
});
studentModel
.findOne({
name: '小红'
})
.populate('xuexiao') //加上这句话也就有了属性值,
.exec(function(err, student) {
console.log('id: ', student.xuexiao, 'name: ', student.xuexiao.name);
//id: { _id: 58ddd5db6216a905ce973de4, name: '第一高中', __v: 0 } name: 第一高中
});
Mongoose 预定义修饰符 Getter 与 Setter
// mongoose 预定义修饰符
trim:true //去首尾空格
lowercase:true //转化为小写
uppercase:true //转化为大写
var UserSchema=mongoose.Schema({
name:{
type:String,
trim:true //去首尾空格
},
age:Number,
status:{
type:Number,
default:1,
lowercase:true
}
})
自定义修饰符 Setter 和 Getter
// 加入我们要对 url 进行格式化,如果数据以 http:// 开头我们原样存入,如果不以 http:// 开头,添加之后再存入数据库
const ArticleSchema = mongoose.Schema({
title:String,
author:String,
img:{
type:String,
set(params){
if(!params) return params;
return /^http:\/\//.test(params) ? params : 'http://' + params
},
get(params){
return 'mongodb:' + params;
}
}
});
const article2 = new Article({
title:'武汉加油',
author: '人民日报',
img:'wuhan/pic02'
});
// 这样存入数据库的数据就是 http://wuhan/pico2