Je ne peux pas renseigner manuellement ou automatiquement le champ créateur sur un objet nouvellement enregistré ... le seul moyen de le trouver est de demander à nouveau les objets que j'ai déjà et que je détesterais faire.
Ceci est la configuration:
var userSchema = new mongoose.Schema({
name: String,
});
var User = db.model('User', userSchema);
var bookSchema = new mongoose.Schema({
_creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
description: String,
});
var Book = db.model('Book', bookSchema);
C'est là que je me tire les 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: le dernier mangouste 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 peuplement du modèle à cette fin: http://mongoosejs.com/docs/api.html#model_Model.populate Dans le gestionnaire de sauvegarde pour le livre 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 je suis resté bloqué là-dessus récemment, et cela pourrait être utile pour d'autres.
Dans le cas où quelqu'un est toujours à la recherche de cela.
Mongoose 3.6 a introduit de nombreuses fonctionnalités intéressantes à peupler:
book.populate('_creator', function(err) {
console.log(book._creator);
});
ou:
Book.populate(book, '_creator', function(err) {
console.log(book._creator);
});
voir plus à: https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population
Mais de cette façon, vous interrogeriez encore l'utilisateur.
Un petit truc pour le réaliser 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 pourrait aider ceux qui souhaitent récupérer des objets 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);
});
});
Utiliser le numéro de document peupler
book.populate('creator').execPopulate();
// summary
doc.populate(options); // not executed
doc.populate(options).execPopulate() // executed, returns promise
Mise en oeuvre possible
var populatedDoc = doc.populate(options).execPopulate();
var populatedDoc.then(doc => {
...
});
Lire à propos de la population de documents ici .
La solution pour moi était d’utiliser execPopulate
, comme
const t = new MyModel(value)
return t.save().then(t => t.populate('my-path').execPopulate())
Je pensais que j'ajouterais à cela pour clarifier les choses pour des noobs complets comme moi.
Ce qui déroute énormément 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 d'objets différents (Modèle vs Document), prennent différentes entrées et donnent différentes sorties (Document vs Promises).
Les voici pour ceux qui sont déroutés:
Voir la documentation complète.
Celui-ci travaille sur des documents et retourne un document. Dans l'exemple original, cela ressemblerait à ceci:
book.save(function(err, book) {
book.populate('_creator', function(err, book) {
// Do something
})
});
Comme cela fonctionne sur les documents et renvoie un document, vous pouvez les chaîner comme suit:
book.save(function(err, book) {
book
.populate('_creator')
.populate('/* Some other ObjectID field */', function(err, book) {
// Do something
})
});
Mais ne soyez pas stupide, comme moi, et essayez de faire ceci:
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 n’a aucun sens. Si vous voulez une promesse, il vous faut ...
Voir la documentation complète.
Celui-ci fonctionne sur les documents MAIS il retourne 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 ...
Voir la documentation complète.
Celui-ci fonctionne sur les modèles et renvoie une promesse. C'est donc utilisé un peu différemment:
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 concernant la mangouste qui, à mon avis, n’a pas encore été résolu:
https://github.com/LearnBoost/mongoose/issues/570
Ce que vous pouvez faire, c'est écrire votre propre getter/setter personnalisé (et définir real_customer
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: String,
});
NOTE: Je ne l'ai pas testé et cela pourrait fonctionner étrangement avec .populate
et lors de la définition d'un identifiant pur.
a fini par écrire des fonctions Promise curieuses dans lesquelles vous déclarez votre schéma, vos fonctions query_adapter, data_adapter et votre chaîne de caractères à l'avance. Pour une mise en œuvre plus courte/plus simple plus facile.
Ce n'est probablement pas très efficace, mais je pensais que le bit d'exécution était assez élégant.
fichier github: curry_Promises.js
declartion
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 )
Probablement qc. comme
Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator"));
Serait le moyen le plus gentil et le moins problématique de faire ce travail (en utilisant les promesses Bluebird).
Mongoose 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);
});
};