ElasticSearch扫盲之十二:ElasticSearch关联查询即父子文档查询和嵌套文档nested查询

注:ElasticSearch系列文章适用于ElasticSearch 6.7,部分内容适用于ElasticSearch7.0

在关系型数据库中,可以通过join实现多表的联表查询,那么在ES中,是否能实现多个index联合查询呢?显然,是不能的,那么如何实现多个index联合查询呢?根据本人的一些微薄经验,大体可以通过以下几个方便来实现:

  • 定义一个组合的index,将多个index的值合并到一个index中
    • 以嵌套文档的形式存储:通过数据冗余的方式来提高性能
    • 以父子文档的形式存储: 通过在同个文档中定义父子关系来模拟实现多个index的联合查询
  • 客户端将多个index查询出来的数据进行组合

使用场景浅析:什么场景下使用嵌套文档,什么场景下使用父子文档,什么场景下使用客户端组合呢?

A. 组合文档(包括嵌套文档和父子文档)与客户端组合

  • 当各个index联系非常紧密,共同属于某个模块或服务,不可分割的情况下,优先选择组合文档,比如在商城订单系统中,有母订单和子订单的说法,母订单可以认为是同一批次的订单,而子订单表示每一种订单的商品,这种母子订单关联比较紧密,建议使用组合文档.
  • 当某个index与其他index有一定的关联,但它可以作为一个独立的系统或服务,这种,建议使用客户端组合.如,活动系统中,有活动信息,和活动参与信息(参与信息一般只存关联关系),还有活动参与的用户的信息,这里用户的基本信息与活动参与信息有一定的关联,但是用户信息不只是单独为活动系统服务的,它可以认为是一个独立的服务,因此,比较适合使用客户端组合

B.嵌套文档与父子文档

  • 但某个index与另外一个index是1:1或者1:n(但n是很小的值时),比较适合嵌套文档
  • 但某个index与另外一个index是典型的1:n的情况(而且n比较大),比较适合使用父子文档

一、嵌套文档nested

将多个index组合为一个index,其中某个或某些字段的值存储另外一个文档的数据

1.定义文档结构
  • 通过type为nested来注明内嵌字段
  • 在内嵌字段内部通过properties来定义内嵌的文档的结构

以一个简单的用户系统为例:

(1)独立的index

A.用户账号信息

  1. PUT user_account
  2. {
  3. "mappings": {
  4. "_doc":{
  5. "properties":{
  6. "user_id":{
  7. "type":"long"
  8. },
  9. "account":{
  10. "type":"text"
  11. },
  12. "password":{
  13. "type":"keyword",
  14. "index":false
  15. },
  16. "status":{
  17. "type":"integer"
  18. },
  19. "nickname":{
  20. "type":"text"
  21. },
  22. "create_time":{
  23. "type":"date"
  24. }
  25. }
  26. }
  27. }
  28. }

B.用户扩展信息

  1. PUT user_extend
  2. {
  3. "mappings": {
  4. "_doc":{
  5. "properties":{
  6. "user_id":{
  7. "type":"long"
  8. },
  9. "realname":{
  10. "type":"text"
  11. },
  12. "birthday":{
  13. "type":"date"
  14. },
  15. "gender":{
  16. "type":"integer"
  17. },
  18. "province":{
  19. "type":"integer"
  20. },
  21. "city":{
  22. "type":"text"
  23. },
  24. "area":{
  25. "type":"text"
  26. },
  27. "create_time":{
  28. "type":"date"
  29. }
  30. }
  31. }
  32. }
  33. }
(2)合并为嵌套文档
  1. PUT user_info
  2. {
  3. "mappings": {
  4. "_doc": {
  5. "properties": {
  6. "user_id": {
  7. "type": "long"
  8. },
  9. "account": {
  10. "type": "text"
  11. },
  12. "password": {
  13. "type": "keyword",
  14. "index": false
  15. },
  16. "status": {
  17. "type": "integer"
  18. },
  19. "nickname": {
  20. "type": "text"
  21. },
  22. "create_time": {
  23. "type": "date"
  24. },
  25. "extend": {
  26. "type": "nested",
  27. "properties": {
  28. "realname": {
  29. "type": "text"
  30. },
  31. "birthday": {
  32. "type": "date"
  33. },
  34. "gender": {
  35. "type": "integer"
  36. },
  37. "province": {
  38. "type": "integer"
  39. },
  40. "city": {
  41. "type": "text"
  42. },
  43. "area": {
  44. "type": "text"
  45. },
  46. "create_time": {
  47. "type": "date"
  48. }
  49. }
  50. }
  51. }
  52. }
  53. }
  54. }
  • extend作为一个内嵌字段,包含了原来user_extend的结构和内容

