MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Proyeksi MongoDB dari Array Bersarang

Pembaruan 2017

Pertanyaan yang diajukan dengan baik seperti itu layak mendapat tanggapan modern. Jenis pemfilteran array yang diminta sebenarnya dapat dilakukan dalam rilis MongoDB modern pasca 3.2 hanya melalui $match dan $project tahapan pipeline, seperti yang diinginkan oleh operasi kueri biasa.

db.accounts.aggregate([
  { "$match": {
    "email" : "[email protected]",
    "groups": {
      "$elemMatch": { 
        "name": "group1",
        "contacts.localId": { "$in": [ "c1","c3", null ] }
      }
    }
  }},
  { "$addFields": {
    "groups": {
      "$filter": {
        "input": {
          "$map": {
            "input": "$groups",
            "as": "g",
            "in": {
              "name": "$$g.name",
              "contacts": {
                "$filter": {
                  "input": "$$g.contacts",
                  "as": "c",
                  "cond": {
                    "$or": [
                      { "$eq": [ "$$c.localId", "c1" ] },
                      { "$eq": [ "$$c.localId", "c3" ] }
                    ]
                  } 
                }
              }
            }
          }
        },
        "as": "g",
        "cond": {
          "$and": [
            { "$eq": [ "$$g.name", "group1" ] },
            { "$gt": [ { "$size": "$$g.contacts" }, 0 ] }
          ]
        }
      }
    }
  }}
])

Ini menggunakan $filter dan $map operator untuk hanya mengembalikan elemen dari larik jika memenuhi persyaratan, dan kinerjanya jauh lebih baik daripada menggunakan $unwind . Karena tahapan pipeline secara efektif mencerminkan struktur "query" dan "project" dari .find() operasi, kinerja di sini pada dasarnya setara dengan operasi itu.

Perhatikan bahwa tujuannya adalah untuk benar-benar berfungsi "di seluruh dokumen" untuk menyatukan detail dari "beberapa" dokumen daripada "satu", maka ini biasanya memerlukan beberapa jenis $unwind operasi untuk melakukannya, sehingga memungkinkan item array dapat diakses untuk "pengelompokan".

Ini pada dasarnya pendekatannya:

db.accounts.aggregate([
    // Match the documents by query
    { "$match": {
        "email" : "[email protected]",
        "groups.name": "group1",
        "groups.contacts.localId": { "$in": [ "c1","c3", null ] },
    }},

    // De-normalize nested array
    { "$unwind": "$groups" },
    { "$unwind": "$groups.contacts" },

    // Filter the actual array elements as desired
    { "$match": {
        "groups.name": "group1",
        "groups.contacts.localId": { "$in": [ "c1","c3", null ] },
    }},

    // Group the intermediate result.
    { "$group": {
        "_id": { "email": "$email", "name": "$groups.name" },
        "contacts": { "$push": "$groups.contacts" }
    }},

    // Group the final result
    { "$group": {
        "_id": "$_id.email",
        "groups": { "$push": {
            "name": "$_id.name",
            "contacts": "$contacts" 
        }}
    }}
])

Ini adalah "pemfilteran array" pada lebih dari satu kecocokan yang merupakan kemampuan proyeksi dasar .find() tidak bisa.

Anda memiliki array "bersarang" karena itu Anda perlu memproses $unwind dua kali. Bersama dengan operasi lainnya.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Pemantauan Database Tanpa Agen dengan ClusterControl

  2. Apa cara yang disarankan untuk menjatuhkan indeks menggunakan Mongoose?

  3. Dapatkan _id dari dokumen yang dimasukkan di MongoDB?

  4. ScaleGrid Mengumumkan Layanan Hosting MongoDB di Kanada

  5. Kunci dinamis setelah $group by