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.
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 am using
$user = User::find($user_id);
return response()->json(array('user'=>$user),200);
On local server with php5.9 it returns all the keys except id as string.
{
"success": "1",
"message": "success",
"user": {
"id": 75,
"name": "",
"postal_code": "73733",
}
}
But the same code on production server with php7.0 returns other keys as of type integer ex. check this postal_code value.
{
"success": "1",
"message": "success",
"user": {
"id": 75,
"name": "",
"postal_code": 73733,
}
}
So solve this i am using $cast=[] in User.php.
But i have used raw queries also. What is the best way to convert all the values in response json to be of string type.
The difference in the type is most likely due to the fact that your local server is using the php5-mysqld (non-native) driver, whereas your production server is probably using the php-mysqlnd (native) driver. One of the main differences is that the non-native driver reads all fields as strings, whereas the native driver will automatically convert integer fields to PHP integers.
The id shows up as an integer in both cases because Laravel automatically adds the primary key field ('id') to the casts array with the type defined by the $keyType property (default to int).
I would say you have four options:
Attempt to install the non-native mysql driver for PHP 7 on your production server (not recommended).
Don't do anything on the PHP side, and just make sure that whatever is consuming the json can handle strings or integers (probably a good idea either way, but still doesn't solve the real issue).
Add postal_code to your casts array, to ensure it is always casted to a string (not bad; this will work for most cases, but is not exactly the correct solution).
Change the field type of the postal_code field from an integer to a varchar(5), varchar(9), or varchar(10), depending on if you're going to store the +4, and with or without a hyphen (best solution).
Changing the postal_code data type in the database to a varchar really is the best option. The main reason is that, while they are comprised of numbers, postal codes are not actually integers, or numeric in nature. You will never be doing any arithmetic with them. Additionally, there are postal codes that start with a leading 0, and if the value is stored as an integer, this is an extra edge case condition you have to contend with whenever displaying postal codes.
Enabling PDO::ATTR_STRINGIFY_FETCHES setting will solve this problem. You can add this PDO setting under database configurations.
'options' => array(
PDO::ATTR_STRINGIFY_FETCHES => true,
),
You could cast to string like:
$user['postal_code'] = (string) $user['postal_code'];
Further information on variable type casting is in the PHP manual.
Hope this helps :)
When calling an REST API method I get back that there is an error
Error processing request stream. The payload must represent a valid array format for collections.
But when searching for:
valid array format for collections
I get back a lot, but nothing clarifies what is meant by this. I'm guessing the data i send is not valid (currently i'm sending an array('foo' => 'Bar')) but this is probably not correct.
Has anybody got a pointer to what is happening here? Or what i could check?
The documentation of ExactOnline (which I'm posting to) is not sufficient. It only states what fields they have, but nothing about these kind of error messages.
==========================
Ok, this needs some clarification, my bad!
As written, i'm communication with ExactOnline, via their API.
I'm calling the method to post a sales order. With that, i'm using a set of scripts Exact provides on their website (for developers).
on page:
https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?name=SalesOrderSalesOrders
under 'POST', you can read the mandatory fields, under which 'SalesOrderLines' is one of them. It does not tell me what it expects or in what format.
I wrapped my array in a json_encode and tried again, but no luck. It still tells me the same error.
I'am currently using the same ExactOnline API. Have to say that the documentation lacks in information on this topic indeed!
To make a valid array for collections you have to use the following base:
$array = array(
'InvoiceTo' => 'bc960e43-be9d-409c-9cfe-31ce56cc3238',
'SubscriptionLines' => array(
array('Item' => '7e50702b-5bbf-4b77-ab73-5dad50016e82')
)
)
The json_encode($array) on this list would be:
{
"InvoiceTo":"bc960e43-be9d-409c-9cfe-31ce56cc3238",
"SubscriptionLines":[
{"Item":"7e50702b-5bbf-4b77-ab73-5dad50016e82"}
]
}
So the important part here is to do array(array()) inside the SubScriptionLines. This tells the JSON that you want to use an JSON Array instead of the JSON Object notation.
For your particular question you need to change the keys into the keys given in the documentation for a SalesOrder. Not all manditory fields of the api are included here, because this solution is for Subscriptions. However, the principle will be the same.
Hope this will help you and others implementing the exact API fully :)
How are you serializing your payload? If it is meant to be in JSON format, a collection would look like this:
[
{
"foo": "bar"
},
{
"foo": "baz"
}
]
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'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.