Мангуст заселяют после сохранения



Я не могу вручную или автоматически заполнить поле creator на вновь сохраненном объекте ... единственный способ, который я могу найти,-это повторно запросить объекты, которые у меня уже есть, которые я бы не хотел делать.



Это настройки:



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


вот где я дергаю себя за волосы



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: последний Мангуст исправил эту проблему и добавил функциональность заполнения, см. новый принятый ответ.

799   10  

10 ответов:

вы должны быть в состоянии использовать функцию заполнения модели, чтобы сделать это: http://mongoosejs.com/docs/api.html#model_Model.populate в обработчике сохранения для книги, вместо:

book._creator = user;

вы бы сделали что-то вроде:

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

вероятно, слишком поздно ответ, чтобы помочь вам, но я застрял на этом недавно, и это может быть полезно для других.

В случае, если кто-то все еще ищет этого.

Мангуст 3.6 ввел много интересных функций для заполнения:

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

или:

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

на https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population

но таким образом вы все равно будете запрашивать пользователя снова.

небольшой трюк, чтобы выполнить его без дополнительных запросов будет:

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

просто чтобы уточнить и привести еще один пример, как это помогло мне. Это может помочь тем, кто хочет получить частично заполненные объекты после сохранения. Метод также немного отличается. Потратил больше часа или двух на поиски правильного способа сделать это.

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

решение, которое возвращает обещание (не обратными):

использовать документ#заполнения

book.populate('creator').execPopulate();

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

Возможной Реализации

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

читайте о населении документа здесь.

решение для меня было использовать execPopulate вот так

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

Я думал, что добавлю к этому, чтобы прояснить вещи для полных нубов, таких как я.

что массово сбивает с толку, если вы не будете осторожны, так это то, что есть три очень разных метода заполнения. Они являются методами различных объектов (модель против документа), принимают разные входы и дают разные выходы (документ против обещания).

вот они для тех, кто сбит с толку:

документ.прототип.заполнить()

посмотреть полный доктора.

этот работает с документами и возвращает документ. В исходном примере это будет выглядеть так:

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

поскольку он работает с документами и возвращает документ, вы можете связать их вместе следующим образом:

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

но не глупи, как я, и попробуй сделать это:

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

Помните: Документ.прототип.populate () возвращает документ, так что это нонсенс. Если вы хотите обещание, вы необходимость...

документ.прототип.execPopulate ()

смотрите полные документы.

этот работает с документами, но он возвращает обещание, которое разрешает документ. Другими словами, вы можете использовать его следующим образом:

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

это лучше. Наконец-то есть...

модель.заполнить()

смотрите полные документы.

этот работает на моделях и возвращает обещание. Это поэтому используется немного по-другому:

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

надеюсь, что это помогло некоторым другим новичкам.

к сожалению, это давняя проблема с Мангустом, которая, я считаю, еще не решена:

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

что вы можете сделать, это написать свой собственный пользовательский геттер/сеттер ( и set реальные_customer в отдельном свойстве) для этого. Например:

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,
});

Примечание: я не проверял его, и он может работать странно с .populate и при установке чистого id.

вероятно, sth. как

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

было бы самым приятным и наименее проблематичным способом сделать эту работу (используя обещания Bluebird).

Мангуст 5.2.7

это работает для меня (просто много головной боли !)

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

закончил писать некоторые Карри-способные функции Promise, где вы объявляете свою схему, query_adapter, data_adapter функции и заполняете строку заранее. Для более короткой / простой реализации проще.

это, вероятно, не очень эффективно, но я думал, что исполнение бит был довольно элегантным.

гитхаб файл: 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}
})

исполнение

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

Comments

    Ничего не найдено.