插入数据:

  1. PUT user_info/_doc/1
  2. {
  3. "user_id":1,
  4. "account":"jack",
  5. "password":"A458#$%2",
  6. "status":1,
  7. "nickname":"jack",
  8. "create_time":1556500288,
  9. "extend":{
  10. "realname":"Jack",
  11. "birthday":561172520,
  12. "gender":1,
  13. "province":37,
  14. "city":3701,
  15. "area":370101,
  16. "create_time":1556100226
  17. }
  18. }
  19. PUT user_info/_doc/2
  20. {
  21. "user_id":2,
  22. "account":"tom",
  23. "password":"A458#$%2",
  24. "status":1,
  25. "nickname":"jack",
  26. "create_time":1556600288,
  27. "extend":{
  28. "realname":"Jet",
  29. "birthday":551172520,
  30. "gender":2,
  31. "province":31,
  32. "city":3101,
  33. "area":310107,
  34. "create_time":1556200226
  35. }
  36. }
2.嵌套文档查询
  • nested : 作为嵌套文档查询的参数
    • path : 要查询的嵌套文档的对应的字段
    • query : 嵌套文档查询条件

例如:查询city为3301的用户

  1. GET user_info/_doc/_search
  2. {
  3. "query":{
  4. "nested":{
  5. "path":"extend",
  6. "query":{
  7. "term":{
  8. "extend.city":3101
  9. }
  10. }
  11. }
  12. }
  13. }

查询结果:

  1. {
  2. "took" : 3,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 5,
  6. "successful" : 5,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : 1,
  12. "max_score" : 0.2876821,
  13. "hits" : [
  14. {
  15. "_index" : "user_info",
  16. "_type" : "_doc",
  17. "_id" : "2",
  18. "_score" : 0.2876821,
  19. "_source" : {
  20. "user_id" : 2,
  21. "account" : "tom",
  22. "password" : "A458#$%2",
  23. "status" : 1,
  24. "nickname" : "jack",
  25. "create_time" : 1556600288,
  26. "extend" : {
  27. "realname" : "Jet",
  28. "birthday" : 551172520,
  29. "gender" : 2,
  30. "province" : 31,
  31. "city" : 3101,
  32. "area" : 310107,
  33. "create_time" : 1556200226
  34. }
  35. }
  36. }
  37. ]
  38. }
  39. }

二、父子文档

所谓父子文档是指在同一个文档中定义父子关系的文档

父子文档的注意点:

  • 父子文档是存储在同一个index的同一个type中的,即有的记录是父文档,有的记录是子文档
  • 父子文档必须存储在同一个shard中
  • 一个子文档只能定义一个父文档关联
1.活动系统需求分析

这里以一个小型活动系统为例:

活动系统流程

(1)实体和数据库表
  • 2个实体:
    • 用户
    • 活动
  • 3张数据表:
    • 活动信息表
    • 用户表
    • 用户参与活动记录表

活动与活动参与记录是一对多的关系,即一个活动有多条参与记录,这里只将活动参与记录和活动信息组合为一个文档,而不将用户信息合到该文档种,基于以下几个原因考虑:

  • 用户基础信息属于一个独立模块(服务),如果与活动信息等合并为一个文档,耦合性太强
  • 相对于参与活动的用户量为说,用户基础信息数据量较大,如果合并到一个文档,那用户信息更新需要同步到该文档中.
(2)文档

基于以上的分析,文档只包含活动信息和活动参与信息:

  • 父文档为活动信息
  • 子文档为活动参与信息
2.文档定义

父子文档定义时,通过一个关联字段来指定父子文档的关联关系

