MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Abflachen des mongoDB-Schemas

Neue Antwort

Daten drucken

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

Aktualisieren Sie die Daten

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 = [];
}

Ausgabeformular

{
    "_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"
        }
    ]
}

Originaldaten

{
    "_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")
              }
            ]
          }
        ]
      }
    ]
}

Originalantwort

Wenn Sie versuchen, Ihre Daten zu "aktualisieren", ist dies viel komplizierter als das, was Sie versuchen. Sie haben mehrere Arrays und müssen die Array-Elemente tatsächlich "durchqueren", anstatt zu versuchen, direkt auf sie zuzugreifen.

Hier ist nur ein Beispiel zum "Ausdrucken" der "reduzierten" Daten:

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

Was meiner Meinung nach die Struktur ergibt, nach der Sie suchen:

{
    "_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"
        }
    ]

}

Jetzt ziehe ich keine Möglichkeit in Betracht, dass in Ihren "details" Ordnen Sie die Dokumente mit Schlüsseln wie "a" an usw. könnten möglicherweise mehrfach vorkommen. Ich überlege also nur, dass es dort immer nur 1 Dokument gibt, das ein "a" hat oder ein "b" usw., und der letzte gefundene Wert, der mit diesem Schlüssel übereinstimmt, wird immer zugewiesen, wenn die neuen Schlüssel zur obersten Ebene der "details" hinzugefügt werden Dokumente.

Wenn Ihr tatsächlicher Fall variiert, müssten Sie verschiedene .forEach() ändern Schleifen darin, um auch den "Index" als Parameter zu verwenden und diesen Indexwert als Teil des Schlüsselnamens einzuschließen. d.h.:

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

Aber das ist ein Detail, das Sie gegebenenfalls ausarbeiten müssen, da dies von der Darstellung der Daten in der Frage abweichen würde.

Wenn dies jedoch perfekt zu dem passt, worauf Sie aktualisieren möchten, führen Sie die Schleife einfach mit .bulkWrite() Anweisungen, die in regelmäßigen Abständen ausgeführt werden:

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 = [];
}

Sie erscheint auch aus der _id Felder, die in jedem Array-Member-Dokument vorhanden sind, das Sie Mongoose verwenden. Was auch immer Sie tun, versuchen Sie nicht, den Code mit Mongoose selbst auszuführen. Es ist eine "einmalige" Massenaktualisierung Ihrer Daten und sollte direkt von der Shell ausgeführt werden. Dann müssen Sie natürlich Ihr Schema an die neue Struktur anpassen.

Aber deswegen solltest du deine Daten in der Shell mit dem printjson() durchgehen Methode zuerst.