Mongoose peupler après sauvegarde

Je ne peux pas remplir manuellement ou automatiquement le champ créateur sur un object nouvellement enregistré … la seule façon que je puisse trouver est de demander à nouveau les objects que je déteste déjà.

Ceci est la configuration:

var userSchema = new mongoose.Schema({ name: Ssortingng, }); var User = db.model('User', userSchema); var bookSchema = new mongoose.Schema({ _creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, description: Ssortingng, }); var Book = db.model('Book', bookSchema); 

C’est là que je tire mes cheveux

 var user = new User(); user.save(function(err) { var book = new Book({ _creator: user, }); book.save(function(err){ console.log(book._creator); // is just an object id book._creator = user; // still only attaches the object id due to Mongoose magic console.log(book._creator); // Again: is just an object id // I really want book._creator to be a user without having to go back to the db ... any suggestions? }); }); 

EDIT: la dernière mongoose a résolu ce problème et ajouté une fonctionnalité de remplissage, voir la nouvelle réponse acceptée.

Vous devriez pouvoir utiliser la fonction de remplissage du modèle pour faire ceci: http://mongoosejs.com/docs/api.html#model_Model.populate Dans le gestionnaire de sauvegarde de book, au lieu de:

 book._creator = user; 

vous feriez quelque chose comme:

 Book.populate(book, {path:"_creator"}, function(err, book) { ... }); 

Probablement trop tard une réponse pour vous aider, mais j’ai été coincé récemment, et cela pourrait être utile pour les autres.

Au cas où quelqu’un est encore à la recherche de cela.

Mongoose 3.6 a introduit de nombreuses fonctionnalités intéressantes à remplir:

 book.populate('_creator', function(err) { console.log(book._creator); }); 

ou:

 Book.populate(book, '_creator', function(err) { console.log(book._creator); }); 

voir plus sur: https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population

Mais de cette façon, vous interrogez encore l’utilisateur.

Un petit truc pour y parvenir sans requêtes supplémentaires serait:

 book = book.toObject(); book._creator = user; 

Juste pour élaborer et donner un autre exemple, car cela m’a aidé. Cela peut aider ceux qui veulent récupérer des objects partiellement remplis après leur enregistrement. La méthode est également légèrement différente. J’ai passé plus d’une heure ou deux à chercher la bonne façon de le faire.

  post.save(function(err) { if (err) { return res.json(500, { error: 'Cannot save the post' }); } post.populate('group', 'name').populate({ path: 'wallUser', select: 'name picture' }, function(err, doc) { res.json(doc); }); }); 

Solution qui renvoie une promesse (pas de rappel):

Utiliser le document n °

 book.populate('creator').execPopulate(); // summary doc.populate(options); // not executed doc.populate(options).execPopulate() // executed, returns promise 

Mise en œuvre possible

 var populatedDoc = doc.populate(options).execPopulate(); var populatedDoc.then(doc => { ... }); 

Lisez à propos de la population de documents ici .

La solution pour moi était d’utiliser execPopulate , comme ça

 const t = new MyModel(value) return t.save().then(t => t.populate('my-path').execPopulate()) 

Je pensais append à cela pour clarifier les choses pour des noobs complets comme moi.

Ce qui est extrêmement déroutant si vous ne faites pas attention, c’est qu’il existe trois méthodes de remplissage très différentes. Ce sont des méthodes de différents objects (modèle vs document), prennent des entrées différentes et donnent des résultats différents (Document vs. Promise).

Les voici pour ceux qui sont perplexes:

Document.prototype.populate ()

Voir les documents complets

Celui-ci travaille sur des documents et renvoie un document. Dans l’exemple original, cela ressemblerait à ceci:

 book.save(function(err, book) { book.populate('_creator', function(err, book) { // Do something }) }); 

Comme il fonctionne sur des documents et renvoie un document, vous pouvez les enchaîner comme suit:

 book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */', function(err, book) { // Do something }) }); 

Mais ne sois pas stupide, comme moi, et essaie de faire ça:

 book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */') .then(function(book) { // Do something }) }); 

Rappelez-vous: Document.prototype.populate () renvoie un document, ce qui est absurde. Si vous voulez une promesse, vous avez besoin de …

Document.prototype.execPopulate ()

Voir les documents complets

Celui-ci fonctionne sur des documents MAIS il renvoie une promesse qui résout le document. En d’autres termes, vous pouvez l’utiliser comme ceci:

 book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */') .execPopulate() .then(function(book) { // Do something }) }); 

C’est mieux. Enfin, il y a …

Model.populate ()

Voir les documents complets

Celui-ci fonctionne sur des modèles et renvoie une promesse. C’est donc un peu différent:

 book.save(function(err, book) { Book // Book not book .populate(book, { path: '_creator'}) .then(function(book) { // Do something }) }); 

J’espère que cela a aidé d’autres nouveaux arrivants.

Malheureusement, il s’agit d’un problème de longue date avec la mongoose qui, à mon avis, n’est pas encore résolu:

https://github.com/LearnBoost/mongoose/issues/570

Qu’est-ce que vous pouvez faire est d’écrire votre propre getter / setter personnalisé (et définissez _customer réel dans une propriété séparée) pour cela. Par exemple:

 var get_creator = function(val) { if (this.hasOwnProperty( "__creator" )) { return this.__creator; } return val; }; var set_creator = function(val) { this.__creator = val; return val; }; var bookSchema = new mongoose.Schema({ _creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', get: get_creator, set: set_creator }, description: Ssortingng, }); 

REMARQUE: je ne l’ai pas testé et cela pourrait fonctionner étrangement avec .populate et lors de la définition de l’ID pur.

Probablement sth. comme

 Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator")); 

Serait le moyen le plus agréable et le moins problématique de faire fonctionner cette solution (Utiliser les promesses de Bluebird).

Mangouste 5.2.7

Cela fonctionne pour moi (juste beaucoup de maux de tête!)

 exports.create = (req, res, next) => { const author = req.userData; const postInfo = new Post({ author, content: req.body.content, isDraft: req.body.isDraft, status: req.body.status, title: req.body.title }); postInfo.populate('author', '_id email role display_name').execPopulate(); postInfo.save() .then(post => { res.status(200).json(post); }).catch(error => { res.status(500).json(error); }); }; 

vous avez fini par écrire des fonctions Promise qui peuvent être archivées, où vous déclarez votre schéma, query_adapter, data_adapter et remplissez la chaîne à l’avance. Pour une implémentation plus courte / plus simple, plus facile.

Ce n’est probablement pas super efficace, mais je pensais que le bit d’exécution était assez élégant.

fichier github: curry_Promises.js

déclartion

 const update_or_insert_Item = mDB.update_or_insert({ schema : model.Item, fn_query_adapter : ({ no })=>{return { no }}, fn_update_adapter : SQL_to_MDB.item, populate : "headgroup" // fn_err : (e)=>{return e}, // fn_res : (o)=>{return o} }) 

exécution

 Promise.all( items.map( update_or_insert_Item ) ) .catch( console.error ) .then( console.log )