使用“node.js”的底线是您需要实现“回调”或“承诺”来解决来自先前查询操作的异步响应。这基本上是必需的,因为您首先需要从其他集合中“查询”您想要的项目,然后再将这些项目“添加”到您的相关对象。
这是async.waterfall 的示例,它可用于将先前查询的结果“传入”另一个参数:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
var letterSchema = new Schema({
name: { type: String, required: true, unique: true },
type: { type: String, enum: ['consonant','vowel'] }
});
var favoriteSchema = new Schema({
name: { type: String, required: true },
letters: [{ type: Schema.Types.ObjectId, ref: 'Letter' }]
});
var Letter = mongoose.model( 'Letter', letterSchema ),
Favorite = mongoose.model( 'Favorite', favoriteSchema );
mongoose.connect('mongodb://localhost/test');
mongoose.set("debug",true);
async.series(
[
function(callback) {
async.each([Letter,Favorite],function(model,callback) {
model.remove({},callback);
},callback);
},
function(callback) {
async.each(
[
{ "name": "a", "type": "vowel" },
{ "name": "b", "type": "consonant" },
{ "name": "c", "type": "consonant" }
],
function(letter,callback) {
Letter.create(letter,callback);
},
callback
);
},
function(callback) {
Favorite.create({ "name": "mine" },callback);
},
function(callback) {
async.waterfall(
[
function(callback) {
Letter.find({ "name": { "$in": ["a","c"] } },callback);
},
function(letters,callback) {
Favorite.findOneAndUpdate(
{ "name": "mine" },
{ "$push": { "letters": { "$each": letters } } },
{ "new": true },
callback
);
}
],
callback
)
},
function(callback) {
Favorite.find().populate('letters').exec(function(err,docs) {
console.log(docs);
callback(err)
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
它提供了很好的输出,例如:
[ { _id: 55eed7dfc7b23b7c4838903b,
name: 'mine',
__v: 0,
letters:
[ { _id: 55eed7dfc7b23b7c48389038,
name: 'a',
type: 'vowel',
__v: 0 },
{ _id: 55eed7dfc7b23b7c4838903a,
name: 'c',
type: 'consonant',
__v: 0 } ] } ]
请注意列表中的行:
{ "$push": { "letters": { "$each": letters } } }
在使用的.findOneAndUpdate() 方法中,$push 运算符将“原子地”附加到文档中已经存在的数组,而$each 修饰符允许它接受参数的“数组”,而不是到要附加的单个对象。
Mongoose 还处理从先前的 .find() 返回的“对象”的“转换”,以插入架构所需的 _id 值。整个async.waterfall 进程也将先前结果回调的返回值传递到函数的下一个阶段。
那个“最后”基本上比写这个“更好”:
Letter.find({ "name": { "$in": ["a","c"] } },function(err,docs) {
Favourite.findOneAndUpdate(
{ "name": "mine" },
{ "$push": { "letters": { "$each": letters } } },
{ "new": true },
function(err,result) {
console.log(result);
}
);
});
“缩进蠕变”令人讨厌。
所以“底线”再次是您需要先.find() 结果,然后在“更新”操作中“使用”这些结果以附加到数组。有多种方法可以做到这一点,但使用“原子”$push 是性能和可靠性的最佳选择。
除了创建一个集合来存储“字母”详细信息的一般“实用性”以及使用 ObjectId 而不是字母本身的自然“键”作为链接的东西之外,这是如何处理。