使用Spring Data创建投影嵌套数组的聚合查询

3

这是我的文档样式:

{
"_id" : ObjectId("583cb6bcce047d1e68339b64"),
"variantDetails" : [ 
    {
        "variants" : {
            "_" : "_"
        },
        "sku" : "069563-59690"
    }, 
    {
        "variants" : {
            "size" : "35"
        },
        "sku" : "069563-59690-35",
        "barcode" : "809702246941"
    }, 
    {
        "variants" : {
            "size" : "36"
        },
        "sku" : "069563-59690-36",
        "barcode" : "809702246958"
    }
    ......
] }

我想要使用类似于这样的复杂聚合查询:

db.getCollection('product').aggregate([
    { '$match': { 'variantDetails.sku': { '$in': ['069563-59690', '069563-59690-36', '069563-59690-37', '511534-01001'] } } },
    { '$project': {'_id': 1, 'variantDetails': 1, 'variantLength': { '$size': '$variantDetails' } } },
    { '$unwind': '$variantDetails' },
    { '$match': { 'variantDetails.sku': { '$in': ['069563-59690', '069563-59690-36', '069563-59690-37', '511534-01001'] } } },
    { '$match': { '$or': [
        {'variantLength': { '$ne': 1 }, 'variantDetails.variants._': { '$ne': '_' } },
        {'variantLength': 1 }
    ] } },
    { '$group': { '_id': '$_id', 'variantDetails': { '$push': '$variantDetails' } } },
    { '$project': {'_id': 1, 'variantDetails.sku': 1, 'variantDetails.barcode': 1} }
])

这是我的Java代码:

    final Aggregation agg = Aggregation.newAggregation(
            Aggregation.match(Criteria.where("variantDetails.sku").in(skus)),
            Aggregation.project("_id", "variantDetails").and("variantDetails").project("size").as("variantLength"),
            Aggregation.unwind("variantDetails"),
            Aggregation.match(Criteria.where("variantDetails.sku").in(skus)),
            Aggregation.match(new Criteria().orOperator(Criteria.where("variantLength").is(1), Criteria.where("variantLength").ne(1).and("variantDetails.variants._").is("_"))),
            Aggregation.group("_id").push("variantDetails").as("variantDetails"),
            Aggregation.project("_id", "variantDetails.sku", "variantDetails.barcode")
            );

    final AggregationResults<Product> result =  this.mongo.aggregate(agg, this.mongo.getCollectionName(Product.class), Product.class);
    return result.getMappedResults();

问题在于Spring翻译

Aggregation.project("_id", "variantDetails.sku", "variantDetails.barcode")

To

{ "$project" : { "_id" : 1 , "sku" : "$variantDetails.sku" , "barcode" : "$variantDetails.barcode"}

但我期望

{ '$project': {'_id': 1, 'variantDetails.sku': 1, 'variantDetails.barcode': 1} }

请问有人可以告诉我如何正确地做吗?

3个回答

1
我遇到了同样的问题,这种方法有效:

Aggregation.project("_id")
.andExpression("variantDetails.sku").as("variantDetails.sku")                
.andExpression("variantDetails.barcode").as("variantDetails.barcode"));

预计结果将是:

{'$project': {'_id': 1, 'variantDetails.sku': '$variantDetails.sku', 
'variantDetails.barcode': '$variantDetails.barcode'} }

0

这可能是一个老问题,但我遇到了Sean指出的同样问题。

如果你想要期望的结果,我发现

{ '$project': {'_id': 1, 'variantDetails.sku': 1, 'variantDetails.barcode': 1} }

一个解决方案可以是:
Aggregation.project("_id")
    .andExpression("1").as("variantDetails.sku")
    .andExpression("1").as("variantDetails.barcode")

Virginia León的回答是找到这个解决方案的起点


请不要将“谢谢”作为答案。一旦你获得足够的 声望,你就可以投票支持你认为有帮助的问题和答案了。- 来自审阅 - Evgeny K

0

你只需要在投影操作中将标签指定为别名,因为Spring提供的默认值不匹配。请使用Spring 1.8.5版本。

Aggregation.project("_id")
                   .and(context -> new BasicDBObject("$arrayElemAt", Arrays.asList("variantDetails.sku", 0))).as("variantDetails.sku")
                   .and(context -> new BasicDBObject("$arrayElemAt", Arrays.asList("variantDetails.barcode", 0))).as("variantDetails.barcode"));

然后Spring将其翻译为{"$project": {"_id": 1,"variantDetails.sku": "$variantDetails.sku","variantDetails.barcode": "$variantDetails.barcode"}},它将以类似于{"variantDetails": [{"sku": ["069563-59690-36"],"barcode": ...}]}的数组形式返回sku和条形码。 - Sean
但这正是在Mongo shell中运行您提供的查询时所得到的结果。它是一个数组,输出也显示了这一点。我不知道我错过了什么。 - s7vr
Noop。如果我在Mongo shell中运行查询,它会返回"variantDetails" : [ { "sku" : "069563-59690-36" , "barcode": ...]}而不是[ { "sku" : ["069563-59690-36"] , "barcode": ...}]。sku是单个值而不是数组。 - Sean
更新为返回单个值。 - s7vr
1
不幸的是,为了获得更好的事务支持,我已经迁移到了MySQL,并且可能无法验证您的建议。但我认为使用BasicDBObject编写原始查询肯定有效。非常感谢您的所有帮助 :) - Sean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接