mogoose 创建数据库并增删改查

下载

npm i mongoose -s

连接数据库

const mongoose = require("mongoose");
mongoose.connect(dbURL);

const db = mongoose.connection;

db.on("error", () => {
    console.log("链接失败");
});
db.on("open", () => {
    console.log("链接成功");
});

创建表结构Schema

Schema相当于MySql的表结构

通过定义Schema来约束数据的类型,支持以下类型数据

类型 作用
String 定义字符串
Number 定义数字
Date 定义日期
Buffer 定义二进制
Boolean 定义布尔值
Mixed 定义混合类型
ObjectId 定义对象ID
Array 定义数组
Decimal128
Map

约束能用对象的方法描述数据类型 是否必须 是否重复 默认值 等,如下定义了一个用户表结构

注意:如果定义表结构时没有定义_id,mongoose会自己添加一个该字段,该字段不会重复,类型为ObjectId,通过findById()查询

const userSachem = new mongoose.Schema(
    {
        name: {
            type: String,
            required: true, //! 必须
        },
        email: {
            type: String,
            required: true,
            unique: true, //! 不重复
        },
        passWord: {
            type: String,
            required: true,
        },
        avatar: {
            type: String,
            default: null, //! 默认值
        },
        bio: String, //! 默认没有可以不写
    },
    {
        timestamps: true, //! 添加`createdAt updatedAt`创建时间和更新时间两个字段
    }
);

如果在定义了结构后需要添加新字段,在实例上使用add()方法

创建表model

通过mongoose.model(name,sechem)来创建表结构构造器,通过传入数据来实例化构造器获得具体的表

注意:在这一步的时候数据库已经有了表,表名全是小写且表明为name加上s,如这里会创建表users

const User = mongoose.model("User", userSechem);

通过上面的操作就获得了表的构造函数,接下来就可以向里面进行增删改查了

有三种方法在表内增加数据:

通过实例化数据:

  • 创建表数据实例化model

通过传入具体的数据来实例化表,能获得一条具体的表数据,类型为Mongoose Documents,向数据库中查找到的也是这种类型数据

const user = new User(userData);
  • 保存save

获得具体的表后只需要调用Model.prototype.save就会把数据存入数据库中 注意:该方法为异步方法

await user.save();

通过Model.create方法:

通过表构造器的静态方法create自动在表中插入新的数据

该方法可以接收多个插入数据,最后的回调函数参数根据数据量决定

该方法支持两种调用:

  • 错误优先的回调
  • async await
const users = await User.create(
    { name: "1", email: "[email protected]", passWord: "123" },
    { name: "2", email: "[email protected]", passWord: "456" },
    { name: "3", email: "[email protected]", passWord: "789" }
);
res.status(200).json(users); // users是数组

// 或者
User.create(
    { name: "str", email: "[email protected]", passWord: "159" },
    { name: "1", email: "[email protected]", passWord: "123" },
    { name: "2", email: "[email protected]", passWord: "456" },
    { name: "3", email: "[email protected]", passWord: "789" },
    (err, doc1, doc2, doc3) => {
        if (err) {
            return err;
        }
        res.status(200).json({ doc1, doc2, doc3 });
    }
);

通过Model.insertMany方法

该方法与create的区别是它接收的第一个参数是数据组成的数组,多条数据只会插入第一条

const user = await User.insertMany({ name: "1", email: "[email protected]", passWord: "123" });
const users = await User.insertMany([
    { name: "2", email: "[email protected]", passWord: "456" },
    { name: "3", email: "[email protected]", passWord: "789" },
]);


查找数据

通过Model.find方法

不传入参数会查找该表的所有数据

该方法返回值始终是数组

第一个参数

指定数据的某个键进行查找,键也能是正则表达式

const data = await User.find({ name: /\d/ });

限制查找范围,通过内置的字段限制某个字段的范围,$where函数参数来指定查询的限制范围

const data = await User.find({
    name: { $gt: 1 },
    $where: () => this.passWord == parseInt(this.email),
}); // 查找name大于1且密码和邮箱一样的

还能通过$and $or $not等参数来决定查找的范围

const data = await User.find({
    $or: [{ $and: [{ name: /[1,2]/ }, { email: /(@qq.com)$/ }] }, { name: /\w+/ }],
}); // 查找 name为1或2且为QQ邮箱 或 name为字符串 的数据

如果查找的是对象中的属性用字符串做键或者嵌套查找

注意 嵌套查找必须顺序一致

// 查找这条数据 { name: "4", email: "[email protected]", passWord: "357", bio: { head: 123, foot: 789 } }
const datas = await User.find({ "bio.head": 123 }); // 字符串查找
const datas = await User.find({ bio: { head: 123, foot: 456 } }); // 嵌套对象查找 对象要写全且顺序不能改变,里面只能用具体的数据,不能用正则表达式或其它的限制

如果查找的是数组中的某项

