mogoose 建立資料庫並增刪改查

影依賢者發表於2021-09-25

下載

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: "123@qq.com", passWord: "123" },
    { name: "2", email: "456@qq.com", passWord: "456" },
    { name: "3", email: "789@qq.com", passWord: "789" }
);
res.status(200).json(users); // users是陣列

// 或者
User.create(
    { name: "str", email: "159@163.com", passWord: "159" },
    { name: "1", email: "123@qq.com", passWord: "123" },
    { name: "2", email: "456@qq.com", passWord: "456" },
    { name: "3", email: "789@qq.com", 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: "123@qq.com", passWord: "123" });
const users = await User.insertMany([
    { name: "2", email: "456@qq.com", passWord: "456" },
    { name: "3", email: "789@qq.com", 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: "357@163.com", 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: "357@163.com", passWord: "357", bio: [123, 456, "hahaha"] }
//             { name: "5", email: "258@163.com", 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: "357@163.com",
    passWord: "357",
    bio: [
        { head: 123, foot: 456 },
        { head: 456, foot: 789 },
    ],
},
{
    name: "5",
    email: "258@163.com",
    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 匹配陣列大小
$type 匹配資料的型別
$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方法

現在推薦使用Model.deleteOne Model.deleteMany來刪除 用法一樣

不傳入引數會刪除該表的所有資料

該方法返回的是刪除資料的條數,不會返回被刪除資料

指定要刪除資料的某個鍵,鍵也可以使用正規表示式

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方法

是上面的語法糖,獲得修改後的資料

相關文章