0

I've made a simplified collection to show my problem:

  db.testcol.insert({ a: 1, msgs: [ { listname: "list1", someinfo: "info"}, { listname: "list2", someinfo: "info"}]});
db.testcol.insert({ a: 1, msgs: [ { listname: "list2", someinfo: "info"}]});
db.testcol.insert({ a: 1, msgs: [ { listname: "list3", someinfo: "info"}]});
db.testcol.insert({ a: 1, msgs: [ { listname: "list4", someinfo: "info"}]});
db.testcol.insert({ a: 1, msgs: [ ]});
db.testcol.insert({ a: 2 });

I need to get all documents from this collection which DOES NOT CONTAIN object with field listname: "list1" in array msgs, in other words I need all docs except first. I have problem with this query, I think I should use $nin operator but I can't find any example how to use it with objects. I've tried queries like this:

db.testcol.find({ "msgs.listName": { "$nin":[ "list1" ] } }).pretty()
db.testcol.find({ "msgs": { "$nin":[ { listName: "list1" } ] } }).pretty()

but all of them doen't work as i need I still can't get the right result. Thanks in advance.

2 Answers 2

3

You have an quite common mistake.

In your collection, the field is named listname (note the lowercase) whereas in your query the field is name listName (note the camel case). Field names are case sensitive. so when adjusting the first query to

db.testcol.find({ "msgs.listname": { "$nin":[ "list1" ] } }).pretty()

you get the expected result.

EDIT

As @NeilLunn correctly pointed out in the comments, the better approach when ruling out a single value as per the question would be:

db.testcol.find({ "msgs.listname": { "$ne": "list1" } })

This approach is both cleaner and faster when just a single value needs to be ruled out.

All kudos to him.

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

4 Comments

Thanks it a really stupid mistake i thought problem was with query(((
@DmitryMalugin While the other answer given here was incorrect in it's assumptions there was one valid point not addressed. You don't need operators like $nin or $in to work on an array element within a document. Simply db.testcol.find({ "msgs.listname": { "$ne": "list1" } }) is sufficient. $nin and $in are meant to be supplied an "array of arguments" themselves. So it it an almost useless use of the operator with a single argument. The "array" applies to arguments, not the content of the document.
@NeilLunn: Right you are, as always. Especially since $nin is much worth performance wise.
Thank a lot guys, I'll follow your advises
-2
db.testcol.find({'msgs.0.listname':{'$ne':'list1'}})

2 Comments

This query is not very robust, is it?
Sometimes speed is better than robustness. Thanks for the -

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.