其基本格式如下:

  1. PUT indexName
  2. {
  3. "mappings":{
  4. "typeName":{
  5. "properties":{
  6. "relationFieldName":{
  7. "type":"join",
  8. "relations":{
  9. "parentName":"childName"
  10. }
  11. }
  12. }
  13. }
  14. }
  15. }
  • indexName为文档索引名称
  • typeName为文档type名称,ES6.x一般指定为_doc,ES7.x不再需要type
  • relationFieldName : 用于定义关联关系的字段名称
    • parentName : 为父文档为名称,用于插入数据时指定是父文档或子文档(或查询时指定的文档)
    • childName : 子文档名称

以活动系统为例:

  1. PUT activity
  2. {
  3. "mappings": {
  4. "_doc": {
  5. "properties": {
  6. "activity_id":{
  7. "type":"long"
  8. },
  9. "type":{
  10. "type":"integer"
  11. },
  12. "title":{
  13. "type":"text"
  14. },
  15. "status":{
  16. "type":"integer"
  17. },
  18. "active":{
  19. "type":"integer"
  20. },
  21. "begin_time":{
  22. "type":"date"
  23. },
  24. "end_time":{
  25. "type":"date"
  26. },
  27. "create_time":{
  28. "type":"date"
  29. },
  30. "activity_member": {
  31. "type": "join",
  32. "relations": {
  33. "activity": "member"
  34. }
  35. }
  36. }
  37. }
  38. }
  39. }

字段说明:

  • status : 活动进行状态
  • active : 活动启用状态
  • activity_member为关联父子文档的字段
    • type: join指定为这是一个父子文档关联字段
    • relations : 定义父子关系,键为父文档,值为子文档

注:对于动态mapping,除关联字段外,其他字段都可以不定义

3.向文档插入数据
(1)插入父文档数据

A.插入数据说明

  • 通过关系字段对象中的name指定父文档名称,表示这是插入父文档
    • 因为我们在mappings中定义的关联字段为activity_member,所以插入的时候也要指定关联字段
    • 因为mappings中定义的父文档为actvity,所以插入父文档时指定name为activity 
  • 通过请求URI中的routing指定分区,以便子文档与之设置相同的分区

B.插入数据:

  • 插入第1条活动数据
  1. PUT activity/_doc/1?routing=1
  2. {
  3. "activity_id":1,
  4. "title":"劳动节特惠活动",
  5. "type":1,
  6. "status":1,
  7. "active":1,
  8. "begin_time":1556262929,
  9. "end_time":1556985599,
  10. "create_time":1556260929,
  11. "activity_member":{
  12. "name":"activity"
  13. }
  14. }
  • 插入第2条活动数据
  1. PUT activity/_doc/2?routing=1
  2. {
  3. "activity_id":2,
  4. "title":"青年节特惠活动",
  5. "type":1,
  6. "status":1,
  7. "active":1,
  8. "begin_time":1556899200,
  9. "end_time":1556985599,
  10. "create_time":1556263929,
  11. "activity_member":{
  12. "name":"activity"
  13. }
  14. }
  • 插入第3条活动数据 
  1. PUT activity/_doc/3?routing=1
  2. {
  3. "activity_id":3,
  4. "title":"儿童节特惠活动",
  5. "type":1,
  6. "status":1,
  7. "active":1,
  8. "begin_time":1559318400,
  9. "end_time":1559664000,
  10. "create_time":1556263929,
  11. "activity_member":{
  12. "name":"activity"
  13. }
  14. }
(2)插入子文档数据

A.插入数据说明

  • 通过关系字段对象中的name指定子文档名称,表示这是插入子文档
    • 因为我们在mappings中定义的关联字段为activity_member,所以插入的时候也要指定关联字段
    • 因为mappings中定义的子文档为member,所以插入子文档时指定name为member
  • 通过关系字段对象中的parent指定父文档ID,与父文档建立关联
  • 通过请求URI中的routing指定分区,与父文档设置相同的routing,以便与父文档设置相同的分区

