MongoDB:查找与最多标签匹配的文档

5
在我的Meteor应用程序中,我有一个包含大量文档的集合,每个文档都有一个tags字段,基本上是这样的:
{..., tags: ["a","b","c"], ...},
{..., tags: ["a","b","d"], ...},
{..., tags: ["b","c","e"], ...},
{..., tags: ["x","y","z"], ...},
....

现在我想使用一些标签(例如["a","d","y"])在服务器上查询集合,并获取至少匹配一个标签的所有结果,并按匹配标签的数量排序结果集。因此,在示例集中,结果应为:
{..., tags: ["a","b","d"], ...},
{..., tags: ["a","b","c"], ...},
{..., tags: ["x","y","z"], ...}

因为第一个文档有两个匹配项"a""d",而另外两个元素只有一个匹配项"a""y"
目前我知道可以使用$in来匹配至少有一个匹配项的所有文档,可以使用$all获取每个标签都匹配的所有文档,但这似乎不够。如果需要,还可以使用MongoDB的聚合框架。
所需查询是什么样的?
1个回答

6
如果需要,您可以使用mongoDB的聚合框架。您需要使用聚合管道,可以编写如下代码:
- 匹配tags数组中至少有一个匹配值的文档。 - 展开并处理tags数组,因此在每个记录中保留tags数组的副本。 - 展开tags数组。 - 匹配其标记值存在于输入数组中的记录。 - 按_id字段分组,并计算已匹配的文档数。 - 根据它们的匹配数对组进行排序。 - 投影所需字段以及我们创建的原始tags数组副本。
代码:
var inp = ["a","d","y"];

db.collection.aggregate([
{$match:{"tags":{$in:inp}}},
{$project:{"tagsCopy":"$tags","tags":1}},
{$unwind:"$tags"},
{$match:{tags:{$in:inp}}},
{$group:{"_id":"$_id","noOfMatches":{$sum:1},"tags":{$first:"$tagsCopy"}}},
{$sort:{noOfMatches:-1}},
{$project:{"_id":0,"noOfMatches":1,tags:1}} //remove noOfMatches and 
                                            //add other required 
                                            //fields which are necessary.
])

输出:

{ "noOfMatches" : 2, "tags" : [ "a", "b", "d" ] }
{ "noOfMatches" : 1, "tags" : [ "x", "y", "z" ] }
{ "noOfMatches" : 1, "tags" : [ "a", "b", "c" ] }

非常欢迎。;-) 作为一个附加问题,当Meteor对聚合的支持非常有限时,您为什么选择Meteor而不是Node.js? - BatScream
1
https://atmospherejs.com/meteorhacks/aggregate <-- 举个例子。Meteor中的聚合功能工作得还不错。使用Meteor的重点是我的应用程序概念,除了这个查询。许多客户端计算分布在活跃用户和(软)实时能力上。(类似新闻汇编器)。 - Maximilian Stroh
1
跟进:在整个管道中完全跳过$tagsCopy(因此仅使用tags、_id和sum)将处理2300个文档的时间从1300毫秒降至<=12毫秒(每个文档约有15个标签)。相当令人印象深刻。在2013年早期的rMBP上进行了测试。 - Maximilian Stroh
我有一个类似的集合,{"_id": "test-id", {"val" {"tags": ["a", "b", "c"]}}}。我该如何查询它? - Harish Kommuri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接