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

Query Mongodb berdasarkan jumlah bidang dalam catatan

Ini masih bukan kueri yang bagus untuk dijalankan, tetapi ada cara yang sedikit lebih modern untuk melakukannya melalui $objectToArray dan $redact

db.collection.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$eq": [
          { "$size": { "$objectToArray": "$value" } },
          3
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

Dimana $objectToArray pada dasarnya memaksa objek ke dalam bentuk array, seperti kombinasi Object.keys() dan .map() akan di JavaScript.

Itu masih bukan ide yang fantastis karena memang memerlukan pemindaian seluruh koleksi, tetapi setidaknya operasi kerangka kerja agregasi menggunakan "kode asli" sebagai lawan dari interpretasi JavaScript seperti halnya menggunakan $where .

Jadi secara umum masih disarankan untuk mengubah struktur data dan menggunakan larik alami serta properti "ukuran" yang disimpan jika memungkinkan untuk membuat operasi kueri yang paling efektif.

Ya itu mungkin untuk dilakukan tetapi tidak dengan cara yang paling baik. Alasannya adalah karena Anda pada dasarnya menggunakan $where kueri operator yang menggunakan evaluasi JavaScript untuk mencocokkan konten. Bukan cara yang paling efisien karena ini tidak pernah dapat menggunakan indeks dan perlu menguji semua dokumen:

db.collection.find({ "$where": "return Object.keys(this.value).length == 3" })

Ini mencari kondisi yang cocok dengan elemen "tiga", maka hanya dua dari dokumen terdaftar Anda yang akan dikembalikan:

{ "_id" : "number1", "value" : { "a" : 1, "b" : 2, "f" : 5 } }
{ "_id" : "number2", "value" : { "e" : 2, "f" : 114, "h" : 12 } }

Atau untuk bidang "lima" atau lebih, Anda dapat melakukan hal yang sama:

db.numbers.find({ "$where": "return Object.keys(this.value).length >= 5" })

Jadi argumen ke operator itu secara efektif adalah pernyataan JavaScript yang dievaluasi di server untuk mengembalikan ke tempat true .

Cara yang lebih efisien adalah dengan menyimpan "jumlah" elemen dalam dokumen itu sendiri. Dengan cara ini Anda dapat "mengindeks" bidang ini dan kueri jauh lebih efisien karena setiap dokumen dalam kumpulan yang dipilih oleh kondisi lain tidak perlu dipindai untuk menentukan panjangnya:

{_id:'number1', value:{'a':1, 'b':2, 'f':5} count: 3},
{_id:'number2', value:{'e':2, 'f':114, 'h':12}, count: 3},
{_id:'number3', value:{'i':2, 'j':22, 'z':12, 'za':111, 'zb':114}, count: 5}

Kemudian untuk mendapatkan dokumen dengan elemen "lima" Anda hanya perlu query sederhana:

db.collection.find({ "count": 5 })

Itu umumnya bentuk yang paling optimal. Tetapi poin lain adalah bahwa struktur "Objek" umum yang mungkin Anda sukai dari praktik umum bukanlah sesuatu yang "bermain baik" dengan MongoDB secara umum. Masalahnya adalah "traversal" elemen dalam objek, dan dengan cara ini MongoDB jauh lebih bahagia ketika Anda menggunakan "array". Dan bahkan dalam bentuk ini:

{
    '_id': 'number1', 
    'values':[
        { 'key': 'a', 'value': 1 },
        { 'key': 'b', 'value': 2 }, 
        { 'key': 'f', 'value': 5 }
    ],
},
{
    '_id': 'number2', 
    'values':[
        { 'key': 'e', 'value': 2 }, 
        { 'key': 'f', 'value': 114 }, 
        { 'key': 'h', 'value': 12 }
    ],
},
{
    '_id':'number3', 
    'values': [
        { 'key': 'i', 'values': 2 }, 
        { 'key': 'j', 'values': 22 }, 
        { 'key': 'z'' 'values': :12 }, 
        { 'key': 'za', 'values': 111 },
        { 'key': 'zb', 'values': 114 }
    ]
}

Jadi, jika Anda benar-benar beralih ke format "array" seperti itu, Anda dapat melakukan tepat panjang larik dengan satu versi $size operator:

db.collection.find({ "values": { "$size": 5 } })

Operator tersebut dapat bekerja dengan tepat nilai untuk panjang array karena itu adalah ketentuan dasar dari apa yang dapat dilakukan dengan operator ini. Apa yang tidak dapat Anda lakukan seperti yang didokumentasikan dalam kecocokan "kesetaraan". Untuk itu Anda memerlukan "kerangka kerja agregasi" untuk MongoDB, yang merupakan alternatif yang lebih baik untuk operasi JavaScript dan mapReduce:

db.collection.aggregate([
    // Project a size of the array
    { "$project": {
        "values": 1,
        "size": { "$size": "$values" }
    }},
    // Match on that size
    { "$match": { "size": { "$gte": 5 } } },
    // Project just the same fields 
    {{ "$project": {
        "values": 1
    }}
])

Jadi itulah alternatifnya. Ada metode "asli" yang tersedia untuk agregasi dan tipe array. Tetapi cukup diperdebatkan bahwa evaluasi JavaScript juga "asli" untuk MongoDB, hanya karena itu tidak diimplementasikan dalam kode asli.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB:Bagaimana cara mengetahui apakah bidang array berisi elemen?

  2. Cara deserialize objek BsonDocument kembali ke kelas

  3. Kerangka agregasi MongoDB $kurangi

  4. Sinkronkan MongoDB Melalui ssh

  5. Membuat daftar bernomor untuk data Meteor