是否可以在ArangoDB中编写查询以聚合已连接文档中的值?

时间:2017-03-31 17:35:54

标签: arangodb

假设您拥有普通会员和高级会员资格的电影订阅服务。

以下是用户活动生成的数据样本,并作为文档存储在集合中:

[
    {
        "eventType": "sessionInfo",
        "userType": "premium",
        "sessionGroupID": 1
    },
    {
        "eventType": "mediaPlay",
        "productSKU": "starwars",
        "sessionGroupID": 1,
        "elapsed": 200
    },
    {
        "eventType": "sessionInfo",
        "userType": "premium",
        "sessionGroupID": 2
    },
    {
        "eventType": "mediaPlay",
        "productSKU": "xmen",
        "sessionGroupID": 2,
        "elapsed": 500
    },
    {
        "eventType": "sessionInfo",
        "userType": "normal",
        "sessionGroupID": 3
    },
    {
        "eventType": "mediaPlay",
        "productSKU": "xmen",
        "sessionGroupID": 3,
        "elapsed": 10
    },
    {
        "eventType": "sessionInfo",
        "userType": "normal",
        "sessionGroupID": 4
    },
    {
        "eventType": "mediaPlay",
        "productSKU": "xmen",
        "sessionGroupID": 4,
        "elapsed": 100
    },
    {
        "eventType": "sessionInfo",
        "userType": "normal",
        "sessionGroupID": 5
    },
    {
        "eventType": "mediaPlay",
        "productSKU": "xmen",
        "sessionGroupID": 5,
        "elapsed": 5
    },
    {
        "eventType": "mediaPlay",
        "productSKU": "starwars",
        "sessionGroupID": 5,
        "elapsed": 25
    }
]

您可以看到有两个“eventTypes”:

  • “sessionInfo”文档,包含整个公共信息 用户会话

  • “mediaPlay”文件,用于存储多少秒 电影被观看了。

(每个“mediaPlay”事件都包含sessionGroupID,因此它可以与该会话相关联。)

问题#1:

鉴于总共有数千万份文件,您如何编写一个总计每部电影的已用观看时间的查询,按用户类型分组?

所需的查询结果:

premium users - total of "elapsed":
    xmen: 500
    starwars: 200

normal users - total of "elapsed":
    xmen: 115
    starwars: 25

问题#2:

如果数据没有针对此类查询进行最佳结构化,那么理想的结构是什么?

  • 例如,将“mediaInfo”文档中的“mediaPlay”事件嵌套为嵌套数组会更好吗?

喜欢这个吗?

[
    {
        "eventType": "sessionInfo",
        "userType": "premium",
        "sessionGroupID": 1,
        "viewLog": [
            {
                "eventType": "mediaPlay",
                "productSKU": "starwars",
                "sessionGroupID": 1,
                "elapsed": 200
            }
        ]
    },
    {
        "eventType": "sessionInfo",
        "userType": "premium",
        "sessionGroupID": 2,
        "viewLog": [
            {
                "eventType": "mediaPlay",
                "productSKU": "xmen",
                "sessionGroupID": 2,
                "elapsed": 500
            }
        ]
    },
    {
        "eventType": "sessionInfo",
        "userType": "normal",
        "sessionGroupID": 3,
        "viewLog": [
            {
                "eventType": "mediaPlay",
                "productSKU": "xmen",
                "sessionGroupID": 3,
                "elapsed": 10
            }
        ]
    },
    {
        "eventType": "sessionInfo",
        "userType": "normal",
        "sessionGroupID": 4,
        "viewLog": [
            {
                "eventType": "mediaPlay",
                "productSKU": "xmen",
                "sessionGroupID": 4,
                "elapsed": 100
            }
        ]
    },
    {
        "eventType": "sessionInfo",
        "userType": "normal",
        "sessionGroupID": 5,
        "viewLog": [
            {
                "eventType": "mediaPlay",
                "productSKU": "xmen",
                "sessionGroupID": 5,
                "elapsed": 5
            },
            {
                "eventType": "mediaPlay",
                "productSKU": "starwars",
                "sessionGroupID": 5,
                "elapsed": 25
            }
        ]
    }
]

感谢您提供任何指导和建议!

1 个答案:

答案 0 :(得分:2)

以下查询迭代集合并收集按userTypes分组的所有会话ID。然后它创建一个子查询,它遍历集合并收集所有电影以及eventType为“mediaPlay”且收集的会话包含sessionGroupID的已用时间总和。

@@collbind parameter,其中包含您的收藏名称。

FOR doc IN @@coll
  FILTER doc.eventType == "sessionInfo"
  COLLECT userTypes = doc.userType INTO sessions = doc.sessionGroupID
  RETURN {
    "userTypes" : userTypes,
    "movies" : (
      FOR event IN @@coll
        FILTER event.sessionGroupID IN sessions
        FILTER event.eventType == "mediaPlay"
        COLLECT movie = event.productSKU INTO elapsed = event.elapsed
        RETURN { "movie" : movie, "elapsed" : SUM(elapsed) }
      )
  }

此查询的结果是:

[
  {
    "userTypes": "normal",
    "movies": [
      {
        "movie": "starwars",
        "elapsed": 25
      },
      {
        "movie": "xmen",
        "elapsed": 115
      }
    ]
  },
  {
    "userTypes": "premium",
    "movies": [
      {
        "movie": "starwars",
        "elapsed": 200
      },
      {
        "movie": "xmen",
        "elapsed": 500
      }
    ]
  }
]

关于你的第二个问题。嵌套数组/对象不会优化此查询,但您应该将数据拆分为两个集合。每个eventType一个(例如,将事件命名为eventType sessionInfomediaPlay)。这减少了所需过滤器语句的数量,更重要的是,它允许您通过sessionInfos和mediaPlay单独查询,从而大大提高您的性能。

查询将如下所示:

FOR doc IN sessionInfo
  COLLECT userTypes = doc.userType INTO sessions = doc.sessionGroupID
  RETURN {
    "userTypes" : userTypes,
    "movies" : (
      FOR event IN mediaPlay
        FILTER event.sessionGroupID IN sessions
        COLLECT movie = event.productSKU INTO elapsed = event.elapsed
        RETURN { "movie" : movie, "elapsed" : SUM(elapsed) }
      )
  }