0

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.

prasad_
  • 12,755
  • 2
  • 24
  • 36

2 Answers2

0

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
prasad_
  • 12,755
  • 2
  • 24
  • 36
  • hey prasad_, thank you very much for your answer. This was extactly what I was looking for. Like Sloth mentioned below, my main intention was to get all keys dynamicly by searching for the entrySet of each key. What I did was just nesting multiple for-loops like yours and getting Embedded documents one by one. I think what I was missing before was the right usage of `subDoc.getEmbedded();`. – Karuzo Rodriguez Feb 07 '21 at 11:20
0

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?

Sloth
  • 11
  • 1
  • 4
  • 1
    In general, the path "vehicles.cars.coupes" is a known path - these represent _known_ fields (another example is "name.firstName" and "name.lastName". The "Mercedes", "Ford", "Ferrari", etc., are not known and they are dynamic. Ideally, the sub-document fields "Mercedes", etc should be designed as an array like this: `coupes: [ { model: "Mercedes", production: "2011"}, { model: "Ford", production: "2015"}, ...]`. Then you can query without guessing what the _dynamic_ (the unknown) fields are. – prasad_ Feb 08 '21 at 04:47