web-dev-qa-db-fra.com

Mangouste peupler après sauvegarde

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.

66
Pykler

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.

118
user1417684

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;
34
Eric Saboia

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);
    });
  });
11
Pratik Bothra

Solution qui retourne une promesse (pas de rappel):

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 .

10
Govind Rai

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

const t = new MyModel(value)
return t.save().then(t => t.populate('my-path').execPopulate())
6
François Romain

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:

Document.prototype.populate ()

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 ...

Document.prototype.execPopulate ()

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 ...

Model.populate ()

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.

5
curzmg

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.

1
freakish

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 )
0
WouldBeNerd

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).

0
kboom

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);
    });
};
0
Whisher