Search code examples
javamongodbmongodb-java

$unwind $push Mongo


I have a Educational Intitution document which seems like this:

{ name: ..., addresses: [...], courses: [ {name: ... , duration: ..., tags[...]} ] }

tags has an String array.

I am trying find a course which has some tags inside, like: java, eclipse, struts and so on...

My search method looks like this:

public BasicDBList coordinates(List tags){

    BasicDBObject cmdBody = new BasicDBObject("aggregate", "EducationalInstitution");

    List<BasicDBObject> pipeline = new ArrayList<BasicDBObject>();

    BasicDBObject projectParams = new BasicDBObject();
    projectParams.put("name", 1);
    projectParams.put("addresses.state", 1);
    projectParams.put("addresses.locs", 1);
    projectParams.put("courses", 1);

    pipeline.add(new BasicDBObject("$project", projectParams));
    pipeline.add(new BasicDBObject("$unwind", "$addresses"));
    pipeline.add(new BasicDBObject("$unwind", "$courses"));
    pipeline.add(new BasicDBObject("$match", new BasicDBObject("courses.tags", new BasicDBObject("$all", tags))));

    cmdBody.put("pipeline", pipeline); 

    return (BasicDBList) getDatastore().getDB().command(cmdBody).get("result");
}

When I run this I receive results like:

{ "_id" : ... , "name" : "X25" , "addresses" : { "state" : "DF" , "locs" : [ -15.806789 , -47.912779]} , "courses" : { "name" : "Microsoft Office Word 2010" , "duration" : 22 , "tags" : [...]}}

{ "_id" : ... , "name" : "X25" , "addresses" : { "state" : "DF" , "locs" : [ -15.806789 , -47.912779]} , "courses" : { "name" : "Microsoft Office Excel 2010" , "duration" : 18 , "tags" : [...]}}

{ "_id" : ... , "name" : "X25" , "addresses" : { "state" : "DF" , "locs" : [ -15.806789 , -47.912779]} , "courses" : { "name" : "Microsoft Office PowerPoint 2010" , "duration" : 14 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "DF" , "locs" : [ -15.797209 , -47.883596]} , "courses" : { "name" : "MS Visio" , "duration" : 0 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "DF" , "locs" : [ -15.797209 , -47.883596]} , "courses" : { "name" : "Acrobat Professional" , "duration" : 12 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "DF" , "locs" : [ -15.797209 , -47.883596]} , "courses" : { "name" : "Framemaker" , "duration" : 0 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "PR" , "locs" : [ -25.431803 , -49.279532]} , "courses" : { "name" : "MS Visio" , "duration" : 0 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "PR" , "locs" : [ -25.431803 , -49.279532]} , "courses" : { "name" : "Acrobat Professional" , "duration" : 12 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "PR" , "locs" : [ -25.431803 , -49.279532]} , "courses" : { "name" : "Framemaker" , "duration" : 0 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "SP" , "locs" : [ -23.574942 , -46.71048]} , "courses" : { "name" : "MS Visio" , "duration" : 0 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "SP" , "locs" : [ -23.574942 , -46.71048]} , "courses" : { "name" : "Acrobat Professional" , "duration" : 12 , "tags" : [...]}}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "SP" , "locs" : [ -23.574942 , -46.71048]} , "courses" : { "name" : "Framemaker" , "duration" : 0 , "tags" : [...]}}

What I want is group courses that I unwind by education institution name and address. Like this: { "_id" : ... , "name" : "X25" , "addresses" : { "state" : "DF" , "locs" : [ -15.806789 , -47.912779]} , "courses" : [{ "name" : "Microsoft Office Word 2010" , "duration" : 22 , "tags" : [...]}, { "name" : "Microsoft Office Excel 2010" , "duration" : 18 , "tags" : [...]}, { "name" : "Microsoft Office PowerPoint 2010" , "duration" : 14 , "tags" : [...]}]}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "DF" , "locs" : [ -15.797209 , -47.883596]} , "courses" : [{ "name" : "MS Visio" , "duration" : 0 , "tags" : [...]}, { "name" : "Acrobat Professional" , "duration" : 12 , "tags" : [...]}, { "name" : "Framemaker" , "duration" : 0 , "tags" : [...]}]}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "PR" , "locs" : [ -25.431803 , -49.279532]} , "courses" : [{ "name" : "MS Visio" , "duration" : 0 , "tags" : [...]}, { "name" : "Acrobat Professional" , "duration" : 12 , "tags" : [...]}, { "name" : "Framemaker" , "duration" : 0 , "tags" : [...]}]}

{ "_id" : ... , "name" : "ENG" , "addresses" : { "state" : "SP" , "locs" : [ -23.574942 , -46.71048]} , "courses" : [{ "name" : "MS Visio" , "duration" : 0 , "tags" : [...]}, { "name" : "Acrobat Professional" , "duration" : 12 , "tags" : [...]}, { "name" : "Framemaker" , "duration" : 0 , "tags" : [...]}]}

I read about $push and try implement however without success. I tried add BasicDBObject in pipeline variable and append in cmdBody the command.

Did someone pass for similar problem?


Solution

  • You can use the $push operator along with the $group pipeline operator like this in shell:

    db.t.aggregate([{$unwind:'$b'},{$unwind:'$c'},{$group:{_id:'$b',cs:{$push:'$c'}}}])
    

    In your case in JAVA something like :

    pipeline.add(new BasicDBObject("$group", new BasicDBObject(new BasicDBObject("_id", groupParams)).append("courses", new BasicDBObject("$push", "$courses"))));
    

    If you are strictly likely to use the same format as you described you can include a $project step at the end which with you can reformat the result documents.