Voting system with Backbone.js - mongodb

I have a Book model that has the property upVotes. Book instances can be queried from the database (MongoDB), modified, and then saved. If a user upvotes a book, I update the upVotes count, and save the whole model back to the server.
The problem is that if someone else votes between the time the instance is loaded, and the time the instance is saved, then the two votes will be saved as just one vote. What I need is an easy way to say "increment the model by 1 server-side", instead of "increment the model by 1 client-side and hope there will be no conflict".

You don't have to save the whole model to the server just to change one thing, you can (and should in this case) add an upVote method to your model that does an "increment upvotes" AJAX call to your server. In your model you'd have something like this:
upVote: function() {
var self = this;
$.ajax({
url: '/some/upvote/path',
type: 'POST',
success: function(data) {
self.set('upVotes', data.upVotes);
},
// ...
});
}
And then the view would have this to handle the upvote action:
upVote: function() {
// Highlight the upvote button or provide some other feedback that
// the upvote has been seen.
this.model.upVote();
}
and you'd probably have a listener for change events on the model's upVotes property to properly increment the displayed upvote counter (if you have such a thing).
Furthermore, your /some/upvote/path on the server would just send an $inc update into MongoDB to avoid the same "two things happening at once" problem on your server. If you were using a relational database, you'd want to end up doing something like update t set upvotes = upvotes + 1 where id = ?.
There is no need for a "query, update, save" round trip on either the client or the server for a simple increment operation. Instead, treat the increment as a single increment operation and push that increment all the way down to your final persistent data storage layer.

Related

Firestore idempotency for a virtual wallet

I'm coming to you guys again for help. I have an app, in which you can top up your own virtual wallet from your credit card.
My structure is as followers:
collection transactions/{transactionId} -- contains an owner UID and the top up amount.
collection users/{userId}/personal/wallet containing { funds: 0 }
I am keeping the wallet into a subcollection of personal info because I don't want other users to see it.
Anyway, I have an onCreate trigger called walletSync for new documents under transactions collection, from which I take the amount and add it to the user's current funds via runTransaction.
Problem is, the function sometime triggers three times ... for one document. Here's a screenshot. I have logged the transactionId ( which is just one document ) and as you can see, onCreate, is being processed three times, therefore, topping up my wallet with three times the actual value.
Here's my function code, in which I am marking any processed transaction with processed: true so I can ignore it next time it triggers. As you can see in the logs, that processed_already message never pops up, which means the trigger does not fetch the new data, next time it triggers.
I am out of ideas here, please advise.
EDIT: Here's my function: https://pastebin.com/PRA7CbxL
I have managed to figure it out, with the help of the mighty #Doug and the mentioned similar questions.
After all, the issue with my code was that while I was marking my transaction as processed, I was assuming that the second / third time the function triggers, snapshot.data() would be the value of the document, ( took me some time to realize ) it was actually the change data sent towards the database trigger. I know it sounds confusing, but the function is not being sent the value of the document ( for that you could get snapshot.ref and fetch the data from there, in order to get the updated value in a transaction ).
So here's my updated function on Pastebin. Here's a screenshot of the code in action: https://i.imgur.com/fbQSGT6.png

Using childByAutoId On Single Value?

