如何只检索 MongoDB 中嵌入文档数组的一个子集?
How to retrieve only a subset of an array of embedded documents in MongoDB?
我是 MongoDB 的新手,我无法仅检索嵌入文档数组的一个子集。例如,我有以下文件:
{
"_id": "Stock1",
"data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
{"value": 12.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 14.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
"_id": "Stock2",
"data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
{"value": 8.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 6.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
"_id": "Stock3",
"data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
{"value": 10.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 10.0, "date": "2020-01-01T00:00:00.000Z"}]
}
而且我想在 date
2010-01-01 和 2020-01-01(包括)之间检索“Stock1”和“Stock3”,即我想结束于此:
{
"_id": "Stock1",
"data": [{"value": 12.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 14.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
"_id": "Stock3",
"data": [{"value": 10.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 10.0, "date": "2020-01-01T00:00:00.000Z"}]
}
我试过 find
命令:
{"_id": {$in: ["Stock1", "Stock3"]}, "data.date": {$gte: ISODate('2010-01-01'), $lte: ISODate('2020-01-01')}}
但我正在检索所有日期,这是不可取的。
我知道 aggregate
命令,但我不确定如何构建管道。有人可以指出我应该如何进行吗?
如有任何帮助,我们将不胜感激!
解决方案 1
$unwind
- 将 data
数组解构为文档。
$match
- 基于 id
和 data.date
. 的日期范围进行过滤
$group
- 按 id
分组(步骤 1 反向)。
db.collection.aggregate([
{
$unwind: "$data"
},
{
$match: {
$expr: {
$and: [
{
$in: [
"$_id",
[
"Stock1",
"Stock3"
]
]
},
{
$gte: [
{
$toDate: "$data.date"
},
ISODate("2010-01-01")
]
},
{
$lte: [
{
$toDate: "$data.date"
},
ISODate("2020-01-01")
]
}
]
}
}
},
{
$group: {
"_id": "$_id",
"data": {
$push: "$data"
}
}
}
])
Sample Solution 1 on Mongo Playground
解决方案 2
$match
- 根据 _id
. 过滤文档
$project
- 显示带有 $filter
数据数组的文档。
db.collection.aggregate([
{
$match: {
"_id": {
$in: [
"Stock1",
"Stock3"
]
}
}
},
{
$project: {
"_id": 1,
"data": {
"$filter": {
"input": "$data",
"cond": {
"$and": [
{
$gte: [
{
$toDate: "$$this.date"
},
ISODate("2010-01-01")
]
},
{
$lte: [
{
$toDate: "$$this.date"
},
ISODate("2020-01-01")
]
}
]
}
}
}
}
}
])
您可以使用 $elemMatch
:
{"_id": {$in: ["Stock1", "Stock3"]}, "data":{$elemMatch:{date: {$gte: ISODate('2010-01-01'), $lte: ISODate('2020-01-01')}}}}
单个嵌套文档在嵌套字段上满足多个查询条件
使用 $elemMatch 运算符对一组嵌入文档指定多个条件,以便至少一个嵌入文档满足所有指定条件。
来源:https://docs.mongodb.com/manual/tutorial/query-array-of-documents/
要避免 $unwind
和 $group
,您可以在这样的聚合查询中使用 $filter
:
db.collection.aggregate([
{
"$match": {
"_id": {
"$in": ["Stock1","Stock3"]
}
}
},
{
"$project": {
"data": {
"$filter": {
"input": "$data",
"as": "d",
"cond": {
"$and": [
{
"$gte": [{"$toDate": "$$d.date"},ISODate("2010-01-01")]
},
{
"$lte": [{"$toDate": "$$d.date"},ISODate("2020-01-01")]
}
]
}
}
}
}
}
])
示例here
我是 MongoDB 的新手,我无法仅检索嵌入文档数组的一个子集。例如,我有以下文件:
{
"_id": "Stock1",
"data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
{"value": 12.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 14.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
"_id": "Stock2",
"data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
{"value": 8.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 6.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
"_id": "Stock3",
"data": [{"value": 10.0, "date": "2000-01-01T00:00:00.000Z"},
{"value": 10.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 10.0, "date": "2020-01-01T00:00:00.000Z"}]
}
而且我想在 date
2010-01-01 和 2020-01-01(包括)之间检索“Stock1”和“Stock3”,即我想结束于此:
{
"_id": "Stock1",
"data": [{"value": 12.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 14.0, "date": "2020-01-01T00:00:00.000Z"}]
},
{
"_id": "Stock3",
"data": [{"value": 10.0, "date": "2010-01-01T00:00:00.000Z"},
{"value": 10.0, "date": "2020-01-01T00:00:00.000Z"}]
}
我试过 find
命令:
{"_id": {$in: ["Stock1", "Stock3"]}, "data.date": {$gte: ISODate('2010-01-01'), $lte: ISODate('2020-01-01')}}
但我正在检索所有日期,这是不可取的。
我知道 aggregate
命令,但我不确定如何构建管道。有人可以指出我应该如何进行吗?
如有任何帮助,我们将不胜感激!
解决方案 1
$unwind
- 将data
数组解构为文档。$match
- 基于id
和data.date
. 的日期范围进行过滤
$group
- 按id
分组(步骤 1 反向)。
db.collection.aggregate([
{
$unwind: "$data"
},
{
$match: {
$expr: {
$and: [
{
$in: [
"$_id",
[
"Stock1",
"Stock3"
]
]
},
{
$gte: [
{
$toDate: "$data.date"
},
ISODate("2010-01-01")
]
},
{
$lte: [
{
$toDate: "$data.date"
},
ISODate("2020-01-01")
]
}
]
}
}
},
{
$group: {
"_id": "$_id",
"data": {
$push: "$data"
}
}
}
])
Sample Solution 1 on Mongo Playground
解决方案 2
$match
- 根据_id
. 过滤文档
$project
- 显示带有$filter
数据数组的文档。
db.collection.aggregate([
{
$match: {
"_id": {
$in: [
"Stock1",
"Stock3"
]
}
}
},
{
$project: {
"_id": 1,
"data": {
"$filter": {
"input": "$data",
"cond": {
"$and": [
{
$gte: [
{
$toDate: "$$this.date"
},
ISODate("2010-01-01")
]
},
{
$lte: [
{
$toDate: "$$this.date"
},
ISODate("2020-01-01")
]
}
]
}
}
}
}
}
])
您可以使用 $elemMatch
:
{"_id": {$in: ["Stock1", "Stock3"]}, "data":{$elemMatch:{date: {$gte: ISODate('2010-01-01'), $lte: ISODate('2020-01-01')}}}}
单个嵌套文档在嵌套字段上满足多个查询条件
使用 $elemMatch 运算符对一组嵌入文档指定多个条件,以便至少一个嵌入文档满足所有指定条件。
来源:https://docs.mongodb.com/manual/tutorial/query-array-of-documents/
要避免 $unwind
和 $group
,您可以在这样的聚合查询中使用 $filter
:
db.collection.aggregate([
{
"$match": {
"_id": {
"$in": ["Stock1","Stock3"]
}
}
},
{
"$project": {
"data": {
"$filter": {
"input": "$data",
"as": "d",
"cond": {
"$and": [
{
"$gte": [{"$toDate": "$$d.date"},ISODate("2010-01-01")]
},
{
"$lte": [{"$toDate": "$$d.date"},ISODate("2020-01-01")]
}
]
}
}
}
}
}
])
示例here