Planejador de consultas v2 - Amazon DocumentDB

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Planejador de consultas v2

O novo planejador de consultas do Amazon DocumentDB (planejador versão 2.0) apresenta recursos avançados de otimização de consultas e performance aprimorada. A versão 2.0 do planejador para Amazon DocumentDB 5.0 oferece uma melhoria de performance de até 10 vezes em relação à versão anterior no uso dos operadores find e update com índices. As melhorias de performance vêm principalmente do uso de planos de indexação mais otimizados e da ativação do suporte à varredura de índice para operadores como operadores de negação ($neq, $nin) e $elementMatch aninhados. As consultas da versão 2.0 do planejador são executadas mais rapidamente por meio de melhores técnicas de estimativa de custos, algoritmos otimizados e estabilidade aprimorada. A versão 2.0 do Planner também suporta o filtro APIs de cache do plano, o que melhora a estabilidade do planejador. Com esse recurso, o Amazon DocumentDB 5.0 agora oferece a capacidade de selecionar entre as diferentes versões do planejador de consultas.

Pré-requisitos

Os pré-requisitos a seguir se aplicam à versão 2.0 do planejador:

  • A versão 2.0 do planejador está disponível em todas as regiões em que a versão 5.0 do mecanismo está disponível.

  • Para optar por usar a versão 2.0 como planejador de consultas padrão, seu cluster precisa estar na versão de patch do mecanismo 3.0.15902 ou posterior do Amazon DocumentDB versão 5.0. Para ver as etapas de atualização para o patch da versão mais recente do mecanismo, consulte Executar uma atualização de patch para a versão do mecanismo de um cluster.

  • Para definir o planejador versão 2.0 como o planejador de consultas padrão, você precisa de permissões do IAM para atualizar os grupos de parâmetros do cluster.

Seleção do planejador versão 2.0 como o planejador de consultas padrão

Use as etapas a seguir para selecionar a versão 2.0 como o planejador de consultas padrão no console ou na CLI:

  • Siga as etapas em Modificando os parâmetros de cluster do Amazon DocumentDB para modificar o grupo de parâmetros do seu cluster.

  • Para o parâmetro intitulado 'plannerVersion', altere o valor para 2.0 indicando a versão 2.0 do planejador.

  • Selecione Aplicar imediatamente (selecionar Aplicar na reinicialização tornará a seleção ineficaz até a próxima reinicialização do cluster).

Práticas recomendadas

Para obter os resultados esperados, use as práticas recomendadas a seguir ao aplicar a versão 2.0 do planejador:

  • Em um cluster global, selecione o mesmo valor de plannerVersion (1.0 ou 2.0) nos grupos de parâmetros do cluster para ambas as regiões. Observe que a seleção de diferentes versões do planejador nas regiões primária e secundária pode causar comportamento e performance de consultas inconsistentes.

  • A atualização para a versão 2.0 do planejador durante uma janela de manutenção programada ou durante períodos de tráfego reduzido será a menos perturbadora, pois pode haver um aumento nas taxas de erro se a versão do planejador for alterada quando as workloads estiverem em execução ativa.

  • A versão 2.0 do planejador funciona de forma mais otimizada com a versão 5.0 do shell do MongoDB.

Limitações

As limitações a seguir se aplicam ao planejador versão 2.0:

  • Não há suporte para a versão 2.0 do planejador em clusters elásticos, que retornarão à versão 1.0 do planejador.

  • Não há suporte para a versão 2.0 do planejador para agregação e comandos distintos, que retornarão à versão 1.0 do planejador.

  • Não há suporte para consultas que contenham regex, pesquisa de texto, geoespacial, jsonschema ou $expr em filtros com o filtro de cache de plano na versão 2.0 do planejador.

Aprimoramentos aos operadores Find e Update

A versão 2.0 do Planner otimiza as operações fundamentais, incluindo os comandos find, update, delete e find-and-modify. As seções com guias a seguir mostram recursos aprimorados para índices, bem como as melhorias na performance da consulta com a versão 2.0 do planejador:

