sql >> Database >  >> NoSQL >> MongoDB

MongoDB-schema afvlakken

Nieuwe reactie

Druk de gegevens af

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

De gegevens bijwerken

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

Uitvoerformulier

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

Oorspronkelijke gegevens

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

Oorspronkelijk antwoord

Als u uw gegevens probeert te "updaten", dan is er veel meer bij betrokken dan wat u probeert. U hebt verschillende arrays en u moet de array-elementen daadwerkelijk "doorkruisen" in plaats van ze rechtstreeks te proberen te benaderen.

Hier is slechts een voorbeeld om de "afgeplatte" gegevens te "afdrukken":

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

Wat volgens mij de structuur geeft waarnaar u op zoek bent:

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

}

Nu houd ik geen rekening met de mogelijkheid dat in uw "details" rangschik de documenten met sleutels zoals "a" enz. kan misschien meerdere keren verschijnen. Dus ik bedenk gewoon dat er maar één document in zit met een "a" of een "b" enz., en de laatst gevonden waarde die overeenkomt met die sleutel wordt altijd toegewezen wanneer de nieuwe sleutels worden toegevoegd aan het bovenste niveau van de "details" documenten.

Als het werkelijke geval varieert, moet u verschillende .forEach() . aanpassen lussen daarbinnen om ook de "index" als parameter te gebruiken en die indexwaarde op te nemen als onderdeel van de sleutelnaam. dat wil zeggen:

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

Maar dat is een detail dat u zo nodig zult moeten uitwerken, aangezien dit anders zou zijn dan hoe de gegevens in de vraag worden gepresenteerd.

Als dit echter perfect past bij datgene waarnaar u wilt updaten, voer dan gewoon de lus uit met .bulkWrite() opdrachten die met regelmatige tussenpozen worden uitgevoerd:

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

Het blijkt ook uit de _id velden die aanwezig zijn in elk matrixliddocument dat u mangoest gebruikt. Dus wat je ook doet, probeer de code niet uit te voeren met behulp van mangoest zelf. Het is een "eenmalige" bulkupdate van uw gegevens en moet rechtstreeks vanuit de shell worden uitgevoerd. Dan moet je natuurlijk je schema aanpassen aan de nieuwe structuur.

Maar dit is waarom u uw gegevens in de shell moet doorlopen met de printjson() methode eerst.



  1. MongoDb-verbinding geweigerd

  2. Verbinding maken met MongoDB-replicaset met rmongodb

  3. Wat is het verschil tussen findOneAndUpdate en findOneAndReplace?

  4. $pull meerdere objecten in Mongo werkt niet