How to read attributes out of multiple nested documents in MongoDB Java?

1k Views Asked by At

I need some help with a project I am planing to do. At this stage I am trying to learn using NoSQL Databases in Java. I've got a few nested documents looking like this: MongoDB nesting structure

enter image description here

Like you can see on the image, my inner attributes are "model" and "construction".

Now I need to iterate through all the documents in my collection, whose keynames are unknown, because they are generated in runtime, when a user enters some information.

At the end I need to list them in a TreeView, keeping the structure they have already in the database. What I've tried is getting keySets from documents, but I cannot pass the second layer of the structure. I am able to print the whole Object in Json format, but I cannot access the specific attributes like "model" or "construction".

MongoCollection collection= mongoDatabase.getCollection("test");           
MongoCursor<Document> cursor = collection.find().iterator();
for(String keys: document.keySet()) {
                Document vehicles = (Document) document.getString(keys);

                //System.out.println(keys);
                //System.out.println(document.get(keys));
            }

                /Document cars = (Document) vehicle.get("cars");
                Document  types = (Document) cars.get("coupes");
                Document brands = (Document) types.get("Ford");
                Document model = (Document) brands.get("Mustang GT");

Here I tried to get some properties, by hardcoding the keynames of the documents, but I can't seem to get any value either. It keeps telling me that it could not read from vehicle, because it is null.

The most tutorials and posts in forums, somehow does not work for me. I don't know if they have any other version of MongoDB Driver. Mine is: mongodb driver 3.12.7. if this helps you in any way.

I am trying to get this working for days now and it is driving me crazy. I hope there is anyone out there who is able to help me with this problem.

2

There are 2 best solutions below

1
On BEST ANSWER

Here is a way you can try using the Document class's methods. You use the Document#getEmbedded method to navigate the embedded (or sub-document) document's path.

try (MongoCursor<Document> cursor = collection.find().iterator()) {
    while (cursor.hasNext()) {
    
        // Get a document
        Document doc = (Document) cursor.next();
        
        // Get the sub-document with the known key path "vehicles.cars.coupes"
        Document coupes = doc.getEmbedded(
                                    Arrays.asList("vehicles", "cars", "coupes"), 
                                    Document.class);
        
        // For each of the sub-documents within the "coupes" get the
        // dynamic keys and their values.
        for (Map.Entry<String, Object> coupe :  coupes.entrySet()) {
        
            System.out.println(coupe.getKey()); // e.g., Mercedes
            
            // The dynamic sub-document for the dynamic key (e.g., Mercedes):
            // {"S-Class": {"model": "S-Class", "construction": "2011"}}
            Document coupeSubDoc = (Document) coupe.getValue(); 
            
            // Get the coupeSubDoc's keys and values
            coupeSubDoc.keySet().forEach(k -> {
                System.out.println("\t" + k); // e.g., S-Class
                System.out.println("\t\t" + "model" + " : " +
                    coupeSubDoc.getEmbedded(Arrays.asList(k, "model"), String.class));
                System.out.println("\t\t" + "construction" + " : " +
                    coupeSubDoc.getEmbedded(Arrays.asList(k, "construction"), String.class));
            });
        }
    }
}

The above code prints to the console as:

Mercedes
        S-Class
                model : S-Class
                construction : 2011
Ford
        Mustang
                model : Mustang GT
                construction : 2015
1
On

I think it's not the complete answer to his question. Here he says:

Now I need to iterate through all the documents in my collection, whose keynames are unknown, because they are generated in runtime, when a user enters some information.

Your answer @prasad_ just refers to his case with vehicles, cars and so on. He needs a way to handle unknown key/value pairs i guess. For example, in this case he only knows the keys:vehicle,cars,coupe,Mercedes/Ford and their subkeys. If another user inserts some new key/value paairs in the collection he will have problems because he can't navigate trough the new document without to have a look into the database.

I'm also interested in the solution because I never nested my key/value pairs and cant see the advantage of it. Am I wrong or does it make the programming more difficult?