Enhanced index support
  • A versão 2.0 do planejador adiciona suporte de índices para operadores de negação, incluindo $nin, $ne, $not {eq} e $not {in}, bem como para $type e $elemMatch

    Sample Document: { "x": 10, "y": [1, 2, 3] } db.foo.createIndex({ "x": 1, "y": 1 }) db.foo.find({ "x": {$nin: [20, 30] }}) db.foo.find({"x":{ $type: "string" }}) db.foo.createIndex({"x.y": 1}) db.foo.find({"x":{$elemMatch:{"y":{$elemMatch:{"$gt": 3 }}}}})
  • A versão 2.0 do planejador utiliza índices esparsos ou parciais mesmo quando $exists não está presente na expressão de consulta.

    Sample Document: {"name": "Bob", "email": "example@fake.com" } Using Planner Version 1.0, you can specify the command as shown below: db.foo.find({email: "example@fake.com", email: {$exists: true}}) Using Planner Version 2.0, you can specify command without $exists: db.foo.find({ email: "example@fake.com" })
  • A versão 2.0 do planejador utilizará índices parciais mesmo quando a condição de consulta não corresponder exatamente à expressão de filtro do índice parcial.

    Sample Document: {"name": "Bob", "age": 34} db.foo.createIndex({"age":1},{partialFilterExpression:{"age":{$lt:50}}}) With Planner Version 1.0, index is used only when the query condition meets the partial index filter criterion: db.foo.find({"age":{$lt:50}}) With Planner Version 2.0, index is used even when the query condition doesn’t meet the index criterion: db.foo.find({"age":{$lt:30}})
  • A versão 2.0 do planejador utiliza varredura parcial de índices com consultas $elemMatch.

    Sample Document: {"name": "Bob", "age": [34,35,36]} db.foo.createIndex({"age":1},{partialFilterExpression:{"age":{$lt:50,$gt:20}}}) db.foo.find({age:{$elemMatch:{$lt:50,$gt:20}}})
  • A versão 2.0 do planejador inclui suporte à varredura de índices para $regex, sem a necessidade de fornecer $hint no código da sua aplicação. $regex oferece suporte a índices somente em pesquisas de prefixo.

    Sample Document: { "x": [1, 2, 3], "y": "apple" } db.foo.createIndex({ "x": 1, "y": 1 }) db.foo.find({"y":{ $regex: "^a" }})
  • A versão 2.0 do planejador melhora a performance das consultas envolvendo índices de várias chaves, com condições de igualdade no campo de várias chaves.

    Sample Document: {"x": [1, 2, 3], "y": 5} db.foo.createIndex({"x": 1, "y":1}) db.foo.find({"x": 2, "y": {$gt: 1}}).limit(1)
  • A versão 2.0 do planejador melhora a performance das consultas que envolvem vários filtros, especialmente em coleções com documentos maiores que 8 KB.

    Sample Document: {"x": 2, "y": 4, "z": 9, "t": 99} db.foo.find({$and: [{"x": {$gt : 1}, "y": {$gt : 3}, "z": {$lt : 10}, "t":{$lt : 100}}]})
  • A versão 2.0 do planejador melhora a performance das consultas ao usar o operador $in com um índice composto, eliminando o estágio de classificação.

    Sample Document: {"x": 2, "y": 4, "z": 9, "t": 99} db.foo.createIndex({"x":1, "y":1}) db.foo.find({"x":2, "y":$in:[1,2,3,4]}).sort({x:1,y:1})

    Também melhora o desempenho das consultas que usam índices de várias chaves com elementos. $in

    Sample Document: {"x": [1, 2, 3]} db.foo.createIndex({"x": 1}) db.foo.find("x":{$in:[>100 elements]})
Query performance improvements
  • A versão 2.0 do planejador melhora a performance das consultas que envolvem vários filtros, especialmente em coleções com documentos maiores que 8 KB.

    Sample Document: {"x": 2, "y": 4, "z": 9, "t": 99} db.foo.find({$and: [{"x": {$gt : 1}, "y": {$gt : 3}, "z": {$lt : 10}, "t":{$lt : 100}}]})
  • A versão 2.0 do planejador melhora a performance das consultas ao usar o operador $in com um índice composto, eliminando o estágio de classificação.

    Sample Document: {"x": 2, "y": 4, "z": 9, "t": 99} db.foo.createIndex({"x":1, "y":1}) db.foo.find({"x":2, "y":$in:[1,2,3,4]}).sort({x:1,y:1})

    Ela também melhora a performance das consultas que usam índices de várias chaves com elementos $in.

    Sample Document: {"x": [1, 2, 3]} db.foo.createIndex({"x": 1}) db.foo.find("x":{$in:[>100 elements]})

