MongoDB query _id - mongodb

So in my MongoDB test the _id field is a unique string in format of "SensorSN:YrMonthDay"
What I want to query is all data for 2016 month 3. But I can't quite get the Regex right.
So here is some sample _ids:
12345678:2016325
87654321:2016325
Basically I want to return both of the documents because they are in the month of March.
My first attempts have been similar to db.collection.find({'_id':'/:20163/'}) and so far no luck.
Thanks!

Take off the quotes, the find is looking for a string matching exactly that instead of doing the regex search.
db.collection.find({ '_id': /:20163/ })
or
db.collection.find({ _id: /:20163/ })
both work fine for me!
Your case would only match if your sample document was:
{ _id: "/:20163/" }

Remove the quotes
db.collection.find({ _id: /:20163/ });
Or try using regex -
db.collection.find({ _id: { $regex: /:20163/ } });
https://docs.mongodb.com/manual/reference/operator/query/regex/

Related

How to write a mongo query that returns fields with the expected results?

For instance I am trying to bring up the organization ids that are tagged to multiple countries in db.
db.collection.find({"Region":{$in:["CHINA","JAPAN","SOUTH_KOREA"]}})
this doesnot give me the results that they have all 3 countries in the same document. Obviously $where does not work which I can query to bring up the fields that have more than 1 country in it.
Trying this for 2 days and need your help.
Thanks in advance.
Use $all
The $all operator selects the documents where the value of a field is an array that contains all the specified elements.
db.collection.find({"Region":{ $all :["CHINA","JAPAN","SOUTH_KOREA"] } })
i hope this will go acording youre need's:
db.collection.find({
$and: [
{ Region: {$in: /\bCHINA\b/i} },
{ Region: {$in: /\bJAPAN\b/i} },
{ Region: {$in: /\bSOUTH_KOREA\b/i} }
]
})
If I'm understanding your question correctly, you are trying to match a document where the Region key is a list conataining all three countries.
db.collection.find({$and: [
{Region: {$in: ["CHINA"]}},
{Region: {$in: ["JAPAN"]}},
{Region: {$in: ["SOUTH_KOREA"]}}
])
If so, this should work for you.
These two queries worked in my case. They are as simple as they look like but somehow I missed them our after many trials I may have miswritten them. Anyways here is the solution to my question:
db.collection.find({region:{$size:3}})
db.collection.find({ "region.2":{$exists:true}})

How to find in MongoDB by last 4 chars in ObjectID?

I don't want to expose the full object ID to the client, instead I want to show him only a short of the last 4 chars of the actual object ID of an entity in the collection.
For example: ObjectId("5fcca5d997239a74da0d67a9") will become just 67a9
So it will be much easier to "talk" with ids of documents instead of the full object it.
Then I need to find the document in the DB using only the 67a9.
Is this possible and how?
According to this issue in Jira the resolution is "Won't fix".
ObjectId is not a String, is another object, so $regex is no possible.
Check this example where $regex works ok when _id is an String but not an ObjectId.
So one possible option is duplicate every field _id in another field called id or whatever where the id is in String format.
Then, you can do this query:
db.collection.find({
"_id": {
"$regex": "67a9$"
}
})
Example here where I've added more _id fields that not match the pattern
As pointed out, regex won't work on an ObjectId. But there is an easy workaround. Just use aggregation to first convert your ObjectId into a string and then match it.
db.collection.aggregate([
{
$addFields: {
tempId: { $toString: '$_id' },
}
},
{
$match: {
tempId: { $regex: "67a9"}
}
}
])
Obviously not a great solution to use on very large collections.

Meteor collection get last document of each selection

Currently I use the following find query to get the latest document of a certain ID
Conditions.find({
caveId: caveId
},
{
sort: {diveDate:-1},
limit: 1,
fields: {caveId: 1, "visibility.visibility":1, diveDate: 1}
});
How can I use the same using multiple ids with $in for example
I tried it with the following query. The problem is that it will limit the documents to 1 for all the found caveIds. But it should set the limit for each different caveId.
Conditions.find({
caveId: {$in: caveIds}
},
{
sort: {diveDate:-1},
limit: 1,
fields: {caveId: 1, "visibility.visibility":1, diveDate: 1}
});
One solution I came up with is using the aggregate functionality.
var conditionIds = Conditions.aggregate(
[
{"$match": { caveId: {"$in": caveIds}}},
{
$group:
{
_id: "$caveId",
conditionId: {$last: "$_id"},
diveDate: { $last: "$diveDate" }
}
}
]
).map(function(child) { return child.conditionId});
var conditions = Conditions.find({
_id: {$in: conditionIds}
},
{
fields: {caveId: 1, "visibility.visibility":1, diveDate: 1}
});
You don't want to use $in here as noted. You could solve this problem by looping through the caveIds and running the query on each caveId individually.
you're basically looking at a join query here: you need all caveIds and then lookup last for each.
This is a problem of database schema/denormalization in my opinion: (but this is only an opinion!):
You could as mentioned here, lookup all caveIds and then run the single query for each, every single time you need to look up last dives.
However I think you are much better off recording/updating the last dive inside your cave document, and then lookup all caveIds of interest pulling only the lastDive field.
That will give you immediately what you need, rather than going through expensive search/sort queries. This is at the expense of maintaining that field in the document, but it sounds like it should be fairly trivial as you only need to update the one field when a new event occurs.

MongoDB: distinct tuples

Suppose to have a collection of MongoDB documents with the following structure:
{
id_str: "some_value",
text: "some_text",
some_field: "some_other_value"
}
I would like to filter such documents so as to obtain the ones with distinct text values.
I learned from the MongoDB documentation how to extract unique field values from a collection, using the distinct operation. Thus, by performing the following query:
db.myCollection.distinct("text")
I would obtain an array containing the distinct text values:
["first_distinct_text", "second_distinct_text",...]
However, this is not the result that i would like to obtain. Instead, I would like to have the following:
{ "id_str": "a_sample_of_id_having_first_distinct_text",
"text": "first_distinct_text"}
{ "id_str": "a_sample_of_id_having_second_distinct_text",
"text": "second_distinct_text"}
I am not sure if this can be done with a single query.
I found a similar question which, however, do not solve fully my problem.
Do you have any hint on how to solve this problem?
Thanks.
You should look into making an aggregate query using the $group stage, and probably using the $first operator.
Maybe something along the lines of:
db.myCollection.aggregate([{ $group : { _id : { text: "$text"},
text: { $first: "$id_str" }
}
}])
try:
db.myCollection.aggregate({$group: {_id: {'text': "$text", 'id_str': '$id_str'}}})
More information here: http://docs.mongodb.org/manual/reference/method/db.collection.aggregate/

Checking if a field contains a string

I'm looking for an operator, which allows me to check, if the value of a field contains a certain string.
Something like:
db.users.findOne({$contains:{"username":"son"}})
Is that possible?
You can do it with the following code.
db.users.findOne({"username" : {$regex : "son"}});
As Mongo shell support regex, that's completely possible.
db.users.findOne({"username" : /.*son.*/});
If we want the query to be case-insensitive, we can use "i" option, like shown below:
db.users.findOne({"username" : /.*son.*/i});
See: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RegularExpressions
https://docs.mongodb.com/manual/reference/sql-comparison/
http://php.net/manual/en/mongo.sqltomongo.php
MySQL
SELECT * FROM users WHERE username LIKE "%Son%"
MongoDB
db.users.find({username:/Son/})
As of version 2.4, you can create a text index on the field(s) to search and use the $text operator for querying.
First, create the index:
db.users.createIndex( { "username": "text" } )
Then, to search:
db.users.find( { $text: { $search: "son" } } )
Benchmarks (~150K documents):
Regex (other answers) => 5.6-6.9 seconds
Text Search => .164-.201 seconds
Notes:
A collection can have only one text index. You can use a wildcard text index if you want to search any string field, like this: db.collection.createIndex( { "$**": "text" } ).
A text index can be large. It contains one index entry for each unique post-stemmed word in each indexed field for each document inserted.
A text index will take longer to build than a normal index.
A text index does not store phrases or information about the proximity of words in the documents. As a result, phrase queries will run much more effectively when the entire collection fits in RAM.
As this is one of the first hits in the search engines, and none of the above seems to work for MongoDB 3.x, here is one regex search that does work:
db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )
No need to create and extra index or alike.
Here's what you have to do if you are connecting MongoDB through Python
db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})
you may also use a variable name instead of 'Son' and therefore the string concatenation.
Simplest way to accomplish this task
If you want the query to be case-sensitive
db.getCollection("users").find({'username':/Son/})
If you want the query to be case-insensitive
db.getCollection("users").find({'username':/Son/i})
ideal answer its use index
i option for case-insensitive
db.users.findOne({"username" : new RegExp(search_value, 'i') });
This should do the work
db.users.find({ username: { $in: [ /son/i ] } });
The i is just there to prevent restrictions of matching single cases of letters.
You can check the $regex documentation on MongoDB documentation.
Here's a link: https://docs.mongodb.com/manual/reference/operator/query/regex/
I use this code and it work for search substring
db.users.find({key: { $regex: new RegExp(value, 'i')}})
If you need to do the search for more than one attribute you can use the $or. For example
Symbol.find(
{
$or: [
{ 'symbol': { '$regex': input, '$options': 'i' } },
{ 'name': { '$regex': input, '$options': 'i' } }
]
}
).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
Here you are basing your search on if the input is contained in the symbol attribute or the name attribute.
If the regex is not working in your Aggregate solution and you have nested object. Try this aggregation pipeline: (If your object structure is simple then, just remove the other conditions from below query):
db.user.aggregate({$match:
{$and:[
{"UserObject.Personal.Status":"ACTV"},
{"UserObject.Personal.Address.Home.Type":"HME"},
{"UserObject.Personal.Address.Home.Value": /.*son.*/ }
]}}
)
One other way would be to directly query like this:
db.user.findOne({"UserObject.Personal.Address.Home.Value": /.*son.*/ });
If your regex includes a variable, make sure to escape it.
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
This can be used like this
new RegExp(escapeRegExp(searchString), 'i')
Or in a mongoDb query like this
{ '$regex': escapeRegExp(searchString) }
Posted same comment here
For aggregation framework
Field search
('$options': 'i' for case insensitive search)
db.users.aggregate([
{
$match: {
'email': { '$regex': '#gmail.com', '$options': 'i' }
}
}
]);
Full document search
(only works on fields indexed with a text index
db.articles.aggregate([
{
$match: { $text: { $search: 'brave new world' } }
}
])
How to ignore HTML tags in a RegExp match:
var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest cat species, most recognizable for its pattern of dark vertical stripes on reddish-orange fur with a lighter underside. The species is classified in the genus <i>Panthera</i> with the lion, leopard, jaguar, and snow leopard. It is an apex predator, primarily preying on ungulates such as deer and bovids.</p>';
var searchString = 'largest cat species';
var rx = '';
searchString.split(' ').forEach(e => {
rx += '('+e+')((?:\\s*(?:<\/?\\w[^<>]*>)?\\s*)*)';
});
rx = new RegExp(rx, 'igm');
console.log(text.match(rx));
This is probably very easy to turn into a MongoDB aggregation filter.