Mongoose模型的很多类方法都不能直接返回查询或操作结果,其会返回一个Query对象,我们需要从Query对象中获取操作结果。Query对象是一个链式查询,我们可以在查询过程中引用其它文档,也可以流式的传输查询结果。
1. Queries
Mongoose的模型(Model)为CRUD操作提供了几个静态辅助函数,这些函数中的每个操作都会返回一个mongoose Query对象。
Model.deleteMany()Model.deleteOne()Model.find()Model.findById()Model.findByIdAndDelete()Model.findByIdAndRemove()Model.findByIdAndUpdate()Model.findOne()Model.findOneAndDelete()Model.findOneAndRemove()Model.findOneAndUpdate()Model.replaceOne()Model.updateMany()Model.updateOne()
以上操作都会返回Query对象,该对象默认不会执行查询。可以通过以下两种方式之一执行mongoose查询:
传入回调函数
传入回调函数时,相关操作会立即执行,并会将查询结果传递给回调。
使用回调函数执行查询时,将查询指定为JSON文档。JSON文档的语法与MongoDB shell相同。
var Person = mongoose.model('Person', yourSchema);
// find each person with a last name matching 'Ghost', selecting the `name` and `occupation` fields
Person.findOne({ 'name.last': 'Ghost' }, 'name occupation', function (err, person) {
if (err) return handleError(err);
// Prints "Space Ghost is a talk show host".
console.log('%s %s is a %s.', person.name.first, person.name.last,
person.occupation);
});
如上所示,传入回调函数后查询会立即执行,其结果也会传入到回调函数中。在Mongoose中,所有的回调函数的格式都是:callback(error, result)。如果执行查询时发生错误,error参数中会包含错误文档,而result会是null;如果查询成功,error会是null,result会使用查询结果填充。
无论何时将回调传递给Mongoose中的查询,回调的格式都是callback(error, results)。而results取决于具体的操作:对于findOne(),会是一个可能为null的单文档;find()会是文档列表;count()为文档数;update()则为受影响的文档数等。可以通过Model API 查看有关传递给回调的更多详细信息。
.exec()方法
查询还有又.then()函数,因此可以作为promise。
没有传入callback时,可以像下面这样获取查询结果:
// 查找 last name 为 'Ghost' 的 person
var query = Person.findOne({ 'name.last': 'Ghost' });
// 仅查询 `name` 和 `occupation` 字段
query.select('name occupation');
// 稍后执行查询,并通过 callback 获取查询结果
query.exec(function (err, person) {
if (err) return handleError(err);
// Prints "Space Ghost is a talk show host."
console.log('%s %s is a %s.', person.name.first, person.name.last,
person.occupation);
});
// 或者通过 .then() 获取查询结果
query.exec().then((person) => {
// Prints "Space Ghost is a talk show host."
console.log('%s %s is a %s.', person.name.first, person.name.last,
person.occupation);
}).catch((err) => {
handleError(err);
})
如上所示,query变量是一个Query实例。Query允许你使用链式语法构建查询,而不仅是指定JSON对象。以下2个示例是等效的:
// With a JSON doc
Person.
find({
occupation: /host/,
'name.last': 'Ghost',
age: { $gt: 17, $lt: 66 },
likes: { $in: ['vaporizing', 'talking'] }
}).
limit(10).
sort({ occupation: -1 }).
select({ name: 1, occupation: 1 }).
exec(callback);
// Using query builder
Person.
find({ occupation: /host/ }).
where('name.last').equals('Ghost').
where('age').gt(17).lt(66).
where('likes').in(['vaporizing', 'talking']).
limit(10).
sort('-occupation').
select('name occupation').
exec(callback);
2. Queries不是Promise
Mongoose查询不是Promise。它们有.then()方法以便于co和async/await使用。 但是,与Promise不同,调用query的.then()可以多次执行查询。
在下例中,updateMany()会执行3次,一次是因为回调函数,而两次是因为.then():
const q = MyModel.updateMany({}, { isDeleted: true }, function() {
console.log('Update 1');
});
q.then(() => console.log('Update 2'));
q.then(() => console.log('Update 3'));
不要在查询中混合使用回调和promise,因为可能会引起重复操作。
3. 引用其它文档
MongoDB中没有连接查询,但有时我们仍然希望引用其他集合中的文档。这时可通过填充( population)来实现。更多关于如何在查询结果中包含其他集合中的文档Query#populate() 。
4. 流
Mongoose支持从MongoDB中流式传输查询结果,需要调用Query#cursor()方法来返回QueryCursor的实例。
下一步
现在我们已经介绍了Queries,接下来让我们来看看验证-Validation。
变更记录
- [2018-12-03] 基于Mongoose官方文档
v5.3.12首次发布
