How to match an array against another array query - mongodb

Say I have a collection that has documents like this where the crossRefs field is an array of strings:
{ name: "joe", crossRefs: [ "1" , "2" , "10a"] }
{ name: "jane", crossRefs: [ "10a" , "0xfgh" , "9"] }
{ name: "john", crossRefs: [ "11" , "hhj12" , "13dd"] }
...
Question 1: How to build a query against crossRefs with an array of strings
I would like to have a query that says "give me all the documents that have any one of crossRefs '10a', '1' and '2'". So the result from the above 3 documents would be just the first 2. I'm thinking I need $elemMatch or $in with a combination of ors but I just don't know how to formulate this.
Question 2: How to specify an index
I would like for MongoDB to build an index based on the crossRefs field. In Java is this as simple as:
mainDB.getCollection("theCollection").ensureIndex("crossRefs");
I.e. does that work ok when the field is actually an array of strings?
Thanks in advance.

$in works with array fields as well as non-array fields, so in the shell it would be:
db.theCollection.find({crossRefs: {$in: ['10a', '1', '2']}})
This will find the docs where at least one crossRefs element matches an $in element.
And yes, that's the correct way to index the field, even when it's an array.

Related

MonogDB: How to get all the documents with specific value in a field?

I have an array of 10 unique Object IDs named Arr
I have 10,000 documents in a collection named xyz.
How can I find documents using Object IDs in the array Arr from the collection xyz with only one request?
There are $all and $in operators but are used to query fields with an array.
Or do I need to make requests equal to the length of Arr and get individual document using findOne?
EDIT:
I'm expecting something like this:
db.getCollection("xyz").find({"_id" : [array containing 10 unique IDs]})
....for which the result callback will contain an array of all the matched IDs of query array.
According to the documentation here: https://docs.mongodb.com/manual/reference/operator/query/in/
You should use the following query:
db.getCollection("xyz").find({"Arr" : { $in: [123, 456, 789 ] }});

Return array index from $elemMatch query

Say I have a document like this
{
title : 'myTitle',
favorites : [{name : 'text', number : 6}, {name : 'other', number : 4}]
}
I would like to return the array index (if any) from where the embedded document was retrieved within the favorites array.
Say I have the following query
{title : 'myTitle'}
and the projection
{favorites : {$elemMatch : {name : 'text', number : 6} }}
if the projection returns the document AND it contains a favorites array with the sub document, is there a way to know at which index that sub document was found? Which in this case is index 0.
The reason I would like the index is because as soon as I retrieve the document, I proceed to update it, and it would boost the performance if I had a specific index to update instead of using $elemMatch again which would cause mongo to iterate through all the array entries until finding the document that matches.
Unfortunately, it is not possible using the $elemMatch operator. If you are using mongodb 3.2, you could make use of the $unwind operator and aggregate instead of doing a find()
db.collection.aggregate([
{$match:{"favorites.name":"text","favorites.number":6}},
{$unwind:{"path":"$favorites","includeArrayIndex":"index"}},
{$match:{"favorites.name":"text","favorites.number":6}}
])
The document would be returned, with its array index in the field - index. If you want the entire document, with other array elements, you would have to $group, after $unwind instead of $match.
For previous versions, iterating the array in the client side, and getting the sub document's index would be the way to go.

mongodb , wildcard in $in

I have a mongodb query where i want to get documents if a field has particular value.
db.collection.find({key:{$in:['value1','value2']}}) if i run above command i get documents containing either 'value1' or 'value2'. but lets just say there are no values. and i search db.collection.find({key:{$in:[]}}), nothing is displayed. and db.collection.find({key:{$in:[*]}}) gives unexpected token* which wild card do i use in $in to show all results.?
I think this is logically consistent behavior for $in. The query
db.collection.find({ "key" : { "$in" : [] } })
could be translated as "find all the documents where the value of key is one of the values contained in the array []". Since there are no values in the array [], there are no matching documents. If you want to find all of the extant values for key, use .distinct to return them as an array:
db.collection.distinct("key")
.distinct will use an index if possible.
If you want a query to match all documents, omit the query selector from .find:
db.collection.find()
as suggested in the comments.

mongodb: Multikey indexing structure?

I'm finding it hard to understand how exactly indexing is done on multikeys in mongodb.
This is what I read about multikeys in mongodb docs on its website:
1) "Creating an index on an array element indexes results in the database indexing each element of the array"
2) "...will index all the tags on the document, and create index entries for "X", "Y" and "Z" for that document."
So what exactly does it mean by index entries for that document? Does each doc remember the entries, in which case searching is gonna be a full table scan? Or is it the same b-tree index of mysql where each index entry will point to multiple documents for each respective occurrence, in which case I'm over thinking too much.
Let's take an example:
obj1 = {
name: "Apollo",
text: "Some text about Apollo moon landings",
tags: [ "moon", "apollo", "spaceflight", "nasa" ]
}
obj2 = {
name: "Atlantis",
text: "Some text about Atlantis flight missions",
tags: [ "space", "atlantis", "spaceflight", "nasa" ]
}
db.articles.ensureIndex( { tags : 1 } )
Please help me understand! Thanks, in advance.
In this case, your index (which is a B-tree) would look like this:
apollo => [ obj1 ]
atlantis => [ obj2 ]
moon => [ obj1 ]
nasa => [ obj1, obj2 ]
space => [ obj2 ]
spaceflight => [ obj1, obj2 ]
This is just a "regular" B-tree index, except that every document can appear more than once (it appears once for every unique tag value).
I think you misunderstood the difference between Multiindex and Compound indexes:
Compound indexes are user-defined indexes for multiple fields at once.
Multykey indexes: MongoDB determine if the field on which the Index is released is an array and create an index for each of the array elements, for example
db.user.ensureIndex({"address.street":1});
In this case and because the target field is an Array the index will store all the items but only once.
I highly recomend you to take a look at this simple articlw that will clarify you doubts about simple imdex types in MongoDB: http://mongodbspain.com/en/2014/01/24/mongodb-indexes-part1/
Regards,

How do I do a "NOT IN" query in Mongo?

This is my document:
{
title:"Happy thanksgiving",
body: "come over for dinner",
blocked:[
{user:333, name:'john'},
{user:994, name:'jessica'},
{user:11, name: 'matt'},
]
}
What is the query to find all documents that do not have user 11 in "blocked"?
You can use $in or $nin for "not in"
Example ...
> db.people.find({ crowd : { $nin: ["cool"] }});
I put a bunch more examples here: http://learnmongo.com/posts/being-part-of-the-in-crowd/
Since you are comparing against a single value, your example actually doesn't need a NOT IN operation. This is because Mongo will apply its search criteria to every element of an array subdocument. You can use the NOT EQUALS operator, $ne, to get what you want as it takes the value that cannot turn up in the search:
db.myCollection.find({'blocked.user': {$ne: 11}});
However if you have many things that it cannot equal, that is when you would use the NOT IN operator, which is $nin. It takes an array of values that cannot turn up in the search:
db.myCollection.find({'blocked.user': {$nin: [11, 12, 13]}});
Try the following:
db.stack.find({"blocked.user":{$nin:[11]}})
This worked for me.
See http://docs.mongodb.org/manual/reference/operator/query/nin/#op._S_nin
db.inventory.find( { qty: { $nin: [ 5, 15 ] } } )
This query will
select all documents in the inventory collection where the qty field
value does not equal 5 nor 15. The selected documents will include
those documents that do not contain the qty field.
If the field holds an array, then the $nin operator selects the
documents whose field holds an array with no element equal to a value
in the specified array (e.g. , , etc.).