Mungo Array-Element im Dokument löschen und speichern

73

Ich habe ein Array in meinem Modelldokument. Ich möchte Elemente in diesem Array basierend auf einem von mir bereitgestellten Schlüssel löschen und dann MongoDB aktualisieren. Ist das möglich?

Hier ist mein Versuch:

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var favorite = new Schema({
    cn: String,
    favorites: Array
});

module.exports = mongoose.model('Favorite', favorite, 'favorite');

exports.deleteFavorite = function (req, res, next) {
    if (req.params.callback !== null) {
        res.contentType = 'application/javascript';
    }
    Favorite.find({cn: req.params.name}, function (error, docs) {
        var records = {'records': docs};
        if (error) {
            process.stderr.write(error);
        }
        docs[0]._doc.favorites.remove({uid: req.params.deleteUid});

        Favorite.save(function (error, docs) {
            var records = {'records': docs};
            if (error) {
                process.stderr.write(error);
            }
            res.send(records);

            return next();
        });
    });
};

Bisher findet es das Dokument, aber das Entfernen oder Speichern funktioniert.

gelegentlich
quelle

Antworten:

119

Sie können das Update auch direkt in MongoDB durchführen, ohne das Dokument laden und mithilfe von Code ändern zu müssen. Verwenden Sie die Operatoren $pulloder $pullAll, um das Element aus dem Array zu entfernen:

Favorite.updateOne( {cn: req.params.name}, { $pullAll: {uid: [req.params.deleteUid] } } )

(Sie können updateMany auch für mehrere Dokumente verwenden.)

http://docs.mongodb.org/manual/reference/operator/update/pullAll/

Daniel Flippance
quelle
6
Ich verstehe nicht, wie dies ein Element aus dem Favoriten-Array entfernt (das Unter-Array nicht das Dokument), ohne auf den Namen Favoriten zu verweisen
Dominic
Auch diese Operation ist atomar. Dies bedeutet, dass das Dokument nicht zwischen separaten Such- und Aktualisierungsvorgängen wechseln kann.
James
1
Vielen Dank! Sehr elegante Lösung.
Miguel Lara
59

Die aktivierte Antwort funktioniert, aber offiziell in MongooseJS spätestens sollten Sie Pull verwenden .

doc.subdocs.push({ _id: 4815162342 }) // added
doc.subdocs.pull({ _id: 4815162342 }) // removed

https://mongoosejs.com/docs/api.html#mongoosearray_MongooseArray-pull

Ich habe das auch nur nachgeschlagen.

Siehe Daniels Antwort für die richtige Antwort. Viel besser.

Jason Sebring
quelle
@LondonRob +1 hat eine gute Bearbeitung vorgenommen, wir sollten darauf achten, keine unsicheren Links im Allgemeinen zu verwenden.
Jason Sebring
das brauchte ich! Es ist sauber und einfach mit IDs zu verwenden, die ein Ref in einem anderen Modell sind
Tarafenton
14

Die obigen Antworten zeigen, wie Sie ein Array entfernen und wie Sie ein Objekt aus einem Array ziehen.

Referenz: https://docs.mongodb.com/manual/reference/operator/update/pull/

db.survey.update( // select your doc in moongo
    { }, // your query, usually match by _id
    { $pull: { results: { $elemMatch: { score: 8 , item: "B" } } } }, // item(s) to match from array you want to pull/remove
    { multi: true } // set this to true if you want to remove multiple elements.
)
Mike Musni
quelle
5

Da Favoriten ein Array sind, müssen Sie es nur abspleißen und das Dokument speichern.

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var favorite = new Schema({
    cn: String,
    favorites: Array
});

module.exports = mongoose.model('Favorite', favorite);

exports.deleteFavorite = function (req, res, next) {
    if (req.params.callback !== null) {
        res.contentType = 'application/javascript';
    }
    // Changed to findOne instead of find to get a single document with the favorites.
    Favorite.findOne({cn: req.params.name}, function (error, doc) {
        if (error) {
            res.send(null, 500);
        } else if (doc) {
            var records = {'records': doc};
            // find the delete uid in the favorites array
            var idx = doc.favorites ? doc.favorites.indexOf(req.params.deleteUid) : -1;
            // is it valid?
            if (idx !== -1) {
                // remove it from the array.
                doc.favorites.splice(idx, 1);
                // save the doc
                doc.save(function(error) {
                    if (error) {
                        console.log(error);
                        res.send(null, 500);
                    } else {
                        // send the records
                        res.send(records);
                    }
                });
                // stop here, otherwise 404
                return;
            }
        }
        // send 404 not found
        res.send(null, 404);
    });
};
Hozuki
quelle
Vielen Dank für eine sehr gründliche Antwort.
gelegentlich
4
Wenn Sie versuchen, zwei Dinge gleichzeitig zu entfernen, erhalten beide möglicherweise das Array und ändern es dann. Die erste gespeicherte Änderung wird von der zweiten überschrieben. Ich würde lieber mit etw wie diesem stackoverflow.com/questions/16959099/… gehen .
Maximosaic
3

Das funktioniert bei mir und ist wirklich sehr hilfreich.

SubCategory.update({ _id: { $in:
        arrOfSubCategory.map(function (obj) {
            return mongoose.Types.ObjectId(obj);
        })
    } },
    {
        $pull: {
            coupon: couponId,
        }
    }, { multi: true }, function (err, numberAffected) {
        if(err) {
            return callback({
                error:err
            })
        }
    })
});

Ich habe ein Modell mit dem Namen SubCategoryund möchte Coupon aus dieser Kategorie Array entfernen. Ich habe eine Reihe von Kategorien, die ich verwendet habe arrOfSubCategory. Also rufe ich jedes Array von Objekten mit Hilfe des $inOperators mit Map-Funktion aus diesem Array ab .

Codierer
quelle
2
keywords = [1,2,3,4];
doc.array.pull(1) //this remove one item from a array
doc.array.pull(...keywords) // this remove multiple items in a array

Wenn Sie verwenden möchten, ...sollten Sie 'use strict';oben in Ihrer js-Datei aufrufen. :) :)

crazy_phage
quelle