我需要帮助才能解决以下问题。我的收藏品有一个“目标”字段。
每个用户可以拥有0个或更多目标。
当我运行查询时,我想检索具有最大匹配目标数的文档。
例如:
documents=[{
targets:{
"cluster":"01",
}
},{
targets:{
"cluster":"01",
"env":"DC",
"core":"PO"
}
},{
targets:{
"cluster":"01",
"env":"DC",
"core":"PO",
"platform":"IG"
}
}];
userTarget={
"cluster":"01",
"env":"DC",
"core":"PO"
}
答案 0 :(得分:0)
您似乎要求返回满足最多条件的文档,并且可能不是所有条件。基本过程是$or
查询,用于返回可以匹配任一条件的文档。那么你基本上需要一个语句来计算"文档中满足多少个术语" ,并返回最匹配的术语。
所以这里的组合是一个.aggregate()
语句,使用$or
的初始结果来计算然后对结果进行排序:
// initial targets object
var userTarget = {
"cluster":"01",
"env":"DC",
"core":"PO"
};
// Convert to $or condition
// and the calcuation condition to match
var orCondition = [],
scoreCondition = []
Object.keys(userTarget).forEach(function(key) {
var query = {},
cond = { "$cond": [{ "$eq": ["$target." + key, userTarget[key]] },1,0] };
query["target." + key] = userTarget[key];
orCondition.push(query);
scoreCondition.push(cond);
});
// Run aggregation
Model.aggregate(
[
// Match with condition
{ "$match": { "$or": orCondition } },
// Calculate a "score" based on matched fields
{ "$project": {
"target": 1,
"score": {
"$add": scoreCondition
}
}},
// Sort on the greatest "score" (descending)
{ "$sort": { "score": -1 } },
// Return the first document
{ "$limit": 1 }
],
function(err,result) {
// check errors
// Remember that result is an array, even if limitted to one document
console.log(result[0]);
}
)
因此,在处理聚合语句之前,我们将根据userTarget
对象中的输入生成管道操作的动态部分。这会产生orCondition
,如下所示:
{ "$match": {
"$or": [
{ "target.cluster" : "01" },
{ "target.env" : "DC" },
{ "target.core" : "PO" }
]
}}
scoreCondition
会扩展为这样的编码:
"score": {
"$add": [
{ "$cond": [{ "$eq": [ "$target.cluster", "01" ] },1,0] },
{ "$cond": [{ "$eq": [ "$target.env", "DC" ] },1,0] },
{ "$cond": [{ "$eq": [ "$target.core", "PO" ] },1,0] },
]
}
这些将用于选择可能的文件,然后用于计算可能匹配的术语。特别是"得分"通过评估$cond
三元运算符中的每个条件,然后将得分1
归因于匹配,或0
得出该字段上没有匹配的结果。
如果需要,可以很容易地改变逻辑以分配更高的重量"根据所认为的比赛重要性,向具有不同值的每个场进行得分。无论如何,您只需$add
将这些得分结果一起用于整个"得分"的每个字段。
然后,只需将$sort
应用于返回的"得分",然后使用$limit
返回顶部文档。
它不是超级高效的,因为即使所有三个条件都匹配,您要求数据的基本问题也不能假设存在,因此需要查看的所有数据"至少有一个" 条件匹配,然后从那些可能的结果中找出"最佳匹配" 。
理想情况下,我会亲自运行一个额外的查询"首先"查看是否满足所有三个条件,如果没有,则查找其他情况。这仍然是两个单独的查询,并且不同于简单地只是推动"和"所有字段的条件作为$or
中的第一个语句。
所以我认为首选的实现应该是:
查找与所有给定字段值匹配的文档;如果不是那么
运行每个/或每个字段并计算条件匹配。
这样,如果所有字段匹配,那么第一个查询最快,只需要回退到列表中显示的较慢但必需的实现,如果没有实际结果。