模型

模型 是從 Schema 定義編譯而來的精巧建構函式。模型的一個實例稱為文件。模型負責從底層 MongoDB 資料庫建立和讀取文件。

編譯您的第一個模型

當您對 schema 呼叫 mongoose.model() 時,Mongoose 會為您編譯一個模型。

const schema = new mongoose.Schema({ name: String, size: String });
const Tank = mongoose.model('Tank', schema);

第一個參數是您的模型所針對的集合的單數名稱。Mongoose 會自動查找模型名稱的複數、小寫版本。 因此,對於上面的範例,模型 Tank 是針對資料庫中的 tanks 集合。

注意: .model() 函式會複製 schema。請確保在呼叫 .model() 之前,您已將所有想加入 schema 的內容,包括 hook 都加入!

建構文件

模型的一個實例稱為文件。建立它們並儲存到資料庫很容易。

const Tank = mongoose.model('Tank', yourSchema);

const small = new Tank({ size: 'small' });
await small.save();

// or

await Tank.create({ size: 'small' });

// or, for inserting large batches of documents
await Tank.insertMany([{ size: 'small' }]);

請注意,在您的模型使用的連線開啟之前,不會建立/移除任何 tank。每個模型都有一個相關聯的連線。當您使用 mongoose.model() 時,您的模型將使用預設的 mongoose 連線。

await mongoose.connect('mongodb://127.0.0.1/gettingstarted');

如果您建立自訂連線,請改用該連線的 model() 函式。

const connection = mongoose.createConnection('mongodb://127.0.0.1:27017/test');
const Tank = connection.model('Tank', yourSchema);

查詢

使用 Mongoose 查找文件很容易,它支援 MongoDB 的豐富查詢語法。可以使用 modelfindfindByIdfindOnewhere 靜態函式來檢索文件。

await Tank.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec();

有關如何使用 Query API 的更多詳細資訊,請參閱查詢章節。

刪除

模型具有靜態的 deleteOne()deleteMany() 函式,用於移除所有符合給定 filter 的文件。

await Tank.deleteOne({ size: 'large' });

更新

每個 model 都有自己的 update 方法,用於修改資料庫中的文件,而無需將它們返回到您的應用程式。有關更多詳細資訊,請參閱 API 文件。

// Updated at most one doc, `res.nModified` contains the number
// of docs that MongoDB updated
await Tank.updateOne({ size: 'large' }, { name: 'T-90' });

如果您想更新資料庫中的單個文件並將其返回到您的應用程式,請改用 findOneAndUpdate

變更串流

變更串流為您提供了一種監聽所有通過 MongoDB 資料庫的插入和更新的方法。請注意,除非您連線到 MongoDB 副本集,否則變更串流無法運作。

async function run() {
  // Create a new mongoose model
  const personSchema = new mongoose.Schema({
    name: String
  });
  const Person = mongoose.model('Person', personSchema);

  // Create a change stream. The 'change' event gets emitted when there's a
  // change in the database
  Person.watch().
    on('change', data => console.log(new Date(), data));

  // Insert a doc, will trigger the change stream handler above
  console.log(new Date(), 'Inserting doc');
  await Person.create({ name: 'Axl Rose' });
}

上面 async 函式的輸出將如下所示。

2018-05-11T15:05:35.467Z '正在插入文件' 2018-05-11T15:05:35.487Z '已插入文件' 2018-05-11T15:05:35.491Z { _id: { _data: ... }, operationType: 'insert', fullDocument: { _id: 5af5b13fe526027666c6bf83, name: 'Axl Rose', __v: 0 }, ns: { db: 'test', coll: 'Person' }, documentKey: { _id: 5af5b13fe526027666c6bf83 } }

您可以在這篇部落格文章中閱讀有關 mongoose 中變更串流的更多資訊

視圖

MongoDB 視圖本質上是唯讀集合,其中包含使用聚合從其他集合計算出的資料。在 Mongoose 中,您應該為每個視圖定義單獨的模型。您也可以使用createCollection()建立視圖。

以下範例顯示如何基於 User 模型建立新的 RedactedUser 視圖,該視圖會隱藏潛在的敏感資訊,例如姓名和電子郵件。

// Make sure to disable `autoCreate` and `autoIndex` for Views,
// because you want to create the collection manually.
const userSchema = new Schema({
  name: String,
  email: String,
  roles: [String]
}, { autoCreate: false, autoIndex: false });
const User = mongoose.model('User', userSchema);

const RedactedUser = mongoose.model('RedactedUser', userSchema);

// First, create the User model's underlying collection...
await User.createCollection();
// Then create the `RedactedUser` model's underlying collection
// as a View.
await RedactedUser.createCollection({
  viewOn: 'users', // Set `viewOn` to the collection name, **not** model name.
  pipeline: [
    {
      $set: {
        name: { $concat: [{ $substr: ['$name', 0, 3] }, '...'] },
        email: { $concat: [{ $substr: ['$email', 0, 3] }, '...'] }
      }
    }
  ]
});

await User.create([
  { name: 'John Smith', email: 'john.smith@gmail.com', roles: ['user'] },
  { name: 'Bill James', email: 'bill@acme.co', roles: ['user', 'admin'] }
]);

// [{ _id: ..., name: 'Bil...', email: 'bil...', roles: ['user', 'admin'] }]
console.log(await RedactedUser.find({ roles: 'admin' }));

請注意,Mongoose 目前強制執行視圖為唯讀。如果您嘗試從視圖 save() 文件,您將收到來自 MongoDB 伺服器的錯誤。

還有更多

API 文件涵蓋了許多其他可用的方法,例如 countmapReduceaggregate 等等。

下一步

現在我們已經介紹了 Models,讓我們看一下文件