Mongodb聚合:投影没有最后一个元素的数组

Posted

技术标签:

【中文标题】Mongodb聚合:投影没有最后一个元素的数组【英文标题】:Mongodb Aggregation : Project an array without the last element 【发布时间】:2018-05-06 03:16:14 【问题描述】:

在spring Data中使用聚合管道,我有嵌套数组的文档,我想投影一个数组,除了它的最后一项。 例如对于每个文档,例如:


    "_id" : ObjectId("59ce411c2708c97154d13150"),
    "doc1" : [ 
        
            "nodeValue" : "AAA"
        , 
        
            "nodeValue" : "BBB"
        , 
        
            "nodeValue" : "CCC"
        , 
        
            "nodeValue" : "DDD"
        
    ],
    "field2" : 20170102,
    "field3" : 4,

我想要结果:


    "_id" : ObjectId("59ce411c2708c97154d13150"),
    "doc1" : [ 
        
            "nodeValue" : "AAA"
        , 
        
            "nodeValue" : "BBB"
        , 
        
            "nodeValue" : "CCC"
        , 
        
            "nodeValue" : "DDD"
        
    ],
    "doc1_without_last" : [ 
        
            "nodeValue" : "AAA"
        , 
        
            "nodeValue" : "BBB"
        , 
        
            "nodeValue" : "CCC"
        
    ],
    "field2" : 20170102,
    "field3" : 4,

我尝试了类似的方法,但没有找到可以 $pop 数组并从中删除最后一项的运算符。

Aggregation agg = Aggregation.newAggregation(
                      Aggregation.project()
                        .andInclude("doc1","field2","field3"),
                       Aggregation.project().and(ArrayOperators.arrayOf("doc1")..).as("doc1_without_last")

                       new OutOperation("newCollection")
                ).withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).build());

感谢您的帮助

【问题讨论】:

那里有一个$slice $slice 只是控制要投影的数组的项目数。 $slice(-n) 仅投射最后 n 个元素,$slice(n) 投射前 n 个元素。但是如何投影除最后一个之外的数组的所有数据。 对不起,忘了说还有$size。除了最后一个是$slice($size - 1)。以防万一docs.mongodb.com/manual/reference/operator/aggregation-array 拥有所有这些。 java中的管道$slice中的spring数据没有办法做到这一点,只得到一个数字整数参数。我的想法是反转数组以简单地将最后一个作为第一个像这样.and(ArrayOperators.arrayOf(doc1).reverse()).as("Reversed_doc1)但是如何从投影中排除Reversed_doc1.0.nodeValue 我很确定您可以使用服务器端计算的 $size - 1 构建自定义 $slice,请参阅 ***.com/questions/39393672/… 以获得灵感 【参考方案1】:

shell查询可以是这样的:

db.collection.aggregate([
     $project: 
        doc1: 1,
        doc1_without_last:  $slice: [ 
            "$doc1", 
             $subtract: [  $size: "$doc1" , 1 ]  
        ] 
     
])

文档:

$size $slice $subtract

如果 spring 中有任何限制不允许您构建此类查询,您可以使用$let 来使用查询变量:

db.collection.aggregate([
     $project: 
        doc1: 1,
        doc1_without_last:  $let: 
            vars:  size:  $subtract: [  $size: "$doc1" , 1 ]  ,
            in:  $slice: [ "$letters", "$$size"] 
             
     
])

【讨论】:

感谢 Alex 的帮助,我尝试过类似的方法:.and(VariableOperators .define(VariableOperators.Let.ExpressionVariable.newVariable("SSIZE") .forExpression(AggregationFunctionExpressions.SUBTRACT.of(Fields.field("pathLengthInInteraction"),1))) .andApply(ArrayOperators.Slice.sliceArrayOf("doc").offset(?))).as("WITHOUT_LAST") "pathLengthInInteraction 是已经投影的大小,偏移函数支持仅整数值,我无法恢复 SSIZE价值【参考方案2】:

最后,在让我大吃一惊之后,诀窍就是:

Aggregation agg = Aggregation.newAggregation(
Aggregation.project()
.andInclude("doc1","field1","field2")
.andExpression("slice(doc1, size(doc1)-1)").as("doc1_without_last"),
new OutOperation("newCollection")
                ).withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).build());

投影中的 andExpression 用于以字符串格式包含一些 mongo 运算符。

【讨论】:

以上是关于Mongodb聚合:投影没有最后一个元素的数组的主要内容,如果未能解决你的问题,请参考以下文章

通过聚合中的索引投影嵌套数组字段值

MongoDB - 仅投影数组中的匹配元素

MongoDB - 仅投影数组中的匹配元素

MongoDB聚合,如何在组管道中addToSet数组的每个元素

mongodb $查找带有投影的数组中的嵌套对象

MongoDB:使用正则表达式聚合数组元素