如何使用 Mongoose 正确更新数组中的元素

Posted

技术标签:

【中文标题】如何使用 Mongoose 正确更新数组中的元素【英文标题】:How to correctly update an element in an array using Mongoose 【发布时间】:2020-05-23 14:43:42 【问题描述】:

我已经阅读了尽可能多的关于如何正确更新 MongoDB 中数组中的元素的文章(例如这篇文章:Mongoose, update values in array of objects),并认为我已经遵循了所有建议,但我仍然得到这个错误,如果有人能发现我的错误,将不胜感激,因为我已经尝试调试了好几个小时!

我特别遇到的问题是 findOneAndUpdate 调用似乎只是更新“itineraryItems”数组中的第一个元素,无论它是否匹配我对特定元素的查询。

我的用户集合中的数据(用户文档上的 itineraryItems 数组中的 2 个数组元素):

db.users.find(_id: ObjectId("5dd65ce7998d626a2c71a547"), itineraryItems: 1)

 "_id" : ObjectId("5dd65ce7998d626a2c71a547"), 
  "itineraryItems" : [ 
      "_id" : ObjectId("5e3d5a301b65f3f9fd1621f8"), 
       "iType" : "event", 
       "startDate" : ISODate("2020-02-07T11:00:00Z"), 
       "endDate" : ISODate("2020-02-07T13:00:00Z"), 
       "includeTravelTime" : false, 
       "travelTimeMinutes" : 0, 
       "item" : null, 
       "event" : ObjectId("5dea66c182d9ac6fb4c6f36e") 
     , 
      "_id" : ObjectId("5e3d5a341b65f3f9fd1621ff"), 
       "iType" : "item", 
       "startDate" : ISODate("2020-02-07T11:00:00Z"), 
       "endDate" : ISODate("2020-02-07T13:00:00Z"), 
       "includeTravelTime" : false, 
       "travelTimeMinutes" : 0, 
       "item" : ObjectId("5e29df801f026697b71f7f48"), 
       "event" : null 
      
  ] 

我的查询构建功能: 请注意,满足第一个 if 语句的查询(即我为数组中的元素传入一个已知的 id)似乎工作正常。其他 2 个案例似乎失败了。

function getUpdateItineraryElementQuery(user, id, type, startDate, endDate, includeTravelTime, travelTimeMinutes, itemId) 
    let query = ;
    if (
        (id!=null) && 
        (id!='not_set')
    ) 
        query = 
            _id:                    user._id,
            'itineraryItems._id':   mongoose.Types.ObjectId(id)
        ;
     else 

        if (type==='event') 
            query = 
                _id:                                    user._id,
                'itineraryItems.iType':                 type,
                'itineraryItems.startDate':             startDate,
                'itineraryItems.endDate':               endDate,
                'itineraryItems.includeTravelTime':     includeTravelTime,
                'itineraryItems.travelTimeMinutes':     travelTimeMinutes,
                'itineraryItems.event':                 mongoose.Types.ObjectId(itemId)
            ;
         else 
            if (type==='item') 
                query = 
                    _id:                                    user._id,
                    'itineraryItems.iType':                 type,
                    'itineraryItems.startDate':             startDate,
                    'itineraryItems.endDate':               endDate,
                    'itineraryItems.includeTravelTime':     includeTravelTime,
                    'itineraryItems.travelTimeMinutes':     travelTimeMinutes,
                    'itineraryItems.item':                  mongoose.Types.ObjectId(itemId)
                ;
            
        
    
    return query;

我的 Mongoose 调用 findOneAndUpdate:

 User.findOneAndUpdate(
                query,
                
                    'itineraryItems.$.startDate':           dtNewStartDate,
                    'itineraryItems.$.endDate':             dtNewEndDate,
                    'itineraryItems.$.includeTravelTime':   newIncludeTravelTime,
                    'itineraryItems.$.travelTimeMinutes':   newTravelTimeMinutes
                // eslint-disable-next-line no-unused-vars
                , (err, doc) => 
                    if (err) 
                        // not found?
                        res.sendStatus(404).end();
                     else 
                        // ok
                        res.sendStatus(200).end();
                         
                
            );

如果你能告诉我我做错了什么,非常感谢!

【问题讨论】:

如果你想更新数组中的 all 元素,那么语法应该是 itineraryItems.$[].startDate 而不是 itineraryItems.$.startDate 谢谢温弗里德。我不打算这样做,但很高兴知道这种语法 - 非常感谢! 【参考方案1】:

如果您只想更新匹配所有条件

subdocument,则需要使用$elemMatch 匹配您的subdocument

这样,


    _id: user._id,
    'itineraryItems':
        $elemMatch:
            iType: type,
            startDate: startDate,
            endDate: endDate,
            includeTravelTime: includeTravelTime,
            travelTimeMinutes: travelTimeMinutes,
            item: mongoose.Types.ObjectId(itemId)
        
    

【讨论】:

谢谢!我刚刚修改了我的代码并且它正在工作。非常感谢!

以上是关于如何使用 Mongoose 正确更新数组中的元素的主要内容,如果未能解决你的问题,请参考以下文章

如何用mongoose更新这个文档中的数组中的对象中的数组里的值?

Mongoose 不更新 mongodb 中的数组

更新对象数组中的元素在 Mongoose 中不起作用

mongoose如何查找某个数组里含有某个值

如何使用猫鼬更新子文档数组中的特定元素? [复制]

Mongoose - 更新数组中的每个子文档(node.js)