web-dev-qa-db-ja.com

MongoDBは配列要素でドキュメントをソートします

私は次のようなドキュメント構造を持っています:

{
    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
        }
    ]
}

ポイントタイプtype1のすべてのマップをdistanceToSpawnで昇順に並べ替えたいのですが。

期待される結果 :

{
    map: 'B',
    points: [
        {
            type: 'type1',
            distanceToSpawn: 100
        }
    ]
},
{
    map: 'A',
    points: [
        {
            type: 'type1',
            distanceToSpawn: 110
        }
    ]
}

私は次のようなことを試しました:

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

しかし、これは昇順でマップをソートしないことです。

ありがとう。

19
Guillaume S

配列を使用してこれを行うことはできません。ここでの主な問題は、一致した要素で「ソート」を実行したいためです。このように結果を並べ替える場合は、代わりに .aggregate() を使用する必要があります。次のいずれか:

最新のMongoDBバージョンの場合:

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

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 } }
])

または、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 } }         
])

これが、正しい要素を照合し、それらを「ソート」操作で考慮する唯一の方法です。デフォルトのカーソルソートでは、代わりに、選択した「タイプ」と一致しない配列要素のフィールドの値が考慮されます。

18
Neil Lunn