如何在MongoDB $ projection中使用$ arrayElemAt并从该元素中删除字段?

时间:2016-09-22 22:02:33

标签: mongodb mongoose

我有工作'和'用户'采集。每个用户都可以为给定的“jobCategoryId”创建一份工作,然后将该工作保存在“工作”中。收集并包含' userId'它的创建者和' jobCategoryId'。

我试图合并这两个系列,所以当我取得工作时,我会有“用户”#39;包含所有用户数据的字段,而不是' userId'那份工作的领域。这就是我现在这样做的方式:

Job.aggregate([{
  $match: {
    jobCategoryId: mongoose.Types.ObjectId(jobCategoryId)
  }
}, {
  $lookup: {
    from: 'users',
    localField: 'userId',
    foreignField: '_id',
    as: 'user'
  }
}, {
  $project: {
    _id: 1,
    description: 1,
    title: 1,
    user: { $arrayElemAt: ['$user', 0] }
  }
}, {
  $project: {
    _id: 1,
    title: 1,
    description: 1,
    'user.name': '$user.name'
  }
}])

返回以下内容:

[{
  _id: 'some id',
  title: 'title',
  description: 'description',
  user: {
    name: 'Mike'
  }
}]

结果是正确的,但我真的很感兴趣,如果有任何其他方法在使用$ arrayElemAt时只保留用户对象的某些字段,或者我注定要在管道中使用2个投影? 有谁可以帮我解决这个小问题?我真的很感激。

1 个答案:

答案 0 :(得分:7)

这来自arrayElemAt

的语法
  

表达式可以是任何有效的表达式,只要它   解析为数组。

这意味着您可以根据需要构建数组元素。在您的情况下,您只需要名称。所以这应该有效:

[{
  $match: {
    jobCategoryId: mongoose.Types.ObjectId(jobCategoryId)
  }
}, {  
  $lookup: {  
    from: 'users',
    localField: 'userId',
    foreignField: '_id',
    as: 'user'
  }
}, {  
  $project: {  
    _id: 1,
    description: 1,
    title: 1,
    user: {  
      name: {
        $arrayElemAt: ["$user.name", 0]
      }
    }
  }
}]

跟进更新: 有人询问如何在name之上添加其他属性。这是项目:

{  
  $project: {  
    _id: 1,
    description: 1,
    title: 1,
    user: {  
      name: {  
        $arrayElemAt: ["$user.name", 0]
      },
      email: {  
        $arrayElemAt: ["$user.email", 0]
      }
    }
  }
}

第二次跟进,因为Drag0在评论中提到:如果上述结果不够好,因为结果会生成一个用户:[]数组大小为1而不是对象用户:{可以使用以下内容。

{  
  $project: {
    _id: 1,
    description: 1,
    title: 1,
    user: {
      $let: {
        vars: {
          firstUser: {
            $arrayElemAt: ["$user", 0]
          }
        },
        in: {
          name: "$$firstUser.name",
          email: "$$firstUser.email"
        }
      }
    }
  }
}