【问题标题】:Trying to filter values of an array within an array in MongoDB尝试在 MongoDB 中的数组中过滤数组的值
【发布时间】:2020-08-17 16:24:00
【问题描述】:

我是 MongoDB 新手,我正在尝试过滤数组中的数组值。下面是模式的一个示例。该模式基本上是一个 3 层字典的转储,其中一个简单的标量对象作为叶节点。

“I”成员包含带有字符串键(k)的键值对的文档数组(外部数组),值(v)是键值对的文档数组(中间数组)以日期作为键和值是另一个字典,它不是这个问题的一部分。

基本上,我需要做的是从中间数组(日期,键值)中检索外部数组(字符串,键值)的给定值的最新数据。

(Collection Sample)
{
    "_id" : ObjectId("5eacfbe62758834aefdec003"),
    "UserId" : UUID("46942978-29f4-4521-9932-840cead6743e"),
    "Data" : {
        "I" : [
            {
                "k" : "LRI39",
                "v" : [
                    {
                        "k" : ISODate("2020-03-11T20:24:41.591Z"),
                        "v" : [
                            {
                                "k" : ISODate("2020-03-11T20:24:41.594Z"),
                                "v" : {
                                    "Source" : 1,
                                    "Value" : 19
                                }
                            }
                        ]
                    },
                    {
                        "k" : ISODate("2020-01-22T11:37:23.393Z"),
                        "v" : [
                            {
                                "k" : ISODate("2020-01-22T11:37:23.412Z"),
                                "v" : {
                                    "Source" : 1,
                                    "Value" : 20
                                }
                            }
                        ]
                    }
                ]
            },
            ...
        ]
    }
}

我已经能够生成一个文档,该文档基本上是您从“数据”到样本末尾看到的内容,是 LRI39 的整个记录​​,使用:

db.threetier.aggregate([
{   
    $project: {
        "Data.I": {
            $filter: {
                input: "$Data.I",
                as: "item",
                cond: {
                    $eq: [ "$$item.k", "LRI39" ]                        
                }
            }
        }
    }
}
])

但是,无论我做什么,我似乎都无法返回中间数组记录的任何子集:我得到了 2020-03-11 和 2020-01-22 元素,或者我什么也得不到。

我尝试在上面的投影中添加如下所示的阶段,我认为我会得到 1 条记录(2020-01-22 记录),但我都得到了。如果我将日期更改为 2019 年,我将一无所获(如预期的那样)。

$project: {
    "Data.I.v": {
        $filter: {
            input: "$Data.I.v",
            as: "stamp",
            cond: { $lt: [ "$$stamp.k", ISODate("2020-02-14T00:00:00Z") ] }             
        } 
    }
}   

我也试过了:

{ $match: { $expr: { $lt: [ "Data.I.v.k", ISODate("2020-02-14T00:00:00Z") ] } } }

但这根本不返回任何结果(可能是因为 $match 适用于文档而不是数组)以及尝试在匹配之前使用 $unwind: "$Data.I.v" 展开数组,但这也不会返回任何结果。

似乎我在这里遗漏了一些基本的东西。我确实意识到 Mongo 被设计为(我认为)将这些数组项作为文档,但我确实想看看这是否会按原样工作。

【问题讨论】:

    标签: arrays mongodb aggregation


    【解决方案1】:

    您需要同时展开 Data.IData.I.v,以便您可以分别考虑每个子元素。

    然后按日期字段反向排序。 按 _id 和键分组,仅选择每个组中的第一个文档。 最后,replaceRoot,因此返回的只是选定的文档。

    db.collection.aggregate([
      {$unwind: "$Data.I"},
      {$unwind: "$Data.I.v"},
      {$sort: {"Data.I.v.k": -1}},
      {$group: {
          _id: {
            _id: "$_id",
            key: "$Data.I.k"
          },
          document: {$first: "$$ROOT"}
      }},
      {$replaceRoot: {newRoot: "$document"}}
    ])
    

    Playground

    【讨论】:

    • 非常感谢您提供答案。关于如何使用 MQL 的事情开始在我的脑海中浮现 - 一点一点。
    猜你喜欢
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 2014-06-30
    相关资源
    最近更新 更多