Ambil dokumen yang cocok dari array bersarang [duplikat]

Saya mencoba mengumpulkan semua objek dalam array bersarang di mana bidang spec sama dengan unknown.

Struktur per dokumen serupa dengan ini:

{
    "_id" :"5b1e73786f11e421956023c3",
    "subs" : [ 
        {
            "name" : "subrepo1",
            "files" : [ 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }, 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }
            ]
        },
        {
            "name" : "subrepo2",
            "files" : [ 
                {
                    "name" : "file2",
                    "spec" : "Unknown"
                }, 
                {
                    "name" : ".....",
                    "spec" : "1234"
                }
            ]
        }
    ]
}

Saya mencoba yang berikut ini tetapi tidak berhasil. Saya pikir ini ke arah yang benar tetapi saya mungkin melewatkan sesuatu yang penting.

db.col.aggregate([
    {$match: {'subs.files.spec': 'Unknown'}},
    {$project: {
        'subs.files': {$filter: {
            input: '$subs.files',
            //as: 'subs.files',
            cond: {$eq: ['this.spec', 'FunSuite']}
        }},
        //_id: 0
    }}
])

Output yang diharapkan adalah: (jadi HANYA file yang spesifikasinya sama dengan Unknown (BUKAN yang lainnya)

{
    "_id" : "5b1e73786f11e421956023c3",
    "subs" : [ 
        {
            "name" : "subrepo1",
            "files" : [ 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }, 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }
            ]
        },
        {
            "name" : "subrepo2",
            "files" : [ 
                {
                    "name" : "file2",
                    "spec" : "Unknown"
                }
            ]
        }
    ]
}

person Captain Obvious    schedule 12.06.2018    source sumber
comment
Apa hasil yang Anda harapkan?   -  person Mạnh Quyết Nguyễn    schedule 12.06.2018
comment
@MạnhQuyếtNguyễn Menambahkan keluaran untuk memperjelas.   -  person Captain Obvious    schedule 12.06.2018


Jawaban (2)


Anda perlu menggunakan operator $filter yang hanya memberikan elemen yang cocok dari array dan lolos dari elemen lainnya

db.collection.aggregate([
  {
    $unwind: "$subs"
  },
  {
    $project: {
      "subs.name": "$subs.name",
      "subs.files": {
        $filter: {
          input: "$subs.files",
          as: "file",
          cond: {
            $eq: [
              "$$file.spec",
              "Unknown"
            ]
          }
        }
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      subs: {
        $push: "$subs"
      }
    }
  }
])

Di atas akan memberikan output berikut

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "subs": [
      {
        "files": [
          {
            "name": ".....",
            "spec": "Unknown"
          },
          {
            "name": ".....",
            "spec": "Unknown"
          }
        ],
        "name": "subrepo1"
      },
      {
        "files": [
          {
            "name": "file2",
            "spec": "Unknown"
          }
        ],
        "name": "subrepo2"
      }
    ]
  }
]

Anda dapat memeriksa hasilnya di sini

Dan jika Anda ingin mendapatkan bidang seperti dalam array, hapus $unwind dan tahap $replaceRoot dari pipeline

db.collection.aggregate([
  {
    $unwind: "$subs"
  },
  {
    $project: {
      "subs.name": "$subs.name",
      "subs.files": {
        $filter: {
          input: "$subs.files",
          as: "file",
          cond: {
            $eq: [
              "$$file.spec",
              "Unknown"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$subs.files"
  },
  {
    $replaceRoot: {
      newRoot: "$subs.files"
    }
  }
])

Di atas akan memberikan output berikut

[
  {
    "name": ".....",
    "spec": "Unknown"
  },
  {
    "name": ".....",
    "spec": "Unknown"
  },
  {
    "name": "file2",
    "spec": "Unknown"
  }
]
person Ashh    schedule 12.06.2018
comment
Ini bukan data masukan yang sama seperti yang diberikan pada contoh, dapatkah Anda mengubahnya? (Outputnya baik-baik saja) - person Captain Obvious; 12.06.2018
comment
@CaptainObvious Saya telah mengubah input dan output... Silakan periksa lagi... - person Ashh; 12.06.2018
comment
tampaknya berhasil; terima kasih. Bisakah Anda juga memberikan kueri untuk keluaran asli Anda? Outputnya hanya berisi file {name: ..., spec: ....} karena saya ingin memilikinya juga. Saya akan menerima jika Anda memasukkan yang itu. - person Captain Obvious; 12.06.2018

Coba cara ini:

db.col.aggregate([
    {
        $unwind: '$subs'
    },
    {
        $unwind: '$subs.files'
    },
    {
        $match: {
            'subs.files.spec': 'Unknown'
        }
    }
]);
person karaxuna    schedule 12.06.2018
comment
Ini juga mengembalikan elemen dalam array file yang spesifikasinya tidak sama dengan tidak diketahui, yang tidak saya inginkan (lihat keluaran) - person Captain Obvious; 12.06.2018