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

时间:2015-01-14 01:55:08

标签: mongodb mongodb-query aggregation-framework

这是我收藏的结构部分:

_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", [] ] } } } } } } ] );

但我现在将 $ sort 用于我的名称数组和我的子名称数组以获取此结果(子名称可能不存在):

_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
    }
    ...
],
...

你能帮助我吗?

1 个答案:

答案 0 :(得分:2)

你可以做到这一点,但很难。我很乐意在$sort运算符的行中投票选择$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",
                []
            ]
        }
    }}
])

你可以躲避"如图所示,来自内部文档的原始空数组,但是很难删除所有外部"名称"数组没有拉出类似的条件数组" 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
            }
    ]
}