sql >> データベース >  >> NoSQL >> MongoDB

arrayFiltersを使用してMongoDBのネストされたサブドキュメントを更新します

    したがって、arrayFilters 位置フィルタリングされた$[<identifier>]のオプション 実際には、MongoDB 3.5.12以降の開発リリースシリーズ、および実際に正式にリリースされるMongoDB3.6シリーズの現在のリリース候補で適切に機能します。もちろん、唯一の問題は、使用中の「ドライバー」が実際にはまだこれに追いついていないことです。

    MongoDBを使用したネストされた配列の更新ですでに配置したのと同じコンテンツを繰り返します:

    皮肉なことに、これは.update()の"options"引数で指定されているためです。 メソッドと同様に、構文は通常、最近のすべてのリリースドライバーバージョンと互換性があります。

    ただし、これはmongoには当てはまりません。 シェル、メソッドがそこで実装される方法(「下位互換性のために皮肉なことに」)arrayFilters 引数は、以前のMongoDBサーバーバージョンおよび「レガシー」.update()との「下位互換性」を提供するためにオプションを解析する内部メソッドによって認識および削除されません。 API呼び出しの構文。

    したがって、mongoでコマンドを使用する場合 シェルまたはその他の「シェルベース」の製品(特にRobo 3T)には、3.6以降の開発ブランチまたは製品リリースの最新バージョンが必要です。

    これはすべて、.update()の現在の「ドライバー」実装を意味します arrayFiltersの定義を使用して、必要な引数を実際に「削除」します 。 NodeJSの場合、これはドライバーの3.xリリースシリーズで対処されます。もちろん、「mongoose」は、そのリリース後、更新されたドライバーへの独自の依存関係を実装するのに時間がかかる可能性があります。そのような行動。

    ただし、これはサポートされているでも実行できます。 サーバーインスタンス。実装されたドライバーメソッドをバイパスしたため、基本的な「updatecommand」構文の使用法に戻ります。

    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();
      }
    
    })()
    

    これにより「コマンド」がサーバーに直接送信されるため、予想される更新が実際に行われていることがわかります。

    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
            }
          ]
        }
      ]
    }
    

    そうです「今」 「既成」で利用可能なドライバーは、実際には.update()を実装していません。 または、必要なarrayFiltersを実際に通過することと互換性のある方法で他の実装対応物です 口論。したがって、開発シリーズまたはリリース候補サーバーで「遊んでいる」場合は、「最先端」のドライバーやリリースされていないドライバーでも作業できるように準備する必要があります。

    ただし、実際には、発行されているコマンドが変更されない正しい形式で、任意のドライバーで示されているようにこれを行うことができます。

    2017年11月11日の執筆時点では、「公式」はありません。 MongoDBまたはこれを実際に実装するサポートされているドライバーのリリース。本番環境での使用は、サーバーの公式リリースとサポートされているドライバーのみに基づく必要があります。




    1. MongoDBでのプッシュ操作

    2. MongoDbで15分の時間間隔で結果をグループ化します

    3. AmazonEC2にMongoDBをデプロイするための6つのベストプラクティス

    4. mongodbの日付でグループ化