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

Perbarui subdokumen bersarang di MongoDB dengan arrayFilters

Jadi arrayFilters opsi dengan $[<identifier>] yang difilter posisi benar-benar bekerja dengan baik dengan seri rilis pengembangan sejak MongoDB 3.5.12 dan juga dalam kandidat rilis saat ini untuk seri MongoDB 3.6, di mana ini sebenarnya akan dirilis secara resmi. Satu-satunya masalah tentu saja adalah "driver" yang digunakan belum benar-benar memahami hal ini.

Mengulangi konten yang sama yang telah saya tempatkan pada Memperbarui Array Bersarang dengan MongoDB:

CATATAN Agak ironis, karena ini ditentukan dalam argumen "opsi" untuk .update() dan seperti metode, sintaks umumnya kompatibel dengan semua versi driver rilis terbaru.

Namun ini tidak berlaku untuk mongo shell, karena cara metode ini diterapkan di sana ( "ironisnya untuk kompatibilitas ke belakang" ) arrayFilters argumen tidak dikenali dan dihapus oleh metode internal yang mem-parsing opsi untuk memberikan "kompatibilitas mundur" dengan versi server MongoDB sebelumnya dan .update() "warisan" Sintaks panggilan API.

Jadi jika Anda ingin menggunakan perintah di mongo shell atau produk "berbasis shell" lainnya (terutama Robo 3T ) Anda memerlukan versi terbaru baik dari cabang pengembangan atau rilis produksi mulai 3.6 atau lebih tinggi.

Semua ini berarti bahwa implementasi "driver" saat ini dari .update() sebenarnya "menghapus" argumen yang diperlukan dengan definisi arrayFilters . Untuk NodeJS ini akan dibahas dalam seri rilis driver 3.x, dan tentu saja "luwak" kemungkinan akan memakan waktu beberapa saat setelah rilis itu untuk mengimplementasikan dependensinya sendiri pada driver yang diperbarui, yang kemudian tidak akan lagi "menghapus" tindakan seperti itu.

Namun Anda tetap dapat menjalankan ini di didukung server instance, dengan kembali ke penggunaan sintaks "perbarui perintah" dasar, karena ini melewati metode driver yang diterapkan:

const mongoose = require('mongoose'),
      Schema = mongoose.Schema,
      ObjectId = mongoose.Types.ObjectId;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/test',
      options = { useMongoClient: true };

const contactSchema = new Schema({
  data: String,
  type: String,
  priority: String,
  retries: String
});

const personSchema = new Schema({
  name: String,
  level: String,
  priority: String,
  enabled: Boolean,
  contacts: [contactSchema]
});

const groupSchema = new Schema({
  name: String,
  people: [personSchema],
  workingHours: { start: String, end: String },
  workingDays: { type: [Number], default: undefined },
  contactTypes: {
    workingHours: { type: [String], default: undefined },
    contactTypes: { type: [String], default: undefined }
  }
});

const Group = mongoose.model('Group', groupSchema);

function log(data) {
  console.log(JSON.stringify(data, undefined, 2))
}

(async function() {

  try {

    const conn = await mongoose.connect(uri,options);

    // Clean data
    await Promise.all(
      Object.entries(conn.models).map(([k,m]) => m.remove() )
    );

    // Create sample

    await Group.create({
      name: "support",
      people: [
        {
          "_id": ObjectId("5a05a8c3e0ce3444f8ec5bd8"),
          "enabled": true,
          "level": "1",
          "name": "Someone",
          "contacts": [
            {
              "type": "email",
              "data": "[email protected]"
            },
            {
              "_id": ObjectId("5a05a8dee0ce3444f8ec5bda"),
              "retries": "1",
              "priority": "1",
              "type": "email",
              "data": "[email protected]"
            }
          ]
        }
      ]
    });

    let result = await conn.db.command({
      "update": Group.collection.name,
      "updates": [
        {
          "q": {},
          "u": { "$set": { "people.$[i].contacts.$[j].data": "new data" } },
          "multi": true,
          "arrayFilters": [
            { "i._id": ObjectId("5a05a8c3e0ce3444f8ec5bd8") },
            { "j._id": ObjectId("5a05a8dee0ce3444f8ec5bda") }
          ]
        }
      ]
    });

    log(result);

    let group = await Group.findOne();
    log(group);

  } catch(e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }

})()

Karena itu mengirimkan "perintah" langsung ke server, kami melihat pembaruan yang diharapkan memang terjadi:

Mongoose: groups.remove({}, {})
Mongoose: groups.insert({ name: 'support', _id: ObjectId("5a06557fb568aa0ad793c5e4"), people: [ { _id: ObjectId("5a05a8c3e0ce3444f8ec5bd8"), enabled: true, level: '1', name: 'Someone', contacts: [ { type: 'email', data: '[email protected]', _id: ObjectId("5a06557fb568aa0ad793c5e5") }, { _id: ObjectId("5a05a8dee0ce3444f8ec5bda"), retries: '1', priority: '1', type: 'email', data: '[email protected]' } ] } ], __v: 0 })
{ n: 1,
  nModified: 1,
  opTime:
   { ts: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
     t: 24 },
  electionId: 7fffffff0000000000000018,
  ok: 1,
  operationTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
  '$clusterTime':
   { clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
     signature: { hash: [Object], keyId: 0 } } }
Mongoose: groups.findOne({}, { fields: {} })
{
  "_id": "5a06557fb568aa0ad793c5e4",
  "name": "support",
  "__v": 0,
  "people": [
    {
      "_id": "5a05a8c3e0ce3444f8ec5bd8",
      "enabled": true,
      "level": "1",
      "name": "Someone",
      "contacts": [
        {
          "type": "email",
          "data": "[email protected]",
          "_id": "5a06557fb568aa0ad793c5e5"
        },
        {
          "_id": "5a05a8dee0ce3444f8ec5bda",
          "retries": "1",
          "priority": "1",
          "type": "email",
          "data": "new data"            // <-- updated here
        }
      ]
    }
  ]
}

Jadi benar "sekarang" driver yang tersedia "di luar rak" sebenarnya tidak mengimplementasikan .update() atau rekan pelaksana lainnya dengan cara yang kompatibel dengan benar-benar melewati arrayFilters yang diperlukan argumen. Jadi jika Anda "bermain dengan" seri pengembangan atau server kandidat rilis, maka Anda harus benar-benar siap untuk bekerja dengan "bleeding edge" dan juga driver yang belum dirilis.

Tetapi Anda sebenarnya dapat melakukan ini seperti yang ditunjukkan pada driver apa pun, dalam bentuk yang benar di mana perintah yang dikeluarkan tidak akan diubah.

Pada saat penulisan pada 11 November 2017 tidak ada "resmi" rilis MongoDB atau driver yang didukung yang benar-benar mengimplementasikan ini. Penggunaan produksi harus didasarkan pada rilis resmi server dan driver yang didukung saja.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Bagaimana Cara Membuat Skema Luwak dengan Array ID Objek?

  2. Kueri dengan format tanggal string di mongodb

  3. Membawa MongoDB ke Produksi

  4. Kueri MongoDB dengan elemMatch untuk data array bersarang

  5. Bagaimana cara mencatat kueri saya di MongoDB C# Driver 2.0?