首页 > 编程知识 正文

upsert和insert的区别,mongotemplate.upsert

时间:2023-05-05 00:22:55 阅读:271617 作者:3749

文章目录 1. Update API 简介2. 使用脚本更新3. 非script的部分文档更新4. 检测空操作更新 noop updates5. Upserts1. scripted_upsert2. doc_as_upsert 6. 参数

1. Update API 简介

update API 允许基于script脚本来更新doc。对应的操作从index当中获取doc,然后run script, 然后再将修改后的doc indexing到原来的index。在这个过程中使用了version控制,以便于确保在获取和重新索引没有更新发生。

注意,此操作仍然意味着对文件做重新的全索引。它只是删除了一些网络往返,减少了在索引和获取时候版本冲突的几率。 _source需要启用此功能工作。

例如:一个简单的索引文件:

PUT test/_doc/1{ "counter" : 1, "tags" : ["red"]} 2. 使用脚本更新

现在,我们可以执行一个脚本,用做计数器:

POST test/_update/1{ "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } }}

我们可以添加标签来进行标记(注意,如果标签存在,仍然会添加,因为是一个列表)

POST test/_update/1{ "script" : { "source": "ctx._source.tags.add(params.tag)", "lang": "painless", "params" : { "tag" : "blue" } }}

我们可以从标签列表中删除标签。请注意,删除标签的painless的remove函数将要删除的元素的数组索引作为其参数,因此需要更多的逻辑来定位它,同时避免运行时错误。请注意,如果该标签在列表中出现多次,则只会删除一次该标签

POST test/_update/1{ "script" : { "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }", "lang": "painless", "params" : { "tag" : "blue" } }}

除了_source,下列变量通过 ctx map 都是可用的:_index,_type,_id,_version,_routing,_parent,和_now(当前的时间戳)。

我们也可以将新字段添加到文档:

POST test/_update/1{ "script" : "ctx._source.new_field = 'value_of_new_field'"}

或者从文件中删除字段:

POST test/_update/1{ "script" : "ctx._source.remove('new_field')"}

而且,我们甚至可以改变已执行的操作。这个例子就是如果 tags包含 green删除文档,否则就什么也不做(noop):

POST test/_update/1{ "script" : { "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }", "lang": "painless", "params" : { "tag" : "green" } }} 3. 非script的部分文档更新

更新 API 还支持部分文档的更新,将合并到现有的文件(简单的递归合并,内合并,更换核心“键/值”对和数组)。例如:

POST test/_update/1{ "doc" : { "name" : "new_name" }}

如果同时 doc 和 script 被指定,那么 doc将被忽略。推荐的做法是使用script来update部分文档。

4. 检测空操作更新 noop updates

默认情况下回进行无更新检测,当要merged的doc片段和原有的doc中的字段是一致的话,不会有更新操作产生,在response当中会有一个"result": "noop"标识
比如下面的操作

POST test/_update/1{ "doc" : { "name" : "new_name" }}

如果 name字段在这个精明的小刺猬之前就是 new_name,那么整个更新请求会被忽略。如果请求被忽略了,在 result响应中的返回 noop。

{ "_shards": { "total": 0, "successful": 0, "failed": 0 }, "_index": "test", "_type": "_doc", "_id": "1", "_version": 7, "result": "noop"}

你可以通过设置 “detect_noop” 禁用此行为:

POST test/_update/1{ "doc" : { "name" : "new_name" }, "detect_noop": false} 5. Upserts

如果该文件存在,那么 script将执行。如果该文件不存在,则upsert内容将被插入作为一个新的文档。

POST test/_update/1{ "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } }, "upsert" : { "counter" : 1 }}

上面的请求如果_id为1的doc不存在的话,会插入一个文档,source中只有一个字段,是counter:1

1. scripted_upsert

如果你想你的脚本无论该文件存在与否都要运行-即脚本处理初始化文件而不是 upsert -然后设置 scripted_upsert为 true:

POST sessions/_update/dh3sgudg8gsrgl{ "scripted_upsert":true, "script" : { "id": "my_web_session_summariser", "params" : { "pageViewEvent" : { "url":"foo.com/bar", "response":404, "time":"2014-01-01 12:32" } } }, "upsert" : {}} 2. doc_as_upsert

doc 添加一个 upsert文档,设置 doc_as_upsert为 true ,将使用 doc 内容作为 upsert 值:

POST test/_update/1{ "doc" : { "name" : "new_name" }, "doc_as_upsert" : true} 6. 参数

更新操作支持以下查询字符串参数:

retry_on_conflict 在更新的 get 和 index 时,它可能是另一种方法可能已经更新了相同的文件。默认情况下,更新将失败,版本冲突异常。该 retry_on_conflict 参数控制抛出异常之前重试更新的次数。
routing 用于追踪更新请求正确的分片,如果文档更新不存在把其设置为更新插入请求。不能用于更新现有文档的路径。
timeout 超时等待一个分片变得可用。
wait_for_active_shards 在更新操作时,复制分片需要处在活跃状态的数目。
refresh 控制被该请求所做更改时进行的搜索。
_source 允许控制是否以及更新源如何在响应中返回。默认情况下不返回更新的源。见 source_filtering 详情。
version 更新 API 使用 Elasticsearch 的internal version。您可以使用 version 参数指定版本,如果文件匹配那么指定的文件需要更新。
if_seq_no and if_primary_term: 可以用来做并发控制,可以控制仅在文档的最后一次因为修改分配的_seq_no和_primary_term 参数和请求时传进来的if_seq_no和if_primary_term参数相等的情况下才能执行操作。如果检测到不匹配,则该操作将导致VersionConflictException和状态码409。

注意:
update api只支持internal version,External (version types external and external_gte) 是不支持的。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。