0

I have some mongo data that looks like this

{
    "_id": {
        "$oid": "5984cfb276c912dd03c1b052"
    },
    "idkey": "123",
    "objects": [{
        "key1": "481334",
        "key2": {
            "key3":"val3",
            "key4": "val4"
        }
    }]

}

I want to know what the value of key4 is. I also need to filter the results byidkey and key1. So I tried

doc = mongoCollection.find(and(eq("idKey", 123),eq("objects.key1", 481334))).first();

and this works. But i want to check the value of key4 without having to unwrap the entire object. Is there some query i can perform that gives me just the value of key4? Note that I can update the value of key4 as

mongoCollection.updateOne(and(eq("idKey", 123), eq("objects.key1", 481334)),Updates.set("objects.$.key2.key4", "someVal"));

Is there a similar query i can run just to get the value of key4?

Upadte

thanks a lot @dnickless for your help. I tried both of your suggestions but i am getting null. Here is what i tried

existingDoc = mongoCollection.find(and(eq("idkey", 123), eq("objects.key1", 481334))).first();

this gives me

Document{{_id=598b13ca324fb0717c509e2d, idkey="2323", objects=[Document{{key1="481334", key2=Document{{key3=val3, key4=val4}}}}]}}

so far so good. next i tried

mongoCollection.updateOne(and(eq("idkey", "123"), eq("objects.key1", "481334")),Updates.set("objects.$.key2.key4", "newVal"));

now i tried to get the updated document as

updatedDoc = mongoCollection.find(and(eq("idkey", "123"),eq("objects.key1","481334"))).projection(Projections.fields(Projections.excludeId(), Projections.include("key4", "$objects.key2.key4"))).first();

for this i got

Document{{}}

and finally i tried

updatedDoc = mongoCollection.aggregate(Arrays.asList(Aggregates.match(and(eq("idkey", "123"), eq("objects.key1", "481334"))),
                            Aggregates.unwind("$objects"), Aggregates.project(Projections.fields(Projections.excludeId(), Projections.computed("key4", "$objects.key2.key4")))))
                    .first();

and for this i got

Document{{key4="newVal"}}

so i'm happy :) but can you think of a reason why the firs approach did not work?

Final answer

thanks for the update @dnickless

document = collection.find(and(eq("idkey", "123"), eq("objects.key1", "481334"))).projection(fields(excludeId(), include("key4", "objects.key2.key4"))).first();

AbtPst
  • 7,778
  • 17
  • 91
  • 172

1 Answers1

1

Your data sample contains a lowercase "idkey" whereas your query uses "idKey". In my examples below, I use the lowercase version. Also you are querying for integers 123 and 481334 as opposed to strings which would be correct looking at your sample data. I'm going for the string version with my below code in order to make it work against the provided sample data.

You have two options:

Either you simply limit your result set but keep the same structure using a simple find + projection:

document = collection.find(and(eq("idkey", "123"), eq("objects.key1", "481334"))).projection(fields(excludeId(), include("objects.key2.key4"))).first();

Or, probably nicer in terms of output (not necessarily speed, though), you use the aggregation framework in order to really just get what you want:

document = collection.aggregate(Arrays.asList(match(and(eq("idkey", "123"), eq("objects.key1", "481334"))), unwind("$objects"), project(fields(excludeId(), computed("key4", "$objects.key2.key4"))))).first();
dnickless
  • 10,733
  • 1
  • 19
  • 34
  • in `include("test", "objects.key2.key4")` why did you use `test`? – AbtPst Aug 09 '17 at 14:19
  • 1
    I'm sorry, that's just a mistake. I used test in my query and then changed it when I pasted the query as an answer. Forgot to do it in one case, will fix it now. – dnickless Aug 09 '17 at 14:25
  • thanks! the second approach works, but as you said, it takes more time. any idea why i might be getting a blank document when i use the first approach? – AbtPst Aug 09 '17 at 14:27
  • 1
    Just a second, there's some more stuff wrong with the first query. I'm all confused because I'm working on some complex stuff as I'm typing this here. I'll get this fixed for you. – dnickless Aug 09 '17 at 14:56
  • sure thing, thanks. i think i got it. i removed the `$` and it worked `document = collection.find(and(eq("idkey", "123"), eq("objects.key1", "481334"))).projection(fields(excludeId(), include("key4", "objects.key2.key4"))).first();` – AbtPst Aug 09 '17 at 14:59
  • oh i see. i think in your original post you had `document = collection.find(and(eq("idkey", "123"), eq("objects.key1", "481334"))).projection(fields(excludeId(), include("test", "$objects.key2.key4"))).first();` – AbtPst Aug 09 '17 at 14:59
  • 1
    No, the $ sign is only there for the aggregation framework version. That must have been a copy and paste problem. Anyhoo, I fixed another thing: The "key4" stuff (which used to be "test") is not needed at all... ;) So, now, I think, we got the final versions working... Phew! – dnickless Aug 09 '17 at 15:02