前言:
眼前同学们对“mysql如何更新json嵌套的json数据”可能比较珍视,咱们都想要分析一些“mysql如何更新json嵌套的json数据”的相关知识。那么小编也在网上汇集了一些关于“mysql如何更新json嵌套的json数据””的相关内容,希望大家能喜欢,兄弟们快快来学习一下吧!项目需求
实际的软件项目开发过程中,因为业务上的需要,我们的数据库表与表之间的结构是一对多的关系,以订单表中的数据为例,在 mysql 数据库里面,他们的关系如下图:
如果是在mysql中查询,完全可以使用join语句来实现;而ES本身就是平铺的NoSQL,对于这种1:N的关联关系应该如何来实现呢
需求落地
比较常用的实践方案,有以下三种:
● 嵌套对象
● 嵌套文档
● 父子文档
嵌套对象
先看一下像什么样子
{ "order_id":{ "type":"keyword" }, "cancel_time":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss" }, "order_status":{ "type":"keyword" }, "completed_time":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss" }, "create_time":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss" }, "is_delete":{ "type":"keyword" }, "modify_time":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss" }, "order_user":{ "properties":{ "name":{ "type":"text", "analyzer":"ik_max_word" }, "tel":{ "type":"text", "analyzer":"ik_max_word" }, "user_id":{ "type":"keyword" } } }}
那嵌套对象在ES中如何筛选呢,请看示例
POST order_index/_search{ "query":{ "bool":{ "must":[ { "match":{ "order_user.name":"张三" } }, { "match":{ "order_user.tel":"18866668888" } } ] } }}
优点:查询时不涉及join,查询效率很高
缺点:由于json对象数组的处理是压扁了处理的,存储成扁平化的键值对列表,因此缺失关联关系。
嵌套文档
先看一下像什么样子
{ "address_list":{ "type":"nested", "properties":{ "city_id":{ "type":"keyword" }, "city_name":{ "type":"text", "analyzer":"ik_max_word" } "district_id":{ "type":"keyword" }, "district_name":{ "type":"text", "analyzer":"ik_max_word" }, "lat":{ "type":"geo_point" }, "lon":{ "type":"geo_point" }, "name":{ "type":"text", "analyzer":"ik_max_word" }, "province_id":{ "type":"keyword" }, "province_name":{ "type":"text", "analyzer":"ik_max_word" } } }
那嵌套对象在ES中如何筛选呢,请看示例
POST order_index/_search{ "query":{ "nested":{ "path":"address_list", "query":{ "bool":{ "must":[ { "match":{ "address_list.province_name":"上海市" } }, { "match":{ "address_list.district_name":"浦东新区" } } ] } } } }}优点:嵌套文档将实体关系嵌套组合在单文档内部(类似与json的一对多层级结构)缺点:nested子文档在ES内部是独立的文档,会造成数据量剧增,会影响查询性能。更新主文档的时候要全部更新,影响写的性能。不支持子文档从属多个主文档的场景。父子文档
先看一下像什么样子
{ "mappings":{ "_doc":{ "properties":{ "parent_id":{ "type":"keyword" }, "parent_join_child":{ "type":"join", "relations":{ "question":"answer" } } } } }}
parent_id是自定义的字段,parent_join_child是给我们的父子文档关系的名字,这个可以自定义,join表示这是一个父子文档关系,relations里面表示question是父,answer是子。
首先我们插入两个父文档。
PUT exam_index/_doc/1{ "parent_id":"1", "text":"这是一个问题1", "parent_join_child":{ "name":"question" }}PUT exam_index/_doc/2{ "parent_id":"2", "text":"这是一个问题2", "parent_join_child":{ "name":"question" }}
其中"name":"question"表示插入的是父文档。
然后插入两个子文档
PUT exam_index/_doc/3?routing=1{ "parent_id":"3", "text":"这是一个回答1,对应问题1", "parent_join_child":{ "name":"answer", "parent":"1" }}PUT exam_index/_doc/4?routing=1{ "parent_id":"4", "text":"这是一个回答2,对应问题1", "parent_join_child":{ "name":"answer", "parent":"1" }}
子文档要解释的东西比较多,首先从文档id我们可以判断子文档都是独立的文档(跟nested不一样)。其次routing关键字指明了路由的id是父文档1, 这个id和下面的parent关键字对应的id是一致的。需要强调的是,索引子文档的时候,routing是必须的,因为要确保子文档和父文档在同一个分片上。"name":"answer"关键字指明了这是一个子文档。
特点:父子文档类似关系型数据库中的关联关系,适用于写多的场景
现在exam_index索引中有四个独立的文档,我们来看父子文档在搜索的时候是什么姿势。
如果我们想通过子文档信息,查询父文档,可以通过如下方式实现:
POST exam_index/_search{ "query":{ "has_child":{ "type":"answer", "query":{ "match":{ "text":"回答" } } } }}
返回结果:
[ { "_index":"exam_index", "_type":"_doc", "_id":"1", "_score":1, "_source":{ "my_id":"1", "text":"这是一个问题1", "parent_join_child":{ "name":"question" } } }]
如果我们想通过父文档信息,查询子文档,可以通过如下方式实现:
POST exam_index/_search{ "query":{ "has_parent":{ "parent_type":"question", "query":{ "match":{ "text":"问题" } } } }}
返回结果:
[ { "_index":"crm_exam_index", "_type":"_doc", "_id":"3", "_score":1, "_routing":"1", "_source":{ "my_id":"3", "text":"这是一个回答1,对应问题1", "parent_join_child":{ "name":"answer", "parent":"1" } } }, { "_index":"crm_exam_index", "_type":"_doc", "_id":"4", "_score":1, "_routing":"1", "_source":{ "my_id":"4", "text":"这是一个回答2,对应问题1", "parent_join_child":{ "name":"answer", "parent":"1" } } }]
如果我们想通过父 ID 查询子文档,可以通过如下方式实现:
POST exam_index/_search{ "query":{ "parent_id":{ "type":"answer", "id":"1" } }}
返回结果和上面一样,区别在于parent_id搜索默认使用相关性算分,而has_parent默认情况下不使用算分。
使用父子文档的模式有一些需要特别关注的点:
● 每一个索引只能定义一个join field
● 父子文档必须在同一个分片上,意味着查询,更新操作都需要加上routing
● 可以向一个已经存在的join field上新增关系
● 父子文档,适合那种数据结构基本一致的场景,如果两个表结构完全不一致,不建议使用这种结构
● 父子文档也有缺点,查询速度是这三个方案里面最慢的一个