Adding an object to an IndexedDB objectStore will fail if the key already exists. How can I check for the existence of an object with a given key – preferably synchronously (no reason for another layer of callbacks) and without pulling the object.
I know how to do get requests asynchronously via transactions, but it seems a bit of an ordeal to go through every time I want to add an object.
note Solution only has to work in Chrome (if that helps)
The best way to check existence of a key is objectStore.count(key). Which is async.
In your case, the best option is openCursor of your key. If exists, cursor will come up.
var req = objectStore.openCursor(key);
req.onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) { // key already exist
cursor.update(obj);
} else { // key not exist
objectStore.add(obj)
}
};
So far none of the browsers have the sync API implemented so you're going to have to do it async. An objectStore exposes a get method which you provide it with a key and it'll return you the object (or null) that matches the key.
There's a really good tutorial on MDN that covers using IDB, and getting a record is covered too, but the inlined code is:
db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess = function(event) {
alert("Name for SSN 444-44-4444 is " + event.target.result.name);
};
If you don't want retrieve the record then you can always used the count method on an index as explained here in the spec. Based on the result of that you can either use add or put to modify the record, it'll save extracting the record if you don't need to.
A bit late for an answer, but possible it helps others. I still stumbled -as i guess- over the same problem, but it's very simple:
If you want to INSERT or UPDATE records you use objectStore.put(object) (help)
If you only want to INSERT records you use objectStore.add(object) (help)
So if you use add(object), and a record key still exists in DB, it will not overwritten and fires error 0 "ConstraintError: Key already exists in the object store".
If you use put(object), it will be overwritten.
The question is why do you want to know this? Maybe you should use another approach?
You can use auto increment, this way you don't need to check if a key exists, you will always get a unique one.
You can also use the put method instead of the add method. With the put the data will be updated if the key exists and if the key doesn't exist the data is added.
Everything depends on the reason why you want to check if something exists.
Related
Last year I made a laravel site with an events table where I needed three fields to be unique for any event (place, date and time). I wasn't able to set up a validation request to do this so I added an unique index for these three fields directly through phpmyadmin and catching the exception that could happen if a duplicated event was inserted.
So basically my store() method has a try/catch like this:
try {
$event = new Event;
$event->place = $request->input('place');
$event->date = $request->input('date');
$event->time = $request->input('time');
$event->save();
return view(...);
} catch (\Illuminate\Database\QueryException $e) {
// Exception if place-date-time is duplicated
if($e->getCode() === '23000') {
return view('event.create')
->withErrors("Selected date and time is not available");
}
}
Well, now I had to change the app so events could be soft deleted and I simply added the 'deleted_at' field to the unique index, thinking it would be so easy... This approach doesn't work anymore so I've been reading here and there about this problem and the only thing I get is I should do it through a validation request with unique, but honestly I just don't get the syntax for this validation rule with three fields that can't be equal while a fourth one, deleted_at, being null.
My app checks for the available places, dates and times and doesn't let the user choose any not available event but no matter how many times I've told them there's always someone who uses the browser back button and saves the event again :(
Any help will be much appreciated. Thank you!
This is not a good approach to solve the problem.
You can do follow things to solve this problem
Before insert into database get a specific row if exist from database
and store into a variable.
Then check the data is already stored into the database or not.
If data is already there create custom validation message using Message Bag Like below.
$ifExist = $event
->wherePlace(request->input('place'))
->whereDate(request->input('date'))
->whereTime(request->input('time'))
->exist();
if ($ifExist) return 'already exist';
It might help you.
#narayanshama91 have pointed the right way.
You said you would like to use the unique rule to validate the input but the problem is that last week there was a post in Laravel Blog warning users of a possible SQL Injection via the unique rule if the input is provided by the user.
I would highly advise you to NOT USE this rule in this case since you depend on users input.
The correct approach in your case would be #narayanshama91 answer.
$ifExist = $event
->wherePlace(request->input('place'))
->whereDate(request->input('date'))
->whereTime(request->input('time'))
->exist();
if ($ifExist) {
return 'already exist';
}
I currently have a database setup within an html page and my requirement is to update a single row within the application.
I could refresh the database with "fresh" data, but that would require too much time.
I had a look at
dbSports().update("aName", object.aname);
However it seems to update all the records in my database instead of just one. Are there any answers to this particular issue?
The Documentation on the matter is missing a major chunk of information, but is covered in a presentation done by the author of the library (http://www.slideshare.net/typicaljoe/better-data-management-using-taffydb-1357773) [Slide 30]
The querying object needs to be pointing to the object you want to update and editing happening from there. i.e.
var obj = dbObject({
Id : value.id
}).update(function() {
this.aName = object.aname;
return this;
});
Where the object in the query points to the ID of the row and the update function then points to it aswell and the callback updates the value that the application needs to update
you first have to find the matching record, then update it
yourDB({"ID":recordID}).update({
"col1":val1,
"col2":val2,
"col3":val3
});
I wanted to ask what's the difference between the value in the adressline and the id I get when i use getId().
For example for one document the getId() value is:
t8K_TLQPmKzgB72pY4TblUg
while in the adressline the key is:
0Amu7sNvd2IoudDhLX1RMUVBtS3pnQjcycFk0VGJsVWc
what i figured out so far is that when you encode getId in base64 you get more or less the last part of the key in the adressline
(base64Encode(t8K_TLQPmKzgB72pY4TblUg) = dDhLX1RMUVBtS3pnQjcycFk0VGJsVWc=).
But I still don't know what 0Amu7sNvd2Iou stands for, because i have the impression that this parts also is different in older documents, therefore i can't just combine the key using all the time 0Amu7sNvd2Iou at the beginning
Why I need to know this: my scripts use the getId method but some users fill in their ids manually (they just copypaste it from the key from the adressline). The result is that when i try to compare them although they refer to the same document i can't match them like they are completly different...
thanks a lot for bringing light into this problem
edit #taras:
i can also open the document with the key and the id. It's just weird that there are kind of two different id's for one document. If for example i want to compare if a value somebody copypasted from the adressline to a document is the same as the file i have opened i won't get a true, even it is the same file
var keyFromHeadline = "0Amu7sNvd2IoudDhLX1RMUVBtS3pnQjcycFk0VGJsVWc"
var id = SpreadsheetApp.getActiveSpreadsheet.getId();
if (keyFromHeadline==id) Browser.msgBox("blabla")
Therefore i would be interested what is the reason for the two different values and how i could match them
If you need to have unique file IDs just normalize them. Everytime a user enters an ID manually just run it trough the fileIdNormalize function:
function fileIdNormalize(id) {
if (typeof id == 'string' && id.length > 0)
return DocsList.getFileById(id).getId();
return '';
}
Just a suggestion :
Since base64Encode seems to give you a significative part of the adress url you could use a match to check if the document is the same.
Something like :
if('manually_entered_key'.match(base64Encode('the_value_obtained_by_getId')==base64Encode('the_value_obtained_by_getId')){
// consider as the same doc ...
I'm using yii active records for mysql, and i have a table where there's a field that needs to be appended with the primary key of the same table. The primary key is an auto increment field, hence i can't access the primary key before saving.
$model->append_field = "xyz".$model->id; // nothing is appending
$model->save();
$model->append_field = "xyz".$model->id; //id is now available
How do i do this?
I know that i can update right after insertion, but is there a better method?
Your record is only assigned an id after the INSERT statement is executed. There is no way to determine what that id is prior to INSERT, so you would have to execute an UPDATE with the concatenated field value after your INSERT.
You could write a stored procedure or trigger in MySQL to do this for you, so your app executes a single SQL statement to accomplish this. However, you are just moving the logic into MySQL and in the end both an INSERT and UPDATE are occurring.
Some more workarounds:
This is almost your approach ;)
$model->save();
$model->append_field = "xyz".$model->id; //id is now available
$model->save();
But you could move this functionality to a behavior with a custom afterSave() method, note that you'd have to take care about not looping the event.
Or just write a getter for it
function getFull_append_field(){
return $this->append_field.$this->id;
}
but then you can not use it in a SQL statement, unless you create the attribute there with CONCAT() or something similar.
Anyone else coming to this question might be interested in exactly how i implemented it, so here's the code :
//in the model class
class SomeModel extends CActiveRecord{
...
protected function afterSave(){
parent::afterSave();
if($this->getIsNewRecord()){
$this->append_field=$this->append_field.$this->id;
$this->updateByPk($this->id, array('append_field'=>$this->append_field));
}
}
}
One way to avoid the looping the event(as mentioned by #schmunk) was to use saveAttributes(...) inside the afterSave() method, but saveAttributes(...) checks isNewRecord, and inserts a value only if it is a new record, so that requires us to use setNewRecord(false); before calling saveAttributes(...).
I found that saveAttributes(...) actually calls updateByPk(...) so i directly used updateByPk(...) itself.
I ran into an interesting problem while using DLINQ. When I instantiate an entity, calling .SubmitChanges() on the DataContext will insert a new row into the database - without having ever called .Insert[All]OnSubmit(...).
//Code sample:
Data.NetServices _netServices = new Data.NetServices(_connString);
Data.ProductOption[] test = new Data.ProductOption[]
{
new Data.ProductOption
{
Name="TEST1",
//Notice the assignment here
ProductOptionCategory=_netServices.ProductOptionCategory.First(poc => poc.Name == "laminate")
}
};
_netServices.SubmitChanges();
Running the code above will insert a new row in the database. I noticed this effect while writing an app to parse an XML file and populate some tables. I noticed there were 1000+ inserts when I was only expecting around 50 or so - then I finally isolated this behavior.
How can I prevent these objects from being persisted implicitly?
Thanks,
-Charles
Think of the relationship as having two sides. When you set one side of the relationship the other side needs to be updated so in the case above as well as setting the ProductOptionCategory it is effectively adding the new object to the ProductOptions relationship on the laminate ProductOptionCategory side.
The work-around is as you have already discovered and to set the underlying foreign key instead so LINQ to SQL will not track the objects in the usual way and require implicit indication it should persist the object.
Of course the best solution for performance would be to determine from the source data which objects you don't want to add and never create the instance in the first place.