有没有办法find一个匹配两个不同的填充文件,并在findOne()中获取他的文档?

我用mongoose与组合mongoDb / nodejs。 我想找一个具有一定条件的文档。

有我的模式

var prognosticSchema = new Schema({ userRef : { type : Schema.Types.ObjectId, ref : 'users'}, matchRef : { type : Schema.Types.ObjectId, ref : 'match'}, ... }); 

模型模式“用户”包含一个string“电子邮件” ,模型“匹配”包含一个数字“id_match”像这样:

 var userSchema = new Schema({ email: String, ... }); 

然后

 var matchSchema = new Schema({ id_match: {type: Number, min: 1, max: 51}, ... }); 

我的目标是find一个文档,其中包含一个id_match = id_match和一个email = req.headers ['x-key']

我试过这个:

 var prognoSchema = require('../db_schema/prognostic'); // require prognostics require('../db_schema/match'); // require match to be able to populate var prognoQuery = prognoSchema.find() .populate({path: 'userRef', // populate userRef match : { 'email' : req.headers['x-key'] // populate where email match with email in headers of request (I'm using Express as node module) }, select : 'email pseudo' }); prognoQuery.findOne() // search for only one doc .populate({path: 'matchRef', // populate match match: { 'id_match': id_match // populate match where id_match is correct }}) .exec(function(err, data) { ... // Return of value as response ... } 

当我运行这个代码,并尝试获取正确的文档,知道其他与这样的其他用户的其他prognosticSchema ,并在我的数据库匹配 ,我会得到userRef为空,正确matchRef在我的数据文档。

在我的数据库中,有其他用户和其他用户 id_match,但是我希望在我的模式中通过这两个objectId帮助的findOne()中获得正确的文档。

有没有办法findOne()匹配两个不同的填充文件,并在findOne()中获取他的文档?

那么你可以在同一个查询中包含“两个” populateexpression式,但是当然,因为你实际上想要“包含在”引用“集合中的属性”匹配“,这意味着从”父“返回的实际数据将需要首先看“所有父母”以填充数据:

 prognoSchema.find() .populate([ { "path": "userRef", "match": { "email": req.headers['x-key'] } }, { "path": "matchRef", "match": { "id_match": id_match } } ]).exec(function(err,data) { /* data contains the whole collection since there was no condition there. But populated references that did not match are now null. So .filter() them: */ data = data.filter(function(doc) { return ( doc.userRef != null && doc.matchRef != null ); }); // data now contains only those item(s) that matched }) 

这不是理想的,但是它是如何使用“引用”数据的作品。

一个更好的方法是search其他集合“个人”单匹配,然后提供find的_id值到“父”集合。 从async.parallel这里得到一点帮助,以便在父对象上执行匹配的值之前等待其他查询的结果。 可以用各种方式完成,但是这看起来比较干净:

 async.parallel( { "userRef": function(callback) { User.findOne({ "email": req.headers['x-key'] },callback); }, "id_match": function(callback) { Match.findOne({ "id_match": id_match },callback); } }, function(err,result) { prognoSchema.findOne({ "userRef": result.userRef._id, "matchRef": result.id_match._id }).populate([ { "path": "userRef", "match": { "email": req.headers['x-key'] } }, { "path": "matchRef", "match": { "id_match": id_match } } ]).exec(function(err,progno) { // Matched and populated data only }) } ) 

作为替代,从3.2版本开始,在现代的MongoDB版本中,您可以使用$lookup aggregation操作符:

 prognoSchema.aggregate( [ // $lookup the userRef data { "$lookup": { "from": "users", "localField": "userRef", "foreignField": "_id", "as": "userRef" }}, // target is an array always so $unwind { "$unwind": "$userRef" }, // Then filter out anything that does not match { "$match": { "userRef.email": req.headers['x-key'] }}, // $lookup the matchRef data { "$lookup": { "from": "matches", "localField": "matchRef", "foreignField": "_id", "as": "matchRef" }}, // target is an array always so $unwind { "$unwind": "$matchRef" }, // Then filter out anything that does not match { "$match": { "matchRef.id_match": id_match }} ], function(err,prognos) { } ) 

但是同样难看,因为“源代码”仍在select所有内容,并且在每次$lookup操作之后,您只是逐渐筛选出结果。

这里的基本前提是“MongoDB并不真正”执行连接“ ,也不是”连接“,而是对相关集合进行额外的查询。 由于这是“不是”“联合”,所以在检索实际相关数据之前无法过滤“父”。 即使它是通过$lookup在“服务器”上完成的,而不是在“client”上通过.populate()

因此,如果您必须以这种方式进行查询,通常最好先查询其他集合中的结果“first”,然后根据匹配的_id属性值作为参考匹配“parent”。

但是另一种情况是,你应该“考虑”embedded数据,而不是“你”在这些属性上“查询”。 只有当数据驻留在“单个集合”中时,MongoDB才能查询这些条件并将其与单个查询和高性能操作进行匹配。