PHP-GDS Upsert overwritring nonspecified values - php

I have a keys only query - something like this -
$Sub = $obj_store->fetchOne("SELECT key WHERE key HAS ANCESTOR KEY(Subscribe, $key)");
I set a value on one of the fields
$Sub->active = TRUE;
then do an upsert
$obj_store->upsert($Sub);
The one value is updated, but the other existing columns are erased. If I do a select * the values are not erased.
I need to avoid a full record read for billing.
How can I update a field in a record and avoid deleting all the others? I'm using the php-gds wrapper for cloud-datastore.
the desire would a query like the following
update subscribe set active = TRUE where keyid = 1234

Writes to Cloud Datastore assume that you are sending in a "whole" entity. You cannot update specific properties of an entity like you can in a relational database. Like you found out, correct way to update an entity is to first read the whole entity from the Datastore, then change one or more properties and then save.

Related

PHP: Propel will save only first column

I've been struggling with this problem for a while now and can't figure out reasonable explanation for this behaviour...
I have in MySQL a table called "notifications" and columns "package_id", "mail_sent_at" and "sms_sent_at", and appropriate Propel model for that.
I'm setting "sms_sent_at" column with current time and saving it. Works perfectly.
$not = new Notification();
$not->setPackageId($package_id);
$not->setSmsSendedAt(time())->save();
The result for this is:
Now I want to add one more thing - set mail_sent_at column. So what I do:
$not = new Notification();
$not->setPackageId($package_id1);
$not->setMailSendedAt(time())->save();
$not->setSmsSendedAt(time())->save();
And here's the magic: only mail_sent_at column was set.
Additional notes:
after var_dump'ing i can see that dumped object has both properties set after executing these operations
var_dump'ing object retrieved from propel query by package_id after these operations executed doesn't have the second column set. As it is in DB.
Same behaviour happens other way around if I first set different column - first saved column goes into DB, second don't.
Why is that happening and how can I fix it?
Ps. Yeah, I know it's "sent", not "sended"
EDIT
Finally I found the solution. In case someone is having similar problem:
check if your primary key in propel schema has autoIncrement="true". If not - add it!
What was happening was: I've created a new object with id=null, saved it to DB using implicitly SQL INSERT (since it's new record ) and while working on the same object modified it and saved it to DB once again, but this time imlpicitly by SQL UPDATE (Propel figures out that I inserted this object once). The problem was, that after first saving I didn't get id for my object set (even though there was ID set in DB). So second SQL contained "UPDATE...WHERE id = NULL".

Read from one database and write to another php/laravel

I'm learning Laravel and would know howto read data from a db and write it automatically to a second db.
First I read from db1 and it works:
$paciente_q = Pacientes::on('db1')->find($id);
Then I wish to move the data to an identical table on db2 (assigned in the configuration)
Pacientes::create($paciente_q);
The error is that I pass an object and "::create" wants an array. I converted it to an array but didn't work. The only option that I can find is to create an array with the data and then make the ::create. But I think that there should be an easier way. I'm talking about 10 columns.
What could I do if we talk about hundreds of columns?
Your approach didn't work probably because by default mass assignment is prevented for security reasons; you need to manually set the model's fields that are mass assignable in the fillable property of the model (that should be an array) - if you do not care about that security or are sure that you'll never directly mass-assign user input to your models you can make all the fields mass assignable by setting the guarded property of the model to an empty array.
Once that's done, your code is mostly correct, just convert the model to an array and don't forget to select the second database when creating the model, like so :
// the model to insert, converted to an array - get() would also work but first() ensures we get only one record even if the primary key is messed up and there are multiple values with the same ID
$paciente_q = Pacientes::on("db1")->find($id)->first()->toArray();
// create the same model on the second database
Pacientes::on("db2")->create($paciente_q);
Now, if you want to do it occasionally for a few rows then the above approach is suitable, otherwise you may look at bulk insertion, here's an example for copying the entire table from your first database to the second one :
// an array with all the rows
$patients = Pacientes::on("db1")->all()->toArray();
// get the model's table name
$table = with(new Pacientes)->getTable();
// bulk insert all these rows into the second database
DB::connection("db2")->table($table)->insert($patients);
Note that here we're not using Eloquent for inserting them, so we must first get the table's name from an instance of the model; if the table's name on the second database is different from the first then adjust the $table variable accordingly.
The solution was to change the get() to first() because we were searching for one item. I read wrong the first solution from #André... sorry! Should learn to read instead of Laravel!
$paciente_q = Pacientes::on('db1')->where('numerohistoria',$numerohistoria)->first()->toArray();
Pacientes::create($paciente_q);
Now it works!! Thanks to all and specially to #André !