API de filtro de cache de plano

nota

Não há suporte para o índice de texto com o filtro de cache de plano.

  • A versão 2.0 do planejador acrescenta suporte ao recurso de filtro de índices que permite especificar uma lista de índices que uma forma de consulta específica pode usar. Esse recurso pode ser acessado por meio da API e pode ser controlado do lado do servidor. Se você enfrentar uma regressão de consulta, esse recurso oferece uma opção mais rápida e flexível para mitigar o problema sem precisar modificar o código da aplicação.

    db.runCommand({ planCacheSetFilter: <collection>, query: <query>, sort: <sort>, // optional, indexes: [ <index1>, <index2>, ...], comment: <any> // optional})

    Para listar todos os filtros da coleção, use o comando a seguir:

    db.runCommand( { planCacheListFilters: <collection> } )

    Esse comando mostra todos os filtros de índice na coleção. Resultado do exemplo:

    { "filters" : [ { "query" : {a: "@", b: "@"}, "sort" : {a: 1}, "indexes" : [ <index1>, ... ] }, ... ], "ok": 1 }
  • É possível usar dois novos campos da saída do comando explain para analisar a filtragem de índice da versão 2.0 do planejador: indexFilterSet e indexFilterApplied. indexFilterSet será definido como “verdadeiro” se houver um filtro de índice definido na coleção que corresponda ao formato da consulta. indexFilterApplied será definido como “verdadeiro” se, e somente se, a consulta tiver aplicado um filtro de índice e escolhido um plano usando um índice na lista de filtros.

    É possível limpar o filtro de índices com o comando a seguir:

    db.runCommand( { planCacheClearFilters: <collection>> query: <query pattern>, // optional sort: <sort specification>, // optional comment: <any>. //optional } )

    Para limpar todos os filtros na coleção “foo”, use o comando a seguir:

    db.runCommand({planCacheClearFilters: "foo"})

    Para limpar uma forma de consulta específica com qualquer classificação, é possível copiar e colar a forma de consulta da saída de planCacheListFilters:

    db.runCommand({planCacheClearFilters: "foo", query: {a: @}})

    Para limpar uma forma de consulta específica com um campo específico para classificar, é possível copiar e colar a forma de consulta da saída de planCacheListFilters:

    db.runCommand({planCacheClearFilters: "foo", query: {a: @},sort: {a: 1}})

Diferenças potenciais de comportamento entre o planejador versão 1.0, 2.0 e o MongoDB

Em alguns casos extremos, é possível que a versão 2.0 do planejador produza resultados ligeiramente diferentes dos resultados do MongoDB. Esta seção mostra alguns exemplos dessas possibilidades.

$(update) and $(projection)
  • Em alguns casos, os operadores $(update) e $(projection) do MongoDB podem se comportar de forma diferente da versão 1.0 do planejador do Amazon DocumentDB. Veja adiante alguns exemplos:

    db.students_list.insertMany( [ { _id: 5, student_ids: [ 100, 200 ], grades: [ 95, 100 ], grad_year: [ 2024, 2023 ] } ] )
    db.students_list.updateOne({ student_ids: 100, grades: 100, grad_year: 2024 }, { $set: { “grad_year.$”: 2025 } }
    • Planejador versão 1.0: campo de atualizações 2022

    • MongoDB: campo de atualizações 2022

    • Planejador versão 2.0: campo de atualizações 2021

  • db.col.insert({x:[1,2,3]}) db.col.update({$and:[{x:1},{x:3}]},{$set:{"x.$":500}})
    • Planejador versão 1.0: atualiza aleatoriamente o primeiro elemento correspondente

    • MongoDB: atualiza aleatoriamente o primeiro elemento correspondente

    • Planejador versão 2.0: não faz atualizações

  • db.col.insert({x:[1,2,3]}) db.col.find()
    • Planejador versão 1.0: seleciona aleatoriamente o elemento correspondente

    • MongoDB: seleciona aleatoriamente o elemento correspondente

    • Planejador versão 2.0: não faz uma seleção

  • db.col.insert({x:100}) db.col.update({x:100},{x:100})
    • Planejador versão 1.0: a contagem nModified é alterada

    • MongoDB: a contagem nModified é alterada

    • Planejador versão 2.0: a contagem nModified não é alterada quando atualizada com o mesmo valor.

  • Quando o operador $(update) é usado com $setOnInsert, o planejador versão 1.0 e o MongoDB geram um erro, mas a versão 2.0 do planejador não.

  • Renomear um campo inexistente para $field gera um erro na versão 2.0 do planejador, mas não produz atualizações na versão 1.0 do planejador e no MongoDB.

Index behavior
  • A versão 2.0 do planejador gera um erro quando $hint é aplicado com um índice inadequado, enquanto a versão 1.0 do planejador e o MongoDB não.

    // Insert db.col.insert({x:1}) db.col.insert({x:2}) db.col.insert({x:3}) // Create index on x with partialFilter Expression {x:{$gt:2}} db.col.createIndex({x:1},{partialFilterExpression:{x:{$gt:2}}}) // Mongodb allows hint on the following queries db.col.find({x:1}).hint("x_1") // result is no documents returned because {x:1} is not indexed by the partial index // Without $hint mongo should return {x:1}, thus the difference in result between COLSCAN and IXSCAN DocumentDB will error out when $hint is applied on such cases. db.col.find({x:1}).hint("x_1") Error: error: { "ok" : 0, "operationTime" : Timestamp(1746473021, 1), "code" : 2, "errmsg" : "Cannot use Hint for this Query. Index is multi key index , partial index or sparse index and query is not optimized to use this index." } rs0:PRIMARY> db.runCommand({"planCacheSetFilter": "col", "query": { location: {$nearSphere: {$geometry: {type: "Point", coordinates: [1, 1]}}}}, "indexes": ["name_1"]}) { "ok" : 0, "operationTime" : Timestamp(1750815778, 1), "code" : 303, "errmsg" : "Unsupported query shape for index filter $nearSphere" }
  • $near não pode usar $hint({“$natural”:1}) na versão 2.0 do planejador.

    // indexes present are index on x and geo index rs0:PRIMARY> db.usarestaurants.getIndexes() [ { "v" : 4, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.usarestaurants" }, { "v" : 4, "key" : { "location" : "2dsphere" }, "name" : "location_2dsphere", "ns" : "test.usarestaurants", "2dsphereIndexVersion" : 1 } ] // Planner Version 2.0 will throw an error when $hint is applied with index "x_1" rs0:PRIMARY> db.usarestaurants.find({ "location":{ "$nearSphere":{ "$geometry":{ "type":"Point", "coordinates":[ -122.3516, 47.6156 ] }, "$minDistance":1, "$maxDistance":2000 } } }, { "name":1 }).hint({"$natural": 1}) Error: error: { "ok" : 0, "operationTime" : Timestamp(1746475524, 1), "code" : 291, "errmsg" : "unable to find index for $geoNear query" } // Planner Version 1.0 and MongoDB will not throw an error db.usarestaurants.find({ "location":{ "$nearSphere":{ "$geometry":{ "type":"Point", "coordinates":[ -122.3516, 47.6156 ] }, "$minDistance":1, "$maxDistance":2000 } } }, { "name":1 }).hint({"$natural": 1}) { "_id" : ObjectId("681918e087dadfd99b7f0172"), "name" : "Noodle House" }
  • Enquanto o MongoDB oferece suporte a varreduras completas de índices regex, a versão 2.0 do planejador oferece suporte à varredura de índices regex somente em campos de prefixo.

    // index on x db.col.createIndex({x:1}) // index scan is used only for prefix regexes rs0:PRIMARY> db.col.find({x: /^x/}).explain() { "queryPlanner" : { "plannerVersion" : 2, "namespace" : "test.col", "winningPlan" : { "stage" : "IXSCAN", "indexName" : "x_1", "direction" : "forward", "indexCond" : { "$and" : [ { "x" : { "$regex" : /^x/ } } ] }, "filter" : { "x" : { "$regex" : /^x/ } } } }, "indexFilterSet" : false, "indexFilterApplied" : false, "ok" : 1, "operationTime" : Timestamp(1746474527, 1) } // COLSCAN is used for non-prefix regexes rs0:PRIMARY> db.col.find({x: /x$/}).explain() { "queryPlanner" : { "plannerVersion" : 2, "namespace" : "test.col", "winningPlan" : { "stage" : "COLLSCAN", "filter" : { "x" : { "$regex" : /x$/ } } } }, "indexFilterSet" : false, "indexFilterApplied" : false, "ok" : 1, "operationTime" : Timestamp(1746474575, 1)
  • Existem algumas diferenças inerentes ao uso de filtros de cache de plano com o planejador versão 2.0 em comparação com o MongoDB. Embora a versão 2.0 do planejador não ofereça suporte à especificação de “projeção” e “agrupamento” com filtros de cache de plano, o MongoDB oferece. No entanto, o filtro de índices do MongoDB está somente na memória e é perdido após a reinicialização. A versão 2.0 do planejador persiste os filtros de índice ao longo de reinicializações e aplicações de patches.

Others
  • O formato dos logs de auditoria do DML ao usar a versão 2.0 do planejador varia um pouco em relação à versão 1.0 do planejador.

    command - db.col.find({x:1}) ************** Audit logs generated ****************** // v1 format for dml audit logs {"atype":"authCheck","ts":1746473479983,"timestamp_utc":"2025-05-05 19:31:19.983","remote_ip":"127.0.0.1:47022","users":[{"user":"serviceadmin","db":"test"}],"param":{"command":"find","ns":"test.col","args":{"batchSize":101,"filter":{"x":1},"find":"col","limit":18446744073709551615,"lsid":{"id":{"$binary":"P6RCGz9ZS4iWBSSHWXW15A==","$type":"4"},"uid":{"$binary":"6Jo8PisnEi3dte03+pJFjdCyn/5cGQL8V2KqaoWsnk8=","$type":"0"}},"maxScan":18446744073709551615,"singleBatch":false,"skip":0,"startTransaction":false},"result":0}} // v2 formal for dml audit logs {"atype":"authCheck","ts":1746473583711,"timestamp_utc":"2025-05-05 19:33:03.711","remote_ip":"127.0.0.1:37754","users":[{"user":"serviceadmin","db":"test"}],"param":{"command":"find","ns":"test.col","args":{"find":"col","filter":{"x":1},"lsid":{"id":{"$binary":"nJ88TGCSSd+BeD2+ZtrhQg==","$type":"4"}},"$db":"test"},"result":0}}
  • A condição do índice como parte do plano de explicação:

    rs0:PRIMARY> db.col.createIndex({index1:1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1, "operationTime" : Timestamp(1761149251, 1) }

    A versão 2.0 do planejador explica a saída do plano exibindo a condição e o filtro do índice:

    rs0:PRIMARY> db.col.find({$and:[{price:{$eq:300}},{item:{$eq:"apples"}}]}).explain() { "queryPlanner" : { "plannerVersion" : 2, "namespace" : "test.col", "winningPlan" : { "stage" : "IXSCAN", "indexName" : "price_1", "direction" : "forward", "indexCond" : { "$and" : [ { "price" : { "$eq" : 300 } } ] }, "filter" : { "$and" : [ { "item" : { "$eq" : "apples" } } ] } } }, "indexFilterSet" : false, "indexFilterApplied" : false, "ok" : 1, "operationTime" : Timestamp(1761149497, 1) }

    A versão 1.0 do planejador explica a saída do plano:

    rs0:PRIMARY> db.col.find({$and:[{price:{$eq:300}},{item:{$eq:"apples"}}]}).explain() { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.col", "winningPlan" : { "stage" : "IXSCAN", "indexName" : "price_1", "direction" : "forward" } }, "ok" : 1, "operationTime" : Timestamp(1761149533, 1) }

A versão 2.0 do planejador preenche a lacuna de comportamento com o MongoDB

Há algumas áreas em que a versão 2.0 do planejador preenche as lacunas de comportamento do MongoDB:

  • A versão 2.0 do planejador permite a pesquisa de índice numérico em matrizes achatadas para $elemMatch:

    doc: {"x" : [ [ { "y" : 1 } ] ] } // Planner Version 2 and mongo > db.bar.find({"x.0": {$elemMatch: {y: 1}}}) { "_id" : ObjectId("68192947945e5846634c455a"), "x" : [ [ { "y" : 1 } ] ] } > db.bar.find({"x": {$elemMatch: {"0.y": 1}}}) { "_id" : ObjectId("68192947945e5846634c455a"), "x" : [ [ { "y" : 1 } ] ] } //Whereas Planner Version 1 wouldn't return any results. > db.bar.find({"x.0": {$elemMatch: {y: 1}}}) > db.bar.find({"x": {$elemMatch: {"0.y": 1}}})
  • Enquanto a versão 1.0 do planejador excluiu strings na projeção, o comportamento do planejador versão 2.0 se alinha ao MongoDB e as trata como valores literais

    // Planner V2/ MongoDB > db.col.find() { "_id" : ObjectId("681537738aa101903ed2fe05"), "x" : 1, "y" : 1 } > db.col.find({},{x:"string"}) { "_id" : ObjectId("681537738aa101903ed2fe05"), "x" : "string" } // Planner V1 treats strings as exclude in projection rs0:PRIMARY> db.col.find() { "_id" : ObjectId("68153744d42969f11d5cca72"), "x" : 1, "y" : 1 } rs0:PRIMARY> db.col.find({},{x:"string"}) { "_id" : ObjectId("68153744d42969f11d5cca72"), "y" : 1 }
  • A versão 2.0 do planejador, como o MongoDB, não permite projeção nos mesmos campos “x” e “x.a”:

    // Planner version 2/MongoDB will error out > db.col.find() { "_id" : ObjectId("68153da2012265816bc9ba23"), "x" : [ { "a" : 1 }, 3 ] } db.col.find({},{"x.a":1,"x":1}) // error // Planner Version 1 does not error out db.col.find() { "_id" : ObjectId("68153da2012265816bc9ba23"), "x" : [ { "a" : 1 }, 3 ] } db.col.find({},{"x.a":1,"x":1}) { "_id" : ObjectId("68153d60143af947c720d099"), "x" : [ { "a" : 1 }, 3 ] }
  • A versão 2.0 do planejador, como o MongoDB, permite a projeção em subdocumentos:

    // Planner Version2/MongoDB supports projections on subdocuments db.col.find() { "_id" : ObjectId("681542d8f35ace71f0a50004"), "x" : [ { "y" : 100 } ] } > db.col.find({},{"x":{"y":1}}) { "_id" : ObjectId("681542b7a22d548e4ac9ddea"), "x" : [ { "y" : 100 } ] } // Planner V1 throws error if projection is subdocument db.col.find() { "_id" : ObjectId("681542d8f35ace71f0a50004"), "x" : [ { "y" : 100 } ] } rs0:PRIMARY> db.col.find({},{"x":{"y":1}}) Error: error: { "ok" : 0, "operationTime" : Timestamp(1746223914, 1), "code" : 2, "errmsg" : "Unknown projection operator y" }
  • Na versão 2.0 do planejador, como o MongoDB, a projeção não oferece suporte a campos após o operador $:

    // Mongo and Planner Version 2 will error out db.col.find() { "_id" : ObjectId("68155fa812f843439b593f3f"), "x" : [ { "a" : 100 } ] } db.col.find({"x.a":100},{"x.$.a":1}) - // error // v1 will not error out db.col.find() { "_id" : ObjectId("68155fa812f843439b593f3f"), "x" : [ { "a" : 100 } ] } db.col.find({"x.a":100},{"x.$.a":1}) { "_id" : ObjectId("68155dee13b051d58239cd0a"), "x" : [ { "a" : 100 } ] }
  • A versão 2.0 do planejador, como o MongoDB, permite o uso de $hint:

    // v1 will error out on $hint if there are no filters db.col.find({}).hint("x_1") Error: error: { "ok" : 0, "operationTime" : Timestamp(1746466616, 1), "code" : 2, "errmsg" : "Cannot use Hint for this Query. Index is multi key index , partial index or sparse index and query is not optimized to use this index." } // Mongo and Planner Version 2 will allow $hint usage db.col.find({}).hint("x_1") { "_id" : ObjectId("6818f790d5ba9359d68169cf"), "x" : 1 }