【问题标题】:N1QL nested json, query on field inside object inside arrayN1QL嵌套json,查询数组内对象内的字段
【发布时间】:2016-10-11 13:41:34
【问题描述】:

我的 Couchbase 集群中有如下所示的 json 文档

 {
    "giata_properties": {
      "propertyCodes": {
        "provider": [
          {
            "code": [
              {
                "value": [
                  {
                    "name": "Country Code",
                    "value": "EG"
                  },
                  {
                    "name": "City Code",
                    "value": "HRG"
                  },
                  {
                    "name": "Hotel Code",
                    "value": "91U"
                  }
                ]
              }
            ],
            "providerCode": "gta",
            "providerType": "gds"
          },
          {
            "code": [
              {
                "value": [
                  {
                    "value": "071801"
                  }
                ]
              },
              {
                "value": [
                  {
                    "value": "766344"
                  }
                ]
              }
            ],
            "providerCode": "restel",
            "providerType": "gds"
          },
          {
            "code": [
              {
                "value": [
                  {
                    "value": "HRG03Z"
                  }
                ]
              },
              {
                "value": [
                  {
                    "value": "HRG04Z"
                  }
                ]
              }
            ],
            "providerCode": "5VF",
            "providerType": "tourOperator"
          }
        ]
      }
    }
  }

我正在尝试创建一个查询,该查询根据giata_properties.propertyCodes.provider.code.value.value 的值和特定的providerType 获取单个文档。

例如,我的输入是071801restel,我想要一个查询来获取我上面粘贴的文档(因为它包含这些值)。

我对 N1QL 很陌生,所以到目前为止我尝试的是(没有 providerType 输入)

SELECT * FROM giata_properties AS gp 
WHERE ANY `field` IN `gp.propertyCodes.provider.code.value` SATISFIES `field.value` = '071801' END;

这会返回一个空的结果集。我可能做错了所有这些。

edit1:

根据 geraldss 的回答,我能够通过 2 个不同的查询实现我的目标

第一个(更一般)~2m50.9903732s

SELECT * FROM giata_properties AS gp WHERE ANY v WITHIN gp SATISFIES v.`value` = '071801' END;

第二(更具体)~2m31.3660388s

SELECT * FROM giata_properties AS gp WHERE ANY v WITHIN gp.propertyCodes.provider[*].code SATISFIES v.`value` = '071801' END;

存储桶有大约 550K 文档。目前没有索引,只有主索引。

问题第 2 部分

当我执行上述任一查询时,我会很快将结果流式传输到我的 shell,然后我会花费剩余的查询时间等待引擎完成对所有文档的迭代。我确信我只会从未来的查询中得到 1 个结果,所以我认为我可以使用 LIMIT 1 以便引擎停止搜索第一个结果,我尝试了类似

SELECT * FROM giata_properties AS gp WHERE ANY v WITHIN gp SATISFIES v.`value` = '071801' END LIMIT 1;

但这并没有什么不同,我将一个文档写入我的 shell,然后继续等待,直到查询完全完成。如何正确配置?

edit2:

我已经升级到最新的企业4.5.1-2844,我只有在giata_properties 存储桶上创建的主索引,当我执行查询以及 LIMIT 1 关键字时,它仍然需要相同的时间,它没有快点停下来。

我也尝试过创建您建议的数组索引,但查询没有使用索引,并且一直坚持使用 #primary 索引(即使我使用 USE INDEX 子句)。

我尝试从您建议的索引中删除 SELF,构建时间更长,现在查询可以使用这个新索引,但老实说我不确定我在这里做什么。

所以 3 个问题:

1) 为什么使用主索引的 LIMIT 1 不会使查询在第一个结果处停止?

2) 你建议的有和没有 SELF 的索引有什么区别?我试图寻找 SELF 关键字文档,但我找不到任何东西。

这是两个索引在 Web ui 中的外观

索引 1(您原来的建议) - 不工作

CREATE INDEX `gp_idx1` ON `giata_properties`((distinct (array (`v`.`value`) for `v` within (array_star((((self.`giata_properties`).`propertyCodes`).`provider`)).`code`) end)))

索引 2(没有SELF

CREATE INDEX `gp_idx2` ON `giata_properties`((distinct (array (`v`.`value`) for `v` within (array_star(((self.`propertyCodes`).`provider`)).`code`) end)))

3) 特定giata_properties.propertyCodes.provider.code.value.value 和特定providerCode 的查询是什么?我设法分别做这两件事,但我没有成功合并它们。

感谢您的帮助,亲爱的

【问题讨论】:

  • 您的文档是否真的包含 giata_properties 字段?
  • @geraldss 不,抱歉。这是我在giata_properties 存储桶pastebin.com/mbXFMPkA 中拥有的文档的真实示例@
  • 好的,这可以解释解决方案中的任何不匹配问题,@pretty。
  • @geraldss 我的错。你能回答我上面的3个问题吗?我真的需要一个查询(和一个索引)来获取基于valueproviderCode 的文档。
  • 你能发布一个新的干净问题吗?我会回答的。

标签: couchbase n1ql


【解决方案1】:

这是一个没有providerType 的查询。

EXPLAIN SELECT *
FROM giata_properties AS gp
WHERE ANY v WITHIN gp.giata_properties.propertyCodes.provider[*].code SATISFIES v.`value` = '071801' END;

您也可以在 Couchbase 4.5.0 及更高版本中对此进行索引。

CREATE INDEX idx1 ON giata_properties( DISTINCT ARRAY v.`value` FOR v WITHIN SELF.giata_properties.propertyCodes.provider[*].code END );

编辑以回答问题编辑

性能已在 4.5.x 中得到解决。您应该在 Couchbase 4.5.1 上尝试以下操作并在此处发布执行时间。

  • 在 4.5.1 上测试。
  • 创建索引。
  • 使用限制。在 4.5.1 中,限制被下推到索引。

【讨论】:

  • 感谢 geraldss,这很有效,而且您不必在 N1QL 中指定您所指的 value 字段真是太好了(顺便说一句,这会影响性能吗?)。但是你能澄清一下我如何在 N1QL 中指定它应该查看哪个字段吗?例如,我希望我的查询只查看gp.propertyCodes.provider.code.value.value,而不是名称为value 的所有字段。我也可以在社区版 4.1.0 上做你建议的索引吗?
  • 数组索引仅在 4.5 及更高版本中可用。我将把答案编辑得更具体一点。
  • 我想知道这个更具体的查询是否比早期更一般的查询有更好的性能,我很快就会做基准测试。非常感谢。
  • 发布了一些基准和对我的问题的更新,非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多