ChatGPT解决这个技术问题 Extra ChatGPT

保存后猫鼬填充

我无法手动或自动在新保存的对象上填充创建者字段......我能找到的唯一方法是重新查询我已经拥有的我不想做的对象。

这是设置:

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

编辑:最新的猫鼬修复了这个问题并添加了填充功能,请参阅新接受的答案。


u
user1417684

您应该能够使用模型的填充函数来执行此操作:http://mongoosejs.com/docs/api.html#model_Model.populate 在 book 的保存处理程序中,而不是:

book._creator = user;

你会做类似的事情:

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

帮助你的答案可能为时已晚,但我最近被困在这个问题上,它可能对其他人有用。


如果这适用于虚拟属性,那就太好了。像creator.profile
如果用户有一些虚拟属性,则不包括在内。
这对我有用,尽管我在保存之前尝试将引用设置为 null 时遇到了一些问题。保存后,调用 Book.populate 错误地用以前的参考值填充了该字段,我不知道为什么。数据库成功包含空值。
而且这不会重新查询数据库?!
这是重新查询数据库
F
François Romain

我的解决方案是使用 execPopulate,就像这样

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

非常感谢@Francois,你救了我的命,我正试图为此寻找解决方案。终于明白了。
也救了我的命。祝你一切顺利,你摇滚!
E
Eric Saboia

万一有人还在寻找这个。

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

save() 之后执行 book._creator = user; 是所有当前答案中唯一正确的答案,所有其他答案都需要额外查询。
M
Mansour Alnasser

返回承诺(无回调)的解决方案:

使用文档#populate

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

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

可能的实施

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

阅读文档填充 here


好东西。谢谢
IDK 你知道与否,但这段代码只是一个语法糖。它将向数据库发送一个新查询。所以这不是一个好的答案。
P
Pratik Bothra

只是为了详细说明并举另一个例子,因为它帮助了我。这可能会帮助那些想要在保存后检索部分填充的对象的人。方法也略有不同。花了一两个多小时寻找正确的方法。

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

C
Community

我想我会补充一点,以澄清像我这样的完全菜鸟的事情。

如果您不小心的话,最令人困惑的是,存在三种非常不同的填充方法。它们是不同对象的方法(模型与文档),接受不同的输入并给出不同的输出(文档与承诺)。

它们是为那些感到困惑的人准备的:

Document.prototype.populate()

See full docs.

这适用于文档并返回文档。在原始示例中,它看起来像这样:

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

记住: Document.prototype.populate() 返回一个文档,所以这是胡说八道。如果你想要一个承诺,你需要...

Document.prototype.execPopulate()

See full docs.

这个适用于文档,但它返回一个解析为文档的承诺。换句话说,您可以像这样使用它:

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

这样更好。最后,有...

模型.populate()

See full docs.

这个适用于模型并返回一个承诺。因此,它的使用方式有所不同:

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

希望这对其他一些新人有所帮助。


这个例子看起来很简单,但 {path: ':_createor'} 的目的到底是什么? _creator 是否与 OP 的示例有关?如果我的文档有几个属性,例如 _Id、Id、title 或 year - 将用于路径?相当于主键?
f
freakish

不幸的是,这是 mongoose 的一个长期存在的问题,我认为尚未解决:

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

您可以为此编写自己的自定义 getter/setter(并在单独的属性中设置 real _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 时奇怪地工作。


他们似乎不想解决这个问题。
此问题已在 3.6 中修复
@Pykler,您确实需要将接受的答案更改为之前评分最高的答案,因为此答案不再有效
W
Whisher

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

k
kboom

大概……喜欢

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

将是完成这项工作的最好且问题最少的方法(使用 Bluebird 承诺)。


W
WouldBeNerd

最终编写了一些可咖喱的 Promise 函数,您可以在其中声明您的架构、query_adapter、data_adapter 函数并提前填充字符串。对于更短/更简单的实现更容易。

它可能不是超级高效,但我认为执行位非常优雅。

github 文件:curry_Promises.js

声明

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 )

S
Sehrish Waheed

将文档保存在模型中,然后填充

   chatRoom = await chatRoom.save();
   const data = await chatRoom
  .populate("customer", "email dp")
  .populate({
    path: "admin",
    select: "name logo",
  })
  .execPopulate();

M
Minh Toàn

它对我有用

    let post = await PostModel.create({
        ...req.body, author: userId
    })

    post = await post.populate('author', 'name')

    res.status(200).json({
        status: 'success',
        data: { post }
    })

正如目前所写的那样,您的答案尚不清楚。请edit添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以找到有关如何写出好答案的更多信息in the help center
你好。请记住,这段代码可能看起来很棒,但它正在做的是向数据库发送另一个查询。所以你的代码只是一点点糖和更短。您可以启用调试模式并查看生成的查询
E
Ed Hollinghurst

在 Mongoose 6.x 中,您可以简单地执行以下操作:

const t = await MyModel.create(value).then((t) =>
  t.populate('my-path')
);

execPopulate() 方法现已被删除。


S
Sehrish Waheed

没有什么对我有用,所以我保存然后使用 findById 再次获取该数据并重新填充

const data: any = await Model.findById(id)
  .populate("name")
  

A
AG_HIHI

我没有在这里添加任何新内容。

这只是使用 async/await 编写此代码的一种更简洁的方式:

const newCourse = new Course(new_course_data);
const populate_options = [
  // Here write your populate options
];
const created_course = await newCourse.save();
await created_course.populate(populate_options).execPopulate();

node:30332) UnhandledPromiseRejectionWarning: TypeError: .populate(...).execPopulate 不是一个函数

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