Mongo Shell - 按数组项排序+按文化过滤

时间:2014-06-16 11:23:22

标签: mongodb aggregation-framework

我有MongoDb的优惠收藏。

[
    {
        "Name": "item01",
        "Descriptions": [
            {
                "Name": "(es) Item01 Name",
                "Culture": "es"
            },
            {
                "Name": "(en) Item01 Name",
                "Culture": "en"
            },
            {
                "Name": "(de) Item01 Name",
                "Culture": "de"
            }
        ]
    },
    {
        "Name": "item02",
        "Descriptions": [
            {
                "Name": "(en) Item02 Name",
                "Culture": "en"
            },
            {
                "Name": "(de) Item03 Name",
                "Culture": "de"
            }
        ]
    }
]

我需要按说明对项目列表进行排序。

必须由用户文化订购。如果没有这样的文化,必须默认使用英语。

我试图使用mongo聚合来解决这个问题。但无法找到。

db.Offer.aggregate(
[
    {$unwind:'$Descriptions'},
    {$group: {
    '_id': '$_id',
    'Culture': '$Culture',
    'ElementNameComp': {$first: {$cond:[
           {$eq:['$Descriptions.Culture', 'es']},
           '$Descriptions.Name',
           {$cond:[
           {$eq:['$Descriptions.Culture', 'en']},
           '$Descriptions.Name',
           'no exists EN'
        ]}
        ]} }

     }}
]
)

一些想法?

更新

文化时的预期结果(ES)。我还修改了数据以涵盖更多示例。

 [
        {
            "Name": "item01",
            "Descriptions": "(es) Item01 Name"

        },
        {
            "Name": "item02",
            "Descriptions": "(en) Item02 Name"

        }
    ]

1 个答案:

答案 0 :(得分:1)

你需要一些东西来分配一个"得分"为了确定哪个是最好的,可以匹配可能的匹配作为基本过程。

一种可以过滤"的方法。 $unwind之前的数组内容:

var locale = "es";

var result = db.Offer.aggregate([
    { "$project": {
        "Name": 1,
        "Descriptions": {
            "$setDifference": [
                { "$map": {
                    "input": "$Descriptions",
                    "as": "el",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.Culture", locale ] },
                            { "name": "$$el.Name", "score": { "$literal": 2 } },
                            { "$cond": [
                                { "$eq": [ "$$el.Culture", "en" ] },
                                { "name": "$$el.Name", "score": { "$literal": 1 } },
                                false
                            ]}
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    { "$unwind": "$Descriptions" },
    { "$sort": { "Descriptions.score": -1 }},
    { "$group": {
        "_id": "$_id",
        "Name": { "$first": "$Name" },
        "Description": { "$first": "$Descriptions.name" }
    }}
]);

这剥夺了"描述"的一些结构。但它基本上似乎是你想要的。原因是只采用所选语言环境的值或以其他方式回退到"默认"如果没有其他项目匹配,则为英语语言环境。

$cond运算符分配"得分"匹配的值,然后相应地对它们进行排序,以便"最高"得分返回。

然后你排序并分组回你的数组。

你可以在MongoDB 2.6之前做同样的事情,它给出了额外的运算符:

var locale = "es";

var result = db.Offer.aggregate([
    { "$unwind": "$Descriptions" },
    { "$project": {
        "Name": 1,
        "Descriptions": {
            "$cond": [
                { "$eq": [ "$Descriptions.Culture", locale ] },
                { "name": "$Descriptions.Name", "score": { "$const": 2 } },
                { "$cond": [
                    { "$eq": [ "$Descriptions.Culture", "en" ] },
                    { "name": "$Descriptions.Name", "score": { "$const": 1 } },
                    false
                ]}
            ]
        }
    }},
    { "$match": { "Descriptions": { "$ne": false } }},
    { "$sort": { "Descriptions.score": -1 } },
    { "$group": {
        "_id": "$_id",
        "Name": { "$first": "$Name" },
        "Description": { "$first": "$Descriptions.name" }
    }}
]);

在任何一种情况下,当匹配语言环境时,结果应为:

{ 
    "_id" : ObjectId("539f91f831d29097dc43e8ae"),
    "Name" : "item02",
    "Description" : "(es) Item02 Name"
},
{ 
    "_id" : ObjectId("539f91f831d29097dc43e8ad"),
    "Name" : "item01",
    "Description" : "(es) Item01 Name"
}

或者在设置不存在的区域设置时

{ 
    "_id" : ObjectId("539f91f831d29097dc43e8ae"),
    "Name" : "item02",
    "Description" : "(en) Item02 Name"
},
{ 
    "_id" : ObjectId("539f91f831d29097dc43e8ad"),
    "Name" : "item01",
    "Description" : "(en) Item01 Name"
}

任何甚至没有违约的结果" en"语言环境将被省略。