I'm using nodejs and mongodb.
x is a variable containing a string (certain color). now, I would like to create a query (in nodejs) that retrieves all docs which their colors field (which is a list of strings, in this case a list of colors) contains the string x.
How should I write it in nodejs?
Your question is a bit confusing, because in the first paragraph you are asking for an OR relation, but your example describes an AND relation.
When you want to find all documents which have red OR green, you have to use the $in operator:
db.collection.find({ colors: { $in:[ "red", "green" ]} });
When you want to find all documents which have red AND green (and maybe also others), you have to use $all:
db.collection.find({ colors: { $all:[ "red", "green" ]} });
Source: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries
Related
What I am trying to achieve is to find a document by its name and the language.
My current attempt looks like the following one:
Model.find({"name.language": languageIso2, "name.value": { "$regex": search, "$options": "i" }}, (error, SpecialConditons) => {...})
Unfortunately, it doesn't work, because of the following case:
lets say the language is "gb" and you use "a" as a filter for the name, this would send you the model shown in the picture above, because the array "name" contains both (1) the language "gb" and (2) the "a" in the object containing the Finnish translation "Touretten syndrooma".
What I want to achieve is to look for the object that contains "gb" as a language and if the object containing the "gb" also includes an "a" in the value field then it should send me the model back. In this case the value for "gb" doesn't contain an "a", so it should not send it back.
Any idea how to achieve this? Thanks in advance
I have two objects:
{
genre: ['music', 'movie']
}
and
{
genre: ['movie', 'music']
}
and my query is:
db.test.find({genre :{ $elemMatch:{ $in : ['movie']}}})
and it only gives me the second object. Why? I want to get all the docs that contain a specific genre in their arrays no matter where in the array. How can I do this?
You need neither $elemMatch nor $in in this case. A simple field:value will match documents where field is an array and any one of the values in that array is value. That means
db.test.find({genre :'movie'});
will suffice.
The array query operators are required in more complex situations.
$in is needed when you have a list of possible values and want documents where any of them is found (so db.test.find({genre : { $in:['movie']} }); would work, but would be needlessly convoluted)
$all works like $in but requires that all provided elements are in the array
$elemMatch is a bit more complex. It is required when you want to use multiple operator-conditions (like $gt or $lt) but want only those documents where one array entry matches all the conditions. Without the $elemMatch operator, you get results where each condition is met by at least one array entry, but not necessarily all by the same entry.
Remember db.test.find() in general returns you cursor object. You can access all doc as follows:
entry = db.test.find({genre :{ $elemMatch:{ $in : ['movie']}}})
for doc in entry:
print(doc)
I try to use text-index in mongodb:
{$text: {$search: 'sport hockey'}}
Is uses OR condition for searching by phrase: 'sport' OR 'hockey'. For example the result can be the following list of titles:
Sport something today...
Sport is hockey
Hockey players
The most relevant document is on the second position (actually I'd like to exclude all other results except this one: 'Sport is hockey').
Is it possible to use AND condition in $text?
Quotation marks are not suitable because {$text: {$search: "\"sport hockey\""}} uses search by exact match.
try to include textScore in your output then sort by it to get most relevant documents (optionally use limit to get top n relevant documents).
db.your_collection.find(
{
$text: { $search: "sport hockey" }
}, {
score: { $meta: "textScore" }
}
).sort(
{
score: { $meta: "textScore" }
}
).limit(2)
The text search does not provide this out-of-the-box. But there are two possible workarounds.
Use the pre-2.6 solution for text search: Break your text field into individual words and safe the individual words as an array in the same documents. You can then perform a $all query on that array.
Perform separate text-searches for each word and generate the set intersection on the application layer.
use as Follow
db.your_collection.find({$text:{$search:' "sport" "hockey" '}})
"text" type search word must be included!
For anyone coming to this thread again, required search criteria of "AND" can be achieved using following find query
{$text:{$search:"\"sport\" \"hockey\""}}
Give attention to how different words are escaped.
In node js, following can be done to create desire search text for "AND" condition
searchText = '"' + userInput.split(" ").join('" "') + '"';
then
collectionObj.find({$text:{$search:searchText}})
I'm building a web application over Node.js and MongoDB which is based on geolocated points.
The document is something like this:
{ name: ""
keywords: [Array of strings]
location: {lng: double, lat: double }
}
I am wondering how could I use find() to find documents that are near from a coordinate but, in addition, are coincident with any of he keywords in the keywords array.
Imagine that keywords are: ["restaurant", "bar", "coffee"]
I've looked into 2d Index, but the secondary index must be a string. It can't be an array of strings.
The problem is that a document could have more than one keyword (or category) so I can't use a simple string to query them
How would you implement this?
Thanks!
What version of mongo? It looks like this was added in 2.4.0: SERVER-8457
I've got an ElasticSearch index with a large set of product properties. They are all looking like that:
{'_id':1,'type':'manufacturer','name':'Toyota'},
{'_id':2,'type':'color','name':'Green'},
{'_id':3,'type':'category','name':'SUV Cars'},
{'_id':4,'type':'material','name':'Leather'},
{'_id':5,'type':'manufacturer','name':'BMW'},
{'_id':6,'type':'color','name':'Red'},
{'_id':7,'type':'category','name':'Cabrios'},
{'_id':8,'type':'material','name':'Steel'},
{'_id':9,'type':'category','name':'Cabrios Hardtop'},
{'_id':10,'type':'category','name':'Cabrios Softtop'},
... and 1 Mio. more ...
There are 4 different types of product properties existing: Categories, Manufacturers, Colors and Materials.
The question: How can i query with only one query (it's a settled performance requirement) the best matching result for each type?
So if i request a full text search query i.e. "Green Toyota Cabrios" i should get the following results:
{'_id':2,'type':'color','name':'Green'},
{'_id':1,'type':'manufacturer','name':'Toyota'},
{'_id':7,'type':'category','name':'Cabrios'},
{one matching result of the 'material'-type if found by the query}
That would be the perfect result set, always at maximum 4 results (for each 'type' one result). If there is no matching result for a specific type available there should be just 3 result items returned.
How is that possible with Elasticsearch? Thanks for your ideas!
I don't understand clearly your use case. What are you indexing in fact?
If you index cars, you should index it like:
{
"color": "Green",
"manufacturer": "Toyota",
"category": "Cabrios"
}
That said, from the question you ask:
You can probably define your fields as not_indexed. That way, if you search for "Green Toyota Cabrios" if field "name" you won't get "Cabrios Hardtop".
Not sure I really answered but I don't see your use case...