从匹配属性的数组中获取所有结果[重复]

时间:2022-09-22 15:41:34

This question already has an answer here:

这个问题在这里已有答案:

I know how to make MongoDB find a row based on an array like this:

我知道如何使MongoDB基于这样的数组找到一行:

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

But how would I for example search and get all items that are activated, or get all items based on an items property? Like for example:

但是,我如何搜索并获取所有激活的项目,或者根据项目属性获取所有项目?例如:

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

Would results in getting all items from the user where activated is true.

将导致从激活的用户获取所有项目是真的。

Here is my items schema:

这是我的项目架构:

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);

3 个解决方案

#1


3  

You want $filter here:

你想要$ filter这里:

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

});

Noting that with the aggregation framework such values as useridhere which mongoose normally allows you to pass in a "string" for and would "autocast" that string into an ObjectId value for you. This does not happen in the aggregation frameworkIssue#1399, simply because since it can possibly change the "shape" of the documents acted on, then no "schema" can be applied.

注意到聚合框架使用像useridhere这样的值,mongoose通常允许你传入一个“字符串”,并将该字符串“autocast”为你的ObjectId值。这在聚合框架问题#1399中不会发生,仅仅因为它可能会改变所作用文档的“形状”,因此不能应用“模式”。

So you likely want to import this from the core driver instead:

所以你可能想从核心驱动程序中导入它:

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

Then you can "cast" the values manually.

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

Of course if such a value is actually retrieved from another mongoose object rather than from req.params or similar, then it already should be of an ObjectId type.

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

The reason why you use .aggregate() for this is because "standard projection" only ever matches one element. i.e:

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

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

 });

Here the positional $ operator returns the "matched" element, but only ever the "first" match.

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

So where you want "multiple" matches you use $filter instead, and that is a lot more effective than earlier versions of MongoDB which require you to $unwind the array first.

所以你想要“多个”匹配,你可以使用$ filter,这比早期版本的MongoDB更有效,它需要你首先解开数组。

The $unwind operator should only be used in modern releases ( Anything past MongoDB 2.4 ) in the case where you actually want to use a "value" from within an array for an operation such as $group where that value is presented as a "grouping key". It's usage in other cases is generally a "huge performance problem", with the exception of directly following a $lookup pipeline stage where it does have a special important use case.

$ unwind运算符应仅用于现代版本(通过MongoDB 2.4的任何内容),在这种情况下,您实际上想要在数组中使用“值”来执行诸如$ group之类的操作,其中该值表示为“分组”键”。它在其他情况下的使用通常是一个“巨大的性能问题”,除了直接遵循$ lookup管道阶段,它确实有一个特殊的重要用例。

Otherwise best avoided though. Use $filter instead.

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

NOTE: The $addFields pipeline stage allows you to "overwrite" a single element without specifying all the other fields. If your MongoDB does not support this operator, use $project instead and specify all fields explicitly. i.e:

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

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

#2


1  

It may be a good choice to use aggregate like:

使用聚合可能是一个很好的选择:

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

You can get further info in this question: How to filter array in subdocument with MongoDB

您可以在此问题中获得更多信息:如何使用MongoDB过滤子文档中的数组

#3


-1  

$elemMatch operator is used to query a value in an embedded document

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

According to description as mentioned in above question, as a solution to it please try executing following find operation in MongoDB shell.

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

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

#1


3  

You want $filter here:

你想要$ filter这里:

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

});

Noting that with the aggregation framework such values as useridhere which mongoose normally allows you to pass in a "string" for and would "autocast" that string into an ObjectId value for you. This does not happen in the aggregation frameworkIssue#1399, simply because since it can possibly change the "shape" of the documents acted on, then no "schema" can be applied.

注意到聚合框架使用像useridhere这样的值,mongoose通常允许你传入一个“字符串”,并将该字符串“autocast”为你的ObjectId值。这在聚合框架问题#1399中不会发生,仅仅因为它可能会改变所作用文档的“形状”,因此不能应用“模式”。

So you likely want to import this from the core driver instead:

所以你可能想从核心驱动程序中导入它:

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

Then you can "cast" the values manually.

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

Of course if such a value is actually retrieved from another mongoose object rather than from req.params or similar, then it already should be of an ObjectId type.

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

The reason why you use .aggregate() for this is because "standard projection" only ever matches one element. i.e:

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

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

 });

Here the positional $ operator returns the "matched" element, but only ever the "first" match.

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

So where you want "multiple" matches you use $filter instead, and that is a lot more effective than earlier versions of MongoDB which require you to $unwind the array first.

所以你想要“多个”匹配,你可以使用$ filter,这比早期版本的MongoDB更有效,它需要你首先解开数组。

The $unwind operator should only be used in modern releases ( Anything past MongoDB 2.4 ) in the case where you actually want to use a "value" from within an array for an operation such as $group where that value is presented as a "grouping key". It's usage in other cases is generally a "huge performance problem", with the exception of directly following a $lookup pipeline stage where it does have a special important use case.

$ unwind运算符应仅用于现代版本(通过MongoDB 2.4的任何内容),在这种情况下,您实际上想要在数组中使用“值”来执行诸如$ group之类的操作,其中该值表示为“分组”键”。它在其他情况下的使用通常是一个“巨大的性能问题”,除了直接遵循$ lookup管道阶段,它确实有一个特殊的重要用例。

Otherwise best avoided though. Use $filter instead.

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

NOTE: The $addFields pipeline stage allows you to "overwrite" a single element without specifying all the other fields. If your MongoDB does not support this operator, use $project instead and specify all fields explicitly. i.e:

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

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

#2


1  

It may be a good choice to use aggregate like:

使用聚合可能是一个很好的选择:

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

You can get further info in this question: How to filter array in subdocument with MongoDB

您可以在此问题中获得更多信息:如何使用MongoDB过滤子文档中的数组

#3


-1  

$elemMatch operator is used to query a value in an embedded document

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

According to description as mentioned in above question, as a solution to it please try executing following find operation in MongoDB shell.

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

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