$in mongoDB operator with _id in perl - perl

I try to execute this query with perl on a MongoDB database :
$db->$collection->find({"_id" : { "$in" : ["4f520122ecf6171327000137", "4f4f49c09d1bd90728000034"]}});
But it return nothing and it must return two documents. What is wrong with this query ?
Thank you.
Edit : It doesn't work too :
$db->$collection->find( {_id => "4f520122ecf6171327000137"} );

First, make sure you're using the correct syntax. Your first example is not valid Perl code, since you're including a chunk of JSON as the query parameter.
Second, assuming these ID values are MongoDB ObjectID's, you'll need to make OID objects in order to differentiate them from ordinary strings. And make sure to use single quotes ('') around $in, otherwise Perl will try to interpolate $in as a variable (which presumably has nothing in it).
So I assume you want to do something like this:
$db->$collection->find( {
"_id" => {
'$in' => [ MongoDB::OID->new( value => "4f520122ecf6171327000137" ),
MongoDB::OID->new( value => "4f4f49c09d1bd90728000034" )
]
}
} );
Edit: Additionally, using autoloaded method names to retrieve collections has been deprecated for a while. You're better off using $db->get_collection( "collection name" )->find( ... )

Related

mongodb- query for finding exact match but not case sensitive - what's wrong with it?

what is wrong with this query ?
db.collection.find( { "name" : "/^test$/i", "group" : "/^Default$/i"} )
I am trying to find an object with name=test, group=default, but not case sensitive.
but I am not getting the result although I know I have this document in the database:
I used exactly as in mongo website it's explained:
In MongoDB, you can also use regular expression objects (i.e. /pattern/) to specify regular expressions:
{ <field>: /pattern/<options> }
The query in its essence is right, you just have a minor syntax error.
In javascript (Which Mongo shell is based on) a regex is of the form of /xxx/ and not "/xxx/", the ladder being a string expression.
So just change your query into this:
db.collection.find( { "name" : /^test$/i, "group" : /^Default$/i} )

MongoDB check if value exists within array

I'm using MongoDB inside a twig framework. I'm trying to determine if the user has access to a certain module.
(a part of) my DB entry looks like:
_id: "579b50a4f5092761a20f4e71",
approvedModules: [
"examplemodule",
"examplemodule1",
"examplemodule2",
"examplemodule3"
],
My code looks like:
session.get('__AUTH_USER').find({ approvedModules : { '$in' : ["examplemodule"]}}, { '$exists' : true })
(the standard functions have to be in quotes).
I keeps returning false. I can only return the value if I use session.get('__AUTH_USER').approvedModules.0
I don't want to include the .0 because that might change.
What am I doing wrong?
Thanks in advance!
What am I doing wrong?
Many things. The worst one is using queries to database inside a template, but it is another problem.
You misunderstood purpose of the $in operator, which is used to match a field in the database to any element of array in the query.
To match any element of array in the collection to a single value you can do simple $eq:
session.get('__AUTH_USER').find({ approvedModules : "examplemodule"})
When you are using $in operator, you need to have 2 input arguments, the first one is the value for which you are checking the array, and the second one should be the array itself.
So, your bson element should look like this:
isModuleInArray : { '$in' : ["examplemodule","$approvedModules"] }

Storing a query in Mongo

