在 ArangoDB 中查询嵌套数组

Query nested arrays in ArangoDB

我正在寻找一种在 ArangoDB 中查询嵌套数组的方法。

我的JSON结构是:

{
  "uid": "bykwwla4prqi",
  "category": "party",
  "notBefore": "2016-04-19T08:43:35.388+01:00",
  "notAfter": "9999-12-31T23:59:59.999+01:00",
  "version": 1.0,
  "aspects": [
    "participant"
  ],
  "description": [
    { "value": "User Homer Simpson, main actor in 'The Simpsons'", "lang": "en"}
  ],
  "properties": [
    {
      "property": [
        "urn:project:domain:attribute:surname"
      ],
      "values": [
        "Simpson"
      ]
    },
    {
      "property": [
        "urn:project:domain:attribute:givennames"
      ],
      "values": [
        "Homer",
        "Jay"
      ]
    }
  ]
}

我尝试使用如下查询来查找具有给定名称 'Jay' 的所有参与方:

FOR r IN resource
FILTER "urn:project:domain:attribute:givennames" IN r.properties[*].targets[*]
   AND "Jay" IN r.properties[*].values[*]
RETURN r

但不幸的是它不起作用 - 它 returns 是一个空数组。如果我对属性数组使用“1”而不是“*”,它就可以工作。但是属性数组没有固定的结构。

有人知道如何解决这个问题吗?

非常感谢!

您可以使用一个简单的技巧来检查过滤器的作用:您 RETURN 实际的过滤条件:

db._query(`FOR r IN resource  RETURN r.properties[*].property[*]`).toArray()
[ 
  [ 
    [ 
      "urn:project:domain:attribute:surname" 
    ], 
    [ 
      "urn:project:domain:attribute:givennames" 
    ] 
  ] 
]

这很清楚发生了什么。 IN 运算符只能作用于一维数组。您可以通过使用 FLATTEN() 删除子层来解决此问题:

db._query(`FOR r IN resource  RETURN FLATTEN(r.properties[*].property[*])`).toArray()
[ 
  [ 
    "urn:project:domain:attribute:surname", 
    "urn:project:domain:attribute:givennames" 
  ] 
]

但是,虽然您的文件有效 json(我猜它是从 xml 转换过来的?)您应该像在 json:[=24 中那样改变结构=]

"properties" : {
  "urn:project:domain:attribute:surname":[
      "Simpson"
  ],
  "urn:project:domain:attribute:givennames": [
      "Homer",
      "Jay"
  ]
}

因为您指定的 FILTER 组合也会找到任何其他 Jay(不仅是那些在 givennames 中找到的组合)并且 FLATTEN() 的使用将禁止使用索引在你的过滤语句中。出于性能原因,您不想使用无法在合理大小的集合上使用索引的查询。

相比之下,您可以在 givennames 上使用数组索引与上述文档布局:

db.resource.ensureIndex({type: "hash",
                        fields:
      ["properties.urn:project:domain:attribute:givennames[*]"]
    })

现在仔细检查查询的解释:

db._explain("FOR r IN resource FILTER 'Jay' IN " + 
            "r.properties.`urn:project:domain:attribute:givennames` RETURN r")
...
  6   IndexNode            1     - FOR r IN resource   /* hash index scan */
...
Indexes used:
By   Type   Collection   Unique   Sparse   Selectivity   Fields           Ranges
  6   hash   resource     false    false       100.00 % \
       [ `properties.urn:project:domain:attribute:givennames[*]` ] \
       ("Jay" in r.`properties`.`urn:project:domain:attribute:givennames`)

它正在使用索引。