[mongodb] MongoDB — Mongoose 介紹與使用教學 (下)
範例資料
經由前面新增的資料,資料庫內共有 3 筆資料,現在就來針對這 3 筆資料做查詢吧。
查詢資料
因為語法的使用方式非常多樣,並不會全部介紹到,有興趣的可以看 MongoDB Cheat Sheet。
使用 find 即可將資料庫內的資料全部查詢出來。
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const findData = async () => { try { const user = await User.find(); console.log(user); } catch (error) { console.log(error.message); }};findData();
如要針對特定條件進行搜尋的話,可以使用 MongoDB 本身提供 Operators 查詢語法,如果有想進一步了解的話,可以看官方文檔。
這邊提幾個常用的
- $gt (greater than) : 大於
- $gte (greater than equal) : 大於等於
- $lt (less than) : 小於
- $lte (less than equal) : 小於等於
- $in (in) : 指定範圍匹配的值
- $nin (not in) : 指定範圍不匹配的值
所以如果想查詢 name 為 Wei 與 name 為 Alex 且 age 大於等於 18 的則可以在 find 裡面傳入以下物件參數,
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const findData = async () => { try { const user = await User.find({ name: { $in: ["Wei", "Alex"] }, age: { $gte: 18 }, }); console.log(user); } catch (error) { console.log(error.message); }};findData();
如果 Operators 用不習慣的話,也可以選擇使用類似 Mysql 的 select where,但必須先 where 後才能執行 select。
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const findData = async () => { try { //查詢name為Wei的,查詢到以後只顯示name欄位,其他欄位不要顯示。 const user = await User.where("name").equals("Wei").select("name"); console.log(user); } catch (error) { console.log(error.message); }};findData();
如果希望查詢結果能夠去除不想要的欄位,則可以在 select 語法中加上一個減號 -
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const findData = async () => { try { //查詢name為Wei的,查詢到以後不要把欄位名稱為name的顯示出來。 const user = await User.where("name").equals("Wei").select("-name"); console.log(user); } catch (error) { console.log(error.message); }};findData();
更新資料
要更新資料的話可以使用 updateOne 或 updateMany。
updateOne 的第一個參數是查詢參數,查詢你想要更新的資料後,在第二個參數中傳入你要更改的欄位名稱與欄位值,而如果要開啟驗證機制的話,必需在第三個參數中將驗證機制設置為 true。
使用這兩個 function 的時候要注意,因 updateOne 和 updateMany 的預設驗證機制是關閉的,所以使用這兩個 function 更新資料的話,並不會通過我們在 Schema 建立的驗證規則,而是會直接無視規則更新資料。
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const updateData = async () => { try { let opts = { runValidators: true }; //將驗證機制設置為true const userUpdateLog = await User.updateOne( { name: "Wei" }, //第一個參數 查詢參數 查詢name為Wei的資料 { age: "30" }, //第二個參數 更改參數 將Wei的age改為30 opts //第三個可選參數 將驗證機制設置為true ); console.log(userUpdateLog); } catch (error) { console.log(error.message); }};updateData();
執行後的結果如下,可以看到更動的資料筆數(modifiedCount)為一筆。
可以試試看如果把第三個參數拿掉,並把 age 設定為 23,再去執行檔案會發生什麼事。
刪除資料
要刪除資料的話使用 deleteOne 與 deleteMany。
直接在 deleteOne 與 deleteMany function 中傳入要刪除的資料,一樣是使用查詢語法,查詢到以後將該筆資料刪除。
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const removeData = async () => { try { //只刪除一筆的話使用deleteOne 要一次刪除多筆的話使用 deleteMany const userRemoveLog = await User.deleteOne({ name: "Alex" }); console.log(userRemoveLog); } catch (error) { console.log(error.message); }};removeData();
Schema Methods
Schema 本身也有提供客製化的 function 供我們使用。
const mongoose = require("mongoose");//定義欄位名稱與欄位型態const userSchema = new mongoose.Schema({ name: { type: String, required: true, }, email: { type: String, required: true, minLength: 10, }, age: { type: Number, required: true, min: 1, validate: { // validator為true時,才能通過驗證。 validator: (v) => v % 2 === 0, message: (props) => `${props.value} 並不是偶數`, }, },});//不能用arrow func 因為會用到thisuserSchema.methods.sayHello = function () { console.log( `Hi My name is ${this.name}, age ${this.age}, email ${this.email}` );};//定義Collection的名稱module.exports = mongoose.model("User", userSchema);
接著回到 server.js 先針對資料進行查詢後,再去使用 sayHello function。
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const customFunction = async () => { try { const user = await User.findOne({ name: "Wei" }); user.sayHello(); } catch (error) { console.log(error.message); }};customFunction();
Schema Statics
Statics 則是可以直接自訂 query 的規則。
const mongoose = require("mongoose");//定義欄位名稱與欄位型態const userSchema = new mongoose.Schema({ name: { type: String, required: true, }, email: { type: String, required: true, minLength: 10, }, age: { type: Number, required: true, min: 1, validate: { // validator為true時,才能通過驗證。 validator: (v) => v % 2 === 0, message: (props) => `${props.value} 並不是偶數`, }, },});//找到age大於等於傳入進來的參數userSchema.statics.findByAgeGreaterThanEqual = function (age) { return this.find({ age: { $gte: age } });};//定義Collection的名稱module.exports = mongoose.model("User", userSchema);
接著回到 server.js 直接使用 findByAgeGreaterThanEqual。
const mongoose = require("mongoose");
const User = require("./User");
mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => {
console.log("connected");
});
const customFunction = async () => {
try {
//找到 age 欄位 大於等於 30 的資料
const user = await User.findByAgeGreaterThanEqual(30);
console.log(user);
} catch (error) {
console.log(error.message);
}
};
customFunction();
Schema Query
Query 定義的方法可以接在 find、findOne、where 之後使用,所以先前在 statics 定義的 findByAgeGreaterThanEqual function 也可以使用。
const mongoose = require("mongoose");//定義欄位名稱與欄位型態const userSchema = new mongoose.Schema({ name: { type: String, required: true, }, email: { type: String, required: true, minLength: 10, }, age: { type: Number, required: true, min: 1, validate: { // validator為true時,才能通過驗證。 validator: (v) => v % 2 === 0, message: (props) => `${props.value} 並不是偶數`, }, },});//找到age大於等於傳入進來的參數userSchema.statics.findByAgeGreaterThanEqual = function (age) { return this.find({ age: { $gte: age } });};//chain query 只能在query function後面接著用 例如find findOne whereuserSchema.query.byName = function (name) { return this.where({ name: name }).select(["name", "age"]);};//定義Collection的名稱module.exports = mongoose.model("User", userSchema);
接著回到 server.js 在 findByAgeGreaterThanEqual 之後使用 byNameAndAge。
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const customFunction = async () => { try { const user = await User.findByAgeGreaterThanEqual(30).byName("Wei"); console.log(user); } catch (error) { console.log(error.message); }};customFunction();
Schema Virtual
最後如果要在應用程式內,傳遞查詢出來的值,可以使用 virtual 提供的 get function。
const mongoose = require("mongoose");const userSchema = new mongoose.Schema({ name: String, email: { type: String, required: true, minLength: 10, }, age: { type: Number, min: 1, validate: { validator: (v) => v % 2 === 0, message: (props) => `${props.value} 並不是偶數`, }, },});//cross applicationuserSchema.virtual("namedEmail").get(function () { return `${this.name} <${this.email}>`;});module.exports = mongoose.model("User", userSchema);
直接在查詢後使用即可
const mongoose = require("mongoose");const User = require("./User");mongoose.connect("mongodb://127.0.0.1:27017/testdb", () => { console.log("connected");});const customFunction = async () => { try { const user = await User.findOne({ name: "Wei" }); console.log(user.namedEmail); } catch (error) { console.log(error.message); }};customFunction();