Mongo Updating current data, reusing fields in dataset - php

My dataset is complete in the DB; however I want to create a new field on each of the documents in the db. This new field I want to be derived by some of my input along with other fields that are currently in the database:
IE:
Document:
{
"_id":myId,
"city":"fooville",
"state":"bar"
}
Then I want to take and iterate through every entry and add something like this:
Document:
{
"_id":myId,
"city":"fooville",
"state":"bar",
"cityState":"fooville, bar"
}
Is there an easy way to do this? Trying to avoid re-inserting the entire dataset.
Thank you in advance for your help
(Mongo is awesome)

Something like this:
$results = $collection->find();
// iterate through the results
foreach ($results as $results)
{
$collection->update(array("_id" => new MongoId($result['_id'])),
array('$set' => array("cityState" => sprintf("%s, %s", $result['city'], $result['state']))));
}
I haven't tested it....but it should work...

Related

How to make update endpoint more general purpose? (PHP)

I have a function in my API to update the name of a person in an SQLite database. You give it the ID of the name you wish to change and the new name.
How can I build a function in a way that allows me to update a wide range of fields in the database? even things from different tables?
I started off trying to use parameters to switch which SQL query is executed, but this feels a bit clunky and not scalable. Is there a better way?
Current code:
private function json_update_authors() {
$input = json_decode(file_get_contents("php://input"));
$query = "UPDATE authors SET name = :name WHERE authorId = :authorId";
$params = ["name" => $input->name, "authorId" => $input->authorId];
$res = $this->recordset->getJSONRecordSet($query, $params);
return json_encode(array("status" => 200, "message" => "ok"));
}
Prependix
You can achieve what you want, but before reading the details, I recommend contemplating about what you would like to restrict this to, because if there is a file your function blindly trusts, then, should malicious input be inside that file, your database can easily be hacked. So, you should have a whitelist of tables/fields that you allow to be updated and apply that.
Decoding JSON
json_decode decodes your JSON into an object that you do not foresee its members. However, according to the documentation you can iterate this object like:
foreach ($obj as $key => $value) {
echo "$key => $value\n";
}
However, json_decode can decode your JSON into an array as well, like:
$input = json_decode(file_get_contents("php://input"), true);
I personally prefer to decode JSON into arrays, but you can operate with the first approach as well. In both cases, you can iterate the array in a similar manner as described above.
Recommended format
Your update has an anatomy as follows:
table
fields
filter
So, I would recommend that you could use a JSON representation of your input, that has a tableName field, which is a string, a fields field, which is an array of key-value pairs, the keys representing the fields to be updated and the values representing the values to update to and finally a filter field, which, if we intend to be very elegant, could also be an array of objects of key-value pairs, the keys representing the fields you are to filter by and the values representing the values you would filter with. A sample Javascript object that would comply to this format would look like the following:
[
{ //Your query
tableName: 'authors',
fields:
[
{
name: 'somename'
}
],
filters:
[
{
authorId: 123
}
]
},
{ //Some other example
tableName: 'books',
fields:
[
{
isbn: 'someisbn',
title: 'sometitle'
}
],
filters:
[
{
pageNumber: 123,
weight: '5kg'
}
]
},
]
I have given an example above, of two objects, so you can see that:
several updates can be notified in the JSON
you can update several fields in a single command
you can filter by several fields
I should mention that this is a rabbit hole, because you might want to vary the operator as well, but since this is a mere answer, I do not write a full elegant project for its purpose. Instead of that, let me just tell you that there is a lot of room for improvement, operator dynamicity springs to mind instantly as an improvement that you may need.
How to generate an update query:
//assuming that $JSON is a variable holding such values as describe in the previous chapter
foreach ($JSON as $obj) {
$tableName = $obj['tableName'];
$fields = [];
$filters = [];
$params = [];
$toExecute = isset($whiteList['tables'][$tableName]);
foreach ($obj['fields'] as $key => $value) {
$fields[]=($key.'=:field_value'.$key);
$params['field_value'.$key] = $value;
$toExecute = $toExecute && isset($whiteList['fields'][$key]);
}
foreach ($obj['filters'] as $key => $value) {
$filters[]=($key.'=:filter_value'.$key);
$params['filter_value'.$key] = $value;
$toExecute = $toExecute && isset($whiteList['filters'][$key]);
}
}
I have used a whitelist above to make sure that the queries will not update tables/fields using filters where the name of the table/field/filter is either badly formatted, malicious or unwanted. This code is untested, it might well contain typos, but the idea should be a good starting point.

Returning Data from database in laravel

I am new to laravel. I have an array. It looks like this.
$state=[
1 => "Utah"
2 => "California"
3 => "Nevada"
6 => "Arizona"
]
I am trying to query the table in a database called a county. I want to display all the county that falls in those states which are in the array.
I write a code like this
foreach($state as $st) {
$data= DB::table('state')->Select(County)->where('name','=', $st)->get();
dd($data);
}
This is the code that I wrote. It does only return for the first state then after that, it gets stopped can someone help me. Any kind of help is appreciated.
It stops because dd() is dump and DIE. So it is like you would call:
dump($data);
die();
Try something like:
$query= DB::table('state');
foreach($state as $st) {
$query->orWhere('name','=', $st);
}
$data = $query->get();
It will make one DB call instead of X calls and returns a collection of records with which you can work.
You can try:
DB::table('country')->whereIn('name', array_values($state))->get();
You have to give categories to filter and next join eachother
App\YourModel::select('what you want')->join('category','your_models.id','=','category.your_model_id')->get();

A more efficient way of saving 125 columns in a Laravel controller

