MongoDB按数组元素对文档进行排序

Gui*_*e S 18 sorting mongodb mongodb-query aggregation-framework

我的文档结构如下:

{
    map: 'A',
    points: [
        {
            type: 'type1',
            distanceToSpawn: 110
        },
        {
            type: 'type4',
            distanceToSpawn: 40
        },
        {
           type: 'type6',
           distanceToSpawn: 30
        }
    ]
},
{
    map: 'B',
    points: [
        {
            type: 'type1',
            distanceToSpawn: 100
        },
        {
            type: 'type2',
            distanceToSpawn: 60
        },
        {
            type: 'type3',
            distanceToSpawn: 25
        }
    ]
},
{
    map: 'C',
    points: [
        {
            type: 'type2',
            distanceToSpawn: 90
        },
        {
            type: 'type3',
            distanceToSpawn: 1
        },
        {
            type: 'type6',
            distanceToSpawn: 76
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我希望得到所有具有type1distanceToSpawn升序排序的点类型的地图.

预期结果 :

{
    map: 'B',
    points: [
        {
            type: 'type1',
            distanceToSpawn: 100
        }
    ]
},
{
    map: 'A',
    points: [
        {
            type: 'type1',
            distanceToSpawn: 110
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我尝试过类似的东西:

db.maps.find({'points.type': {$eq : 'type1'}}, {map: 1, 'points.$':1}).sort({'points.distanceToSpawn': 1}).limit(10)
Run Code Online (Sandbox Code Playgroud)

但是这个东西没有按升序排序地图.

谢谢.

Nei*_*unn 19

你不能用数组做到这一点,这里的主要问题是因为你想在匹配的元素上"排序".如果你想对这样的结果进行排序,那么你需要改为使用.aggregate().如下:

对于现代MongoDB版本:

db.maps.aggregate([
    { "$match": { "points.type": "type1" }},
    { "$addFields": {
        "order": {
            "$filter": {
              "input": "$points",
              "as": "p",
              "cond": { "$eq": [ "$$p.type", "type1" ] }
            }
        }
    }},
    { "$sort": { "order": 1 } }
])
Run Code Online (Sandbox Code Playgroud)

对于MongoDB 2.6到3.0

db.maps.aggregate([
    { "$match": { "points.type": "type1" }},
    { "$project": {
        "points": { 
            "$setDifference": ]
                { "$map": {
                    "input": "$points",
                    "as": "p",
                    "in": { "$cond": [
                        { "$eq": [ "$$p.type", "$type1" ] },
                        "$$p",
                        false
                    ]}
                }},
                [false]   
            ]
        }
    }},
    { "$sort": { "points.distanceToSpawn": 1 } }
])
Run Code Online (Sandbox Code Playgroud)

或者在MongoDB 2.6之前的版本效率较低:

db.maps.aggregate([
    { "$match": { "points.type": "type1" }},
    { "$unwind": "$points" },
    { "$match": { "points.type": "type1" }},
    { "$group": {
        "_id": "$id",
        "points": { "$push": "$points" }
    }},
    { "$sort": { "points.ditanceToSpawn": 1 } }         
])
Run Code Online (Sandbox Code Playgroud)

这是匹配正确元素并在"排序"操作中考虑它们的唯一方法.默认光标排序只会考虑数组元素中与所选"类型"不匹配的字段的值.

  • 对于“现代MongoDB版本”示例,`sort`应该在order.distanceToSpawn上,而不是在order上吗?否则,为什么呢? (2认同)
  • 您会为此排序创建什么索引? (2认同)