MongoDB嵌套数组交集查询

2024-01-12

并提前感谢您的帮助。 我有一个 mongoDB 数据库,其结构如下:

{
  '_id' : objectID(...),

  'userID' : id,

  'movies' : [{

       'movieID' : movieID,

       'rating' : rating
   }]
 }

我的问题是:

我想搜索具有 'userID' : 3 的特定用户,例如,获取所有都是电影,然后我想获取至少拥有 15 部或更多具有相同 'movieID' 的电影的所有其他用户,然后对于该组,我只想选择具有这 15 部相似电影并且具有我选择的额外“movieID”的用户。

我已经尝试过聚合,但失败了,如果我执行单个查询(例如从用户处获取所有用户电影),则循环每个用户电影并进行比较需要大量时间。

有什么想法吗?

谢谢


使用聚合框架有几种方法可以做到这一点

只是一组简单的数据,例如:

{
    "_id" : ObjectId("538181738d6bd23253654690"),
    "movies": [
        { "_id": 1, "rating": 5 },
        { "_id": 2, "rating": 6 },
        { "_id": 3, "rating": 7 }
    ]
},
{
    "_id" : ObjectId("538181738d6bd23253654691"),
    "movies": [
        { "_id": 1, "rating": 5 },
        { "_id": 4, "rating": 6 },
        { "_id": 2, "rating": 7 }
    ]
},
{
    "_id" : ObjectId("538181738d6bd23253654692"),
    "movies": [
        { "_id": 2, "rating": 5 },
        { "_id": 5, "rating": 6 },
        { "_id": 6, "rating": 7 }
    ]
}

以第一个“用户”为例,现在您想要查找其他两个用户中是否有至少两个相同的电影。

对于 MongoDB 2.6 及更高版本,您可以简单地使用$setIntersection http://docs.mongodb.org/manual/reference/operator/aggregation/setIntersection/运算符以及$size http://docs.mongodb.org/manual/reference/operator/aggregation/size/操作员:

db.users.aggregate([

    // Match the possible documents to reduce the working set
    { "$match": {
        "_id": { "$ne": ObjectId("538181738d6bd23253654690") },
        "movies._id": { "$in": [ 1, 2, 3 ] },
        "$and": [
            { "movies": { "$not": { "$size": 1 } } }
        ]
    }},

    // Project a copy of the document if you want to keep more than `_id`
    { "$project": {
        "_id": {
            "_id": "$_id",
            "movies": "$movies"
        },
        "movies": 1,
    }},

    // Unwind the array
    { "$unwind": "$movies" },

    // Build the array back with just `_id` values
    { "$group": {
        "_id": "$_id",
        "movies": { "$push": "$movies._id" }
    }},

    // Find the "set intersection" of the two arrays
    { "$project": {
        "movies": {
            "$size": {
                "$setIntersection": [
                   [ 1, 2, 3 ],
                   "$movies"
                ]
            }
        }
    }},

    // Filter the results to those that actually match
    { "$match": { "movies": { "$gte": 2 } } }

])

在没有这些运算符的早期版本的 MongoDB 中,这仍然是可能的,只需使用几个步骤:

db.users.aggregate([

    // Match the possible documents to reduce the working set
    { "$match": {
        "_id": { "$ne": ObjectId("538181738d6bd23253654690") },
        "movies._id": { "$in": [ 1, 2, 3 ] },
        "$and": [
            { "movies": { "$not": { "$size": 1 } } }
        ]
    }},

    // Project a copy of the document along with the "set" to match
    { "$project": {
        "_id": {
            "_id": "$_id",
            "movies": "$movies"
        },
        "movies": 1,
        "set": { "$cond": [ 1, [ 1, 2, 3 ], 0 ] }
    }},

    // Unwind both those arrays
    { "$unwind": "$movies" },
    { "$unwind": "$set" },

    // Group back the count where both `_id` values are equal
    { "$group": {
        "_id": "$_id",
        "movies": {
           "$sum": {
               "$cond":[
                   { "$eq": [ "$movies._id", "$set" ] },
                   1,
                   0
               ]
           }
        } 
    }},

    // Filter the results to those that actually match
    { "$match": { "movies": { "$gte": 2 } } }
])

详细

这可能有点难以理解,所以我们可以看看每个阶段并将其分解,看看他们在做什么。

$match:您不想对集合中的每个文档进行操作,因此这是一个删除可能不匹配的项目的机会,即使仍然需要做更多工作来查找exact那些。因此,显而易见的事情是排除相同的“用户”,然后仅匹配至少具有与为该“用户”找到的相同电影的一部的文档。

接下来有意义的事情是考虑当你想要匹配时n条目则仅包含“电影”数组大于的文档n-1实际上可能包含匹配项。指某东西的用途$and这里看起来很有趣并且没有特别要求,但是如果所需的匹配是4那么该语句的实际部分将如下所示:

        "$and": [
            { "movies": { "$not": { "$size": 1 } } },
            { "movies": { "$not": { "$size": 2 } } },
            { "movies": { "$not": { "$size": 3 } } }
        ]

所以你基本上“排除”了那些可能不够长的数组n火柴。这里要注意的是,这$size http://docs.mongodb.org/manual/reference/operator/query/size/查询形式中的运算符不同于$size http://docs.mongodb.org/manual/reference/operator/aggregation/size/为聚合框架。例如,无法将其与不等式运算符一起使用,例如$gt它的目的是专门匹配所请求的“尺寸”。因此,此查询表单指定小于的所有可能大小。

$project:此声明有几个目的,其中一些目的根据您拥有的 MongoDB 版本而有所不同。首先,也可以选择将文件副本保存在_id值,以便其余步骤不会修改这些字段。这里的另一部分是将“电影”数组保留在文档顶部作为下一阶段的副本。

2.6 之前的版本中还出现了一个额外的数组,表示_id要匹配的“电影”的值。的用法$cond这里的运算符只是创建数组的“文字”表示的一种方法。有趣的是,MongoDB 2.6 引入了一个称为$literal不用我们正在使用的有趣的方式来做到这一点$cond就在这儿。

$unwind:要做进一步的事情,电影数组需要展开,因为在任何一种情况下,它都是隔离现有的唯一方法_id需要与“集合”匹配的条目的值。因此,对于 2.6 之前的版本,您需要“展开”现有的两个数组。

$group:对于 MongoDB 2.6 及更高版本,您只需分组回一个仅包含以下内容的数组:_id删除“评级”的电影的值。

在 2.6 之前,由于所有值都是“并排”呈现(并且有大量重复),因此您正在对两个值进行比较以查看它们是否相同。那是哪里true,这告诉$cond返回值的运算符语句1 or 0条件是false。这个是直接传回来的$sum将数组中匹配元素的数量总计为所需的“集合”。

$project:这是 MongoDB 2.6 及更高版本的不同部分,因为您已经推回了一组“电影”_id您正在使用的值$setIntersection直接比较这些数组。由于这是一个包含相同元素的数组,因此它被包装在$size运算符以确定该匹配集中返回了多少元素。

$match:是此处实现的最后阶段,它执行明确的步骤,仅匹配那些相交元素计数大于或等于所需数量的文档。


Final

基本上就是这样做的。 2.6 之前的版本有点笨拙,并且需要更多的内存,因为扩展是通过复制集合的所有可能值找到的每个数组成员来完成的,但这仍然是一种有效的方法。

您所需要做的就是将其应用到更大的n匹配值以满足您的条件,当然还要确保您的原始用户匹配具有所需的n的可能性。否则就生成这个n-1来自“用户”的“电影”数组的长度。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MongoDB嵌套数组交集查询 的相关文章

