Poussez les articles dans le réseau mongo via mangouste

185

J'ai parcouru un bon bout de temps à la recherche de la réponse, mais je suis sûr que je suis perdu pour les bons mots pour décrire ce que je recherche.

Fondamentalement, j'ai une collection mongodb appelée `` people '' Le schéma de cette collection est le suivant:

people: {
         name: String, 
         friends: [{firstName: String, lastName: String}]
        }

Maintenant, j'ai une application express très basique qui se connecte à la base de données et crée avec succès des «personnes» avec un tableau d'amis vide.

Dans un emplacement secondaire de l'application, un formulaire est en place pour ajouter des amis. Le formulaire prend firstName et lastName, puis POSTs avec le champ de nom également pour faire référence à l'objet de personnes approprié.

Ce que j'ai du mal à faire, c'est de créer un nouvel objet ami et de le «pousser» dans le tableau des amis.

Je sais que lorsque je fais cela via la console mongo, j'utilise la fonction de mise à jour avec $ push comme deuxième argument après les critères de recherche, mais je n'arrive pas à trouver le moyen approprié pour que la mangouste fasse cela.

db.people.update({name: "John"}, {$push: {friends: {firstName: "Harry", lastName: "Potter"}}});

MISE À JOUR: Donc, la réponse d'Adrian a été très utile. Voici ce que j'ai fait pour atteindre mon objectif.

dans mon fichier app.js, j'ai défini un itinéraire temporaire en utilisant

app.get('/addfriend', users.addFriend);

où dans mon fichier users.js j'ai

exports.addFriend = function (req, res, next)
{
var friend = {"firstName": req.body.fName, "lastName": req.body.lName};
Users.findOneAndUpdate({name: req.user.name}, {$push: {friends: friend}});
};
Neurax
la source
Je vois que je pourrais potentiellement utiliser collections.findOneAndUpdate (), mais je ne sais pas où j'implémenterais cela? Dans mon modèle?
Neurax

Réponses:

282

En supposant, var friend = { firstName: 'Harry', lastName: 'Potter' };

Deux options s'offrent à vous:

Mettez à jour le modèle en mémoire et enregistrez (plain javascript array.push):

person.friends.push(friend);
person.save(done);

ou

PersonModel.update(
    { _id: person._id }, 
    { $push: { friends: friend } },
    done
);

J'essaie toujours de choisir la première option lorsque cela est possible, car elle respectera davantage les avantages que la mangouste vous offre (crochets, validation, etc.).

Cependant, si vous effectuez beaucoup d'écritures simultanées, vous rencontrerez des conditions de course où vous vous retrouverez avec de vilaines erreurs de version pour vous empêcher de remplacer le modèle entier à chaque fois et de perdre l'ami précédent que vous avez ajouté. Alors n'allez au premier que lorsque c'est absolument nécessaire.

Adrian Schneider
la source
1
Je pensais que la deuxième option était en fait la plus sûre en termes de protection en écriture simultanée? Avez-vous accidentellement dit «dernier» alors que vous vouliez dire «ancien»?
Will Brickner
37
Oui, je viens de vérifier et (en novembre 2017), il est prudent d'utiliser la updatefonction mangouste , alors qu'il n'est PAS sûr de trouver un document, de le modifier en mémoire, puis d'appeler la .save()méthode sur le document. Quand je dis qu'une opération est «sûre», cela signifie que même si un, deux ou 50 changements sont appliqués à un document, ils seront tous appliqués avec succès et le comportement des mises à jour sera comme prévu. La manipulation en mémoire est essentiellement dangereuse car vous pourriez travailler sur un document obsolète. Ainsi, lorsque vous enregistrez, les modifications survenues après l'étape de récupération sont perdues.
Will Brickner
2
@Will Brickner un flux de travail commun pour cela consiste à envelopper votre logique dans une boucle de relance: (retryable contient extraire, modifier, enregistrer). Si vous récupérez une erreur VersionError (exception de verrouillage optimiste), vous pouvez réessayer cette opération plusieurs fois et récupérer une nouvelle copie à chaque fois. Je préfère toujours les mises à jour atomiques lorsque cela est possible!
Adrian Schneider
8
@ZackOfAllTrades M'a également confondu, mais je crois que la fonction de rappel est terminée. let done = function(err, result) { // this runs after the mongoose operation }
utilisateur
comment obtenir l'identifiant de l'objet ami dans le rappel?
Dee Nix
41

L' opérateur $ push ajoute une valeur spécifiée à un tableau.

