【问题标题】:Get all results from array that matches property [duplicate]从匹配属性的数组中获取所有结果[重复]
【发布时间】:2017-12-22 14:06:18
【问题描述】:

我知道如何让 MongoDB 根据这样的数组找到一行:

useritems.find({userid: useridhere,  "items.id": idhere})

但是我将如何搜索并获取所有已激活的项目,或者基于items 属性获取所有项目? 比如:

useritems.find({userid: useridhere,  "items.activated": true})

将导致从用户那里获取所有已激活的项目。

这是我的项目架构:

var userItemsSchema = new Schema({
    userid : String,
    items: [
        {
            id: {type: Number, default: 1},
            activated: { type: Boolean, default: false},
            endtime : {type: Number, default: 0},
        },
    ],
});

module.exports = mongoose.model('useritems', userItemsSchema);

【问题讨论】:

  • 您想高效获取所有激活用户吗?
  • 这个已经被问过了,回答的很好;见stackoverflow.com/q/3985214/174843
  • @VinceBowdren 我们知道。但在赏金期到期之前,它不能作为重复项关闭。有时问题会溜走

标签: node.js mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

$elemMatch 运算符用于查询嵌入文档中的值

根据上述问题的描述,作为解决方案,请尝试在MongoDB shell中执行以下查找操作。

    db.useritems.find({
    userid: "random user_id",
    items: {
        $elemMatch: {
            activated: true
        }
    }
 })

【讨论】:

  • 问题是:“获取所有个被激活的项目,”。这不能用标准 positional projection 完成,因为它只返回匹配的 first 响应。但你所说的完全不正确。 1.$elemMatch只有在有“多个”查询条件来匹配数组元素时才需要,并且只需要一个条件。 2. 如果没有位置 $ 运算符 all 数组项无论如何都会返回。该问题要求“仅匹配项”。
【解决方案2】:

你想在这里$filter

useritems.aggregate([
  { "$match": { 
    "userid": ObjectId(useridhere),  
    "items.activated": true
  }},
  { "$addFields": {
    "items": {
      "$filter": {
        "input": "$items",
        "as": "i",
        "cond": "$$i.activated"
      }
    }
  }}
],(err,results) => { 

});

请注意,对于聚合框架,例如 useridhere 之类的值,猫鼬通常允许您传入一个“字符串”,并将该字符串“自动转换”为您的 ObjectId 值。 This does not happen in the aggregation frameworkIssue#1399,因为它可能会改变所作用的文档的“形状”,所以不能应用“模式”。

因此您可能希望从核心驱动程序中导入它:

const ObjectId = require('mongodb').ObjectID;

然后您可以手动“转换”这些值。

当然,如果这样的值实际上是从另一个 mongoose 对象而不是从 req.params 或类似对象中检索到的,那么它应该已经是 ObjectId 类型。

之所以使用.aggregate(),是因为“标准投影”只匹配一个元素。即:

useritems.find({ userid: useridhere,  "items.activated": true })
 .select('items.$')
 .exec((err,items) => {

 });

这里的位置$ 运算符返回“匹配”元素,但只返回“第一个”匹配项。

因此,在您想要“多个”匹配的地方,您使用 $filter 代替,这比早期版本的 MongoDB 更有效,因为早期版本需要您首先使用 $unwind 数组。

$unwind 运算符应该在现代版本(MongoDB 2.4 之后的任何版本)中使用,以防您实际上想要使用数组中的“值”进行操作,例如$group 该值显示为“分组键”。它在其他情况下的使用通常是一个“巨大的性能问题”,除了直接跟随 $lookup 管道阶段,它确实有一个特殊的重要用例。

否则最好避免。请改用$filter

注意:$addFields 管道阶段允许您“覆盖”单个元素而无需指定所有其他字段。如果您的 MongoDB 不支持此运算符,请改用 $project 并明确指定所有字段。即:

  { "$project": {
    "userid": 1,
    "items": {
      "$filter": {
        "input": "$items",
        "as": "i",
        "cond": "$$i.activated"
      }
    }
  }}

【讨论】:

    【解决方案3】:

    使用aggregatelike 可能是个不错的选择:

    useritems.aggregate(
        { $match: {"_id" : id}},
        { $unwind: '$items'},
        { $match: {'items.activated': true}},
        { $group: {_id: '$_id', items: {$push: '$items'}}})
    

    您可以在这个问题中获得更多信息:How to filter array in subdocument with MongoDB

    【讨论】:

      猜你喜欢
      • 2013-04-05
      • 2021-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-06
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多