Get value from Embedded Document Mongo Java
You can do it one of three ways.
You can use aggregation framework to project the value of embedded field using dot notation.
Using Aggregation
import static com.mongodb.client.model.Aggregates.*; import static com.mongodb.client.model.Filters.eq; import static com.mongodb.client.model.Projections.computed; import static java.util.Arrays.*; import static com.mongodb.client.model.Projections.include; MongoClient mc = new MongoClient(); MongoDatabase db = mc.getDatabase("test"); MongoCollection<Document> collection = db.getCollection("collection"); Document document = collection.aggregate(asList( match(eq("day",17)), project(computed("val", "$model1.MondayModel.gtxdotdot.xdotdot")))). first(); Double embeddedField = document.getDouble("val");
Using Distinct
Double embeddedField = collection.distinct("model1.MondayModel.gtxdotdot.xdotdot", eq("day",17), Double.class).first();
Using Find
Document document = collection.find(eq("day",17)).projection(include("model1.MondayModel.gtxdotdot.xdotdot")).first(); Double embeddedField = document.get("model1", Document.class).get("MondayModel", Document.class).get("gtxdotdot", Document.class).getDouble("xdotdot")
I don't think you can use dot notation directly, but you can create your own helper function.
Solution 1: get field with dot notation
public static Object getWithDotNotation( Document document, String dots ) throws MongoException{ String[] keys = dots.split( "\\." ); Document doc = document; for( int i = 0; i < keys.length - 1; i++ ){ Object o = doc.get( keys[ i ] ); if( o == null || !( o instanceof Document ) ){ throw new MongoException( String.format( "Field '%s' does not exist or s not a Document", keys[ i ] ) ); } doc = ( Document ) o; }//end for return doc.get( keys[ keys.length - 1 ] );}
You can then use it like this:
String dotNotation = "model1.MondayModel.gtxdotdot.xdotdot";FindIterable<Document> projection = mongoColl.find() .projection( fields( include( dotNotation ) ) );Double value = ( Double ) getWithDotNotation( projection.first(), dotNotation );System.out.println( value ); // result: 0.0
This will simplify your code a whole lot. The only things to care for are:
- if you are not sure of you dot notation, use a
try catch
block - the method
getWithDotNotation
might return null - be careful about forced casts, use it only if you are 100% sure of the type of your data (here Double).
Solution 2: flatten your doc
public static Document flattenDoc( Document document ){ Document flattened = new Document(); Queue<Pair<String, Document>> queue = new ArrayDeque<>(); queue.add( new Pair<>( "", document ) ); while( !queue.isEmpty() ){ Pair<String, Document> pair = queue.poll(); String key = pair.getKey(); for( Map.Entry<String, Object> entry : pair.getValue().entrySet() ){ if( entry.getValue() instanceof Document ){ queue.add( new Pair<>( key + entry.getKey() + ".", ( Document ) entry.getValue() ) ); }else{ flattened.put( key + entry.getKey(), entry.getValue() ); } }//end for } return flattened;}
With your sample data, the result of flattenDoc
is the following:
Document{{_id=569afce4b932c542500143ec,date=2016-1-17T2:31:0Z,day=17,model1.date=2016-01-17T02:31+0000,model1.MondayModel.gtxdotdot.xdotdot=0.0,model1.MondayModel.gtxdotdot.xdot=0.0,model1.MondayModel.lsxdotdot.xdotdot=0.0,model1.MondayModel.lsxdotdot.xdot=0.0,model1.MondayModel.gtxdot.xdotdot=0.0,model1.MondayModel.gtxdot.xdot=0.0,model1.MondayModel.lsxdot.xdotdot=0.0,model1.MondayModel.lsxdot.xdot=0.0,model1.MondayModel.modeldotdot.mean=0.0,model1.MondayModel.modeldotdot.sdvar=0.0,model1.MondayModel.modeldot.mean=0.0,model1.MondayModel.modeldot.sdvar=0.0}}
So you can use getDouble("model1.MondayModel.gtxdotdot.xdotdot")
directly. This approach might be more efficient if you need to access all the fields.