在查询语言中,数据是无架构的,通常非规范化。 与在关系数据库中一样,联接发生在单个项中,而不是跨实体和集联接数据。 具体而言,联接的范围限定为该项,不能跨多个项和容器发生。
小窍门
如果你发现自己需要跨项和容器联接,请考虑重新工作数据模型以避免这种反模式。
使用单个项进行自联接
让我们看看项内自联接的示例。 考虑包含单个项的容器。 此项表示具有各种大小的产品:
[
{
"name": "Raiot Jacket",
"sizes": [
{
"key": "s",
"description": "Small"
},
{
"key": "m",
"description": "Medium"
},
{
"key": "l",
"description": "Large"
},
{
"key": "xl",
"description": "Extra Large"
}
]
}
]
如果需要查找特定大小的产品,该怎么办? 通常,需要编写一个查询,该查询具有一个筛选器,该查询检查数组中 sizes 每个潜在索引是否有前缀的值。 在此示例中,查询查找大小以 : 结尾 Large的所有产品:
SELECT
*
FROM
products p
WHERE
p.sizes[0].description LIKE "%Large" OR
p.sizes[1].description LIKE "%Large" OR
p.sizes[2].description LIKE "%Large" OR
p.sizes[3].description LIKE "%Large"
此方法可以快速变得不可维持。 查询语法的复杂性或长度会增加数组中潜在项的数量。 此外,此查询不够灵活,无法处理将来可能具有三个以上的尺寸的产品。
在传统的关系数据库中,大小将分隔为单独的表,并且跨表联接是通过应用于结果的筛选器执行的。 在查询语言中,可以使用关键字在项 JOIN 中执行自联接作:
SELECT
p.name,
s.key,
s.description
FROM
products p
JOIN
s in p.sizes
此查询返回一个简单的数组,其中包含标记数组中每个值的项。
[
{
"name": "Raiot Jacket",
"key": "s",
"description": "Small"
},
{
"name": "Raiot Jacket",
"key": "m",
"description": "Medium"
},
{
"name": "Raiot Jacket",
"key": "l",
"description": "Large"
},
{
"name": "Raiot Jacket",
"key": "xl",
"description": "Extra Large"
}
]
让我们分解查询。 查询现在有两个别名: p 结果集中每个产品项以及 s 自联接 sizes 数组。
*如果关键字可以推断输入集,则仅对投影所有字段有效,但现在有两个输入集(p和t)。 由于此约束,我们必须将返回的字段name显式定义为产品以及keydescription大小。
最后,可以使用筛选器查找以 Large结尾的大小。 由于我们使用了 JOIN 关键字,因此筛选器足够灵活,可以处理任何可变数量的标记:
SELECT
p.name,
s.key AS size
FROM
products p
JOIN
s in p.sizes
WHERE
s.description LIKE "%Large"
[
{
"name": "Raiot Jacket",
"size": "l"
},
{
"name": "Raiot Jacket",
"size": "xl"
}
]
自联接多个项
让我们转到一个示例,在此示例中,我们需要在多个项中存在的数组中找到值。 对于此示例,请考虑包含两个产品项的容器。 每个项都包含与该项相关的 colors 项。
[
{
"name": "Gremon Fins",
"colors": [
"science-blue",
"turbo"
]
},
{
"name": "Elecy Jacket",
"colors": [
"indigo-shark",
"jordy-blue-shark"
]
},
{
"name": "Tresko Pack",
"colors": [
"golden-dream"
]
}
]
如果需要查找名称中包含颜色 blue 的每个项,该怎么办? 可以手动搜索字符串 blue,但需要编写一个复杂查询,该查询包含以下两个特征:
子
blue字符串的颜色在每个数组中的不同索引处发生。Elecy Jacket对于产品,颜色为第二项(索引:1)。Gremon Fins对于产品,标记是第一项(索引:0)。 该产品Tresko Pack没有任何包含此子字符串的内容。每个项的
colors数组长度不同。 和Gremon FinsElecy Jacket产品都具有两种颜色,Tresko Pack而产品只有一种颜色。
在这里,关键字 JOIN 是创建项和颜色的交叉积的绝佳工具。 联接创建参与联接的集 的完整 交叉积。 结果是一组元组,其中包含项的每个排列以及目标数组中的值。
示例产品和颜色的联接作将创建以下项:
| 产品 | 颜色 |
|---|---|
Gremon Fins |
science-blue |
Gremon Fins |
turbo |
Elecy Jacket |
indigo-shark |
Elecy Jacket |
jordy-blue-shark |
Tresko Pack |
golden-dream |
此示例 NoSQl 查询使用 JOIN 关键字创建跨产品并返回所有排列:
SELECT
p.name,
c AS color
FROM
products p
JOIN
c in p.colors
[
{
"name": "Elecy Jacket",
"color": "indigo-shark"
},
{
"name": "Elecy Jacket",
"color": "jordy-blue-shark"
},
{
"name": "Gremon Fins",
"color": "science-blue"
},
{
"name": "Gremon Fins",
"color": "turbo"
},
{
"name": "Tresko Pack",
"color": "golden-dream"
}
]
与单个项一样,可以在此处应用筛选器以仅查找与特定标记匹配的项目。 例如,此查询查找包含满足本节前面提到的初始要求的所有子字符串 blue 的项目。
SELECT
p.name,
c AS color
FROM
products p
JOIN
c in p.colors
WHERE
c LIKE "%blue%"
[
{
"name": "Elecy Jacket",
"color": "jordy-blue-shark"
},
{
"name": "Gremon Fins",
"color": "science-blue"
}
]
可以进一步优化此查询,以便仅返回满足筛选器的产品的名称。 此示例不投影颜色值,但筛选器仍按预期工作:
SELECT VALUE
p.name
FROM
products p
JOIN
c in p.colors
WHERE
c LIKE "%blue%"
[
"Elecy Jacket",
"Gremon Fins"
]