在特殊条件下对MongoDB中的文档进行分组 [英] Grouping documents in MongoDB on special condition
问题描述
我的收藏包含
{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 推送到ranges数组中的最后一组,并 $ 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屋!