I'm implementing a very simple conversation system on mongodb.
The idea should be that when I'm opening a convo, it should display send and received messages. It's OK so far and should be pretty easy, by using a simple query like this pseudocode:
(from "my_id" AND to "friend_id") OR (from "friend_id" AND to "my_id")
this should be pretty straightforward and simple, but querying just looks so complicated to me with mongodb (I'm coming from mysql).
I'm trying this, but it's not working at all, and can't find out where the error is.
$cursor =$collection->find
(
array('$or' =>
array('$and' => array("from"=>"$profile", "to"=>"$loggeduser")),
array('$and' => array("to"=>"$profile", "from"=>"$loggeduser"))
)
)->limit(50)->sort(array('date' => -1));
this returns nothing.... Where's the mistake?
Thanks in advance.
Take a look at this page on how to do advanced MongoDB queries: http://www.mongodb.org/display/DOCS/Advanced+Queries
You can use a combination of the $and and $in operators to get what you need. Using the mongo shell, your query would look something like this:
db.yourCollectionName.find({$and: {from: {$in: ["toUser", "loggedOnUser"]}}, {to: {$in: ["toUser", "loggedOnUser"]}}})
I believe this may also give you the equivalent:
db.yourCollectionName.find({$and: {$or: [{from: "toUser"}, {to: "toUser"}]}}, {$or: [{from: "loggedOnUser"}, {to: "loggedOnUser"}]}}})
From there it's a matter of converting the above to the language/DSL that you're using, and sorting by date.
In your code, you don't need the ($and => array()) wrapping each of the objects that you're trying to find. Remove them, so it looks like this:
$cursor = $collection->find(
array('$or' =>
array(
array("from"=>"$profile", "to"=>"$loggeduser"),
array("to"=>"$profile", "from"=>"$loggeduser")
)
)
) ->limit(50)->sort(array('date' => -1));
Related
I have a php backend using phpredis (a php client for the redis server) to store key value pairs to a Redis server. The data I need to store is of this form:
"key1" => "v1", "v2", "v3"
"key2" => "m1", "m2", "m3"
"key3" => "n1", "n2", "n3"
...
Based on my research, I can set multiple keys in a redis using the mset command like so:
$redis->mSet(array('key0' => 'value0', 'key1' => 'value1'));
But what I actually need is something like this:
$redis->mSet(array('key0' => array('v1','v2','v3') , 'key1' => array('m1', 'm2', 'm3')));
But this just stores the value for each key as "Array" instead of the actual array specified.
Is this possible to do with a single command like mset or do I need to iterate my data and set each key separately using something like lPush?
phpredis documentation: https://github.com/phpredis/phpredis
So rather than using mSet you can probably use sADD to get your desired functionality.
$redis->sAdd($key, ...$data);
Full documentation on it here.
This would mean iterating and doing it in multiple steps for which I'd reccomend reading into Redis Pipelines and the non-shameless plug link which contains more information.
Which would look something like;
$redis = new Redis();
$pipeline = $redis->multi(Redis::PIPELINE);
foreach ($dataset as $data) {
$pipeline->sAdd($data['key'], ...$data['values']);
}
$pipeline->exec();
I can't think off the top of my head a way to do this in a singular operation, someone else might come along though who knows more than me :)
Edit: Looks like I misunderstood your question a little as it was more focused on doing this in a single operation. Hopefully the above is still useful but to my knowledge you'll have to do this with multiple.
I've got a fairly simple query that I have working in command line, and am trying to execute using php.
It's looking for documents that match all of the given "tags" entered in a search box:
db.collection.find( { $and: [ { tags: "cats" }, { tags: "video" } ] } )
I can't seem to figure out how to translate this to php. I've been using codeigniter for everything up to this point (Alex Bilbie's library), but have looked into building my own queries with no luck. Most of the methods I've tried eliminate the first tag (cats), since it is looking at the same field name (tags).
any thoughts?
PHP can be a bit tricky with how you need to format the arrays. What I've found to be the best way to create the queries is through doing things like:
json_encode($myQuery);
then comparing that to what actually works directly on the console of the app. In this case you're looking for:
$item = array('$and' => array(array('tags' => 'cats'), array('tags' => 'videos')))
which you can confirm by doing:
echo(json_encode(array('$and' => array(array('tags' => 'cats'), array('tags' => 'videos')))));
Good Luck!
I'm using the latest php mongo driver along with the latest mongodb 2.0. I'm trying to run a base query of host=x return the results then refine the search with other terms.
It's not returning any valid results.
I was thinking something like this, but its obviously not working:
$basefilter = array('host' => new MongoRegex("/1.1.1.1|2.2.2.2/i"));
$filter = array('host' => new MongoRegex("/2.2.2.2/i"));
$basereturn = $collection->find($basefilter);
$initreturn = $basereturn->find($filter);
$return = $initreturn->sort(array('date' => -1))->limit($limit)->skip($skip);
I want to just be able to refine my search. How can this be done?
You can't run a find over a cursor. find only works over collections. I suspect the above fatals out. You can map/reduce into a collection and run find on it.
you probably should scape your regex you have there since the dot is an operator in regex, so that should have been:
$basefilter = array('host' => new MongoRegex("/(1\.1\.1\.1)|(2\.2\.2\.2)/i"));
I've created a query in PHP which is used to add a user to an array. Right now it checks to see if they exist and if they don't it adds them to the array. Here's the full code:
try{ $this->users_db->update(
array(
'_id' => new MongoId($user_id) ,
new MongoId( $group_id ) => array('$nin'=>USER_GROUPS)
),
array(
'$push' => array(USER_GROUPS => array( GROUP_ID => new MongoId($group_id), USER_GROUP_NOTIFY => true ) )
)
); }
catch(Exception $e)
{ return false; }
The problem is that PHP is giving me the Warning "Illegal offset type" since MongoId() is an object and objects can't be used as keys in arrays. Any ideas about how to work around this?
I think you have the order of your "arguments" to $nin backwards. Your query is equivalent to something like this in the mongo shell:
db.users.update({_id: ObjectId("..."), ObjectId("..."): {$nin: ["user_groups"]}}, ...);
Which reads like English, left to right, when pronouncing "$nin" as "is not in". A more correct, by MongoDB's grammar, pronunciation is "does not contain", so your query is actually saying something like "where some ObjectId does not contain this array", which makes little sense when said out loud.
With that in mind, your query should look like:
db.users.update({_id: ObjectId("..."), user_groups: {$nin: [ObjectId("...")]}}, ...);
When running into issues like this with updates or removes, it's often useful to try the query spec portion as an argument to find() or findOne() to determine what's wrong there. Once you can find the document you want to update, you can re-write as a call to update(), remove(), etc.
Also, you should be aware that there is an $addToSet atomic operator which performs this sort of check for you atomically in the database. You could try:
db.users.update({_id: ObjectId("...")}, {$addToSet: {user_groups: ObjectId("...")}});
EDIT: For future reference to OP and other askers, see mongodb docs on query operators and mongodb docs on update operators.
So, I've decided to get my feet wet with MongoDB and love it so far. It seems very fast and flexible which is great. But, I'm still going through the initial learning curve and as such, I'm spending hours digging for info on the most basic things.
I've search throughout the MongoDB online documentation and have spent hours Googling through pages without any mention of this. I know Mongo is still quite new (v1.x) so it explains why there isn't much information yet. I've even trying looking for books on Mongo without much luck. So yes, I've tried to RTM with no luck, so, now I turn to you.
I have an Array of various Hashtags nested in each document (ie: #apples, #oranges, #Apples, #APPLES) and I would like to perform a case-insensitive find() to access all the documents containing apples in any case. It seems that find does support some regex with /i, but I can't seem to get this working either.
Anyway, I hope this is a quick answer for someone.
Here's my existing call in PHP which is case sensitive:
$cursor = $collection->find(array( "hashtags" => array("#".$keyword)))->sort(array('$natural' => -1))->limit(10);
Help?
I suspect your query is not returning what you really want...
If you do
db.col.find( { some_array_field: ["item1", "item2"] } );
then it will only match documents that have EXACTLY these two items in some_array_field. So if there is a document with [item1, item2] hashtags it will match, but a document with [item1, item2, item3] tags won't match.
You could use the $all argument as described in this post:
How do you do an AND query on an array in mongodb?
e.g.
db.col.find( { some_array_field: { $all : ["item1", "item2"] } } );
or:
db.col.find( { some_array_field: "item1", some_array_field: "item2" } );
This distinction of complete-document-match and partial-match was really confusing in MongoDB for me at first.
here is an example for case insensitive search in mongodb with php
$search_string='baR';
$searchQuery = array(
'$or' => array(
array(
'field1' => new MongoRegex("/^$search_string/i"),
),
array(
'field2' => new MongoRegex("/^$search_string/i"),
),
)
);
$cursor = $customers->find($searchQuery);
Hopes this help any.