B.插入数据:

  • 插入第1条参与活动的数据,并且参与的是第1个活动
  1. PUT activity/_doc/4?routing=1
  2. {
  3. "activity_id":1,
  4. "user_id":1001,
  5. "status":1,
  6. "join_time":1556263399,
  7. "activity_member":{
  8. "name":"member",
  9. "parent":1
  10. }
  11. }
  • 插入第2条参与活动的数据,并且参与的是第1个活动
  1. PUT activity/_doc/5?routing=1
  2. {
  3. "activity_id":1,
  4. "user_id":1002,
  5. "status":0,
  6. "join_time":1556263399,
  7. "activity_member":{
  8. "name":"member",
  9. "parent":1
  10. }
  11. }
  • 插入第3条参与活动的数据,并且参与的是第1个活动
  1. PUT activity/_doc/6?routing=1
  2. {
  3. "activity_id":1,
  4. "user_id":1003,
  5. "status":1,
  6. "join_time":1556263399,
  7. "activity_member":{
  8. "name":"member",
  9. "parent":1
  10. }
  11. }
  • 插入第4条参与活动的数据,并且参与的是第2个活动
  1. PUT activity/_doc/7?routing=1
  2. {
  3. "activity_id":2,
  4. "user_id":1001,
  5. "status":1,
  6. "join_time":1556263399,
  7. "activity_member":{
  8. "name":"member",
  9. "parent":2
  10. }
  11. }
4.查询父子文档
(1)通过子文档作为条件来查询文档

一般通过has_child参数来查询,其参数如下:

  • type: 指定子文档的名称
  • query : 子文档的查询条件
  • inner_hists : 内层数据的过滤条件
    • from
    • size
    • sort
    • _source
    • 其他外层文档可使用的查询参数

A. 查询所有进行中的(即active为1而且status为1的)活动:

  1. GET activity/_doc/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. {
  7. "term": {
  8. "status":1
  9. }
  10. },
  11. {
  12. "term":{
  13. "active":1
  14. }
  15. }
  16. ]
  17. }
  18. }
  19. }

查询结果:

  1. {
  2. "took" : 0,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 5,
  6. "successful" : 5,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : 3,
  12. "max_score" : 2.0,
  13. "hits" : [
  14. {
  15. "_index" : "activity",
  16. "_type" : "_doc",
  17. "_id" : "1",
  18. "_score" : 2.0,
  19. "_routing" : "1",
  20. "_source" : {
  21. "activity_id" : 1,
  22. "title" : "劳动节特惠活动",
  23. "type" : 1,
  24. "status" : 1,
  25. "active" : 1,
  26. "begin_time" : 1556262929,
  27. "end_time" : 1556985599,
  28. "create_time" : 1556260929,
  29. "activity_member" : {
  30. "name" : "activity"
  31. }
  32. }
  33. },
  34. {
  35. "_index" : "activity",
  36. "_type" : "_doc",
  37. "_id" : "2",
  38. "_score" : 2.0,
  39. "_routing" : "1",
  40. "_source" : {
  41. "activity_id" : 2,
  42. "title" : "青年节特惠活动",
  43. "type" : 1,
  44. "status" : 1,
  45. "active" : 1,
  46. "begin_time" : 1556899200,
  47. "end_time" : 1556985599,
  48. "create_time" : 1556263929,
  49. "activity_member" : {
  50. "name" : "activity"
  51. }
  52. }
  53. },
  54. {
  55. "_index" : "activity",
  56. "_type" : "_doc",
  57. "_id" : "3",
  58. "_score" : 2.0,
  59. "_routing" : "1",
  60. "_source" : {
  61. "activity_id" : 3,
  62. "title" : "儿童节特惠活动",
  63. "type" : 1,
  64. "status" : 1,
  65. "active" : 1,
  66. "begin_time" : 1559318400,
  67. "end_time" : 1559664000,
  68. "create_time" : 1556263929,
  69. "activity_member" : {
  70. "name" : "activity"
  71. }
  72. }
  73. }
  74. ]
  75. }
  76. }