This is the case: A webshop in which I want to configure which items should be listed in the sjop based on a set of parameters.
I want this to be configurable, because that allows me to experiment with different parameters also change their values easily.
I have a Product collection that I want to query based on multiple parameters.
A couple of these are found here:
within product:
"delivery" : {
"maximum_delivery_days" : 30,
"average_delivery_days" : 10,
"source" : 1,
"filling_rate" : 85,
"stock" : 0
}
but also other parameters exist.
An example of such query to decide whether or not to include a product could be:
"$or" : [
{
"delivery.stock" : 1
},
{
"$or" : [
{
"$and" : [
{
"delivery.maximum_delivery_days" : {
"$lt" : 60
}
},
{
"delivery.filling_rate" : {
"$gt" : 90
}
}
]
},
{
"$and" : [
{
"delivery.maximum_delivery_days" : {
"$lt" : 40
}
},
{
"delivery.filling_rate" : {
"$gt" : 80
}
}
]
},
{
"$and" : [
{
"delivery.delivery_days" : {
"$lt" : 25
}
},
{
"delivery.filling_rate" : {
"$gt" : 70
}
}
]
}
]
}
]
Now to make this configurable, I need to be able to handle boolean logic, parameters and values.
So, I got the idea, since such query itself is JSON, to store it in Mongo and have my Java app retrieve it.
Next thing is using it in the filter (e.g. find, or whatever) and work on the corresponding selection of products.
The advantage of this approach is that I can actually analyse the data and the effectiveness of the query outside of my program.
I would store it by name in the database. E.g.
{
"name": "query1",
"query": { the thing printed above starting with "$or"... }
}
using:
db.queries.insert({
"name" : "query1",
"query": { the thing printed above starting with "$or"... }
})
Which results in:
2016-03-27T14:43:37.265+0200 E QUERY Error: field names cannot start with $ [$or]
at Error (<anonymous>)
at DBCollection._validateForStorage (src/mongo/shell/collection.js:161:19)
at DBCollection._validateForStorage (src/mongo/shell/collection.js:165:18)
at insert (src/mongo/shell/bulk_api.js:646:20)
at DBCollection.insert (src/mongo/shell/collection.js:243:18)
at (shell):1:12 at src/mongo/shell/collection.js:161
But I CAN STORE it using Robomongo, but not always. Obviously I am doing something wrong. But I have NO IDEA what it is.
If it fails, and I create a brand new collection and try again, it succeeds. Weird stuff that goes beyond what I can comprehend.
But when I try updating values in the "query", changes are not going through. Never. Not even sometimes.
I can however create a new object and discard the previous one. So, the workaround is there.
db.queries.update(
{"name": "query1"},
{"$set": {
... update goes here ...
}
}
)
doing this results in:
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 52,
"errmsg" : "The dollar ($) prefixed field '$or' in 'action.$or' is not valid for storage."
}
})
seems pretty close to the other message above.
Needles to say, I am pretty clueless about what is going on here, so I hope some of the wizzards here are able to shed some light on the matter
I think the error message contains the important info you need to consider:
QUERY Error: field names cannot start with $
Since you are trying to store a query (or part of one) in a document, you'll end up with attribute names that contain mongo operator keywords (such as $or, $ne, $gt). The mongo documentation actually references this exact scenario - emphasis added
Field names cannot contain dots (i.e. .) or null characters, and they must not start with a dollar sign (i.e. $)...
I wouldn't trust 3rd party applications such as Robomongo in these instances. I suggest debugging/testing this issue directly in the mongo shell.
My suggestion would be to store an escaped version of the query in your document as to not interfere with reserved operator keywords. You can use the available JSON.stringify(my_obj); to encode your partial query into a string and then parse/decode it when you choose to retrieve it later on: JSON.parse(escaped_query_string_from_db)
Your approach of storing the query as a JSON object in MongoDB is not viable.
You could potentially store your query logic and fields in MongoDB, but you have to have an external app build the query with the proper MongoDB syntax.
MongoDB queries contain operators, and some of those have special characters in them.
There are rules for mongoDB filed names. These rules do not allow for special characters.
Look here: https://docs.mongodb.org/manual/reference/limits/#Restrictions-on-Field-Names
The probable reason you can sometimes successfully create the doc using Robomongo is because Robomongo is transforming your query into a string and properly escaping the special characters as it sends it to MongoDB.
This also explains why your attempt to update them never works. You tried to create a document, but instead created something that is a string object, so your update conditions are probably not retrieving any docs.
I see two problems with your approach.
In following query
db.queries.insert({
"name" : "query1",
"query": { the thing printed above starting with "$or"... }
})
a valid JSON expects key, value pair. here in "query" you are storing an object without a key. You have two options. either store query as text or create another key inside curly braces.
Second problem is, you are storing query values without wrapping in quotes. All string values must be wrapped in quotes.
so your final document should appear as
db.queries.insert({
"name" : "query1",
"query": 'the thing printed above starting with "$or"... '
})
Now try, it should work.
Obviously my attempt to store a query in mongo the way I did was foolish as became clear from the answers from both #bigdatakid and #lix. So what I finally did was this: I altered the naming of the fields to comply to the mongo requirements.
E.g. instead of $or I used _$or etc. and instead of using a . inside the name I used a #. Both of which I am replacing in my Java code.
This way I can still easily try and test the queries outside of my program. In my Java program I just change the names and use the query. Using just 2 lines of code. It simply works now. Thanks guys for the suggestions you made.
String documentAsString = query.toJson().replaceAll("_\\$", "\\$").replaceAll("#", ".");
Object q = JSON.parse(documentAsString);

