使用投影或选择更新猫鼬文档中对象数组内的对象

Posted

技术标签:

【中文标题】使用投影或选择更新猫鼬文档中对象数组内的对象【英文标题】:Update Object Inside the Array of object in a mongoose document with projection or select 【发布时间】:2020-08-08 15:52:30 【问题描述】:

我正在尝试更新文档中的对象

文档:猫


        "_id": "5e5cb512e90bd40017385305",
        "type": "cat"
        "history": [
          
            "id": "randomID",
            "content": "xyz",
          ,
          
            "id": "randomID2",
            "content": "abc",
          
        ]

选择和更新历史数组中的对象的代码:

const editHistory = async (_,  input , ctx) => 
  let query =  _id: input.catId, "history.id": input.historyId ;
  let update =  $set:  "history.$": input.history  ;
  let options = 
    new: true,
    fields:  history:  $elemMatch:  id: "randomID"   
  ;

  let cat = await ctx.models.cats.findOneAndUpdate(query, update, options);

  return cat;
;

输入有以下值

input: 
catId: "5e5cb512e90bd40017385305",
historyId: "randomID",
history: 
id: "randomID",
content: "new content"

我尝试使用 Projection,我使用 select 将其更改为字段,可在 mongoose 文档中找到。 我仍然无法更新这些值。我查询或选择子字段的方式有什么问题吗?

【问题讨论】:

id(文档)或_id(查询)? Cat 文档的 _id 和历史数组对象的 id 当您使用相同的查询运行findOne 时会发生什么? 它只是返回 Cat 文档 @mickl 有办法解决这个问题吗? 【参考方案1】:

通过查看操作符($set)和选项(new,fields)的更多细节找到了解决方案。

问题:

const editHistory = async (_,  input , ctx) => 
  let query =  _id: input.catId, "history.id": input.historyId ;
  let update =  $set:  "history.$": input.history  ;
  let options = 
    // using new option would return the new document
    new: true, 
    /* using fields option would select the based on the given key, but using new: 
       true with fields will throw error: 'cannot use a positional projection and 
   return the new document'
   */
    fields:  history:  $elemMatch:  id: "randomID"    
  ;

  let cat = await ctx.models.cats.findOneAndUpdate(query, update, options);

  return cat;
;

下面的这篇文章回答了 *error: 'cannot use a positional projection and return the new document' 的问题。

https://***.com/a/46064082/5492398

最终解决方案:

const editHistory = async (_,  input , ctx) => 
  let query =  _id: input.catId, "history.id": input.historyId ;
  let update =  $set:  "history.$": input.history  ;
  let options = 
    new: true
  ;

  let cat = await ctx.models.cats.findOneAndUpdate(query, update, options);

  return cat;
;

删除字段选项,因为在原子修改之前我不需要未修改的选择,所以解决了这个问题。

【讨论】:

以上是关于使用投影或选择更新猫鼬文档中对象数组内的对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在猫鼬模型内的数组中查找对象?

如何使用猫鼬更新数组中的现有对象

批量更新猫鼬对象中的数组

嵌入式数组中的猫鼬更新对象

猫鼬选择返回对象ID

将值推送到猫鼬模式中对象内的数组