Force Yii to save new record with specific ID on auto_increment column?

For example: I create new model, set the id field to 1 and save it. It runs fine and saves with the id = 1 into a database. I open MySQL console and delete all records from the table. When I delete it, create new model again and set the id field to 1 - it actually saves it with the 2 as the id field value.
I'm guessing Yii gets the current auto_increment value from mysql and override my id value. Is there a way to prevent that behavior?
EDIT (my code sample):
$sn = new SaplingNode();
$sn->id = 1;
$sn->save();
I call it twice, between calls I delete the record using mysql console. That's all.
There is no way to do this by Yii framework. As its a default behavior of MYSQL.
You can simply do this and reset the Auto increment id after you truncate.
ALTER TABLE tablename AUTO_INCREMENT = 1
This is not a best practice, but if you really want to forcefully set the id of new record on auto increment column, you can do like below:
First under your rules() method of "SaplingNode" model put below line:
array('id', 'safe'),
Then use your code to save new record with whatever id you like, for example:
$sn = new SaplingNode();
$sn->id = 10;
$sn->save();
This code should work, I have tested it.
As you are currently using it, the answer is no, you can't do that, not with CActiveRecord. The reason for this is that Yii is retrieving the record to update based in it's primary key, and will not override that. The only way to override the primary key will be to write your own update query via a CDbCommandBuilder.
BTW: There is an interesting discussion on the subject, on Yii forum.
Have you tried
$sn = new SaplingNode();
$sn->setPrimaryKey(1);
$sn->save();
Yii primary key
If your just testing and it is okay to delete all data from your table, you can empty the table. For example, you can use phpMyAdmin, click your DB to view its tables, find the table you want and click Empty showing on that table row. You will get a confirmation message with a choice of enabling or disabling FK, click OK and all data on that table will be deleted and your auto increment id will start from 1 when saving or inserting new record.

CakePHP: Insert record with specific id

This is essentially the same question as CakePHP: Is it possible to insert record with pre-defined primary key value?. In CakePHP 1.2 I want to insert a record with a pre-determined id. The id's value is determined by an external system, but unlike in the linked question I have no control over that system, so the solution to that question is not an option for me.
If the id field of a model is set when calling $model->save(), Cake will always try to update the record. Cake will even set the id to false, if a record with that id does not exist already [1]:
<?php
function save($data = null, $validate = true, $fieldList = array()) {
// snip
if (!$this->__exists && $count > 0) {
$this->id = false;
}
// snip
}
Saving the model first and then updating the id manually is also not an option, because this would break referencial integrity (this is an architectural limitation that I also have no control over).
So how can I force CakePHP to insert the record with a specific primary key?
Some background around the problems I'm facing:
The application I'm working on is backed by a Postgres database, so new primary keys are determined by sequences. There is a process where an external system will SELECT nextval('my_model_sequence'), do some work with that id and then pass it to the CakePHP application, where I want to INSERT a my_model record with that id.
There is no way for me to invoke the external process after saving the record. There is also no way for me to modify the external process at all.
[1] http://api12.cakephp.org/view_source/model/#l-1260
If you want to create a record with specific id just make sure you fill id field
$this->data['ModelName']['id'] = $your_id;
Also before calling:
$this->save($this->data);
you should remember to call
$this->create();
which will reset the model state which let you create new record.
Finally you should try:
$this->ModelName->create();
$this->ModelName->save($this->data);
On the other hand as I read your post and trying to imagine your tables structure I recommend you thinking over leaving the id field alone and trying to make this foreing id a Foreign key. Is that an option for you?

Auto-incrementing field that isn't a primary key

In my MySQl table I have two fields, id and order. id is an auto-incrementing primary key and I want order's initial value to match this, but to also be editable, not a key and with no uniqueness constraints. How can my database insert method achieve this? Is it possible to do so without requerying to find the last inserted id?
I'm using paris/idiorm so a solution making use of their features would be handy, although plain SQL and php is fine too.
In MySQL (since version 5.0.2) you can create trigger.
Try this on non-production database:
create trigger default_order_value AFTER INSERT ON orders
UPDATE order SET order = id WHERE id = new.id;
It may not work in that way as you wish, but you can edit it. This is another trigger example:
CREATE TRIGGER default_order
BEFORE UPDATE ON orders
REFERENCING NEW ROW AS n
n.order = n.id;

Categories