Perl mongo->collection count using '$in' operator

I was wondering if it was possible to use the "in" operator as you can from the mongo shell, using the perl MongoDB::Collection module. I have tried a number of things, but haven't quite got the result I am expecting. I've check the docs and other posts on stackoverflow but can't seem to find anything specifically about this, unless I am overlooking something.
http://docs.mongodb.org/manual/reference/operator/query/in/
The count query I am running via the mongo shell is
mongo:PRIMARY> db.getCollection("Results").count( { TestClass : "TestClass", TestMethod : { $in: ["method1" , "method2", "method3"] } })
181605
I have tried this a few different ways passing the list as an array or hash-refs or pre-building a string...
my $count = $mongo->{collection}->count({
'TimeStamp' => { '$gt' => $ft, '$lt' => $tt },
'TestClass' => $TestClass,
'TestMethod' => { '$in' => [$whitelist->methods] },
'Result' => $result
});
Where Dumping $whitelist->methods is
$VAR1 = {
'method1' => 1,
'method2' => 1,
'method3' => 1
};
I've looked high and low for an answer, does anyone know if the driver is currently capable of using the $in operator like this? Looping through the returned methods from a previous query and adding up the results will require more code.
The only other stack overflow post I have seen about the $in operator was this $in mongoDB operator with _id in perl recommending using http://api.mongodb.org/perl/current/MongoDB/OID.html but don't think that is relevant in my example as looks more to do with ID's.
Any help or discussion would be greatly appreciated.
The problem is that $in clause expects its value to be an array reference, but you supply a hashref (as Dumper's output shows) into it. The easiest way to turn the latter into the former is to apply keys function:
# ...
'TestMethod' => { '$in' => [keys %{$whitelist->methods}] }
... or just [keys $whitelist->methods], if you're using Perl 5.14+, as ...
starting with Perl 5.14, keys can take a scalar EXPR, which must
contain a reference to an unblessed hash or array
.

MongoDB : use $ positional operator for querying

I have a collection with entries that look like :
{
"userid": 1,
"contents": [
{ "tag": "whatever", "value": 100 },
{"tag": "whatever2", "value": 110 }
]
}
I'd like to be able to query on that collection and returning only one part of the array : the one matching the query. I'm trying to use the $ positional operator to do so but it hasn't worked so far.
Here is more precisely what I'd like to do :
collection.find({'contents.tag':"whatever"},{'contents.$.value':1})
As a result I expect sth with only the value corresponding to the entry in the array that matched query, which is 100 in this case.
Do you know what's wrong ? I was thinking that maybe the $ operator can only be used for update and not for querying. Anyone in the know ?
Thanks !
Yes, you are correct - the positional operator is used for updating an object.
The solution for now would be to return the array an pull the field out in your application.
There is an open enhancement request for this feature (in queries):
https://jira.mongodb.org/browse/SERVER-828
For more information on the positional operator, see:
http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator
What you are looking for is the $elemMatch operator.
It might be an overkill, but I guess you can use map-reduce for this.
first, pre-filter with a query, emit all array elements in map, filter the ones that do not match either in emit or in reduce. If you don't set out everything will happen in RAM.
If you have to run those kinds of queries often, it might be worthwhile to duplicate the data.
Nevertheless, I hope the SERVER-828 will be implemented soon!
Create a query with $in instead and add your equal value to the array, this can solve your issue
$users_array = array(xxxxxxxx,yyyyyy);
$user = Db::find('fb_users', array(
'facebook_id' => array(
'$in' => array($users_array)
)
));