【问题标题】:How to query for sub-document in an array with Mongoose如何使用 Mongoose 查询数组中的子文档
【发布时间】:2021-04-28 00:07:37
【问题描述】:

我有一个如下所示的项目架构:

const ProjectSchema = new mongoose.Schema({
name: {
    type: String,
    Required: true,
    trim: true
},
description: {
    type: String,
},

devices: [{
    name: {type: String, Required: true},
    number: {type: String, trim: true},
    deck: {type: String},
    room: {type: String},
    frame: {type: String}
}],

cables: {
    type: Array
},
user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User'
},
adminsID: {
    type: Array
},
createdAt: {
    type: Date,
    default: Date.now
}

我想从“设备”数组中查询一个对象。 我能够添加、删除和显示该数组中的所有子文档,但我发现很难在数组中获得与 _id 条件匹配的单个对象。

我得到的最接近的是这个(我要求:'/:id/:deviceID/edit' 其中“:id”是 Project ObjectId。

let device = await Project.find("devices._id": req.params.deviceID).lean()
console.log(device)

它为我提供了以下信息:

[
{
_id: 6009cfb3728ec23034187d3b,
cables: [],
adminsID: [],
name: 'Test project',
description: 'Test project description',
user: 5fff69af08fc5e47a0ce7944,
devices: [ [Object], [Object] ],
createdAt: 2021-01-21T19:02:11.352Z,
__v: 0
}
]

我知道这可能真的是微不足道的问题,但我已经测试了不同的解决方案,但似乎没有什么对我有用。感谢理解

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    这是您可以从设备数组中仅过滤单个对象的方法:

     Project.find({"devices._id":req.params.deviceID  },{ name:1,  devices: { $elemMatch:{ _id:req.params.deviceID } }})
    

    【讨论】:

    • 你能解释一下“name: 1”是做什么的吗?不幸的是,这对我来说并不完美,但至少它为我提供了带有单个设备对象的父文档。
    • 它应该为您提供获取数组元素的文档的名称,您可以将其删除,我只是为了清楚起见添加了 :)
    【解决方案2】:

    您可以使用$elemMatch 进入投影或查询阶段进入find,随心所欲:

    db.collection.find({
      "id": 1,
      "devices": { "$elemMatch": { "id": 1 } }
    },{
      "devices.$": 1
    })
    

    db.collection.find({
      "id": 1
    },
    {
      "devices": { "$elemMatch": { "id": 1 } }
    })
    

    示例herehere

    使用猫鼬是同一个查询。

    yourModel.findOne({
      "id": req.params.id
    },
    {
      "devices": { "$elemMatch": { "id": req.params.deviceID } }
    }).then(result => {
      console.log("result = ",result.name)
    }).catch(e => {
      // error
    })
    

    【讨论】:

      【解决方案3】:

      如果您希望单独使用设备,则需要使用聚合。这将返回一个数组

      Project.aggregate([
        { "$unwind": "$devices" },
        { "$match": { "devices._id": req.params.deviceID } },
        {
          "$project": {
            name: "$devices.name",
            // Other fields
          }
        }
      ])
      

      你要么等待这个,要么在最后使用 .then()。

      或者您可以使用 findOne(),它会为您提供只有一个元素的 Project + 设备

      或者查找,它将为您提供一个 object 数组,其中包含项目的 _id 和设备中的单个元素

      Project.findOne({"devices._id": req.params.deviceID}, 'devices.$'})
      .then(project => {
         console.log(project.devices[0])
      })
      

      【讨论】:

      • 代码:let device = await Project.findOne({ "devices._id": req.params.deviceID}, '$devices.$') 给我 MongoDB 错误:MongoError: Positional projection '$ devices.$' 与查询文档不匹配。
      • 是的,设备上没有 $,我的错
      【解决方案4】:

      现在我解决了这个问题:

      let project = await Project.findById(req.params.id).lean()
      let device = project.devices.find( _id => req.params.deviceID)
      

      它为我提供了我想要的东西,但正如你所见,我要求整个项目。希望它不会在未来给我带来任何持久的麻烦。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-16
        • 2013-07-15
        • 2015-04-27
        • 2014-07-01
        • 2014-01-22
        • 2016-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多