下載
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 Model document概念
schema:表的結構,索引Model:使用Schema實例獲得的具體的表,在這上面對表進行增刪改查document:Model實例,相當於表中的每一條數據,Model中查到到的數據也是這種類型
創建表結構Schema
Schema相當於MySql的表結構
通過定義Schema來約束數據的類型,支持以下類型數據
| 類型 | 作用 |
|---|---|
| String | 定義字符串 |
| Number | 定義數字 |
| Date | 定義日期 |
| Buffer | 定義二進制 |
| Boolean | 定義布爾值 |
| Mixed | 定義混合類型 |
| ObjectId | 定義對象ID |
| Array | 定義數組 |
| Decimal128 | 定義小數 |
| Map |
約束能用對象的方法描述數據類型 是否必須 是否重復 默認值 等,如下定義了一個用戶表結構
注意:如果定義表結構時沒有定義
_id,mongoose會自己添加一個該字段,該字段不會重復,類型為ObjectId,通過findById()查詢在定義表結構時某些字段,如unique會自動創建索引,詳情見下章
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 數組中擁有指定的對象就會找到,可以交換順序,可以使用限制,但是不能直接使用正則,正則使用$regex
});
第二個參數
限制返回數據含有的數據
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方法
是上面的語法糖,獲得修改后的數據
