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

mongoDBスキーマのフラット化

    新しい応答

    データを印刷する

    db.test.find().forEach(doc => {
      doc.details = doc.details.map( detail => {
        Object.keys(detail).filter( k => k !== "_id" ).forEach( k => {
          detail[k].forEach( item => {
            Object.keys(item).filter(i => i !== "_id" ).forEach( inner => {
              detail[k + inner.charAt(0).toUpperCase() + inner.substr(1)]
                = item[inner];
            })
          });
          delete detail[k];
        });
        return detail;
      });
      printjson(doc);
    });
    

    データを更新する

    db.test.find().forEach(doc => {
      doc.details = doc.details.map( detail => {
        Object.keys(detail).filter( k => k !== "_id" ).forEach( k => {
          detail[k].forEach( item => {
            Object.keys(item).filter(i => i !== "_id" ).forEach( inner => {
              detail[k + inner.charAt(0).toUpperCase() + inner.substr(1)]
                = item[inner];
            })
          });
          delete detail[k];
        });
        return detail;
      });
    
      ops = [
        ...ops,
        { "updateOne": {
          "filter": { "_id": doc._id },
          "update": { "$set": { "doc.details": doc.details } }
        }}
      ];
    
      if ( ops.length >= 500 ) {
        db.test.bulkWrite(ops);
        ops = [];
      }
    });
    
    if ( ops.length > 0 ) {
      db.test.bulkWrite(ops);
      ops = [];
    }
    

    出力フォーム

    {
        "_id" : ObjectId("58e574a768afb6085ec3a388"),
        "details" : [
            {
              "_id" : ObjectId("58e55f0f68afb6085ec3a2cc"),
              "aUnit" : "08",
              "aSize" : "5",
              "aPos" : "Far",
              "bUnit" : "08",
              "bSize" : "5",
              "bPos" : "Far",
              "cUnit" : "08",
              "cSize" : "3",
              "cPos" : "Far",
              "dUnit" : "08",
              "dSize" : "5",
              "dPos" : "Far"
            }
        ]
    }
    

    元のデータ

    {
        "_id" : ObjectId("58e574a768afb6085ec3a388"),
        "tests" : [
          {
            "_id" : ObjectId("58e542fb68afb6085ec3a1d2"),
            "details" : [
              {
                "a" : [
                  {
                    "unit" : "08",
                    "size" : "5",
                    "pos" : "Far",
                    "_id" : ObjectId("58e542fb68afb6085ec3a1d6")
                  }
                ]
              },
              {
                "b" : [
                  {
                    "pos" : "Drive Side Far",
                    "size" : "5",
                    "unit" : "08",
                    "_id" : ObjectId("58e542fb68afb6085ec3a1d3")
                  }
                ]
              },
              {
                "c" : [
                  {
                    "pos" : "Far",
                    "size" : "3",
                    "unit" : "08",
                    "_id" : ObjectId("58e542fb68afb6085ec3a1d4")
                  }
                ]
              },
              {
                "d" : [
                  {
                    "pos" : "Far",
                    "size" : "5",
                    "unit" : "08",
                    "_id" : ObjectId("58e542fb68afb6085ec3a1d5")
                  }
                ]
              }
            ]
          }
        ]
    }
    

    元の回答

    データを「更新」しようとしている場合、それはあなたが試みているものよりもはるかに複雑です。いくつかの配列があり、それらに直接アクセスしようとするのではなく、実際に配列要素を「トラバース」する必要があります。

    これは、「フラット化された」データを「印刷」するためのサンプルです。

    db.test.find().forEach(doc => {
      doc.tests = doc.tests.map( test => {
        test.details.forEach( detail => {
          Object.keys(detail).forEach( key => {
            detail[key].forEach( item => {
              Object.keys(item).forEach( inner => {
                if ( inner !== '_id' ) {
                  test[key + inner.charAt(0).toUpperCase() + inner.substr(1)]
                    = item[inner];
                }
              });
            });
          });
        });
        delete test.details;
        return test;
      });
      printjson(doc);
    })
    

    これはあなたが探している構造を与えると私は信じています:

    {
        "_id" : ObjectId("58e574a768afb6085ec3a388"),
        "tests" : [
            {
                "_id" : ObjectId("58e542fb68afb6085ec3a1d2"),
                "aUnit" : "08",
                "aSize" : "5",
                "aPos" : "Far",
                "bPos" : "Drive Side Far",
                "bSize" : "5",
                "bUnit" : "08",
                "cPos" : "Far",
                "cSize" : "3",
                "cUnit" : "08",
                "dPos" : "Far",
                "dSize" : "5",
                "dUnit" : "08"
            }
        ]
    
    }
    

    今、私はあなたの"details"の中にある可能性を考慮していません "a"のようなキーでドキュメントを配列します などが複数回表示される可能性があります。したがって、"a"を持つドキュメントは1つしかないと考えています。 または"b" など、およびそのキーに一致する最後に見つかった値は、"details"のトップレベルに新しいキーを追加するときに常に割り当てられます ドキュメント。

    実際のケースが異なる場合は、さまざまな.forEach()を変更する必要があります。 その中でループして、「インデックス」をパラメータとして使用し、そのインデックス値をキー名の一部として含めます。つまり:

    "a0Unit": "08",
    "a0Size": "05",
    "a1Unit": "09",
    "a1Size": "06"
    

    ただし、これは質問でのデータの表示方法とは異なるため、必要に応じて解決する必要がある詳細です。

    ただし、これが更新したいものに完全に適合する場合は、 .bulkWrite() 定期的に実行されるステートメント:

    let ops = [];
    
    db.test.find().forEach(doc => {
      doc.tests = doc.tests.map( test => {
        test.details.forEach( detail => {
          Object.keys(detail).forEach( key => {
            detail[key].forEach( item => {
              Object.keys(item).forEach( inner => {
                if ( inner !== '_id' ) {
                  test[key + inner.charAt(0).toUpperCase() + inner.substr(1)]
                    = item[inner];
                }
              });
            });
          });
        });
        delete test.details;
        return test;
      });
    
      ops = [
        ...ops,
        { "updateOne": {
          "filter": { "_id": doc._id },
          "update": { "$set": { "tests": doc.tests } }
        }}
      ];
    
      if ( ops.length >= 500 ) {
        db.test.bulkWrite(ops);
        ops = [];
      }
    });
    
    if ( ops.length > 0 ) {
      db.test.bulkWrite(ops);
      ops = [];
    }
    

    _idからも表示されます マングースを使用している各配列メンバードキュメントに存在するフィールド。したがって、何をするにしても、マングース自体を使用してコードを実行しようとしないでください。これはデータの「1回限りの」一括更新であり、シェルから直接実行する必要があります。その後、もちろん、新しい構造に合わせてスキーマを変更する必要があります。

    ただし、これが、printjson()を使用してシェル内のデータを実行する必要がある理由です。 最初の方法。



    1. mongodb-native findAndModifyでフィールド名として変数を使用するにはどうすればよいですか?

    2. MongoDBで文字列を配列に変換する方法は?

    3. mongodbに埋め込まれたコメントページング

    4. Spring Boot + Apache Camel+Mongodb統合の問題