// 有这两条数据 { name: "4", email: "[email protected]", passWord: "357", bio: [123, 456, "hahaha"] }
//             { name: "5", email: "[email protected]", passWord: "258", bio: [123, 789, "haha"] }
const datas = await User.find({ bio: 123 }); // 如果数组中有一个数据符合就会找到 也能像上面一样用特殊参数指定范围
const datas = await User.find({ bio: { $all: [123, 456] } }); // 查找含有这两个值 只能找到第二条
const datas = await User.find({ bio: { $in: [456, 789] } }); // 查找这两个值中的任意一条 两条都能找到
const datas = await User.find({ "bio.1": { $gt: 456 } }); // 使用下标指明指定数据的范围 这里找到第二条

如果查找的是数组对象中的某项

// 有这两条数据
{
    name: "4",
    email: "[email protected]",
    passWord: "357",
    bio: [
        { head: 123, foot: 456 },
        { head: 456, foot: 789 },
    ],
},
{
    name: "5",
    email: "[email protected]",
    passWord: "258",
    bio: [
        { head: 123, foot: 789 },
        { head: 789, foot: 456 },
    ],
}
const datas = await User.find({ bio: { head: 123, foot: 789 } }); // 数组中含有这个对象就会找到,对象属性要写全,不能只写部分,循序不能修改
const datas = await User.find({ "bio.foot": 789 }); // 数组中只要有一个对象符合就会找到,这里两个都会找到
const datas = await User.find({
    bio: { $elemMatch: { foot: 456, head: { $gt: 100 } } }, // 使用$elemMatch 数组中拥有指定的对象就会找到,可以交换顺序,可以使用限制,但是不能使用正则
});

第二个参数

限制返回数据含有的数据

const data = await User.find({ name: /\d/ }, { name: 1, email: 1, _id: 0 }); // _id默认带着,这里忽略了

第三个参数

可以使用keip limit sort来对查询结果进行操作

const data = await User.find({ name: /\d/ }, null, { skip: 1 }); // 这里只会查找到 2 3

第二三个参数也能用链式调用的方法定义

查询的结果支持链式调用,可以使用一些方法再对结果进行操作,相当于把第二个参数写道外面了

  • select:设置查询结果的数据包含哪些键 接收列明字符串组成的数组,如果字符串前加上-则是不显示

    const datas = await User.find().select(["name", "-_id"]); // 查询所有数据 返回对象只有name
    
  • limit:限制查找结果的长度

  • skip:设置查找结果的起式位置

  • sort:对查找结果排序 接收列名字符串,按照从小到大排序,如果前面加上-则会从大到小排

    const datas = await User.find().sort("-name"); // str 3 2 1
    const datas = await User.find().sort("name"); // 1 2 3 str
    
  • count:返回查找结果的数量

  • lean:将结果返回为普通的js对象而不是查询得到的Mongoose Documents类型对象

常用的内置字段:

字段 说明
$or 或关系
$nor 或关系取反
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$in 在多个值范围内
$nin 不在多个值范围内
$all 匹配数组中多个值
$regex 正则,用于模糊查询
$size 匹配数组大小
$maxDistance 范围查询,距离(基于LBS)
$mod 取模运算
$near 邻域查询,查询附近的位置(基于LBS)
$exists 字段是否存在
$elemMatch 匹配内数组内的元素
$within 范围查询(基于LBS)
$box 范围查询,矩形范围(基于LBS)
$center 范围醒询,圆形范围(基于LBS)
$centerSphere 范围查询,球形范围(基于LBS)
$slice 查询字段集合中的元素(比如从第几个之后,第N到第M个元素

通过Model.findOne方法

该方法返回符合条件的第一条数据

通过Model.findById方法

通过每个数据的_id属性查询


通过Model.remove方法

不传入参数会删除该表的所有数据

该方法返回的是删除数据的条数,不会返回被删除数据

指定要删除数据的某个键,键也可以使用正则表达式

const remove = await User.remove({ name: /\d/ });

也可以先查找,然后用数据的remove方法

// 可以链式调用
const data = await User.find({ name: "1" }).remove();
// 也能迭代删除
const data = await User.find({ name: "2" });
data.forEach((item) => {
    item.remove();
});

通过Model.findOneAndRemove方法

删除符合条件的第一条数据,并将这条数据返回

通过Model.findByIdAndRemove方法

通过_id删除


Model.update已经不支持

通过Model.updateOne Model.updateMany方法

该方法返回修改的信息,不是返回修改后的数据

先指定查询的条件,再在第二个参数放入修改的数据,第三个参数为一些设置

const datas = await User.updateOne({ name: "1" }, { $set: { name: "999" } }); // 将name为1的数据的name改为999

第三个参数如下,一般用不上

键名 默认值 说明
safe true 安全模式
upsert false 是没有这张表时是不是新建数据
setDefaultsOnInsert 如果upsert选项为true,在新建时插入文档定义的默认值
strict 以strict模式进行更新
overwrite false 禁用update-only模式,允许覆盖记录

通过修改find findOne findById找到的数据后调用save方法

const data = await User.find({ name: "999" }); // data只会是一个数组 如果是findOne findById则不是
data.forEach((item) => {
    item.name = "1";
    item.save();
});

通过findOneAndUpdate findByIdAndUpdate方法

是上面的语法糖,获得修改后的数据

Tags: