【问题标题】:Mongo Query to return common values in arrayMongo查询返回数组中的常见值
【发布时间】:2017-02-17 16:15:20
【问题描述】:

我需要一个 Mongo 查询来返回数组中的常见值。 因此,如果有 4 个文档匹配,则如果这些值存在于所有 4 个文档中,则返回值

假设我的数据库中有以下文档

Mongo 文档

{ “id”:“0”, "商人":["1","2"] } { "id":"1", "商人":["1","2","4"] } { "id":"2", "商人":["4","5"] }

输入:id列表

(i) id 为“0”和“1”的输入

然后它应该返回我的商人:[“1”,“2”],因为两者都存在于 id 为“0”和 id 为“1”的文档中

(ii) id 为“1”和“2”的输入 然后它应该返回我的商人:[“4”],因为它很常见并且出现在两个文档中,id为“1”和id为“2”

(iii) id 为“0”和“2”的输入 应该返回空商家:[]因为这两个文件之间没有共同的商家

【问题讨论】:

  • 您的 MongoDB 服务器版本是多少?

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

您可以尝试以下聚合。

db.collection.aggregate(
   {$match:{id: {$in: ["1", "2"]}}},
   {$group:{_id:null, first:{$first:"$merchants"}, second:{$last:"$merchants"}}},
   {$project: {commonToBoth: {$setIntersection: ["$first", "$second"]}, _id: 0 } }
)   

【讨论】:

  • 这在输入超过两个 id 的情况下不起作用
  • 是的,它不起作用。该查询只考虑第一个和最后一个文档,忽略中间文档
  • 如果您查看标签 firstsecond ,显然它不起作用。我根据您的示例输入提供了答案。考虑更新您的帖子以准确说明您在寻找什么。
【解决方案2】:

假设您有一个函数query 为您执行所需的数据库查询,您将使用idsToMatch 调用该函数,这是一个包含您要匹配的所有元素的数组。我这里用的是JS作为驱动语言,用你用的随便替换吧。

以下代码是动态的,适用于您作为输入提供的任意数量的 id:

const query = (idsToMatch) => {

    db.collectionName.aggregate([
        { $match: { id: {$in: idsToMatch} } },
        { $unwind: "$merchants" },
        { $group: { _id: { id: "$id", data: "$merchants" } } },
        { $group: { _id: "$_id.data", count: {$sum: 1} } },
        { $match: { count: { $gte: idsToMatch.length } } },
        { $group: { _id: 0, result: {$push: "$_id" } } },
        { $project: { _id: 0, result: "$result" } }    
    ])
  1. 第一个$group 声明是为了确保您没有任何 在文档中的任何 merchants 属性中重复。如果 您确定在您的个人文件中不会有任何 merchants 的重复值,您不需要包含它。
  2. 真正的工作只发生在第二个$match 阶段。最后两个 阶段($group$project)只是为了美化结果, 您可以选择不使用它们,而是使用您的语言 选择将其转换为您想要的形式

假设您想根据上面给出的几点减少阶段,实际代码将减少为:

aggregate([
        { $match: { id: {$in: idsToMatch} } },
        { $unwind: "$merchants" },
        { $group: { _id: "merchants", count: {$sum: 1} } },
        { $match: { count: { $gte: idsToMatch.length } } }   
    ])

您需要的值将位于结果数组的每个元素的_id 属性中。

【讨论】:

  • 这也不起作用,因为中间匹配操作不正确。中间匹配操作应该是 { $match: { count: { $gt: "no_of_ids_in_1st_match_operation" } } }
  • 解决该部分是微不足道的。假设您有一个函数query 为您执行此数据库查询,您将其称为:query(idsToMatch),其中 idsToMatch 是您要匹配的 id 数组。您可以简单地将$gt:1 部分替换为$gt: (idsToMatch.length - 1)(假设您使用js,否则使用您的语言的长度函数)。
【解决方案3】:

@jgr0 提供的答案在某种程度上是正确的。唯一的错误是中间匹配操作

(i) 因此,如果输入 id 为“1”和“0”,则查询变为

总计的([ {"$match":{"id":{"$in":["1","0"]}}}, {"$unwind":"$merchants"}, {"$group":{"_id":"$merchants","count":{"$sum":1}}}, {"$match":{"count":{"$eq":2}}}, {"$group":{"_id":null,"merchants":{"$push":"$_id"}}}, {"$project":{"_id":0,"merchants":1}} ])

(ii) 因此,如果输入 id 为“1”、“0”和“2”,则查询变为

总计的([ {"$match":{"id":{"$in":["1","0", "2"]}}}, {"$unwind":"$merchants"}, {"$group":{"_id":"$merchants","count":{"$sum":1}}}, {"$match":{"count":{"$eq":3}}}, {"$group":{"_id":null,"merchants":{"$push":"$_id"}}}, {"$project":{"_id":0,"merchants":1}} ])

中间匹配操作应该是输入中的 id 计数。因此,在情况 (i) 中为 2,在情况 (2) 中为 3。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-19
    • 2018-09-08
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多