web-dev-qa-db-ja.com

MongoDB-$ groupを使用して$ lookup後にネストされた$ unwind配列を巻き戻す

MongoDBの集計は、分単位で指数関数的に複雑になります。

ネストされた配列を$unwindして、巻き戻されたネストされた配列からの各オブジェクトの$lookupによって_idを実行します。私の最後の試みは$groupで巻き戻しを元に戻すことです。ただし、元の埋め込み配列を、元のプロパティ名とともに、各ドキュメントの残りの元の直接プロパティとともに再構築することはできません。

これまでの私の試みは次のとおりです。

db.users.aggregate([
    {
        $unwind: "$profile",
        $unwind: {
            path: "$profile.universities",
            preserveNullAndEmptyArrays: true
        }
    },
    {
        $lookup: {
            from: "universities",
            localField: "profile.universities._id",
            foreignField: "_id",
            as: "profile.universities"
        }
    },
    {
        $group: {
            _id: "$_id",
            emails: { "$first": "$emails" },
            profile: { "$first": "$profile" },
            universities: { "$Push": "$profile.universities" }
        }
    }
]).pretty()

私が得るものはこのようなものです:

{
    "_id" : "A_USER_ID",
    "emails" : [
        {
            "address" : "AN_EMAIL_ADDRESS",
            "verified" : false
        }
    ],
    "profile" : {
        "name" : "NAME",
        "company" : "A COMPANY",
        "title" : "A TITLE",
        "phone" : "123-123-1234",
        "disabled" : false,
        "universities" : [
            {
                "_id" : "ID_1",
                "name" : "UNIVERSITY_NAME_1",
                "code" : "CODE_1",
                "styles" : {AN_OBJECT}
            }
        ]
    },
    "universities" : [
        [
            {
                "_id" : "ID_1",
                "name" : "UNIVERSITY_NAME_1",
                "code" : "CODE_1",
                "styles" : {AN_OBJECT}
            }
        ],
        [
            {
                "_id" : "ID_2",
                "name" : "UNIVERSITY_NAME_2",
                "code" : "CODE_2",
                "styles" : {AN_OBJECT}
            }
        ]
    ]
}

この結果には2つの問題があります。

  1. 結果のuniversitiesは、$lookupが元の$profile.universitiesネスト配列の単一要素配列を返したため、それぞれ1つのオブジェクトの配列の配列です。それはオブジェクトの配列でなければなりません。
  2. 結果のuniversitiesは、profilesの下にネストされた元の場所になります。 profile.universities演算子を使用しているので、元の$firstがそのままの理由を知っています。これの背後にある私の意図は、元のネストされたprofile配列を保持しながら、universitiesの元のプロパティをすべて保持することです。

最終的に、私が必要なのは次のようなものです:

{
    "_id" : "A_USER_ID",
    "emails" : [
        {
            "address" : "AN_EMAIL_ADDRESS",
            "verified" : false
        }
    ],
    "profile" : {
        "name" : "NAME",
        "company" : "A COMPANY",
        "title" : "A TITLE",
        "phone" : "123-123-1234",
        "disabled" : false,
        "universities" : [
            {
                "_id" : "ID_1",
                "name" : "UNIVERSITY_NAME_1",
                "code" : "CODE_1",
                "styles" : {AN_OBJECT}
            },
            {
                "_id" : "ID_2",
                "name" : "UNIVERSITY_NAME_2",
                "code" : "CODE_2",
                "styles" : {AN_OBJECT}
            }
        ]
    }
}

これを達成するために$groupの代わりに使用できる別の演算子はありますか?または、$groupの目的を誤って理解していますか?

編集:これはコンテキストの元の投稿です: Mongo $ lookupが左外部結合である場合、どのようにして非一致するドキュメント?

12
Sun Lee

$lookup演算子は配列フィールドを生成するため、を実行する必要があります $unwind$groupパイプラインの前の新しいフィールド望ましい結果を得るには:

db.users.aggregate([
    { "$unwind": "$profile" },
    { "$unwind": {
        "path": "$profile.universities",
         "preserveNullAndEmptyArrays": true
    } }, 
    { "$lookup": {
        "from": "universities",
        "localField": "profile.universities._id",
        "foreignField": "_id",
        "as": "universities"
    } },    
    { "$unwind": "$universities" },
    { "$group": {
        "_id": "$_id",
        "emails": { "$first": "$emails" },
        "profile": { "$first": "$profile" },
        "universities": { "$Push": "$universities" }
    } },
    { "$project": {
        "emails": 1,  
        "profile.name" : 1,
        "profile.company": 1,
        "profile.title" : 1,
        "profile.phone" : 1,
        "profile.disabled": 1,          
        "profile.universities": "$universities"
    } }
]).pretty()
19
chridam