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

Kondisi pertandingan dan tanggal terbaru dari array

Konsep dasarnya di sini adalah Anda memerlukan kerangka kerja agregasi untuk menerapkan kondisi untuk "memfilter" elemen array ke kondisi. Tergantung pada versi yang tersedia, ada beberapa teknik berbeda yang dapat diterapkan.

Dalam semua kasus inilah hasilnya:

{
    "_id" : ObjectId("593921425ccc8150f35e7664"),
    "user1" : 1,
    "user2" : 4,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-09T10:04:50Z"),
            "body" : "hiii 1"
    }
}
{
    "_id" : ObjectId("593921425ccc8150f35e7663"),
    "user1" : 1,
    "user2" : 3,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-10T10:04:50Z"),
            "body" : "hiii 2"
    }
}
{
    "_id" : ObjectId("593921425ccc8150f35e7662"),
    "user1" : 1,
    "user2" : 2,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-08T10:04:50Z"),
            "body" : "hiii 0"
    }
}

MongoDB 3.4 dan di atasnya

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$replaceRoot": {
    "newRoot": {
      "$let": {
        "vars": {
          "messages": {
            "$filter": {
              "input": "$messages",
              "as": "m",
              "cond": { "$eq": [ "$$m.sender", 1 ] }
            }
          },
          "maxDate": {
            "$max": {
              "$map": {
                "input": {
                  "$filter": {
                    "input": "$messages",
                    "as": "m",
                    "cond": { "$eq": [ "$$m.sender", 1 ] }
                  }
                },
                "as": "m",
                "in": "$$m.datetime"
              }
            }
          }
        },
        "in": {
          "_id": "$_id",
          "user1": "$user1",
          "user2": "$user2",
          "messages": {
            "$arrayElemAt": [
              { "$filter": {
                "input": "$$messages",
                "as": "m",
                "cond": { "$eq": [ "$$m.datetime", "$$maxDate" ] }
              }},
              0
            ]
          }    
        }
      }
    }
  }}
])

Ini adalah cara paling efisien yang memanfaatkan $replaceRoot yang memungkinkan kita mendeklarasikan variabel untuk digunakan dalam struktur "diganti" menggunakan $let . Keuntungan utama di sini adalah bahwa ini hanya membutuhkan "dua" tahap pipa.

Untuk mencocokkan konten larik, Anda menggunakan $filter tempat Anda menerapkan $eq operasi logis untuk menguji nilai "sender" . Jika kondisinya cocok, maka hanya entri larik yang cocok yang dikembalikan.

Menggunakan $filter yang sama sehingga hanya entri "pengirim" yang cocok yang dipertimbangkan, kami kemudian ingin menerapkan $max di atas daftar "difilter" ke nilai dalam "datetime" . $max ]5 nilai adalah tanggal "terbaru" menurut ketentuan.

Kami menginginkan nilai ini sehingga nanti kami dapat membandingkan hasil yang dikembalikan dari larik "terfilter" dengan "maxDate" ini. Itulah yang terjadi di dalam "in" blok $let di mana dua "variabel" yang dideklarasikan sebelumnya untuk konten yang difilter dan "maxDate" diterapkan lagi ke $filter untuk mengembalikan apa yang seharusnya menjadi satu-satunya nilai yang memenuhi kedua kondisi yang memiliki "tanggal terbaru" juga.

Karena Anda hanya menginginkan hasil "satu", kami menggunakan $arrayElemAt untuk menggunakan nilai daripada array.

MongoDB 3.2

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$project": {
    "user1": 1,
    "user2": 1,
    "messages": {
      "$filter": {
        "input": "$messages",
        "as": "m",
        "cond": { "$eq": [ "$$m.sender", 1 ] }
      }
    },
    "maxDate": {
      "$max": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$messages",
              "as": "m",
              "cond": { "$eq": [ "$$m.sender", 1 ] }
            }
          },
          "as": "m",
          "in": "$$m.datetime"
        }
      }
    }         
  }},
  { "$project": {
    "user1": 1,
    "user2": 1,
    "messages": {
      "$arrayElemAt":[
       { "$filter": {
         "input": "$messages",
          "as": "m",
          "cond": { "$eq": [ "$$m.datetime", "$maxDate" ] }
       }},
       0
      ]
    }
  }}
])

Ini pada dasarnya adalah proses yang sama seperti yang dijelaskan, tetapi tanpa $replaceRoot tahap pipa, kita perlu menerapkan dalam dua $project tahapan. Alasan untuk ini adalah kita memerlukan "nilai yang dihitung" dari "maxDate" untuk melakukan itu $filter , dan itu tidak tersedia untuk dilakukan dalam pernyataan majemuk, jadi alih-alih kami membagi jalur pipa. Ini berdampak kecil pada keseluruhan biaya operasi.

Di MongoDB 2.6 hingga 3.0 kita dapat menggunakan sebagian besar teknik di sini kecuali untuk $arrayElemAt dan terima hasil "array" dengan satu entri atau masukkan $unwind tahap untuk menangani apa yang sekarang seharusnya menjadi satu entri.

MongoDB versi sebelumnya

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$unwind": "$messages" },
  { "$match": { "messages.sender": 1 } },
  { "$sort": { "_id": 1, "messages.datetime": -1 } },
  { "$group": {
    "_id": "$_id",
    "user1": { "$first": "$user1" },
    "user2": { "$first": "$user2" },
    "messages": { "$first": "$messages" }
  }}
])

Meskipun terlihat singkat, ini adalah operasi yang paling mahal. Di sini Anda harus menggunakan $unwind untuk menerapkan kondisi ke elemen array. Ini adalah proses yang sangat mahal karena menghasilkan salinan setiap dokumen untuk setiap entri array, dan pada dasarnya digantikan oleh operator modern yang menghindari hal ini dalam kasus "pemfilteran".

$match kedua stage di sini membuang elemen apa pun ( sekarang "dokumen" ) yang tidak cocok dengan kondisi "pengirim". Kemudian kami menerapkan $sort untuk menempatkan tanggal "terbaru" di atas setiap dokumen dengan _id , maka dua kunci "sort".

Akhirnya kami menerapkan $group untuk hanya merujuk ke dokumen asli, gunakan $first sebagai akumulator untuk mendapatkan elemen yang "di atas".




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Apakah urutan Kunci penting dalam dokumen MongoDB BSON?

  2. pymongo auth gagal dalam skrip python

  3. Perbarui array multi-sarang di Mongodb

  4. Tambahkan bidang dengan nilai yang meningkat di Agregasi MongoDB berdasarkan kondisi

  5. Mengalami Kesulitan Menggunakan MongoDb C# Driver's Sample()