我知道如何让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);
答案 0 :(得分:3)
你想要$filter
:
useritems.aggregate([
{ "$match": {
"userid": ObjectId(useridhere),
"items.activated": true
}},
{ "$addFields": {
"items": {
"$filter": {
"input": "$items",
"as": "i",
"cond": "$$i.activated"
}
}
}}
],(err,results) => {
});
注意到聚合框架的值为useridhere
,mongoose通常允许您传入“字符串”,并将该字符串“自动”转换为ObjectId
值。 This does not happen in the aggregation frameworkIssue#1399,因为它可能会改变所采取行动的文件的“形状”,因此不能应用“架构”。
所以你可能想要从核心驱动程序中导入它:
const ObjectId = require('mongodb').ObjectID;
然后你可以手动“施放”这些值。
当然,如果这个值实际上是从另一个猫鼬对象而不是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"
}
}
}}
答案 1 :(得分:1)
使用aggregate
可能是一个不错的选择:
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
答案 2 :(得分:-1)
$ elemMatch 运算符用于查询嵌入文档中的值
根据上述问题中的描述,作为解决方案,请尝试在MongoDB shell中执行以下查找操作。
db.useritems.find({
userid: "random user_id",
items: {
$elemMatch: {
activated: true
}
}
})