随机推荐

  • WCF 数据服务支持的 Linq

    我正在寻找与 WCF 数据服务兼容的受支持 linq 扩展方法的完整列表 通过反复试验 我发现 First Func 和 Single Func 不受支持 还有其他吗 This http msdn microsoft com en us l
  • Java - 如何检查字符串中的重复字符?

    我需要编写一个函数来检查字符串中是否有重复值并返回唯一字符的计数 如果计数大于 3 则应返回 true 如果计数小于 3 则应该为 false 这是我一直在尝试的 注意我是java新手 private boolean isFormatVal
  • SSE (SIMD):向量乘标量

    我在程序中执行的常见操作是按标量缩放向量 V s 例如 1 2 3 4 2 2 4 6 8 除了首先在向量中的每个位置加载标量 例如 mm set ps 2 2 2 2 然后相乘之外 是否有 SSE 或 AVX 指令可以执行此操作 这就是我
  • 如何从 UIView 创建 CGLayer 进行离屏绘图

    我已经阅读了我认为是 Quartz 2D 编程指南的相关部分 但找不到以下内容的答案 他们似乎在文档中没有过多谈论 iOS 我的应用程序在UIView 我时不时地必须以某种方式更新绘图 例如更改其中一个形状的填充颜色 我保留CGPathRe
  • 访问列表视图中的自定义对象

    我目前正在构建一个应用程序 该应用程序将请求发送到网络 然后解析结果并将其放入对象的 ArrayList 中 然后 该列表将填充 ListView 我想创建一个onClickListener这将使我知道单击了哪个对象 但我找不到实现此目的的
  • 如何访问 Sharepoint 2007/2010/2013 _layouts 文件夹

    我正在尝试在该位置插入一些数据 mysiteurl layouts 因为我必须使用第三方软件 该软件使用该文件夹中存储的数据 我是机器的管理员 Windows Server 2008R2 上的 Sharepoint 2010 但 Share
  • ActiveMQ - 通过命令行删除/清除所有队列

    有没有办法通过命令行 win linux 删除 清除ActiveMQ中的所有队列 我只能找到特定队列的命令 或者也许有办法通过 activeMQ 管理员来做到这一点 同样 我只找到了如何一一删除 清除队列 这可能非常乏味 Thanks 你可
  • gitlab.com SSH 连接超时

    我尝试让 Gitlab 与 SSH 一起工作 但不行 我已完成以下步骤 1 生成ssh密钥 ssh keygen t rsa C email protected cdn cgi l email protection b 4096 2 在文件
  • WPF DataGrid 虚拟化无法正常工作?

    我有一个 DataGrid 其中有一个 DataTable 设置为其 ItemsSource DataTable 包含 24 列和约 1600 行 实际上我稍后必须加载更多行 但目前这已经够麻烦的了 尽管将列和行的虚拟化设置为活动状态 Da
  • 使用 libwebsockets 编译 libuv

    我正在尝试运行与 LWS 库一起安装的 libwebsockets test server 但它不会运行 因为 lwsts 31616 libuv support not generated in 我检查过 libuv 已安装 1 8 0
  • 可以在 Try/Except 中重试/循环吗?

    我试图了解是否可以在 Try Except 调用内部设置循环 或者是否需要重构以使用函数 长话短说 在花了几个小时学习 Python 和 BeautifulSoup 后 我设法将一些代码组合在一起来抓取 URL 列表 将数据提取到 CSV
  • 向元组添加元素的有效方法

    我想向元组添加元素 我找到了两种方法 This https stackoverflow com a 16730367 3337089 and this https stackoverflow com a 1380875 3337089答案说
  • 在 Numpy 中生成对称矩阵

    我正在尝试在 numpy 中生成对称矩阵 具体来说 这些矩阵具有随机位置的条目 并且每个条目中的内容可以是随机的 沿着主对角线 我们不关心其中有哪些条目 因此我也将它们随机化 我采取的方法是首先生成一个 nxn 全零矩阵 然后简单地循环矩阵
  • 正则表达式在引号外的特定字符上分割字符串

    如何在保留带引号的字符串的同时分割这一行 gt div a more style ui url in tray value 分割的字符在哪里 gt 产生 gt div a more style ui url in tray value 目前
  • 识别哪个文件包含某些特定的头文件

    有时 对于复杂的标头结构 可能会包含一些标头 但很难分辨出来自哪里 是否有某种工具 依赖项查看器 或一种方法如何查找 包含堆栈 哪个源 哪个标头 哪个标头 包含一个特定的头文件 如果头文件被多次包含 找到第一个包含就足够了 找到所有包含是一
  • 我可以在嵌入式交互式 Python 控制台中使用 IPython 吗?

    我使用以下代码片段将其放入 Python shell 程序中 这工作正常 但我只得到标准控制台 有没有办法做同样的事情但使用IPython http ipython scipy org shell import code class Emb
  • 虚拟Qt信号?

    在查看一些 Qt C 代码时 我遇到了这个 class Foo Q OBJECT signals virtual void someSignal const QString str int n Q UNUSED str Q UNUSED n
  • HTTP 基本身份验证和 Atlassian JIRA、Confluence 和 Bitbucket

    我在 Apache 反向代理后面的服务器上部署了 JIRA Confluence 和 Bitbucket 他们中的每一个都通过应用程序链接与其他人连接 现在 我想通过在此之前实现 HTTP 基本身份验证来添加额外的保护层 当我这样做时 我会
  • 如何将任意数量的值绑定到 mysqli 中的准备好的语句? [复制]

    这个问题在这里已经有答案了 我真的希望有人花一点时间来检查我的代码 我正在解析一些新闻内容 我可以将初始解析插入到我的数据库中 其中包含新闻 URL 和标题 我想进一步扩展它 传递每个文章链接并解析文章的内容并将其包含在我的数据库中 最初的
  • MongoDB嵌套数组交集查询

    并提前感谢您的帮助 我有一个 mongoDB 数据库 其结构如下 id objectID userID id movies movieID movieID rating rating 我的问题是 我想搜索具有 userID 3 的特定用户