Lai*_*zer 7 mongodb aggregation-framework
这个问题 - 是否有可能在Mongo中得到一片?介绍如何在Mongo中获取切片.总之,使用聚合链$unwind
,$skip
,$limit
,$unwind
,$skip
,$limit
,和$group
.
我的问题是如何在多个文档的集合上执行此操作.我想修剪每个嵌套数组.有一次,我$unwind
,虽然,$skip
并且$limit
仅根据第一阵列的编号是有意义的.
有没有办法在集合中的每个文档上运行这种管道,而不是整个集合?我想在聚合管道中做什么呢?显然可以使用Map-Reduce,但这样做要比$unwind
单独对每个文档运行n + 1个查询要慢.
编辑
以下是一个示例记录.
{
title: "Text Title"
vtitle: "Text Version Title"
text: [[["Book1, Chapter 1, Line 1", "Book1, Chapter 1, Line 2"],["Book 1, Chapter 2, Line 1"]],[["Book 2, Chapter 1, Line 1]]]
}
Run Code Online (Sandbox Code Playgroud)
这里的记录是一本大书的文本,存储为深度为3的数组.可以有许多不同vtitle
的相同title
,并且text
可以非常大.
我想从许多书籍集合中的每本书中选择一小部分由索引标识的包含文本 - 返回每个文档的一小部分.
例如,输入参数[3,3]
将返回如下记录:
{ "text" : ["Book 4, Chapter 4, Line 1", "Book 4, Chapter 4, Line 2", ...] }
Run Code Online (Sandbox Code Playgroud)
TL; DR
我认为简短的答案是你还不能真正做你想做的事。当前的选项是等到 v3.1 或通过group
聚合来破解它(但我怀疑这对于您的需求来说太慢了)。
理由
尽管不太清楚您想要获得的确切结果,但其意图显然是您希望能够在集合中找到一组匹配的文档并转换(即映射)文档(通过对嵌套数组进行切片以生成字符串的平面列表)。搜索是无关紧要的,因为您可以在映射之前或之后进行搜索,并且仍然满足您的约束。因此,我将只讨论映射。
这是 MapReduce 的自然用例,但您已明确将其从允许的答案中排除。所以,有3个选择,我会依次选择。
1) 查询
由于您不允许多个查询,因此您唯一的选择是映射请求中的数据。这是通过投影算子处理的。这些是行不通的。
$slice
运算符,但它不处理嵌套数组。 $
运算符仅允许您获取数组中的第一个条目,这也不足以获取数组中的任意位置。$elemMatch
允许您从数组中获取一个字段 - 这也不足以满足您的需求。此外,您无法在查询上链接投影,因此您无法以某种巧妙的方式将多个投影放在一起来多次切片数据。
简而言之,这是行不通的。
2)聚合管道
不幸的是,直到v3.1为止,聚合管道还没有切片运算符。因此,您只能使用$project或可能巧妙地使用其他运算符(根据您链接的文章)。
首先考虑投影算子。虽然您可以对数组字段进行操作,但目前您只能获取大小。您可以尝试使用集合逻辑,但这本质上是无序的,因此您无法在此处获取第 N 个条目。
因此,直接操作显然行不通。那么我们可以增强您链接的文章吗?此解决方法仅适用于一个文档,因为您不需要区分多个文档。因此,您可以展开数组来创建更大的文档列表,然后使用文档级范围操作来有效地进行切片。
遗憾的是,当您需要在最新的展开列表中查找下一个原始文档的开头时,这种方法就会失败。没有任何运算符组合允许您枚举展开的数组,然后在该枚举和原始文档上进行选择。
$unwind
扩展数组,但不会为您提供随后匹配的索引,并且 $skip 无法提供跳到具有匹配条件的下一个文档的方法。$redact
仍然使您保持在原始文档的范围内,但随后会遇到同样的问题,因为$project
它无法对嵌套数组进行操作。简而言之,这也是一个半身像。
3)群组聚合
就在我准备放弃的时候,我发现了一群人聚集在一起。您可以为匹配的文档创建一个过滤器,然后提供任意 JavaScript 函数finalize
来在返回数据之前转换该数据。这意味着您应该能够发出如下命令:
db.runCommand(
{
group:
{
ns: 'books',
key: { title: 1, text: 1 },
cond: { },
$reduce: function (curr, result) { },
initial: { },
finalize: function(result) {
// Insert your code here to slice the array - e.g.
result.text = result.text[0][0]
}
}
})
Run Code Online (Sandbox Code Playgroud)
当然,如此处所述,如果您的数据库已分片、您的结果大于 16MB 或者您有超过 20,000 个文档(因为每个文档现在都是聚合的键),则此方法不起作用。当数据集变大时,它也非常慢。
归档时间: |
|
查看次数: |
511 次 |
最近记录: |