B.查询所有进行中的活动并计算参与人数

  1. GET activity/_doc/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. {
  7. "term": {
  8. "status": 1
  9. }
  10. },
  11. {
  12. "term": {
  13. "active": 1
  14. }
  15. }
  16. ]
  17. }
  18. },
  19. "aggs": {
  20. "members": {
  21. "children": {
  22. "type": "member"
  23. },
  24. "aggs": {
  25. "avaiable": {
  26. "filter": {
  27. "term": {
  28. "status": 1
  29. }
  30. },
  31. "aggs": {
  32. "count": {
  33. "terms": {
  34. "field": "activity_id"
  35. }
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }
  42. }

查询结果:

  1. {
  2. "took" : 1,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 5,
  6. "successful" : 5,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : 3,
  12. "max_score" : 2.0,
  13. "hits" : [
  14. {
  15. "_index" : "activity",
  16. "_type" : "_doc",
  17. "_id" : "1",
  18. "_score" : 2.0,
  19. "_routing" : "1",
  20. "_source" : {
  21. "activity_id" : 1,
  22. "title" : "劳动节特惠活动",
  23. "type" : 1,
  24. "status" : 1,
  25. "active" : 1,
  26. "begin_time" : 1556262929,
  27. "end_time" : 1556985599,
  28. "create_time" : 1556260929,
  29. "activity_member" : {
  30. "name" : "activity"
  31. }
  32. }
  33. },
  34. {
  35. "_index" : "activity",
  36. "_type" : "_doc",
  37. "_id" : "2",
  38. "_score" : 2.0,
  39. "_routing" : "1",
  40. "_source" : {
  41. "activity_id" : 2,
  42. "title" : "青年节特惠活动",
  43. "type" : 1,
  44. "status" : 1,
  45. "active" : 1,
  46. "begin_time" : 1556899200,
  47. "end_time" : 1556985599,
  48. "create_time" : 1556263929,
  49. "activity_member" : {
  50. "name" : "activity"
  51. }
  52. }
  53. },
  54. {
  55. "_index" : "activity",
  56. "_type" : "_doc",
  57. "_id" : "3",
  58. "_score" : 2.0,
  59. "_routing" : "1",
  60. "_source" : {
  61. "activity_id" : 3,
  62. "title" : "儿童节特惠活动",
  63. "type" : 1,
  64. "status" : 1,
  65. "active" : 1,
  66. "begin_time" : 1559318400,
  67. "end_time" : 1559664000,
  68. "create_time" : 1556263929,
  69. "activity_member" : {
  70. "name" : "activity"
  71. }
  72. }
  73. }
  74. ]
  75. },
  76. "aggregations" : {
  77. "members" : {
  78. "doc_count" : 4,
  79. "avaiable" : {
  80. "doc_count" : 3,
  81. "count" : {
  82. "doc_count_error_upper_bound" : 0,
  83. "sum_other_doc_count" : 0,
  84. "buckets" : [
  85. {
  86. "key" : 1,
  87. "doc_count" : 2
  88. },
  89. {
  90. "key" : 2,
  91. "doc_count" : 1
  92. }
  93. ]
  94. }
  95. }
  96. }
  97. }
  98. }

C.查询有用户参加的活动列表

  1. GET activity/_doc/_search
  2. {
  3. "query":{
  4. "has_child":{
  5. "type":"member",
  6. "query":{
  7. "term":{
  8. "status":1
  9. }
  10. }
  11. }
  12. }
  13. }

查询结果:

  1. {
  2. "took" : 18,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 5,
  6. "successful" : 5,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : 2,
  12. "max_score" : 1.0,
  13. "hits" : [
  14. {
  15. "_index" : "activity",
  16. "_type" : "_doc",
  17. "_id" : "1",
  18. "_score" : 1.0,
  19. "_routing" : "1",
  20. "_source" : {
  21. "activity_id" : 1,
  22. "title" : "劳动节特惠活动",
  23. "type" : 1,
  24. "status" : 1,
  25. "active" : 1,
  26. "begin_time" : 1556262929,
  27. "end_time" : 1556985599,
  28. "create_time" : 1556260929,
  29. "activity_member" : {
  30. "name" : "activity"
  31. }
  32. }
  33. },
  34. {
  35. "_index" : "activity",
  36. "_type" : "_doc",
  37. "_id" : "2",
  38. "_score" : 1.0,
  39. "_routing" : "1",
  40. "_source" : {
  41. "activity_id" : 2,
  42. "title" : "青年节特惠活动",
  43. "type" : 1,
  44. "status" : 1,
  45. "active" : 1,
  46. "begin_time" : 1556899200,
  47. "end_time" : 1556985599,
  48. "create_time" : 1556263929,
  49. "activity_member" : {
  50. "name" : "activity"
  51. }
  52. }
  53. }
  54. ]
  55. }
  56. }
(2)通过父文档作为条件查询
  • has_parent:
    • parent_type : 指定父文档的名称
    • query : 指定查询父文档的条件
    • inner_hits : 内层结构过滤

某个用户参加的活动列表:

  1. GET activity/_doc/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. {
  7. "term": {
  8. "status": 1
  9. }
  10. },
  11. {
  12. "term": {
  13. "user_id": 1001
  14. }
  15. },
  16. {
  17. "has_parent": {
  18. "parent_type": "activity",
  19. "query": {
  20. "term": {
  21. "status": 1
  22. }
  23. },
  24. "inner_hits":{}
  25. }
  26. }
  27. ]
  28. }
  29. },
  30. "sort":[
  31. {
  32. "join_time":"desc"
  33. }
  34. ]
  35. }

