2

I've the following data structure:

  • A
    • _id
    • B[]
      • _id
      • C[]
        • _id
        • UserId

I'm trying to run the following query:

where a.B._id == 'some-id' and a.B.C.UserId=='some-user-id'.

That means I need to find a B document that has a C document within with the relevant UserId, something like:

Query.And(Query.EQ("B._id", id), Query.EQ("B.C.UserId", userId));

This is not good, of course, as it may find B with that id and another different B that has C with that UserId. Not good.

How can I write it with the official driver?

1
  • I had some trouble understanding your document structure, maybe you could format it better? Also, now that I understand what you're asking for (I hope), I think you should use a different title: your question isn't about how to reach into 3rd-level objects, but rather how to apply complex predicates to a single sub-document in a collection. Commented Jun 27, 2011 at 9:21

1 Answer 1

3

If the problem is only that your two predicates on B are evaluated on different B instances ("it may find B with that ID and another different B that has C with that UserId"), then the solution is to use an operator that says "find me an item in the collection that satisfies both these predicates together".

Seems like the $elemMatch operator does exactly that. From the docs:

Use $elemMatch to check if an element in an array matches the specified match expression. [...]
Note that a single array element must match all the criteria specified; [...]
You only need to use this when more than 1 field must be matched in the array element.

Try this:

Query.ElemMatch("B", Query.And(
  Query.EQ("_id", id),
  Query.EQ("C.UserId", userId)
));

Here's a good explanation of $elemMatch and dot notation, which matches this scenario exactly.

Sign up to request clarification or add additional context in comments.

1 Comment

Happy to help. I actually learned about this in the process of writing the answer, so thank you :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.