Tuyên bố từ chối trách nhiệm
Trước khi đọc phần còn lại của câu trả lời, vui lòng đọc https:// docs. mongodb.com/manual/core/aggregation-pipeline-limits/ Tài liệu kết quả trong câu hỏi dự kiến sẽ có một mảng gồm tất cả các tài liệu thuộc nhóm tuổi cụ thể. Kích thước của mảng đó không được vượt quá 16MB , do đó, mã bên dưới sẽ chỉ hoạt động cho các bộ sưu tập rất nhỏ các tài liệu nhỏ.
Mã:
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 } }
])
Phần có thể cần giải thích một chút là cách tính nhóm tuổi.
Đối với điều đó, chúng tôi nhận được mọi lứa tuổi bằng cách sử dụng $ group vào một mảng và sau đó $ addFields "phạm vi" - mảng 2D gồm các nhóm tuổi với khoảng cách giữa người cao tuổi nhất trong nhóm trẻ hơn và người trẻ nhất trong nhóm tuổi lớn hơn 2 tuổi.
Mảng được tính bằng cách sử dụng $ giảm của $ phạm vi mảng các chỉ mục thuộc mọi độ tuổi, trừ các chỉ số đầu tiên, chuyển sang giá trị ban đầu.
Biểu thức thu gọn là $ cond tính toán sự khác biệt giữa hiện tại và trước đó ( $ trừ ) phần tử của mảng ở mọi lứa tuổi.
Nếu lớn hơn 2, một nhóm tuổi mới sẽ được thêm vào bằng cách sử dụng $ concatArrays . Nếu không, độ tuổi sẽ được thêm vào nhóm già nhất bằng cách sử dụng $ slice để đẩy lên nhóm cuối cùng trong mảng phạm vi và $ setUnion để loại bỏ các bản sao.
Khi nhóm tuổi được tính toán, chúng tôi $ lookup cùng một bộ sưu tập theo độ tuổi để nhóm chúng trong mảng "nhóm".