在特殊条件下对MongoDB中的文档进行分组 [英] Grouping documents in MongoDB on special condition

查看:105
本文介绍了在特殊条件下对MongoDB中的文档进行分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的收藏包含

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

我想对人员进行分组,以便该组中的任何人在该组中都存在另一个人,以使他们之间的年龄差异最大为2. 这里的结果组将包含

I want to group persons such that for any person in the group there exist another person int the group such that difference between their ages is at most 2. Here resulting group will contain

预期结果

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

p2 -p1 = 1 and p3-p2 = 2

p1,p2,p3组成一个组

p1,p2,p3 form a group

推荐答案

免责声明

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

Disclaimer

Before reading the rest of the answer, please read https://docs.mongodb.com/manual/core/aggregation-pipeline-limits/ The resulting document in the question is expected to have an array of all documents that belong to particular age group. Size of that array cannot exceed 16MB, so the code below will work only for very small collections of tiny documents.

代码:

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 } }
])

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

The part that may require a bit of explanation is how to calculate age groups.

为此,我们使用 $ group 放入单个数组,然后 $ addFields 范围"-二维年龄组阵列,年龄较小的组中的老年人与年龄较大的组中的年轻人之间的差距大于2岁.

For that, we get all ages using $group into a single array and then $addFields "ranges" - a 2D array of age groups with gaps between oldest person in a younger group and a youngest person in the older group is greater than 2 years.

使用 $ reduce 计算数组 $ range 各个年龄段的索引数组但首先要取初始值.

The array is calculated using $reduce of a $range array of indexes of all ages but first, which goes to initial value.

reduce表达式是 $ cond 用来计算当前与先前( $ subtract )的所有年龄数组的元素.

The reduce expression is a $cond which calculates difference between current and previous ($subtract) element of the array of all ages.

如果大于2,则使用 $ slice $ setUnion 以消除重复项.

If it is greater than 2, a new age group is added using $concatArrays. Otherwise the age is added to the oldest group using $slice to push to the last group in the ranges array and $setUnion to eliminate duplicates.

计算年龄段时,我们 $ lookup 按年龄分类相同的收藏集,将它们归入分组"数组.

When the age groups are calculated, we $lookup the same collection by age to group them in the "group" array.

这篇关于在特殊条件下对MongoDB中的文档进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