2

I have a collection of forms:

{ "_id" : { "$oid" : "57050f22d5f79d2e6866c6f8" }, "form_name" : "Form 1", "ver" : 0, "createdAt" : { "$date" : 1459950030037 } }
{ "_id" : { "$oid" : "57050fa6d5f79d2e6866c6f9" }, "form_name" : "Form 1", "ver" : 1, "vid" : { "$oid" : "57050f22d5f79d2e6866c6f8" }, "createdAt" : { "$date" : 1459950030037 } }
{ "_id" : { "$oid" : "57050ff2d5f79d2e6866c6fa" }, "form_name" : "Form 1", "ver" : 2, "vid" : { "$oid" : "57050f22d5f79d2e6866c6f8" }, "createdAt" : { "$date" : 1459950030037 } }
{ "_id" : { "$oid" : "570511ced5f79d2e6866c6fb" }, "form_name" : "Form 2", "ver" : 0, "createdAt" : { "$date" : 1459950030037 } }

I'm getting versioned forms as follows:

db.forms.aggregate([
    {"$match":{"deletedAt":{"$exists":false}}},
    {"$sort":{"createdAt":1}},
    {"$group":{
            "_id": {"$ifNull":["$vid", "$_id"]},
            "vid":{"$push":"$$ROOT"}
        }
    }
])

and I'm getting such JSON answer:

[
    {
        "_id" : ObjectId("57050f22d5f79d2e6866c6f8"),
        "vid" : [
            {
                "_id" : ObjectId("57050f22d5f79d2e6866c6f8"),
                "form_name" : "Form 1",
                "ver" : 0,
                "createdAt" : ISODate("2016-04-06T13:29:06.079Z")
            },
            {
                "_id" : ObjectId("57050fa6d5f79d2e6866c6f9"),
                "form_name" : "Form 1",
                "ver" : 1,
                "createdAt" : ISODate("2016-04-06T13:31:18.742Z"),
                "vid" : ObjectId("57050f22d5f79d2e6866c6f8")
            },
            {
                "_id" : ObjectId("57050ff2d5f79d2e6866c6fa"),
                "form_name" : "Form 1",
                "ver" : 2,
                "createdAt" : ISODate("2016-04-06T13:32:34.986Z"),
                "vid" : ObjectId("57050f22d5f79d2e6866c6f8")
            }
        ]
    },
    {
        "_id" : ObjectId("570511ced5f79d2e6866c6fb"),
        "vid" : [
            {
                "_id" : ObjectId("570511ced5f79d2e6866c6fb"),
                "form_name" : "Form 2",
                "ver" : 0,
                "createdAt" : ISODate("2016-04-06T13:40:30.037Z")
            }
        ]
    }
]

In my Java back end I'm doing it as follows:

List<DBObject> tmpAggr = new ArrayList<>();
tmpAggr.add(new BasicDBObject("$match", new BasicDBObject("deletedAt", new BasicDBObject("$exists", false))));
tmpAggr.add(new BasicDBObject("$sort",  new BasicDBObject("createdAt", 1)));
tmpAggr.add(new BasicDBObject("$group", BasicDBObjectBuilder.start("_id", new BasicDBObject("$ifNull", new String[]{"$vid", "$_id"}))
                                                        .append("vid", new BasicDBObject("$push", "$$ROOT")).get()));
tmpAggr.add(new BasicDBObject("$sort",  new BasicDBObject("_id", 1)));
        list_with_versions = Collections.unmodifiableList(tmpAggr);  
org.getDB().getCollection("forms").aggregate(list_with_versions).results()

How to reproduce this behavior with Spring Data MongoDB framework? The problem is that there is no ifNull construction. How to manage this issue?

1 Answer 1

1

You could create a workaround that implements the AggregationOperation interface to take in a DBObject that represents a single operation in an aggregation pipeline with the $ifNull operator:

public class GroupAggregationOperation implements AggregationOperation {
    private DBObject operation;

    public GroupAggregationOperation (DBObject operation) {
        this.operation = operation;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }
}

Then implement the $group operation as a DBObject in the aggregation pipeline that is the same as the one you have:

DBObject operation = (DBObject) new BasicDBObject(
    "$group", BasicDBObjectBuilder.start(
        "_id", new BasicDBObject(
            "$ifNull", new String[]{"$vid", "$_id"}
        )
    )
    .append("vid", new BasicDBObject("$push", "$$ROOT"))
    .get()              
);

which you can then use as:

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

GroupAggregationOperation groupOp = new GroupAggregationOperation(operation);
Aggregation agg = newAggregation(
    match(Criteria.where("deletedAt").exists(false)),
    sort(ASC, "deletedAt"),
    groupOp 
);
AggregationResults<Forms> results = mongoTemplate.aggregate(agg, Forms.class); 
List<Forms> forms = results.getMappedResults();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.