MongoDB 在数组中创建数组
Posted
技术标签:
【中文标题】MongoDB 在数组中创建数组【英文标题】:MongoDB create an array within an array 【发布时间】:2021-12-17 07:13:53 【问题描述】:我正在努力了解 MongoDB 以及聚合和组。到目前为止,我已经花了大约 3 天时间。
我的源数据看起来像...
"formName" : "my form",
"updatedAt" : "2021-11-02T13:29:00.123Z",
,
"formName" : "another form",
"lastUpdated" : "2021-10-01T13:29:00.123123",
,
请注意,可能有不同的日期名称,尽管这些是唯一的区别。
我正在尝试实现...的输出
"_id": null,
"text": "my form", (NOTE: This is the formName)
"children": [
"text" : 2021, (This is the year part of the updated)
"children" : [
"text" : 1, (These are the month part of the updated)
"text" : 2,
"text" : 3,
"text" : 4
]
,
]
所以,基本上是一棵树,它有 formName,子分支是年,子分支是月。
各种方法我都试过了,很多都不行,比如嵌套在$groups里面的$addToSet。
我已经接近了,但我解决不了。
这是最接近的,但这不起作用。
db.FormsStore.aggregate( [
$match:myKey:"a guid to group my forms together",
$project: formName:1, lastUpdated:1, updatedAt:1,
$group:
_id: formName: "$formName" ,
Year: $addToSet: $year: $dateFromString: dateString: "$lastUpdated" ,
Month: $addToSet: $month: $dateFromString: dateString: "$lastUpdated" ,
,
$group:
_id: formName: "$_id.formName" ,
Time: $addToSet: year: "$Year", month: "$Month"
]
)
输出显示...
_id: formName: 'One of my forms' ,
Time: [
year: [ 2021 ],
month: [ 10, 11 ]
]
这将全部用在 C# 中
非常感谢您的帮助。
【问题讨论】:
【参考方案1】:查询
以日期格式添加一个新字段“日期” 首先将更具体的(formname+year)
分组以将月份放入数组中
然后是不太具体的(formname)
将年份放入数组中
Test code here
aggregate(
["$set":
"date":
"$cond":
["$updatedAt", "$dateFromString": "dateString": "$updatedAt",
"$dateFromString": "dateString": "$lastUpdated"],
"updatedAt": "$$REMOVE",
"lastUpdated": "$$REMOVE",
"$group":
"_id": "text": "$formName", "year": "$year": "$date",
"children": "$push": "text": "$month": "$date",
"$group":
"_id": "$_id.text",
"children":
"$push": "text": "$_id.year", "children": "$children",
"$set": "text": "$_id", "_id": "$$REMOVE"])
编辑
下面也按年/月排序,并且每个 formName 只保留唯一的年/月。
不同之处在于按 formName,year,month 分组来取唯一(第一个 aacumulator 将只取所有 3 中相同的一个) replace-root(将第一个文档设为 ROOT 文档) 然后按这3个字段排序(降年,升月) 群 按 2 个字段排序 最后一组Test code here *mongoplaygroung 丢失了字段的顺序,请在您的驱动程序上运行它以确保
aggregate(
["$set":
"date":
"$cond":
["$updatedAt", "$dateFromString": "dateString": "$updatedAt",
"$dateFromString": "dateString": "$lastUpdated"],
"updatedAt": "$$REMOVE",
"lastUpdated": "$$REMOVE",
"$set": "year": "$year": "$date", "month": "$month": "$date",
"$group":
"_id": "formName": "$formName", "year": "$year", "month": "$month",
"doc": "$first": "$$ROOT",
"$replaceRoot": "newRoot": "$doc",
"$sort": "formName": 1, "year": -1, "month": 1,
"$group":
"_id": "text": "$formName", "year": "$year",
"children": "$push": "text": "$month",
"$sort": "_id.text": 1, "_id.year": -1,
"$group":
"_id": "$_id.text",
"children":
"$push": "text": "$_id.year", "children": "$children",
"$set": "text": "$_id", "_id": "$$REMOVE"])
有数据
[
"formName": "my form",
"updatedAt": "2021-11-02T23:30:15.123Z"
,
"formName": "my form",
"updatedAt": "2021-10-02T23:30:15.123Z"
,
"formName": "my form",
"updatedAt": "2020-06-02T23:30:15.123Z"
,
"formName": "my form",
"updatedAt": "2020-07-02T23:30:15.123Z"
,
"formName": "another form",
"updatedAt": "2021-10-01T23:30:15.123Z"
,
"formName": "another form",
"updatedAt": "2021-10-01T23:30:15.123Z"
,
"formName": "another form",
"updatedAt": "2021-09-01T23:30:15.123Z"
,
"formName": "another form",
"updatedAt": "2021-08-01T23:30:15.123Z"
,
"formName": "another form",
"updatedAt": "2020-10-01T23:30:15.123Z"
]
我得到了结果
[
"children": [
"text": 2021,
"children": [
"text": 10
,
"text": 11
]
,
"text": 2020,
"children": [
"text": 6
,
"text": 7
]
],
"text": "my form"
,
"children": [
"text": 2021,
"children": [
"text": 8
,
"text": 9
,
"text": 10
]
,
"text": 2020,
"children": [
"text": 10
]
],
"text": "another form"
]
【讨论】:
虽然我打开了它,但我自己仍在研究它......并且几乎已经破解它......通过管道进入新的$group,但我对你的解决方案非常感兴趣。我刚刚尝试在本地运行你的并得到一个错误,无法从 BSON 类型字符串转换为日期。我认为问题在于测试代码的链接,您已经设置了 ISODate,但我的数据是字符串(因此是我的 $dateFromString)。每组中的数据将更新At 或 lastUpdated,而不是两者。 好的,我更新了答案,但通常将日期保持为 Dates 更快,您可以使用$dateToString
谢谢。这几乎可以工作,但是当我使用真实数据时,给了我重复的几个月。至于日期,它们来自外部来源并直接导入 MongoDB。现在,我自己的也不太正确,但我也把它作为答案,所以你可以看到我在哪里......
我刚刚将 $push 更新为 $addToSet,这样更好。 (我是 MongoDB 新手,所以阅读这些新指令并看到 $push 和 $addToSet 相似,但 $addToSet 保持唯一值)我现在尝试按年/月排序 - desc (按顺序排列树),但它似乎不想玩。我把 $sort: "date":-1 放在 "lastUpdated": "$$REMOVE" 之后。我在原帖中可能没有说清楚。
我更新了答案排序并只保留唯一的年/月【参考方案2】:
我继续努力,虽然这还不太正确(还),但这是我想出的。
db.FormsStore.aggregate([
$project: formName:1, lastUpdated:1, updatedAt:1,
$group:
_id: formName: "$formName", Year: $year: $dateFromString: dateString: "$updatedAt" , Month: $month: $dateFromString: dateString: "$updatedAt" ,
,
$group:
_id: formName: "$_id.formName", Year: "$_id.Year",
Months: $addToSet: Text: "$_id.Month"
,
$group:
_id: "$_id.formName", Children: $addToSet: Text: "$_id.Year", Children: "$Months",
])
在第一组中获取我的所有数据,然后在第二组中创建一个包含月份的集合,然后在第三组中创建一个包含年份的集合并将月份添加到每年。
【讨论】:
以上是关于MongoDB 在数组中创建数组的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 mongodb (node.js) 在集合中创建一个包含所有值的数组
在同一集合中创建对象的 mongodb 模式数组或创建新集合的更好方法保存引用
如何使用 java spring 注释在 MongoDB 中创建一个完全填充的引用对象