I have a rather large table that has 125 data inputs, each of which has to be saved in a separate column.
I have named each HTML input as 1,2,3 etc... and the same within the table, to hopefully help things.
At the moment, I have the following code:
$observation = new Observation();
$observation->site_id = Input::get('site_id');
$observation->result = Input::get('1');
$observation->result_id = '1';
$observation->save();
Is there a way I could use a loop to iterate through the 125 data inputs (Input::get('X') and result_id = 'X') and then save them all?
for($i=1; $i<=125; $i++) {
$data[$i] = [
'site_id'=>Input::get('site_id'),
'result'=>Input::get($i), 'result_id'=>$i
];
}
Using Query builder:
DB::table('table')->insert($data); // Change this with your table name.
and if you want to use Eloquent:
Model::insert($data);
You can use something like this pattern in your controller to handle creating new Observations and editing existing Observations without worrying about the specific attribute names:
// get all non-empty inputs except 'token'
$inputs = array_filter(Input::except('_token'), 'strlen');
// assuming 'id' is your primary key and sent as an input in your form
if (Input::has('id'))
{
// An edit
$id = Input::get('id');
$observation = Observation::find($id);
foreach ($inputs as $key => $value)
{
$observation->$key = $value;
}
}
else
{
// A create
$observation = new Observation($inputs);
}
This solution doesn't force you to use sequential column names or html input names like 1..125 and will allow you to use more meaningful column names if you prefer. However, it does assume that your column names (and therefore object attributes) are the same as the html input names.
Related, but you might also like to know that if you use the HTML helpers in the Blade view template to construct your form, and open the form with Form::model, it will fill even fill in the values of the inputs using the object that you pass to it.
For example, in the view:
{{ Form::model($observation) }}

How can I build this data structure using an Object instead of an Array?

I'm building a data structure for a Mustache template. I can easily build it using an array. But since I'm trying to learn more about working with Objects, I want to use an Object instead.
$mySlider = array("title" => "Photos of Las Vegas");
$mySlider = array("items" => array());
foreach ( $query as $row ) {
$newItem = [];
$newItem["postTitle"] = $row["imageTitle"];
$newItem["postURL"] = $row["imageURL"];
}
array_push($mySlider["items"], $newItem);
This is my current solution. I don't like it, too much code. By using an Object of "Slider" I'd like to be able to do something like this:
$mySlider = new PhotoSlider("Photos of Las Vegas");
foreach ( $query as $row ) {
$newPhoto = $mySlider->newPhoto();
$newPhoto->addProperty("imageTitle", $row["imageTitle"]);
$newPhoto->addProperty("imageURL", $row["imageURL"]);
}
I know I just made this up but this would be much nicer.
How do I need to write this Object in PHP to make it work this way with only one Class? I got stuck when I noticed I'd need another Object for the "newPhoto()" element, since that would need some methods of its own to do "addProperty", for instance.
I'd appreciate any pointers. Thanks!
You will need to create 2 classes, one for PhotoSlider and one for Photo. Photoslider would have array of Photos, and methods like add the Photo objects to the PhotoSlider, delete etc. Photo class would have the set attribute methods. Like:
$mySlider = new PhotoSlider("Photos of Las Vegas");
foreach ( $query as $row ) {
$newPhoto = new Photo();
$newPhoto->addProperty("imageTitle", $row["imageTitle"]);
$newPhoto->addProperty("imageURL", $row["imageURL"]);
$mySlider->addPhoto($newPhoto);
}

Multiple Keys to an array in if/else search

My code is pretty basic. I'm using an array to generate a datasheet for a product based on it's SKU and a filepath.
My array looks like this:
$a=array(
"/images/ManualSheets/factSheetCLASSIC.pdf"=>"KE800/6",
"/images/ManualSheets/factSheetMICRO.pdf"=>"KE800/12",
"/images/ManualSheets/factSheetSMALL.pdf"=>"KE4000/12",
"/images/ManualSheets/factSheetMEDIUM.pdf"=>"KE8000/12",
);
Where the first Key is the filepath, and the second Key is the SKU (as generated by the system) I then use an if/else to generate a button - so if a product is not in the array it returns a blank value and doesn't have a button which leads to nowhere
$factsheetweblink_url = array_search($product_sku,$a);
if ($factsheetweblink_url==false) {
echo " ";
}
else {
echo "<div class='productpagestockistBTN'>
<img src='/images/FactSheet_btn.png' >
</div>";
}
?>
This code works fine. The catch comes when I have products with different SKUs but the same datasheet file, (same brand and make but a different model). Currently I can only get it to work by uploading multiple copies of the datasheets with different names, but it's becoming a big waste of space.
I have tried using an array as a key to hold multiple values to the one key..
"/images/ManualSheets/factSheetMEDIUM.pdf"=> array("KE8000/12","KE7000/12"),
but it doesn't seem to be working... I'm not quite sure if I need to refine my if statement to search within the sub arrays as well or..?
Any help would be appreciated, thanks in advance.
You should use arrays like this:
$products = array(
0 => array(
"pdf" => "/images/ManualSheets/factSheetCLASSIC.pdf",
"skus" => array("KE800/6","KE900/6")
),
1 => array(
"pdf" => "/images/ManualSheets/factSheetCLASSIC3.pdf",
"skus" => array("KE100/6","KE200/6"))
);
This is because array_search returns just first row whit that key.
Then just do your own search function like:
function findBySku($items, $sku) {
$pdf = ""; // return empty if not found.
foreach($items as $row) {
if (in_array($sku, $row['skus'])) {
$pdf = $row['pdf'];
break;
}
}
return $pdf;
}
and call that function:
$pdf = findBySku($products, "some sku");

Categories