【问题标题】:Match Documents based on Nested Array Values and Count Unique根据嵌套数组值匹配文档并计算唯一值
【发布时间】:2017-12-12 14:13:04
【问题描述】:

我有一个 MongoDB 集合,其中包含给定格式的文档,

{
    "_id" : ObjectId("595f5661f34ae7b2adee31bc"),
    "app_userUpdatedOn" : "2017-03-09T12:01:07.615Z",
    "appId" : 31625,
    "app_lastCommunicatedAt" : "2017-03-09T12:18:53.067Z",
    "currentDate" : "2017-03-09T12:19:28.626Z",
    "objectId" : "58c14850e4b0b2406992b29e",
    "name" : "APPSESSION",
    "action" : "START",
    "installationId" : "98088f6641a0fa79",
    "userName" : "98088f6641a0fa79",
    "properties" : [
        [
            "userid",
            "98088f6641a0fa79"
        ],
        [
            "app_os_version",
            "6.0.1"
        ],
        [
            "app_installAt",
            "2017-03-09T12:01:01.307Z"
        ],
        [
            "app_model",
            "SM-J210F"
        ],
        [
            "app_lastCommunicatedAt",
            "2017-03-09T12:18:53.067Z"
        ],
        [
            "app_carrier",
            "Jio 4G"
        ],
        [
            "app_counter",
            1
        ],
        [
            "app_brand",
            "samsung"
        ],
        [
            "app_lib_version",
            "1.0"
        ],
        [
            "app_app_version",
            "3.0.2"
        ],
        [
            "app_os",
            "Android"
        ]
    ],
    "date" : "2017-03-09"
}
{
    "_id" : ObjectId("595f5661f34ae7b2adee31bd"),
    "app_userUpdatedOn" : "2017-02-05T07:38:32.866Z",
    "appId" : 31625,
    "app_lastCommunicatedAt" : "2017-03-09T08:09:05.342Z",
    "currentDate" : "2017-03-09T12:19:28.806Z",
    "objectId" : "58c14850e4b06ec88ecaa9c6",
    "name" : "APPINSTALL",
    "action" : "START",
    "installationId" : "eef436554fbdf4ac",
    "userName" : "eef436554fbdf4ac",
    "properties" : [
        [
            "userid",
            "eef436554fbdf4ac"
        ],
        [
            "app_os_version",
            "5.1"
        ],
        [
            "app_installAt",
            "2017-02-05T11:20:49.809Z"
        ],
        [
            "app_model",
            "Micromax Q465"
        ],
        [
            "app_lastCommunicatedAt",
            "2017-03-09T08:09:05.342Z"
        ],
        [
            "app_carrier",
            "JIO 4G"
        ],
        [
            "app_counter",
            1
        ],
        [
            "app_brand",
            "Micromax"
        ],
        [
            "app_lib_version",
            "1.0"
        ],
        [
            "app_app_version",
            "3.0.2"
        ],
        [
            "app_os",
            "Android"
        ]
    ],
    "date" : "2017-03-09"
}

我想获取 currentDate 介于 startDateendDate 之间的文档的计数和唯一计数,名称为 x (例如,APPSESSION),包含多个属性嵌套数组(如 ["app_installAt","This 可以是任何值而不是 null"] ,["app_model","This 可以是任何值而不是 null"],等等...),Group By userName

之前我创建了一个查询,其中嵌套数组两个元素都是已知的,如下所示

db.testing.aggregate(
      [
            {$match: {currentDate: {$gte:"2017-03-01T00:00:00.000Z", $lt:"2017-03-02T00:00:00.000Z"},name:"INSTALL"}},
            {$match: {properties: ["app_os_version","4.4.2"]}},
            {$match: {properties: ["app_carrier","telenor"]}},
            {$match: {properties: ["app_brand","Micromax"]}},
            {$group: {_id: "$userName"}},
            {$count: "uniqueCount"}
      ]
);

但我无法找到我只知道属性数据嵌套数组的第 0 个索引的数据。

请帮忙。

在此先感谢.... :)

【问题讨论】:

  • 我能指出数据看起来像这样的唯一方式是因为首先更新到它的代码中的错误。改正错误地编写代码不是更合乎逻辑吗?这是完全错误的存储方式。
  • 是的,我知道,但是写入数据的算法是相同的,而且数据非常庞大,以至于更改数据结构也不可行,因为它包含 TB 的数据。
  • 如果是太字节的数据,那么更有理由修复它。现在,您无法有效地使用索引来帮助查询结果。如果所有标准实际上都基于具有特定路径的键和值的数组,那么索引将更加有效并加快结果。无论如何,我已经用当前格式的查询回答了这个问题。
  • 您认为提供的答案中是否有某些内容无法解决您的问题?如果是这样,那么请对答案发表评论,以澄清究竟需要解决哪些尚未解决的问题。如果它确实回答了您提出的问题,请注意Accept your Answers您提出的问题
  • 我得到了我的问题的答案,您在下面的回答完成了我的工作。我正在努力改进所需的结构更改,并迁移现有的数据源。再次感谢

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

对此的查询本质上是使用$all 来匹配数组中的多个条件,然后使用$elemMatch$eq 来匹配各个数组元素。

例如,要匹配和计算问题中提供的第一个文档,“仅”参数将是:

db.testing.find({
  "currentDate": { 
    "$gte": "2017-03-09T00:00:00.000Z",
    "$lt": "2017-03-10T00:00:00.000Z"
  },
  "properties": {
    "$all": [
      { "$elemMatch": { "$eq": ["app_os_version","6.0.1"] } },
      { "$elemMatch": { "$eq": ["app_carrier", "Jio 4G"] } },
      { "$elemMatch": { "$eq": ["app_brand", "samsung"] } }
    ]   
  }
})

使用.aggregate(),然后将整个查询放入单个$match 阶段,如下所示:

db.testing.aggregate([
  { "$match": {
    "currentDate": { 
      "$gte": "2017-03-09T00:00:00.000Z",
      "$lt": "2017-03-10T00:00:00.000Z"
    },
    "properties": {
      "$all": [
        { "$elemMatch": { "$eq": ["app_os_version","6.0.1"] } },
        { "$elemMatch": { "$eq": ["app_carrier", "Jio 4G"] } },
        { "$elemMatch": { "$eq": ["app_brand", "samsung"] } }
      ]   
    }
  }},
  { "$group": { "_id": "$userName" }
  { "$count": "unique_count"
])

所以$elemMatch 在此上下文中将检查每个“内部”数组并查看它是否与提供的条件匹配,我们将其作为“数组”提供给$eq 运算符。

包装$all 意味着“所有”提供的$elemMatch 条件“必须”满足才能满足查询条件。这就是使用这种结构进行选择的方式。

如果您需要调整其中之一,那么“内部”匹配将使用数组的元素。所以在键上它将使用"0" 作为索引位置。即:

   { "$elemMatch": { "0": "app_os_version" } },

【讨论】:

  • 如果我知道数组中的“app_os_version”而不是“6.0.1”,我想从数组的属性数组中过滤后的所有结果,我只知道数组第一个元素,而不是第二个
  • @Shashank 使用$elemMatch 内的“索引”位置。添加到答案以进行演示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 1970-01-01
  • 1970-01-01
  • 2015-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多