【问题标题】:Grouping documents in MongoDB on special condition在特殊条件下对 MongoDB 中的文档进行分组
【发布时间】:2017-12-11 08:46:36
【问题描述】:

我的收藏包含

{name:'p1', age: 20}
{name: 'p2', age: 21}
{name: 'p3', age: 23}
{name: 'p4', ag:41 }

我想对人员进行分组,使得组中的任何人在组中都存在另一个人,使得他们的年龄差异最多为 2。 这里生成的组将包含

预期结果

[{name:'p1' ...}, {name:'p2' ...}, {name: 'p3'}]

p2 -p1 = 1 and p3-p2 = 2开始

p1,p2,p3 组成一个组

【问题讨论】:

  • 你能显示预期的结果吗?
  • 如果您的收藏中有{name: 'p5', age: 25} 会是什么结果?
  • p1、p2、p3 和 p5 组成一个组

标签: python mongodb pymongo


【解决方案1】:

免责声明

在阅读其余答案之前,请阅读https://docs.mongodb.com/manual/core/aggregation-pipeline-limits/ 问题中的结果文档应包含属于特定年龄组的所有文档的数组。 该数组的大小不能超过 16MB,因此下面的代码仅适用于非常小的微型文档集合。


代码:

db.collection.aggregate([
    { $sort: { age: 1 } },
    { $group: {
            _id: null,
            ages: { $push: "$age" }
    } },
    { $addFields: {
        ranges: { $reduce: { 
            input: { $range: [ 1, { $size: "$ages" }, 1 ] }, 
            initialValue: [ [ { $arrayElemAt: [ "$ages", 0 ] } ] ], 
            in: { $cond: { 
                if:  { $gt: [
                    { $subtract: [ { $arrayElemAt: [ "$ages", "$$this" ] }, { $arrayElemAt: [ "$ages", { $subtract: [ "$$this", 1 ] } ] } ] },
                    2
                    ] }, 
                then: { $concatArrays: [ "$$value",  [ [ { $arrayElemAt: [ "$ages", "$$this" ] } ] ] ] }, 
                else: { $concatArrays: [ 
                    { $slice: [ "$$value" , { $subtract: [ { $size: "$$value" }, 1 ] } ] },
                    [ { $concatArrays: [ 
                        { $arrayElemAt: [ { $slice: [ "$$value" , -1 ] }, 0 ] }  ,  
                        [ { $arrayElemAt: [ "$ages", "$$this" ] } ]
                    ]  } ]
                ] }
            } }
        } } 
    } },
    { $unwind: "$ranges" }, 
    { $lookup: {
       from: "collection",
       localField: "ranges",
       foreignField: "age",
       as: "group"
     } },
     { $project: { _id: 0, group: 1 } }
])

可能需要解释的部分是如何计算年龄组。

为此,我们将使用 $group 的所有年龄放入单个数组,然后将 $addFields“范围” - 年龄组的 2D 数组,其中年轻组中最年长的人和年长组中最年轻的人之间存在差距大于 2 年。

该数组是使用 $range 数组中的 $reduce 计算得出的,该数组包含所有年龄的索引,但首先是初始值。

reduce 表达式是一个 $cond,它计算所有年龄数组的当前和前一个 ($subtract) 元素之间的差异。

如果大于 2,则使用 $concatArrays 添加新的年龄组。否则,年龄将添加到最旧的组中,使用$slice 推送到范围数组中的最后一个组,并使用$setUnion 消除重复项。

在计算年龄组时,我们将$lookup同一个集合按年龄分组到“group”数组中。

【讨论】:

  • 很好的答案,很好的解释。
猜你喜欢
  • 2017-10-24
  • 2012-06-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多