Spring data mongodb filter nested object id in collection of String

Viewed 1038

I would like to filter mongodb collection by multiple nested object's object Id in String with Mongodb aggregation match operation. However spring data mongodb does not converts the String value to object Id in the match operation.

I was able to filter documents by multiple document Ids (primary key, not the nested object's object Id) in String value without any issues as Spring data mongodb converts the String values to oid:

{ "_id" : { "$in" : [{ "$oid" : "61a31853d268434139e7fc11"}, { "$oid" : "61a31853d268434139e7fc12"}]}

What I wanted to achieve is as below :

db.getCollection('products').aggregate(
[
    { "$match" : { "$and" : [{ "type._id" : { "$in" : [ 
       ObjectId("618b99a3b4c24465b074b246"), 
       ObjectId("60afc0920dab8b6d3ac26355") 
    ] }}]}}
])

But I always get the following :

    db.getCollection('products').aggregate(
    [
        { "$match" : { "$and" : [{ "type._id" : { "$in" : [
[{ "$oid" : "618b99a3b4c24465b074b246"}, { "$oid" : "60afc0920dab8b6d3ac26355"}]
        ]}}]}}
    ])

Spring data mongodb generated 2 dimensional arrays for the OIDs in the $in json

My Mongodb entities:

@Document(collection = "products")
public class Product {

    @Id
    private String id;

    @NotNull
    private ProductType type;  

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Type getType() {
        return type;
    }

    public void setType(ProductType type) {
        this.type = type;
    }

}

@Document(collection = "product_types")
public class ProductType {

    @Id
    private String id;

        public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

My java code to execute the aggregation:

List<String> typeIds = Arrays.asList("618b99a3b4c24465b074b246", "60ad10ffc723877d8a977149");
List<AggregationOperation> aggregateOperations = new ArrayList<>(); 
Criteria criteria = Criteria.where("type._id").in(typeIds.stream().map(t -> new ObjectId(t)).collect(Collectors.toList()));
aggregateOperations.add(Aggregation.match(criteria));

Aggregation aggregation = Aggregation.newAggregation(aggregateOperations);  
mongoTemplate.aggregate(aggregation, "products", ProductListDTO.class);

The mongodb collection data is as below:

{
    "_id" : ObjectId("61a31853d268434139e7fc11"),
    "type" : {
        "_id" : ObjectId("618b99a3b4c24465b074b246")
    }
}
1 Answers

It works as expected. When you log your aggregation pipeline, it writes as {$oid: 'hex'} (Same thing for the date).

Internally driver searches as ObjectId(...) as expected:

ObjectId

//WHEN
Criteria criteria = Criteria.where("type._id")
    .in(typeIds.stream().map(ObjectId::new).collect(Collectors.toList()))
    .and("date").is(new Date(currDate));

//Searches:
Document{{$match=Document{{type._id=Document{{$in=[618b99a3b4c24465b074b246]}}, date=Tue Dec 14 01:53:09 CET 2021}}}}

//LOG:
{
    "aggregate": "__collection__",
    "pipeline": [
        {
            "$match": {
                "type._id": {
                    "$in": [
                        {
                            "$oid": "618b99a3b4c24465b074b246"
                        }
                    ]
                },
                "date": {
                    "$date": "2021-12-14T00:53:09.817Z"
                }
            }
        }
    ]
}
Related