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!
Related
I am pretty sure this challenge has been solved by someone already but even searching with different words, I could not find a solution for this problem:
I try to give users the possibility to run certain functions of a class based on an argument like
service_class::do_this( "selection-argument" );
but the user shall be able to use "clear words" as well as "aliases" and even "well known" abbreviations or synonyms.
I use switch-case construction to call the "real" function.
Example: To get the contens of a folder, The user can use "getdir", "dir", "Directory", "getfolder", "getcontent", "content", "d-cont" and a number of more other "matching words" to start the function(s) underlaying and getting back the very same result.
Capture-ing lowercase/uppercase is simple. What I search for is an efficient way to capture all possible "variations" - that are, of course different number of variations for different functions called.
At the moment I use multiple "case "": lines after each other, but that makes the code quite long, and further I would like the user to be able to "enahnce" the recognition set for a certain function.
That's why I thought about "stripos" to determine first what "internal word" to use and only then run into the switch-case construction.
Anyone had that issue and can direct me to a "good and efficient" solution?
Seems that Stck-exchange itself had a similar challenge (https://codereview.stackexchange.com/tags/php/synonyms) ... maybe I can simply re-use the underlying code?
Thanks in advance and sorry if I overlooked a solution already posted.
You could use a database or array. Let's do the latter. So to determine whether an user wants to get a directory you would define an array like this:
$getDirVariants = ['getdir',
'dir',
'directory',
'getfolder',
'getcontent',
'content',
'd-cont'];
It is easy to add more of these arrays. To test the query word you would do:
$queryWord = strtolower($queryWord);
if (in_array($queryWord, $getDirVariants)) service_class::getDir(<arguments>);
elseif (in_array($queryWord, $deleteVariants)) service_class::delete(<arguments>);
You can easily add to the arrays or make it a 2D array to contain more commands. That array could also be placed in a database.
Especially when there are many commands, with many variants, a database will be the better solution, because you can find the query word with one database query.
There's a variation I can think of that will also simplify the code when there are many commands. You could use an associative array to find the command:
$commandVariants = ['getdir' => 'getdir',
'dir' => 'getdir',
'directory' => 'getdir',
'getfolder' => 'getdir',
'getcontent' => 'getdir',
'content' => 'getdir',
'd-cont' => 'getdir',
'delete' => 'delete',
'del' => 'delete',
'remove' => 'delete',
'unlink' => 'delete'];
$queryWord = strtolower($queryWord);
if (isset($commandVariants[$queryWord])) {
$command = $commandVariants[$queryWord];
service_class::$command(<arguments>);
}
else echo "I don't recognize that command.";
This uses a variable identifier.
I've asked to update an Object in mongo, (I am kinda new in NoSQL) so.. much I know is from guides and so, currently I am using this Codeigniter MongoDB library which simplifies the task.
So, this is the object I have stored in MongoDB:
{
"_id": ObjectID("5cfdc59844d81560d407a2e3"),
"equipo": "2bdca4c0-854d-4f73-bca8-cfb78a31f928",
"jugadores": {
"5361aa85-df9c-4099-8157-fd4d558622cc": {
"tipo": "i",
"estado": false,
"nombre": "name",
"apellido_st": "last_name",
"apellido_nd": "second_last_name",
"email": "email#example.com"
}
}
}
And this is the 'query' I am using to update it.
$this->mongo->where(array
(
"equipo" => "2bdca4c0-854d-4f73-bca8-cfb78a31f928",
"jugadores" => "5361aa85-df9c-4099-8157-fd4d558622cc"
))->set(array("estado" => true))->update("torneos_inscripciones");
Obviously.. isn't working and I can't find why is the problem exactly, the estado field isn't getting updated; probably is more simple than I though but can't get into it. The purpose is to update the estado field based on the jugadores uuid, in this case 5361aa85-df9c-4099-8157-fd4d558622cc
Based in B. Fleming answer, I made a change to the code:
$this->mongo->where(array(
"equipo" => "2bdca4c0-854d-4f73-bca8-cfb78a31f928",
"jugadores.5361aa85-df9c-4099-8157-fd4d558622cc" => array(
'$exists' => true
)))->set(array("jugadores.5361aa85-df9c-4099-8157-fd4d558622cc" => array("estado" => true)))->update("torneos_inscripciones");
The problem now is making the array empty only showing the estado field.
I'm not having much luck finding any good documentation for the CodeIgniter methods. Their documentation is terrible. From what I can find, however, I suspect that your problem is in your where query. Specifically, it looks like you're searching for the value 5361aa85-df9c-4099-8157-fd4d558622cc for the key jugadores. The problem with this lookup is that 5361aa85-df9c-4099-8157-fd4d558622cc is a field, not a value, so neither MongoDB nor CodeIgniter would know how to handle this lookup.
You might have more success by checking for the existence of the key 5361aa85-df9c-4099-8157-fd4d558622cc, rather than trying to match it as a value:
$this->mongo->where(array(
"equipo" => "2bdca4c0-854d-4f73-bca8-cfb78a31f928",
"jugadores.5361aa85-df9c-4099-8157-fd4d558622cc" => array(
'$exists' => true
)
))->set(array(
"jugadores.5361aa85-df9c-4099-8157-fd4d558622cc.estado" => true
))->update("torneos_inscripciones");
Please note that I used a single-quoted string, i.e. '$exists' instead of "$exists". This is important, because in PHP if you use double-quoted strings, words prefixed with a $ will be treated as a variable and evaluate the result before inserting into the string. Using single-quoted strings ensures that the value is not interpreted as a variable.
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));
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"));
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.