Mongoose 子文档不会更新

Posted

技术标签:

【中文标题】Mongoose 子文档不会更新【英文标题】:Mongoose Subdocument will not update 【发布时间】:2017-03-17 07:35:20 【问题描述】:

我无法确定我是否正确设计了架构,因为我在尝试从配置文件中修补角色属性的更改时收到 500 错误。 (注意:500 错误只是以空 响应,因此它并不能提供真正的信息)

以下是配置文件架构:

var ProfileSchema = new Schema(
  name: 
    type: String,
    required: true
  ,
  roles: [
    application: 
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'Application'
    ,
    role: 
      type: String,
      required: true,
      enum: [ 'admin', 'author', 'publisher' ]
    
  ]
);

每个配置文件都有一个应用程序的角色,当我将请求发送到控制器操作“更新”时,它失败了:

配置文件更新控制器:

// Updates an existing Profile in the DB
export function update(req, res) 
  try 
    if (req.body._id) 
      delete req.body._id;
    

   console.log('ENDPOINT HIT...');
   console.log(`REQUEST PARAM ID: $req.params.id`);
   console.log('REQUEST BODY:');
   console.log(req.body);
   console.log('ENTIRE REQUEST: ');

   return Profile.findByIdAsync(req.params.id)
    .then(handleEntityNotFound(res))
    .then(saveUpdates(req.body))
    .then(respondWithResult(res))
    .catch(handleError(res));

  catch(ex) 
     console.error('FAILED TO UPDATE PROFILE');
     return handleError(res);
   

我确保 id 和 body 被正确发送,并且我正在到达终点。

这是请求正文 JSON 的示例:

 
  _id: 57e58ad2781fd340563e29ff,
  __updated: Thu Oct 27 2016 15:41:12 GMT-0400 (EDT),
  __created: Fri Sep 23 2016 16:04:34 GMT-0400 (EDT),
  name: 'test',
  __v: 11,
  roles:[ 

    application: 57b70937c4b9fe460a235375,
     role: 'admin',
     _id: 58125858a36bd76d8111ba16 ,

    application: 581b299f0145b48adf8f57bd,
     role: 'publisher',
     _id: 581b481898eefb19ed8a73ee  
   ]

 

当我尝试通过 Id 查找 Profile 时,promise 链直接进入 catch(handleError(res));部分代码并在我的控制台中显示一个空对象。

我的句柄错误函数:

 function handleError(res, statusCode) 
   console.error('HANDLE PROFILE ERROR: ', statusCode);
   statusCode = statusCode || 500;
   return function(err) 
     console.error('PROFILE ERROR:');
     console.error(JSON.stringify(err, null, 2));
     res.status(statusCode).send(err);
   ;
  

更新

我意识到代码在遇到我的 saveUpdates 函数时会中断(注意:我正在使用 lodash):

function saveUpdates(updates) 
  /// the code is fine here ///
  return function(entity) 
    /// once it enters in here, is where it begins to break ///
    var updated = _.merge(entity, updates);

    if(updated.roles.length != updates.roles.length) 
      updated.roles = updates.roles;
    

    for(var i in updates.roles) 
      updated.roles.set(i, updates.roles[i]);
    
    return updated.saveAsync()
     .then(updated => 
        return updated;
      );
    ;

【问题讨论】:

查看错误findByIdAsync(...).catch((err) => console.log(err); handleError(res); ) 您能告诉我们,req.params.id 上到底有什么内容吗? console.log(`REQUEST PARAM ID: $req.params.id`); 向您展示了什么 @GrégoryNEUT,当我控制台记录 params.id 时——这是我检索到的内容:`REQUEST PARAM ID: 57bd9db4f33dcd03c3fd9990` ok 试试 findOne( _id: req.params.id ) (我找不到 findByIdAsync() mongoose 文档) @GrégoryNEUT,所以我意识到如果我从我的承诺链中删除 saveUpdates 函数调用——并将模型的方法切换到Profile.findOneAndUpdate——那么错误就会消失。我确信我的 saveUpdates 功能现在坏了。 【参考方案1】:

经验教训:正确阅读文档。

由于我在此应用程序中使用了 bluebird Promise,因此我忘记在我的 saveUpdates() 回调函数中使用 .spread()

解决方案:

function saveUpdates(updates) 
  return function(entity) 
    var updated = _.merge(entity, updates);
    if(updated.roles.length != updates.roles.length) 
       updated.roles = updates.roles;
    

    for(var i in updates.roles) 
      updated.roles.set(i, updates.roles[i]);
    

    return updated.saveAsync()
      // use `.spread()` and not `.then()` //
      .spread(updated => 
        return updated;
      );
   ;
 

我要感谢导致此结论的以下 SOA:https://***.com/a/25799076/5994486

此外,如果有人对 .spread() 感兴趣,这里是 bluebird 文档的链接:http://bluebirdjs.com/docs/api/spread.html

【讨论】:

以上是关于Mongoose 子文档不会更新的主要内容,如果未能解决你的问题,请参考以下文章

未能成功更新 Mongoose 子文档

Mongoose - 使用 findOneAndUpdate 更新子文档

更新子文档、NodeJS 和 Mongoose 的更有效方式

更新子文档、NodeJS 和 Mongoose 的更有效方式

Mongoose如何更新子文档字段?

Mongoose 按键更新子文档