Find doc from field having all specified words - mongodb

I've problem to find the good document search request do find all documents containing in their 'name' field all the specified values.
I've this document:
{
"_id" : ObjectId("607c1caa4b2964d0185301ff"),
"nb" : 1,
"name" : "mini computer 24GB"
}
When I run the following find request...
db.getCollection('test').find({"$text":{$search:'computer dummy'}})
... the document is returned. An OR is done but I want a AND operation. Should I use a list of $and ?
Many thanks

Ok I found. each word must be in quotes as this:
db.getCollection('test').find({$text:{$search:"\"computer\" \"24GB\""}})
Not really intuitive!

Related

Find a document by a partial String value inside an array element on MongoDB from Azure

I'm trying to find all lists which the person number has '-' or '.' inside of it. I already tried this answer, but it's not working for elements inside of the array.
But when I try to find by the entire String, without the regex notation, the document is found.
Per example:
db.getCollection('list').find({"persons.number": "123456789"}) //works!
db.getCollection('list').find({"persons.number": /3/}) //not work...
db.getCollection('list').find({"persons.number": /.*3.*/}) //not work
db.getCollection('list').find({"persons.number": /.*..*/}) //not work
db.getCollection('list').find({"persons.number": /.*[-\.]+.*/}) //not work
If I try to find the document by some attribute outside of the array (an attribute from the list, per example), the /3/, /.*3.*/ and /.*[-\.]+.*/ works.
Document format:
{
"_id" : ObjectId("5af3037ee8006c4a04e84b2f"),
"id" : 1,
"persons" : [
{
"id" : 1,
"number" : "123.123.123-22"
},
{
"id" : 2,
"number" : "123.456.789-11"
}
]
}
So, what are the options?
I'm using the MongoDB from Azure. Executing the db.version() on console returns 3.2.0.
The regex .*[-\.]+.* should work,
Try this,
db.getCollection('list').find({"persons.number": /.*[-\.]+.*/})
For searching multiple patterns , i.e an OR of patterns the regex format is little different.
(pattern1)|(pattern2)
Tried the below mongo query on my local running 3.4.6 , but it should work on 3.2.x as well
db.list.aggregate([{"$unwind":{"path":"$persons"}},{"$project":{"_id":1,"persons.number":1}},{"$match":{"persons.number":{"$regex":/.*(\.)|(\-).*/}}},{"$group":{_id:"$_id"}}])

compare multiple value in same document in mongodb

My question was, how to find all title of the releases contains the artist name
Here is the 2 Documents for just an example:
`{"release" : {"title" : "DEF day",
"artists" : {"artist" : {"role" : "1","name" : "DEF"}}}
}
{ "release" : {"title" : "XYZ day",
"artists" : {"artist" : {"role" : "1","name" : "KYC"}}}
}`
when i run this following query:
`db.test.find({$where:
"this.release.title.indexOf(this.release.artists.artist.name) > -1"
})`
I get the result "DEF day", so it works excellent!!
BUT, once i run this query to my original data(same format like above) i get this:
`error: {
"$err" : "TypeError: Object 30 has no method 'indexOf'\n at _funcs1 (_funcs1:1:49) near 'his.release.artists.a' ",
"code" : 16722
}`
My collection is big (8GB+).
Just looking at the above error, can anyone tell what may be the problem with the above query? your answer is appreciated. please.
The problem is in the data itself. Somewhere you have a document, where the title field is not String, thus invoking indexOf on the whole data, on that particular document you get the error.
One thing you can do to solve this problem is first of all find that erroneous document. To do that you will need to run a simple query.
MongoDB has the $type operator, which matches fields by their type. And here is the list of all available BSON types a MongoDB document field can have.
The id of String BSON type is 2, thus you need all the documents that have type of title field not equal to 2.
find({field: {$not: {$type: <BSON type>}}}))
After finding the document(s), you may fix or remove them.

Search full document in mongodb for a match