{ $push: { <field1>: <value1>, ... } }

$ push ajoute le champ de tableau avec la valeur comme élément.

La réponse ci-dessus remplit toutes les conditions, mais je l'ai fait fonctionner en procédant comme suit

var objFriends = { fname:"fname",lname:"lname",surname:"surname" };
Friend.findOneAndUpdate(
   { _id: req.body.id }, 
   { $push: { friends: objFriends  } },
  function (error, success) {
        if (error) {
            console.log(error);
        } else {
            console.log(success);
        }
    });
)
Parth Raval
la source
C'est celle que j'ai trouvée pour fonctionner, donc je pense que c'est la plus à jour en 2019. La meilleure réponse à mon avis manque d'une manière ou d'une autre et peut-être incomplète / obsolète.
Toast au fromage
Puis-je simplement signaler que vous avez peut-être une légère erreur dans le code. Je l'ai fait fonctionner parce que j'ai mis la bonne variable pour mon projet. Où vous avez Friend.findOneAndUpdate () Je pense que cela devrait être People.findOneAndUpdate (). Ce serait plus conforme à la question initiale. Je pourrais le modifier pour vous, mais je préférerais que vous le revérifiez au cas où je me trompe (je suis un peu nouveau sur node / express).
Cheesus Toast
@CheesusToast Je pense que si je me trompe, vous pouvez changer la réponse. J'ai mis cette réponse qui fonctionnait bien pour moi. mais si vous trouvez cette réponse erronée, vous pouvez changer cette réponse et je serai heureux si vous me corrigez monsieur :-).
Parth Raval
1
OK, pas de problème, ce n'était qu'une petite modification de toute façon. C'est un peu difficile de ma part parce que les téléspectateurs (comme moi) auraient de toute façon trouvé où le tableau était poussé. Je pense toujours que cela devrait être la meilleure réponse :)
Cheesus Toast
10

Utilisez $pushpour mettre à jour le document et insérer une nouvelle valeur dans un tableau.

trouver:

db.getCollection('noti').find({})

résultat pour trouver:

{
    "_id" : ObjectId("5bc061f05a4c0511a9252e88"),
    "count" : 1.0,
    "color" : "green",
    "icon" : "circle",
    "graph" : [ 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 2.0
        }
    ],
    "name" : "online visitor",
    "read" : false,
    "date" : ISODate("2018-10-12T08:57:20.853Z"),
    "__v" : 0.0
}

mettre à jour:

db.getCollection('noti').findOneAndUpdate(
   { _id: ObjectId("5bc061f05a4c0511a9252e88") }, 
   { $push: { 
             graph: {
               "date" : ISODate("2018-10-24T08:55:13.331Z"),
               "count" : 3.0
               }  
           } 
   })

résultat pour la mise à jour:

{
    "_id" : ObjectId("5bc061f05a4c0511a9252e88"),
    "count" : 1.0,
    "color" : "green",
    "icon" : "circle",
    "graph" : [ 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 2.0
        }, 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 3.0
        }
    ],
    "name" : "online visitor",
    "read" : false,
    "date" : ISODate("2018-10-12T08:57:20.853Z"),
    "__v" : 0.0
}
KARTHIKEYAN.A
la source
2

Un moyen simple de le faire est d'utiliser les éléments suivants:

var John = people.findOne({name: "John"});
John.friends.push({firstName: "Harry", lastName: "Potter"});
John.save();
Felipe Toledo
la source
0

Dans mon cas, j'ai fait ça

  const eventId = event.id;
  User.findByIdAndUpdate(id, { $push: { createdEvents: eventId } }).exec();
Prathamesh Plus
la source
-3

J'ai également rencontré ce problème. Ma solution consistait à créer un schéma enfant. Voir ci-dessous pour un exemple de vos modèles.

---- Modèle de personne

const mongoose = require('mongoose');
const SingleFriend = require('./SingleFriend');
const Schema   = mongoose.Schema;

const productSchema = new Schema({
  friends    : [SingleFriend.schema]
});

module.exports = mongoose.model('Person', personSchema);

*** Important: SingleFriend.schema -> assurez-vous d'utiliser des minuscules pour le schéma

--- Schéma enfant

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

const SingleFriendSchema = new Schema({
  Name: String
});

module.exports = mongoose.model('SingleFriend', SingleFriendSchema);
theRealSheng
la source
Peut-être que la raison du vote défavorable est que cela ne semble pas nécessaire. La réponse de Parth Raval est tout à fait suffisante.
Cheesus Toast