So, I know there are a few similarly named questions, but this is not the same.
I am curious to see if anyone could explain the reasoning for the lack of an increment sentinel, similar to the delete one.
As far as I know, a field deletion is no different than a document update. Meaning, I can just delete my field by simply updating the entire document to some new data, leaving that field out, hence, the question.
If we have a FieldValue.delete(), why the lack of a FieldValue.increment()
Note: I am aware of the 1QPS limit and I doubt it has anything to do with the above.
Regards!
Version 5.9.0 - Mar 14, 2019
Added FieldValue.increment(), which can be used in update() and
set(..., {merge:true}) to increment or decrement numeric field values
safely without transactions.
https://firebase.google.com/support/release-notes/js
Related
Suppose I have an item (model) which has fields that are arrays, for example:
const item = {
name: "",
prices: [{somePriceSpecificObject}],
}
When I want to add a new price to that item prices array, which method is better to be used (in terms of quality I guess), PUT or POST?
Right now I am using PUT because by creating a new price for prices array I am editing the item, but I am now making functionality that will let me edit the existing entries, and it naturally goes into PUTaswell, which got me thinking about this issue.
Because, it also kinda makes sense to use POST, because price relative to the item is a new thing, but the item relative to me with the new price is still the item, just with an edited field (prices).
Now one solution to my dilemma might be to make a separate model for prices? But I never did that, because, a given item in my specific conditions, will never have more than a handful of prices, and it will make me make more queries to the database (I am not concerned about performance, but still, just looking for best practices).
So which route do you think I should go?
EDIT: My api endpoints look like this at the moment:
post("/one", POST.oneItem);
put("/addprice", PUT.addPriceToItem);
put("/editone/:id", PUT.EDIT.item);
put("/editone/:id/price/:priceId", PUT.EDIT.price);
Notice I had to make a nested EDIT object in my PUT object (that provides the handling functions), to be able to easily distinguish between adding a price and editing a price, so that got me into thinking about all of that.
I have seen in most cases of production code there is never a delete query being run as the schema has a soft delete key which gets turned when wanting to delete a particular row/document.
Hence it is always using PUT as a best practice even for delete. Any changes to an existing document need to be a PUT because it will help you in improving performance unless the document is completely different from the one before. It even becomes easier while caching as one needs to update the cache and not add another one in and remove some other one (in case the cache becomes full at that point). In the end, if you intend to keep prices as an array then I guess PUT is a better choice.
"PUT /uri" creates/updates the thing at "/uri". Your example where the URI contains "/addprice" is IMHO a misuse of PUT.
If you have a collection X and want to add an item Y, use "PUT /X/Y". If you want the server to name the item, use "POST /x".
I am trying to do a "small hack" to avoid reading the User document everytime the page loads. So I save it locally, everytime the page loads I get the local version, get the updated_at property and then do something like WHERE last_updated > {{updated_at}}. For that, I want to use this:
firebase.firestore().collection('User')
.where(firebase.firestore.FieldPath.documentId(), '==', firebase.auth().currentUser.uid)
.where('updated_at', '>', updated_at)
.get()
As you can see, I have one equality (==) and one inequality (>). Why do I get the following error on the console:
FirebaseError: Cannot have inequality filters on multiple properties: updated_at
at new t (https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:47054)
at t.fromRpcStatus (https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:116660)
at t.fromWatchChange (https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:125914)
at t.onMessage (https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:242411)
at https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:241212
at https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:241997
at https://www.gstatic.com/firebasejs/6.0.2/firebase-firestore.js:1:144869
I am doing this to try to avoid reading from the database if the local version is the same as the one in the database. Maybe if you have a better way, please let me know.
Thanks
firebaser here
The equality check you have on documentId() is internally converted into a range check by Firestore, because the keys are stored as the last items in existing indexes (if I understand correctly). And that means that server-side you're trying to perform two inequality/range checks, which isn't allowed.
So the behavior you are seeing is correct. But it's definitely not intuitive, and the error message is also not helpful. We'll look for a way to improve the error message by detecting this combination.
I had the same problem and I implemented the following hack: I added the id as part of the field name on which I made the check for the latest version. If your logic allows you to do that, for you this would mean:
firebase.firestore().collection('User')
.where(id + '_updated_at', '>', updated_at)
.get()
This allows to bundle in just one where statement both the check on the id and on the date (documents with different ids wont have the field id + '_updated_at' and wont therefore be selected).
Worked like a charm for me
I am building an API where some fields can be incremented.
After noticing data inconsistency in my MySQL database, I realized that the first version of my code was buggy:
Answer.incrementVotesCount = async (id) => {
// get a copy of the data
let answer = await getAnswer(id);
// update the copy of the data locally
answer.votesCount++;
// replace the persisted data with the updated copy of the original data
await Answer.updateAll({id}, answer);
};
Getting some data, updating it locally and persisting the modification can cause consistency problems when the route is used several times in a short period of time.
Such a situation would look something like this:
Caller A gets data. The persisted votesCount equals 14.
Caller B gets data. The persisted votesCount equals 14.
Caller A updates data. The persisted votesCount becomes 14 + 1.
At this point, the persisted votesCount equals 15, but Caller B's copy of it still equals 14.
Caller B updates data. The persisted votesCount becomes 14 + 1, whereas it should become 15 + 1.
2 increments have been performed, but the second one "crushed" the first one, since it increments an obsolete data.
I thought about using LoopBack3's native SQL functionality, but it seems like it is not fully reliable so I am unsure whether it's a good idea to use it (even though a query as simple as SET a = a + 1 should probably work correctly).
I also thought about using MySQL's triggers to perform some ACID compliant incrementing but I am unsure I can find a clean way to do this.
How do I increment some data without making it inconsistent?
I would take away the votesCount field to a separate hasOne relation, then I would make the Answer model strict='filter', so it would prevent saving data that does not really belong to the model. And when vote-up action would be taken I would increase the voteCount in that separate model, independently of the original Answer.
If you don't want to do it like this, you can try to check the original value in the before save hook, so you could get the latest value from the db and compare votesCount value from the database with the value in the model and update it accordingly.
Is there any documentation about how Revision.Description is populated and under what condition?
I'm writing a Custom Application for Rally so that I can view changes made to Task and HierarchicalRequirement objects via a table with a rolling 7 day period.
The attributes that I'm interested in are:
HierarchicalRequirement
PlanEstimate
TaskEstimateTotal
TaskActualTotal
TaskRemainingTotal
Task
Estimate
ToDo
Actuals
I'm traversing Revisions to get snapshot views of tasks and stories:
It's easy to retrieve these attributes for the current day. However, I need to traverse RevisionHistory -> Revisions and then parse the Revision.Description to apply the differences for Task and HierarchicalRequirement objects. This may provide a daily snapshot of each object.
For example: the following were appended to Revision.Description after took place:
TASK REMAINING TOTAL changed from [7.0] to [4.0]
TASK ESTIMATE TOTAL changed from [7.0] to [4.0]
The "rolling 7 day" period is just an example. My intention is to create a table with a breakdown of Team -> Story -> Task -> Estimate -> ToDo along the y-axis and Iteration -> daily-date along the x-axis.
Tim.
The Revision.description field on many of the Rally object types was not originally intended for developers to get change information but rather for display purposes for our Rally ALM SaaS tool - that's why changes are put in a Revision attribute called 'description' which is just a text field. So there is no developer documentation on the format of this data since it is a text field and not intended to be parsed and the format could change in the future (in the future there will be a better way to get object change information. More on this later in this post...)
However, there is a pattern in this data. It is:
ATTRIBUTE_NAME action VALUE_CLAUSE
The actions are 'added' or 'changed'.
The value clause format is based on the action type. For the 'added' action the value clause is [value]. For the 'changed' action the value clause is 'from [old value] to [new value]'.
For example, for an existing User Story that had an owner set to 'Newt' from 'No Entry', a new revision instance is created the description would have this contained in it:
OWNER added [Newt]
If then later the user changed the owner to 'John', then a new revision will be created that looks like this:
OWNER changed from [Newt] to [John]
If there is more than one attribute change then the changes are separated by commas and there is no guaranteed sorting order of the changes.
Now for the better way to do this in the future. Since you are not the only developer that wants to get at object changes we have a new product under development that will have WSAPI endpoints exposed where you can get changes for an object in a programatic way that should avoid you needing to parse data. But since this product is under development you'll have to do what you are doing now and hopefully my explanation of the format of the data in the description will help you in the meantime.
Hope this helps.
The data you are seeking may also exist in the IterationCumulativeFlowData or ReleaseCumulativeFlowData objects in Rally's WSAPI:
https://rally1.rallydev.com/slm/doc/webservice/
That should be easier (and perform better) than grepping through all the revision history entries.
I am currently using this autocomplete plugin. It's pretty straightforward. It accepts a URL, and then uses that data to perform an auto-complete.
This is my code to auto-complete it.
autocompleteurl = '/misc/autocomplete/?q='+$("#q").val()
$("#q").autocomplete(autocompleteurl, {multiple:true});
If someone types "apple", that autocompleteurl page will return this result:
apple store,applebees,apple.com,apple trailers,apple store locator,apple vacations,applebees menu,apple iphone,apple tablet,apple tv
However, for some reason, when I actually use this auto-complete, everything is junked together. The plugin treats the entire page as a one big string, instead of separating the commas and treating them as individual items.
Can someone tell me what options I need to put in order to treat them as individual items? I've tried many options but none work.
From the manual (http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions)
A value of "foo" would result in this
request url:
my_autocomplete_backend.php?q=foo&limit=10
The result must return with one value
on each line. The result is presented
in the order the backend sends it.
From what you have posted it seems like you have it comma separated.
The plugin automatically adds the q to the querystring and uses the current value of the text box as the value.
This should be sufficient as long as you're returning the data in the correct format:
$("#q").autocomplete('/misc/autocomplete/', {multiple:true});
#alex I'm getting quirky behavior too - for 2/3/4 alphabets.
See http://docs.jquery.com/Plugins/Autocomplete/autocomplete#toptions .
If you set the minChars option to 2 or 3 it makes things more sane.
There's funny behavior when you have 5 results for "ab" and the same 5 results for "abc" - it does nothing, giving the impression that it is not working!
But it is working and I suspect it has to do with caching options.