Is there a way to match a value with every array and sub document inside the document in mongodb collection and return the document
{
"_id" : "2000001956",
"trimline1" : "abc",
"trimline2" : "xyz",
"subtitle" : "www",
"image" : {
"large" : 0,
"small" : 0,
"tiled" : 0,
"cropped" : false
},
"Kytrr" : {
"count" : 0,
"assigned" : 0
}
}
for eg if in the above document I am searching for xyz or "ab" or "xy" or "z" or "0" this document should be returned.
I actually have to achieve this at the back end using C# driver but a mongo query would also help greatly.
Please advice.
Thanks
You could probably do this using '$where'
db.mycollection({$where:"JSON.stringify(this).indexOf('xyz')!=-1"})
I'm converting the whole record to a big string and then searching to see if your element is in the resulting string. Probably won't work if your xyz is in the fieldnames!
You can make it iterate through the fields to make a big string and then search it though.
This isn't the most elegant way and will involve a full tablescan. It will be faster if you look through the individual fields!
While Malcolm's answer above would work, when your collection gets large or you have high traffic, you'll see this fall over pretty quickly. This is because of 2 things. First, dropping down to javascript is a big deal and second, this will always be a full table scan because $where can't use an index.
MongoDB 2.6 introduced text indexing which is on by default (it was in beta in 2.4). With it, you can have a full text index on all the fields in the document. The documentation gives the following example where a text index is created for every field and names the index "TextIndex".
db.collection.ensureIndex(
{ "$**": "text" },
{ name: "TextIndex" }
)

How many level can mongodb append sub-documents dynamicaly?

It seems that i can go further than one subdocument if i want to add it dynamicaly, here is the code:
db.users.update({"pup.cmn.id":id}, {"$addToSet":{"pup.cmn":{"abus":email}}})
this give error:
OperationFailure: can't append to array using string field name: cmn
then, if i add positional element i get this:
db.users.update({"pup.cmn.id":id}, {"$addToSet":{"pup.$.cmn":{"abus":email}}})
"cmn" :
[
{
"fto" : ObjectId("5190e8a53a5f3a0c102af045")
"id" : "14.05.2013 12:29:53"
},
{
"abus" : "u...#example.com"
}
]
so as you can see, it will add it in the same level, and i dont want that, because the application will get errors.
It seems that Mongodb for the time of writing (2.4.x) have not this feature, there is a ticket:
https://jira.mongodb.org/browse/SERVER-831

How do I remove an element in an array based on content?

I am working with MongoDB and Perl. Here is my data structure:
{
"_id" : ObjectId("501976f8005c8b541d000000"),
"err_id" : "err",
"solution" : [
{
"attachment" : "attach",
"macr" : "macrs",
"yammer" : "yam",
"resolution" : "l",
"salesforce" : "salesforce",
"username" : "bob"
},
{
"attachment" : "attach",
"macr" : "macrs",
"yammer" : "yam",
"resolution" : "losssss",
"salesforce" : "salesforce",
"username" : "bob"
}
]
}
As you can see, I have an array with objects inside. I have created this using the Perl MongoDB library.
I am familiar with some syntax for manipulating arrays in the Perl MongoDB lib. For example, I use this to find entries with a username the same as $username.
$users->find({"solution.username" => $username});
I thought removing an element would be as simple:
$users->remove({"solution.username" => $username});
But alas, it is not so. I have tried this and using pull, but to no avail! I've had a hard time finding this. Does anybody know the syntax to remove an array element based on the contents of one of its fields?
The MongoDB::Collection remove() method will remove documents matched by your query .. so definitely not what you are looking for.
To delete specific fields you should use $unset.
Your solution.usernames are actually in an array, so you would have to include an array index for the fields to delete, eg:
$users->update({"_id" => '123'}, {
'$unset' => {
'solution.0.username' => 1,
'solution.1.username' => 1
}
});
I'm not aware of a shorter syntax to unset all fields matching username within the solution array, but you can add multiple solution.#.username fields to the $unset command.
My example above deletes the first two username entries from the array. If the matching document(s) had more than two username entries, each time you ran this update you would delete up to two more entries (if they exist).