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

Javascript 有没有办法找到一个匹配两个不同填充的文档并在findOne()中获取他的文档?,javascript,node.js,mongodb,mongoose,mongodb-query,Javascript,Node.js,Mongodb,Mongoose,Mongodb Query,我将mongoose与mongoDb/nodejs组合使用。我想找到一份有条件的文件 这是我的模式: var prognosticSchema = new Schema({ userRef : { type : Schema.Types.ObjectId, ref : 'users'}, matchRef : { type : Schema.Types.ObjectId, ref : 'match'}, ... }); 模型架构'users'包含字符串“email”,模

我将mongoose与mongoDb/nodejs组合使用。我想找到一份有条件的文件

这是我的模式

var prognosticSchema = new Schema({
    userRef : { type : Schema.Types.ObjectId, ref : 'users'},
    matchRef : { type : Schema.Types.ObjectId, ref : 'match'},
    ...
});
模型架构'users'包含字符串“email”,模型'match'包含数字“id\u match”,如下所示:

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

我的目标是找到一个包含id\u匹配和电子邮件的文档

我试过这个:

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 ...
        }
当我运行这段代码并尝试获取正确的文档时,我知道在我的数据库中还有许多其他用户的预测模式并与之匹配,我将在数据文档中以null和correct分别获得userRef

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

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

好的,您可以在同一个查询中包含“这两个”
填充
表达式,当然,因为您实际上想要“匹配”包含在“引用”中的属性集合这意味着从“父项”返回的实际数据需要首先查看“所有父项”,以便填充数据:

prognoSchema.find()
.填充([
{ 
“路径”:“userRef”,
“匹配”:{“电子邮件”:请求标题['x-key']}
},
{ 
“路径”:“matchRef”,
“匹配”:{“id_match”:id_match}
}
]).exec(函数(错误、数据){
/* 
数据包含整个集合,因为没有
条件存在。但填充的引用不存在
匹配项现在为空。因此.filter()将它们:
*/
数据=数据.过滤器(函数(文档){
返回(doc.userRef!=null&&doc.matchRef!=null);
});
//数据现在只包含匹配的项
})
这并不理想,但这正是使用“引用”数据的工作原理

更好的方法是“单独”搜索其他集合中的单个匹配项,然后将找到的
\u id
值提供给“父”集合。这里提供了一些帮助,以便于在使用匹配值对父查询执行之前等待其他查询的结果。可以通过多种方式完成,但这看起来相对干净:

async.parallel(
{
“userRef”:函数(回调){
findOne({“email”:req.headers['x-key']},回调);
},
“id_匹配”:函数(回调){
findOne({“id\u Match”:id\u Match},回调);
}
},
函数(错误、结果){
芬多诺方案({
“userRef”:result.userRef.\u id,
“matchRef”:result.id\u match.\u id
}).填充([
{“path”:“userRef”,“match”:{“email”:req.headers['x-key']},
{“path”:“matchRef”,“match”:{“id_match”:id_match}
]).exec(函数(错误,程序号){
//仅匹配和填充数据
})
}
)
作为替代方案,在3.2及以后的现代MongoDB版本中,您可以使用聚合运算符:

prognoSchema.aggregate(
[
//$lookup查找userRef数据
{“$lookup”:{
“发件人”:“用户”,
“localField”:“userRef”,
“外域”:“\u id”,
“as”:“userRef”
}},
//目标是一个数组,所以$unwind
{“$unwind”:“$userRef”},
//然后过滤掉任何不匹配的内容
{“$match”:{
“userRef.email”:请求标题['x-key']
}},
//$lookup查找matchRef数据
{“$lookup”:{
“来自”:“匹配项”,
“localField”:“matchRef”,
“外域”:“\u id”,
“as”:“matchRef”
}},
//目标是一个数组,所以$unwind
{“$REWIND”:“$matchRef”},
//然后过滤掉任何不匹配的内容
{“$match”:{
“matchRef.id\u match”:id\u match
}}
],
功能(err、prognos){
}
)
但同样丑陋,因为“源”仍然在选择所有内容,并且在每次操作之后,您只是逐渐过滤出结果

这里的基本前提是“MongoDB不真正执行连接,
.populate()
也不是“连接”,只是对相关集合的附加查询。因为这“不是”一个“连接”,所以在检索到实际的相关数据之前,没有办法过滤掉“父级”。即使是在“服务器”上通过而不是在“客户端”上通过
.populate()

因此,如果您“必须”以这种方式进行查询,通常最好“首先”查询其他集合的结果,然后根据匹配的
\u id
属性值作为参考来匹配“父项”


但是这里的另一个例子是,你应该考虑“嵌入”数据,而你想在这些属性上“查询”。strong>只有当数据位于“单个集合”中时,MongoDB才可以通过单个查询和性能操作查询并匹配这些条件。

我已经在API中使用了async,我应该使用async.parallel来获取我想要的文档。真棒的回答,非常感谢@neil lunn
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 ...
        }