查找数组A至少包含数组B中X值的条目

Wil*_*yor 4 mongodb nosql

我有一个对象集合,每个对象都有一个名为fingerprint的字段,其中包含20个哈希:

{
    title: 'The Chronicles of Narnia',
    authors: ['C.S. Lewis'],
    fingerprint: ['50e...', 'ae2...', ...]
}
Run Code Online (Sandbox Code Playgroud)

然后我有另外20个哈希的查询指纹.我想做的是找到至少共享X哈希值的所有条目.换句话说,两个阵列的交叉点必须是一定的大小.

我有一个使用MySQL的类似系统的旧实现.查询看起来像这样:

SELECT *
FROM Document d
INNER JOIN Fingerprint f
    ON d.id = f.document_id
WHERE f.whorl IN (:hashes)
GROUP BY d.id
HAVING COUNT(d.id) >= X
Run Code Online (Sandbox Code Playgroud)

表中的每个条目都Fingerprint包含文档ID和指纹中的单个轮廓.Fingerprint每个文档将有20个条目.

据我所知,这个查询正在做的是每次旋转匹配然后按唯一文档分组时复制文档.这似乎有点浪费,但它确实有效.

我正试图在MongoDB中重新实现这个系统,但我运气不好.我可以获得至少共享一个或所有轮​​生的所有条目的列表:

at least one: db.objects.find({ fingerprint: {$in: [hashes]})
         all: db.objects.find({ fingerprint: {$all: [hashes]})
Run Code Online (Sandbox Code Playgroud)

我知道我可以在应用程序层中扫描此列表以查找我之后的匹配项.如果我预计有数百万件物品(目前约为150万件),那么这似乎是一个坏主意.

我已经查看了aggregate()功能但无法改进我已有的功能:

db.objects.aggregate({$match: {fingerprint: {$in: [hashes]}}})
Run Code Online (Sandbox Code Playgroud)

从这里我想我可以分组和过滤:

db.objects.aggregate({$match: {fingerprint: {$in: [hashes]}}}, 
                     {$group: {_id: "$_id", matches: {$sum: 1}}})
Run Code Online (Sandbox Code Playgroud)

在这里,我试图复制MySQL查询的作用:为每个匹配发出一个文档然后计算文档.当然,无论有多少匹配,我们只会发出一次文档.

然后我想到$unwind匹配的列表,但每次产生20个文档.

理想情况下,$some我可以使用这样的运算符:

db.objects.find(fingerprint: {$some: {from: [hashes], count: X}})
Run Code Online (Sandbox Code Playgroud)

这样的事情可能有效吗?我希望能够运行这些查询以响应用户的搜索,所以我想MapReduce是不可能的?

谢谢

Asy*_*sky 5

用聚合框架做你想做的事实际上非常简单.我相信你将能够完善以下内容以完全满足您的需求:

db.objects.aggregate([
    {$unwind : "$fingerprint" },
    {$match  : {fingerprint : {$in: [hashes] } } },
    {$group  : {_id:"$title", numMatches: {$sum:1} } },
    {$match  : {numMatches : {$gt: X} } }
])
Run Code Online (Sandbox Code Playgroud)