549 Stimmen

MongoDB-Feld mit dem Wert eines anderen Feldes aktualisieren

Ist es in MongoDB möglich, den Wert eines Feldes mit dem Wert eines anderen Feldes zu aktualisieren? Die entsprechende SQL-Anweisung wäre etwa wie folgt:

UPDATE Person SET Name = FirstName + ' ' + LastName

Und der MongoDB-Pseudocode würde lauten:

db.person.update( {}, { $set : { name : firstName + ' ' + lastName } );

572voto

styvane Punkte 55147

Der beste Weg, dies zu tun, ist in Version 4.2+, die die Verwendung der Aggregationspipeline in der アップデート Dokument und das updateOne , updateMany , oder update (veraltet in den meisten, wenn nicht allen Sprachen Treiber) Sammlung Methoden.

MongoDB 4.2+

Mit Version 4.2 wurde auch die $set Pipeline-Stufenoperator, der ein Alias ist für $addFields . Ich werde verwenden $set hier, da es Karten mit dem, was wir zu erreichen versuchen.

db.collection.<update method>(
    {},
    [
        {"$set": {"name": { "$concat": ["$firstName", " ", "$lastName"]}}}
    ]
)

Beachten Sie, dass die eckigen Klammern im zweiten Argument der Methode eine Aggregationspipeline anstelle eines einfachen Aktualisierungsdokuments angeben, da die Verwendung eines einfachen Dokuments no korrekt funktionieren.

MongoDB 3.4+

In 3.4+ können Sie $addFields und die $out Betreiber von Aggregationspipelines.

db.collection.aggregate(
    [
        { "$addFields": { 
            "name": { "$concat": [ "$firstName", " ", "$lastName" ] } 
        }},
        { "$out": <output collection name> }
    ]
)

Beachten Sie, dass diese aktualisiert Ihre Sammlung nicht, sondern ersetzt die bestehende Sammlung oder erstellt eine neue. Auch bei Aktualisierungsvorgängen, die eine "typecasting" benötigen Sie eine clientseitige Verarbeitung, und je nach Vorgang müssen Sie möglicherweise die find() Methode statt der Methode .aggreate() Methode.

MongoDB 3.2 und 3.0

Wir tun dies, indem wir $project unserer Dokumente und die Nutzung der $concat String-Aggregationsoperator, um die verkettete Zeichenfolge zurückzugeben. Anschließend iterieren Sie die Cursor und verwenden Sie die $set Aktualisierungsoperator, um das neue Feld zu Ihren Dokumenten hinzuzufügen, indem Sie Massengeschäfte für maximale Effizienz.

Aggregationsabfrage:

var cursor = db.collection.aggregate([ 
    { "$project":  { 
        "name": { "$concat": [ "$firstName", " ", "$lastName" ] } 
    }}
])

MongoDB 3.2 oder neuere Version

Sie müssen die bulkWrite Methode.

var requests = [];
cursor.forEach(document => { 
    requests.push( { 
        'updateOne': {
            'filter': { '_id': document._id },
            'update': { '$set': { 'name': document.name } }
        }
    });
    if (requests.length === 500) {
        //Execute per 500 operations and re-init
        db.collection.bulkWrite(requests);
        requests = [];
    }
});

if(requests.length > 0) {
     db.collection.bulkWrite(requests);
}

MongoDB 2.6 und 3.0

Ab dieser Version müssen Sie das inzwischen veraltete Bulk API und seine verbundene Methoden .

var bulk = db.collection.initializeUnorderedBulkOp();
var count = 0;

cursor.snapshot().forEach(function(document) { 
    bulk.find({ '_id': document._id }).updateOne( {
        '$set': { 'name': document.name }
    });
    count++;
    if(count%500 === 0) {
        // Excecute per 500 operations and re-init
        bulk.execute();
        bulk = db.collection.initializeUnorderedBulkOp();
    }
})

// clean up queues
if(count > 0) {
    bulk.execute();
}

MongoDB 2.4

cursor["result"].forEach(function(document) {
    db.collection.update(
        { "_id": document._id }, 
        { "$set": { "name": document.name } }
    );
})

264voto

Carlos Morales Punkte 5293

Sie sollten iterativ vorgehen. Für Ihren speziellen Fall:

db.person.find().snapshot().forEach(
    function (elem) {
        db.person.update(
            {
                _id: elem._id
            },
            {
                $set: {
                    name: elem.firstname + ' ' + elem.lastname
                }
            }
        );
    }
);

108voto

Niels van der Rest Punkte 30365

Anscheinend gibt es seit MongoDB 3.4 eine Möglichkeit, dies effizient zu tun, siehe styvane's Antwort .


Überholte Antwort unten

Sie können in einer Aktualisierung (noch) nicht auf das Dokument selbst verweisen. Sie müssen die Dokumente iterativ durchgehen und jedes Dokument mit einer Funktion aktualisieren. Siehe 本答 für ein Beispiel, oder diese für serverseitige eval() .

49voto

Eric Kigathi Punkte 1617

Bei einer Datenbank mit hoher Aktivität können Sie auf Probleme stoßen, wenn Ihre Aktualisierungen sich aktiv ändernde Datensätze betreffen, und aus diesem Grund empfehle ich snapshot()

db.person.find().snapshot().forEach( function (hombre) {
    hombre.name = hombre.firstName + ' ' + hombre.lastName; 
    db.person.save(hombre); 
});

http://docs.mongodb.org/manual/reference/method/cursor.snapshot/

43voto

Xavier Guihot Punkte 42435

Start: Mongo 4.2 , db.collection.update() kann eine Aggregationspipeline akzeptieren, die schließlich die Aktualisierung/Erstellung eines Feldes auf der Grundlage eines anderen Feldes ermöglicht:

// { firstName: "Hello", lastName: "World" }
db.collection.update(
  {},
  [{ $set: { name: { $concat: [ "$firstName", " ", "$lastName" ] } } }],
  { multi: true }
)
// { "firstName" : "Hello", "lastName" : "World", "name" : "Hello World" }
  • Der erste Teil {} ist die Abgleichsabfrage, die filtert, welche Dokumente aktualisiert werden sollen (in unserem Fall alle Dokumente).

  • Der zweite Teil [{ $set: { name: { ... } }] ist die Aggregationspipeline für die Aktualisierung (beachten Sie die eckigen Klammern, die die Verwendung einer Aggregationspipeline anzeigen). $set ist ein neuer Aggregationsoperator und ein Alias von $addFields .

  • Vergessen Sie nicht { multi: true } , andernfalls wird nur das erste übereinstimmende Dokument aktualisiert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X