【问题标题】:MongoDB create an array within an arrayMongoDB 在数组中创建数组
【发布时间】: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# 中

非常感谢您的帮助。

【问题讨论】:

    标签: json mongodb bson


    【解决方案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"}}, 
            
        }
      }
    ])
    

    在第一组中获取我的所有数据,然后在第二组中创建一个包含月份的集合,然后在第三组中创建一个包含年份的集合并将月份添加到每年。

    【讨论】:

      猜你喜欢
      • 2017-07-02
      • 2021-06-10
      • 2019-10-19
      • 2016-02-27
      • 2021-12-19
      • 2021-08-03
      • 1970-01-01
      • 2016-08-31
      • 2021-12-11
      相关资源
      最近更新 更多