查询结果:

  1. {
  2. "took" : 1,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 5,
  6. "successful" : 5,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : 2,
  12. "max_score" : null,
  13. "hits" : [
  14. {
  15. "_index" : "activity",
  16. "_type" : "_doc",
  17. "_id" : "4",
  18. "_score" : null,
  19. "_routing" : "1",
  20. "_source" : {
  21. "activity_id" : 1,
  22. "user_id" : 1001,
  23. "status" : 1,
  24. "join_time" : 1556263399,
  25. "activity_member" : {
  26. "name" : "member",
  27. "parent" : 1
  28. }
  29. },
  30. "sort" : [
  31. 1556263399
  32. ],
  33. "inner_hits" : {
  34. "activity" : {
  35. "hits" : {
  36. "total" : 1,
  37. "max_score" : 1.0,
  38. "hits" : [
  39. {
  40. "_index" : "activity",
  41. "_type" : "_doc",
  42. "_id" : "1",
  43. "_score" : 1.0,
  44. "_routing" : "1",
  45. "_source" : {
  46. "activity_id" : 1,
  47. "title" : "劳动节特惠活动",
  48. "type" : 1,
  49. "status" : 1,
  50. "active" : 1,
  51. "begin_time" : 1556262929,
  52. "end_time" : 1556985599,
  53. "create_time" : 1556260929,
  54. "activity_member" : {
  55. "name" : "activity"
  56. }
  57. }
  58. }
  59. ]
  60. }
  61. }
  62. }
  63. },
  64. {
  65. "_index" : "activity",
  66. "_type" : "_doc",
  67. "_id" : "7",
  68. "_score" : null,
  69. "_routing" : "1",
  70. "_source" : {
  71. "activity_id" : 2,
  72. "user_id" : 1001,
  73. "status" : 1,
  74. "join_time" : 1556263399,
  75. "activity_member" : {
  76. "name" : "member",
  77. "parent" : 2
  78. }
  79. },
  80. "sort" : [
  81. 1556263399
  82. ],
  83. "inner_hits" : {
  84. "activity" : {
  85. "hits" : {
  86. "total" : 1,
  87. "max_score" : 1.0,
  88. "hits" : [
  89. {
  90. "_index" : "activity",
  91. "_type" : "_doc",
  92. "_id" : "2",
  93. "_score" : 1.0,
  94. "_routing" : "1",
  95. "_source" : {
  96. "activity_id" : 2,
  97. "title" : "青年节特惠活动",
  98. "type" : 1,
  99. "status" : 1,
  100. "active" : 1,
  101. "begin_time" : 1556899200,
  102. "end_time" : 1556985599,
  103. "create_time" : 1556263929,
  104. "activity_member" : {
  105. "name" : "activity"
  106. }
  107. }
  108. }
  109. ]
  110. }
  111. }
  112. }
  113. }
  114. ]
  115. }
  116. }