let's say I have a column in my database table that contains a list of comma-separated values like:
MyTable.values = a,b,c,d,e,f,etc....
How do I construct the condition in the find('all') function of cakePHP to retrieve the entries whose MyTable.values contain let's say "c" for example
Thanks
You should be able to use the LIKE operator. Percent-sign is a wildcard.
<?php
$this->Model->find("all", array(
"conditions" => array("Model.field LIKE" => "%c%")
));
?>
Gotta love that automagic.
Edit: Found it! The complex find conditions page has official documentation on this, though it's kind of buried.
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 use this script to get the collection of my mongo database: http://datatables.net/development/server-side/php_mongodb
My question is: how to retrieve the rows where foo == 'mystring' only?
As you will notice (on line 29) from the source code in the file the mongo collection has been given the name: $m_collection as such:
$m_collection->find(array('foo' => 'mystring'))
Should work.
If this is not what you are looking for maybe you can be more specific and explain exactly what you are trying to do.
UPDATE
It has come to my attention you might want to instead edit the $searchTermsAll variable to search by this field in a doc. By the looks of it this PHP class links in the same as it would normally for SQL as such you should need to do anyhting special and can just enable filtering on datatables and add the value mystring to the foo field.
However to know if it is the right answer you will need to clarify.
UPDATE 2
A more destructive way of doing this that should keep filtering is to replace line 99 with:
$cursor = $m_collection->find(array_merge($searchTerms,
array('foo' => 'mystring')), $fields);
That will always make sure that your condition is added to the search terms but keeps the users own search terms.
Use as below
$cursor = $collection->find(array("foo" => "mystring"));
Here is more details: http://www.php.net/manual/en/mongo.queries.php
I am trying to save some db action by compiling a looped bit of code with a single query, Before I was simply adding to the the like statements using a loop before firing off the query but i cant get the same idea going in Mongo, id appreciate any ideas....
I am basically trying to do a like, but with the value as an array
('app', replaces 'mongodb' down to my CI setup )
Here's how I was doing it pre mongofication:
foreach ($workids as $workid):
$this->ci->app->or_like('work',$workid) ;
endforeach;
$query = $this->ci->db->get("who_users");
$results = $query->result();
print_r($results);
and this is how I was hoping I could get it to work, but no joy here, that function is only designed to accept strings
$query = $this->ci->app->like('work',$workids,'.',TRUE,TRUE)->get("who_users");
print_r($query);
If anyone can think of a way any cunning methods I can get my returned array with a single call again it would be great I've not found any documentation on this sort of query, The only way i can think of is to loop over the query and push it into a new results array.... but that is really gonna hurt if my app scales up.
Are you using codeigniter-mongodb-library? Based on the existing or_like() documentation, it looks like CI wraps each match with % wildcards. The equivalent query in Mongo would be a series of regex matches in an $or clause:
db.who_users.find({
$or: [
{ work: /.*workIdA.*/ },
{ work: /.*workIdB.*/ },
...
]});
Unfortunately, this is going to be quite inefficient unless (1) the work field is indexed and (2) your regexes are anchored with some constant value (e.g. /^workId.*/). This is described in more detail in Mongo's regex documentation.
Based on your comments to the OP, it looks like you're storing multiple ID's in the work field as a comma-delimited string. To take advantage of Mongo's schema, you should model this as an array of strings. Thereafter, when you query on the work field, Mongo will consider all values in the array (documented discussed here).
db.who_users.find({
work: "workIdA"
});
This query would match a record whose work value was ["workIdA", "workIdB"]. And if we need to search for one of a set of ID's (taking this back to your OR query), we can extend this example with the $in operator:
db.who_users.find({
work: { $in: ["workIdA", "workIdB", ...] }
});
If that meets your needs, be sure to index the work field as well.
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.
Hey guys, been having this problem for a while now, and can't for the life of me seem to track down anything remotely helpful.
I'm trying to, once a user logs into the application (using the built-in Auth component), use the school_id field to find the name of the school that they are associated with (and display this name in the header of the view). I also figure that I will need to call up various other pieces of school information in other actions down the road.
I've tried both of the following, but neither seems to work. No matter whether I School->find() based on the user's "school_id" or by a number that I have included manually. It simply returns the information of the same school every time (the school with the ID of 1).
Here's what I've tried:
$this->set('school_name', $this->School->find('first', array('conditions' => array('School.id' == 2))));
$this->set('school_info', $this->School->find('first', array('conditions' => array('School.id' == $this->Auth->User('school_id')))));
$this->set('school_info', $this->School->find($this->Auth->User('school_id');
Once again, not a problem with the code not returning anything. It just returns the same school every time (where ID = 1).
As you can imagine, this has been fairly frustrating, and I would love any help that you could provide.
Thanks,
Ben
You are using the == sign instead of => in your condition.
It should be:
$this->School->find('first', array('conditions' => array('School.id' => 2))));
Remember: == is a conditional operator. => is the arrow notation used to create array key-value pairs.
A short way to do it would be:
$this->School->findById($this->Auth->user('school_id'));
If you're supplying the id, supply it to the findById and not the all-encompassing find method. That said, you should still take care to see that you're using the right operators. :)
Quick Note: 'School.id' == 2 evaluates to false and array(false) is an array with one element false which is why you didn't get any errors.