在数组和子数组中使用 $size 和 $sort

Use $size with $sort in array and sub array

这是我的 collection 的结构部分:

_id: ObjectId("W"),
names: [
    {
        number: 1,
        subnames: [ { id: "X", day: 1 }, { id: "Y", day: 10 }, { id: "Z", day: 2 } ],
        list: ["A","B","C"],
        day: 1
    },
    {
        number: 2,
        day: 5
    },
    {
        number: 3,
        subnames: [ { id: "X", day: 8 }, { id: "Z", day: 5 } ],
        list: ["A","C"],
        day: 2
    },
    ...
],
...

我使用这个请求:

db.publication.aggregate( [ { $match: { _id: ObjectId("W") } }, { $group: { _id: "$_id", SizeName: { $first: { $size: { $ifNull: [ "$names", [] ] } } }, names: { $first: "$names" } } }, { $unwind: "$names" }, { $sort: { "names.day": 1 } }, { $group: { _id: "$_id", SzNames: { $sum: 1 }, names: { $push: { number: "$names.number", subnames: "$names.subnames", list: "$names.list", SizeList: { $size: { $ifNull: [ "$names.list", [] ] } } } } } } ] );

但我现在会为我的 names 数组和 subnames 数组使用 $sort获得此结果(subnames 可能不存在):

_id: ObjectId("W"),
names: [
    {
        number: 2,
        SizeList: 0,
        day: 5
    },
    {
        number: 3,
        subnames: [ { id: "Z", day: 5 }, { id: "X", day: 8 } ],
        list: ["A","C"],
        SizeList: 2,
        day: 2
    },
    {
        number: 1,
        subnames: [ { id: "X", day: 1 }, { id: "Z", day: 2 }, { id: "Y", day: 10 } ],
        list: ["A","B","C"],
        SizeList: 3,
        day: 1
    }
    ...
],
...

你能帮帮我吗?

你可以做到,但难度很大。我个人很乐意投票支持 $sort along the lines of the $map 运算符的内联版本。那会让事情变得容易得多。

目前您需要在排序后解构并重建数组。你必须对此非常小心。因此在处理 $unwind:

之前用单个条目制作假数组
db.publication.aggregate([
    { "$project": {
        "SizeNames": { 
            "$size": { 
                "$ifNull": [ "$names", [] ]
             }
        },
        "names": { "$ifNull": [{ "$map": {
            "input": "$names",
            "as": "el",
            "in": {
                "SizeList": { 
                    "$size": { 
                        "$ifNull": [ "$$el.list", [] ]
                     }
                 },
                "SizeSubnames": {
                    "$size": { 
                        "$ifNull": [ "$$el.subnames", [] ]
                     }
                },
                "number": "$$el.number",
                "day": "$$el.day",
                "subnames": { "$ifNull": [ "$$el.subnames", [0] ] },
                "list": "$$el.list"
            }
        }}, [0] ] }
    }},
    { "$unwind": "$names" },
    { "$unwind": "$names.subnames" },
    { "$sort": { "_id": 1, "names.subnames.day": 1 } },
    { "$group": {
        "_id": {
            "_id": "$_id",
            "SizeNames": "$SizeNames",
            "names": {
                "SizeList": "$names.SizeList",
                "SizeSubnames": "$names.SizeSubnames",
                "number": "$names.number",
                "list": "$names.list",
                "day": "$names.day"
            }
        },
        "subnames": { "$push": "$names.subnames" }
    }},
    { "$sort": { "_id._id": 1, "_id.names.day": 1 } },
    { "$group": {
        "_id": "$_id._id",
        "SizeNames": { "$first": "$_id.SizeNames" },
        "names": {
            "$push": { "$cond": [
                { "$ne": [ "$_id.names.SizeSubnames", 0 ] },
                {
                    "number": "$_id.names.number",
                    "subnames": "$subnames",
                    "list": "$_id.names.list",
                    "SizeList": "$_id.names.SizeList",
                    "day": "$_id.names.day"
                },
                {
                    "number": "$_id.names.number",
                    "list": "$_id.names.list",
                    "SizeList": "$_id.names.SizeList",
                    "day": "$_id.names.day"
                }
            ]}
        }
    }},
    { "$project": {
        "SizeNames": 1,
        "names": { 
            "$cond": [
                { "$ne": [ "$SizeNames", 0 ] },
                "$names",
                []
            ]
        }
    }}
])

您可以 "hide away" 内部文档中的原始空数组,如图所示,但是如果不拉出类似的条件数组 "push" 技术,这确实不是一种实用的方法。

如果所有这些只是关于对单个文档中的数组元素进行排序,那么聚合框架不应该是执行此操作的工具。它可以如图所示完成,但根据文档,这在客户端代码中更容易完成。

输出:

{
    "_id" : ObjectId("54b5cff8102f292553ce9bb5"),
    "SizeNames" : 3,
    "names" : [
            {
                    "number" : 1,
                    "subnames" : [
                            {
                                    "id" : "X",
                                    "day" : 1
                            },
                            {
                                    "id" : "Z",
                                    "day" : 2
                            },
                            {
                                    "id" : "Y",
                                    "day" : 10
                            }
                    ],
                    "list" : [
                            "A",
                            "B",
                            "C"
                    ],
                    "SizeList" : 3,
                    "day" : 1
            },
            {
                    "number" : 3,
                    "subnames" : [
                            {
                                    "id" : "Z",
                                    "day" : 5
                            },
                            {
                                    "id" : "X",
                                    "day" : 8
                            }
                    ],
                    "list" : [
                            "A",
                            "C"
                    ],
                    "SizeList" : 2,
                    "day" : 2
            },
            {
                    "number" : 2,
                    "SizeList" : 0,
                    "day" : 5
            }
    ]
}