web-dev-qa-db-ja.com

配列内のドキュメントから特定のフィールドを投影する方法は?

これが典型的なドキュメントです

{
   title : 'someTitle',
   places : [{name : 'someName', location : 'someLocation'}, {name ...}]
}

私は次のクエリを持っています

var qs = {title : 'someTitle', places : {$elemMatch : {name : 'someName' } } };

ここで、タイトルに一致し、「places」配列内に「someName」と等しい名前のドキュメントエントリを含むドキュメントを選択します。ただし、問題は、places配列内のエントリが大きなドキュメントであり、そのドキュメントのいくつかのフィールドのみが必要なことです。そのようにフィールドを投影してみましたが、うまくいきませんでした。

var projection = {'places.$.name': 1, 'places.$.location' : 1};

これは、'name'プロパティと'location'プロパティのみを含むドキュメントを含む配列を返すことになっています。

次のエラーが発生しました

Can't canonicalize query: BadValue Cannot specify more than one positional proj. per query.  

明確にするために、集約フレームワークなしでこれを達成したいと思います

10
naughty boy

あなたはそれを誤解している。 ドキュメント によると

投影ドキュメントに表示できる位置$演算子は1つだけです。

ただし、期待される結果を得るには、 $ 演算子を使用する必要があります。

var qs = { title : 'someTitle', 'places.name' : 'someName' };
var projection = {'places.$': 1 };
db.collection.find(qs, projection);

どちらが返されますか:

{
        "_id" : ObjectId("564f52d7d9a433df958b5630"),
        "places" : [
                {
                        "name" : "someName",
                        "location" : "someLocation"
                }
        ]
}

また、ここでは$elemMatch演算子は必要ありません。代わりに "ドット表記" を使用してください。


ここで、必要なのが配列内の各サブドキュメントの「名前」と「場所」の配列である場合は、集約が最適です。

db.collection.aggregate([
    { '$match': { 
        'title' : 'someTitle', 
        'places.name' : 'someName' 
    }}, 
    { '$project': { 
        'places': {
            '$map': { 
                'input': '$places', 
                'as': 'place', 
                'in': { 
                    'name': '$$place.name', 
                    'location': '$$place.location'
                }
            }
        }
    }}
])

どちらが得られますか:

{
    "_id" : ObjectId("564f52d7d9a433df958b5630"),
    "places" : [
            {
                    "name" : "someName",
                    "location" : "someLocation"
            },
            {
                    "name" : "bar",
                    "location" : "foo"
            }
    ]
}
15
styvane

配列内のフィールドについては、埋め込みオブジェクトと同じように投影できます
var projection = {'places.name': 1, 'places.location' : 1};
このガイドラインを確認してください
https://docs.mongodb.com/manual/reference/operator/aggregation/project/#include-specific-fields-from-embedded-documents

4