I am pretty new to both Swift and Firebase, and I am attempting to make a simple app using Firebase as the backend. As far as I know, there is no memory-efficient way to use the numChildren() function without loading every single child into memory for counting, so I am implementing my own simple counter for the number of "Events" that have been created in my app.
The documentation for Firebase states that the childByAutoID() method should be used for updating lists in multi-user applications. I am assuming it adds a timestamp to the requested update and does them in order.
My question is whether it is necessary to use childByAutoID() when only updating a SINGLE field in a multi-user application. That is, will there be conflicts on my numEvents field if I do:
dbRef = FIRDatabase.database().reference()
dbRef.child("numEvents").setValue(num)
Or must I do:
dbRef = FIRDatabase.database().reference()
dbRef.child("numEvents").childByAutoId().setValue(num)
In order to avoid write conflicts? My only real confusion is that the documentation for childByAutoID stresses that it is useful when the children are a list of items, but mine is only a single item.
If you are only updating a single field you should not be using childByAutoId. To update a child value for an object, you need to obtain a reference to that object somehow, perhaps by a query of some sort (in many cases you will naturally already have a reference to the object if it needs to be changed) and you can change the value like this:
dbRef.child("events").child(objectToUpdateId).child(fieldToUpdateKey).setValue(newValue)
childByAutoId in this context would be used to create a new field like:
dbRef.child("events").childByAutoId().setValue(newObject)
I'm not exactly sure how this applies to your situation, but those are some descriptions of how to update a field, and use childByAutoId.
What childByAutoId does is create a unique key for a node, to avoid using the same key multiple times and then creating data conflicts like inconsistency (not write conflicts) to avoid write conflicts you use the transaction blocks.
The best way to learn is to try it out
If num == 1 , in the first example the result will be
dbRef:{
numEvents:1
}
While the second will be
dbRef:{
numEvents:{
//The auto-generated key
KLBHJBjhbjJBJHB:1
}
}
The childByAutoId would be useful if you want to save in a node multiple children of the same type, that way each children will have its own unique identifier
For example
pet:{
KJHBJJHB:{
name:fluffy,
owner:John Smith,
},
KhBHJBJjJ:{
name:fluffy,
owner:Jane Foster,
}
}
This way you have a unique identifier for cases where there is no clear way with the item data to guarantee it will be unique (in this case the pet's name)
Few things here:
childByAutoId is not a timestamp. But is used to create unique nodes in any given node.
Use case of childByAutoId :
You have messages node which stores messages from multiple user who are involved in a group chat. So each user can add messages in the group chat so you would do something like this each time user sends message:
dbRef = FIRDatabase.database().reference()
dbRef.child("messages").childByAutoId().setValue(messageText)
So this will create a unique message id for each message from different users. This will kind of act like primary key of message in normal databases.
The structure of database will be something like this:
messages: {
"randomIdGenerated-12asd12" : "hello",
"randomIdGenerated-12323D123" : "Hi, HOw are you",
}
So in your case your first approach is good enough! Since you dont need unique node for counting number of events added.

How to save one value of Parse object without overwriting entire object?

I have two users accessing the same object. If userA saves without first fetching the object to refresh their version, data that userB has already successfully saved would be overwritten. Is there any way(perhaps cloud code?) to access and update one, and only one, data value of a PFObject?
I was thinking about pushing the save out to the cloud, refreshing the object once it gets there, updating the value in the cloud, and then saving it back. However that's a pain and still not without it's faults.
This seems easy enough, but to me was more difficult than it should have been. Intuitively, you should be able to filter out the fields you don't want in beforeSave. Indeed, this was the advice given in several posts on Parse.com. In my experience though, it would actually treat the filtering as deletions.
My goal was a bit different - I was trying to filter out a few fields and not only save a few fields, but translating to your context, you could try querying the existing matching record, and override the new object. You can't abort via response.failure(), and I don't know what would happen if you immediately save the existing record with the field of interest and null out the request.object property - you could experiment on your own with that:
Parse.Cloud.beforeSave("Foo", function(request, response) {
// check for master key if client is not end user etc (and option you may not need)
if (!request.master) {
var query = new Parse.Query("Foo");
query.get(request.object.id).then(function(existing) {
exiting.set("some_field", request.object.get("some_field"));
request.object = exiting; // haven't tried this, otherwise, set all fields from existing to new
response.success();
}, function(error) {
response.success();
});
}
});

Firebase: how to generate a unique numeric ID for key?

I need numeric IDs for human readability. How do I get it in Firebase?
I want numeric ID for keys, e.g. "000000001", "000000002","00000003","00000004".
The reason I need it is because these IDs will become the permanent object ID both online and offline. I want users to be able to browse that object page by just entering URL "/objects/00000001" without efforts.
I am asking here, because I want to know if this can be done without using .priority, sub-properties, etc. I guess set method can do it somehow. If it is not possible, just tell me no, I can accept that answer.
I'd suggest reading through the Firebase documentation. Specifically, see the Saving Data portion of the Firebase JavaScript Web Guide.
From the guide:
Getting the Unique ID Generated by push()
Calling push() will return a reference to the new data path, which you can use to get the value of its ID or set data to it. The following code will result in the same data as the above example, but now we'll have access to the unique push ID that was generated
// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push({
author: "gracehop",
title: "Announcing COBOL, a New Programming Language"
});
// Get the unique ID generated by push() by accessing its key
var postID = newPostRef.key;
Source: https://firebase.google.com/docs/database/admin/save-data#section-ways-to-save
A push generates a new data path, with a server timestamp as its key. These keys look like -JiGh_31GA20JabpZBfa, so not numeric.
If you wanted to make a numeric only ID, you would make that a parameter of the object to avoid overwriting the generated key.
The keys (the paths of the new data) are guaranteed to be unique, so there's no point in overwriting them with a numeric key.
You can instead set the numeric ID as a child of the object.
You can then query objects by that ID child using Firebase Queries.
From the guide:
In JavaScript, the pattern of calling push() and then immediately calling set() is so common that we let you combine them by just passing the data to be set directly to push() as follows. Both of the following write operations will result in the same data being saved to Firebase:
// These two methods are equivalent:
postsRef.push().set({
author: "gracehop",
title: "Announcing COBOL, a New Programming Language"
});
postsRef.push({
author: "gracehop",
title: "Announcing COBOL, a New Programming Language"
});
Source: https://firebase.google.com/docs/database/admin/save-data#getting-the-unique-key-generated-by-push
As explained above, you can use the Firebase default push id.
If you want something numeric you can do something based on the timestamp to avoid collisions
f.e. something based on date,hour,second,ms, and some random int at the end
01612061353136799031
Which translates to:
016-12-06 13:53:13:679 9031
It all depends on the precision you need (social security numbers do the same with some random characters at the end of the date). Like how many transactions will be expected during the day, hour or second. You may want to lower precision to favor ease of typing.
You can also do a transaction that increments the number id, and on success you will have a unique consecutive number for that user. These can be done on the client or server side.
(https://firebase.google.com/docs/database/android/read-and-write)
Adding to the #htafoya answer.
The code snippet will be
const getTimeEpoch = () => {
return new Date().getTime().toString();
}
As the docs say, this can be achieved just by using set instead if push.
As the docs say, it is not recommended (due to possible overwrite by other user at the "same" time).
But in some cases it's helpful to have control over the feed's content including keys.
As an example of webapp in js, 193 being your id generated elsewhere, simply:
firebase.initializeApp(firebaseConfig);
var data={
"name":"Prague"
};
firebase.database().ref().child('areas').child("193").set(data);
This will overwrite any area labeled 193 or create one if it's not existing yet.
https://firebase.google.com/docs/firestore/manage-data/transactions
Use transactions and keep a number in the database somewhere that you can increase by one. This way you can get a nice numeric and simple id.

Meteor and MongoDB dropdown population and integrity

Hopefully I can describe this correctly but I come from the RDBMS world and I'm building an inventory type application with Meteor. Meteor and Mongodb may not be the best option for this application but hopefully it can be done and this seems like a circumstance that many converts will run into.
I'm trying to forget many of the things I know about relational databases and referential integrity so I can get my head wrapped around Mongodb but I'm hung up on this issue and how I would appropriately find the data with Meteor.
The inventory application will have a number of drop downs but I'll use an example to better explain. Let's say I wanted to track an item so I'll want the Name, Qty on Hand, Manufacturer, and Location. Much more than that but I'm keeping it simple.
The Name and Qty on Hand are easy since they are entered by the user but the Manufacturer and the Location should be chosen in a drop down from a data driven list (I'm assuming a Collection of sorts (or a new one added to the list if it is a new Manufacturer or Location). Odds are that I will use the Autocomplete package as well but the point is the same. I certainly wouldn't want the end user to misspell the Manufacturer name and thereby end up with documents that are supposed to have the same Manufacturer but that don't due to a typo. So I need some way to enforce the integrity of the data stored for Manufacturer and Location.
The reason is because when the user is viewing all inventory items later, they will have the option of filtering the data. They might want to filter the inventory items by Manufacturer. Or by Location. Or by both.
In my relational way of thinking this would just be three tables. INVENTORY, MANUFACTURER, and LOCATION. In the INVENTORY table I would store the ID of the related respective table row.
I'm trying to figure out how to store this data with Mongodb and, equally important, how to then find these Manufacturer and Location items to populate the drop down in the first place.
I found the following article which helps me understand some things but not quite what I need to connect the dots in my head.
Thanks!
referential data
[EDIT]
Still working at this, of course, but the best I've come up with is to do it normalized way much like is listed in the above article. Something like this:
inventory
{
name: "Pen",
manufacturer: id: "25643"},
location: {id: "95789"}
}
manufacturer
{
name: "BIC",
id: "25643"
}
location
{
name: "East Warehouse",
id: "95789"
}
Seems like this (in a more simple form) would have to be an extremely common need for many/most applications so want to make sure that I'm approaching it correctly. Even if this example code were correct, should I use an id field with generated numbers like that or should I just use the built-in _id field?
I've come from a similar background so I don't know if I'm doing it correctly in my application but I have gone for a similar option to you. My app is an e-learning app so an Organisation will have many Courses.
So my schema looks similar to yours except I obviously have an array of objects that look like {course_id: <id>}
I then registered a helper than takes the data from the organisation and adds in the additional data I need about the courses.
// Gets Organisation Courses - In your case could get the locations/manufacturers
UI.registerHelper('organisationCourses', function() {
user = Meteor.user();
if (user) {
organisation = Organisations.findOne({_id: user.profile.organisation._id});
courses = organisation.courses.courses;
return courses;
} else {
return false;
}
});
// This takes the coursedata and for each course_id value finds and adds all the course data to the object
UI.registerHelper('courseData', function() {
var courseContent = this;
var course = Courses.findOne({'_id': courseContent.course_id});
return _.extend(courseContent, _.omit(course, '_id'));
});
Then from my page all I have to call is:
{{#each organisationCourses}}
{{#with courseData}}
{{> admListCoursesItem}}
{{/with}}
{{/each}}
If I remember rightly I picked up this approach from an EventedMind How-to video.