模型

¥Models

模型 是从 Schema 定义编译而来的奇特构造函数。模型的一个实例称为 document。模型负责从底层 MongoDB 数据库创建和读取文档。

¥Models are fancy constructors compiled from Schema definitions. An instance of a model is called a document. Models are responsible for creating and reading documents from the underlying MongoDB database.

编译你的第一个模型

¥Compiling your first model

当你在结构上调用 mongoose.model() 时,Mongoose 会为你编译一个模型。

¥When you call mongoose.model() on a schema, Mongoose compiles a model for you.

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

第一个参数是模型所属集合的单一名称。Mongoose 会自动查找模型名称的复数小写版本。因此,对于上面的示例,模型 Tank 用于数据库中的坦克集合。

¥The first argument is the singular name of the collection your model is for. Mongoose automatically looks for the plural, lowercased version of your model name. Thus, for the example above, the model Tank is for the tanks collection in the database.

注意:.model() 函数复制 schema。在调用 .model() 之前,请确保你已将所需的所有内容添加到 schema,包括钩子!

¥Note: The .model() function makes a copy of schema. Make sure that you've added everything you want to schema, including hooks, before calling .model()!

构建文档

¥Constructing Documents

模型的一个实例称为 document。创建它们并将其保存到数据库很容易。

¥An instance of a model is called a document. Creating them and saving to the database is easy.

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' }]);

请注意,在模型使用的连接打开之前,不会创建/删除任何水箱。每个模型都有一个关联的连接。当你使用 mongoose.model() 时,你的模型将使用默认的 mongoose 连接。

¥Note that no tanks will be created/removed until the connection your model uses is open. Every model has an associated connection. When you use mongoose.model(), your model will use the default mongoose connection.

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

如果你创建自定义连接,请改用该连接的 model() 函数。

¥If you create a custom connection, use that connection's model() function instead.

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

查询

¥Querying

使用 Mongoose 查找文档很容易,它支持 MongoDB 的 rich 查询语法。可以使用 modelfindfindByIdfindOnewhere 静态函数检索文档。

¥Finding documents is easy with Mongoose, which supports the rich query syntax of MongoDB. Documents can be retrieved using a model's find, findById, findOne, or where static functions.

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

有关如何使用 查询 api 的更多详细信息,请参阅有关 queries 的章节。

¥See the chapter on queries for more details on how to use the Query api.

删除

¥Deleting

模型具有静态 deleteOne()deleteMany() 函数,用于删除与给定 filter 匹配的所有文档。

¥Models have static deleteOne() and deleteMany() functions for removing all documents matching the given filter.

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

更新

¥Updating

每个 model 都有自己的 update 方法,用于修改数据库中的文档而不将它们返回到你的应用。有关更多详细信息,请参阅 API 文档。

¥Each model has its own update method for modifying documents in the database without returning them to your application. See the API docs for more detail.

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

如果你想更新数据库中的单个文档并将其返回到你的应用,请改用 查找并更新

¥If you want to update a single document in the db and return it to your application, use findOneAndUpdate instead.

改变流

¥Change Streams

改变流 为你提供了一种监听 MongoDB 数据库中所有插入和更新的方法。请注意,除非你连接到 MongoDB 副本集,否则更改流不起作用。

¥Change streams provide a way for you to listen to all inserts and updates going through your MongoDB database. Note that change streams do not work unless you're connected to a MongoDB replica set.

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' });
}

上述 异步函数 的输出将如下所示。

¥The output from the above async function will look like what you see below.

2018-05-11T15:05:35.467Z 'Inserting doc' 2018-05-11T15:05:35.487Z 'Inserted doc' 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 中的流 的更多信息。

¥You can read more about change streams in mongoose in this blog post.

意见

¥Views

MongoDB 视图 本质上是只读集合,其中包含使用 aggregations 从其他集合计算得出的数据。在 Mongoose 中,你应该为每个视图定义一个单独的模型。你还可以使用 createCollection() 创建视图。

¥MongoDB Views are essentially read-only collections that contain data computed from other collections using aggregations. In Mongoose, you should define a separate Model for each of your Views. You can also create a View using createCollection().

以下示例展示了如何在 User 模型上创建新的 RedactedUser 视图,以隐藏潜在的敏感信息,例如名称和电子邮件。

¥The following example shows how you can create a new RedactedUser View on a User Model that hides potentially sensitive information, like name and email.

// 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 服务器收到错误。

¥Note that Mongoose does not currently enforce that Views are read-only. If you attempt to save() a document from a View, you will get an error from the MongoDB server.

还有更多

¥Yet more

API 文档 涵盖了许多可用的附加方法,例如 countmapReduceaggregate 等。

¥The API docs cover many additional methods available like count, mapReduce, aggregate, and more.

下一步

¥Next Up

现在我们已经介绍了 Models,让我们来看看 文档

¥Now that we've covered Models, let's take a look at Documents.