Why accumulate Cloud Firestore doc.id? - javascript

I stored some data using db.collection("articles").doc(); and update it using db.collection("articles").doc(postData.articleId).update(postData);. But creating new article next time, the postData.articleId is accumulated.
First, I create a doc, then update data in real time using socket.io. but I create another doc later, postData.id was accumulated.
var doc = db.collection("articles").doc();
var postData = {
author: user.email,
articleId: doc.id,
currentTime: new Date()
}
doc.set(postData);
--- get data from client code here (using socket) ---
db.collection("articles").doc(postData.articleId).update(postData); /*Update Data to postData.id.*/
The expected result is not accumulation postData.id when new data added.
(For more info: https://github.com/officialmansu/opinion-express/tree/develop)

The update() method of Cloud Firestore is specifically meant to provide partial updates (sometimes also known as patches) to an existing document.
If you want to instead replace all existing data of the document, use set(). So:
db.collection("articles").doc(postData.articleId).set(postData);

Related

Display Firebase data appended with jquery to a table in order

I am currently trying to append data through I pull from Firebase to a table in the order of newest to oldest posts. I currently have the following setup in my code base (simplified to address issue):
var theDataRef = new Firebase('https://my-app.firebaseio.com');
theDataRef.orderByChild("timestamp").limitToLast(25).on('child_added', function (snapshot) {
var message = snapshot.val();
displaytableRow(message.name, message.text);
}
function displaytableRow(name, message) {
$("#sch").find('tbody > tr:first')
.before($("<tr><td><div>" + name + ":" + message + "</div></td></tr>"))
};
I have tried to create a table that displays newest to oldest data by using both firebase and jquery techniques but every time my data is displayed in a random order. I have a working timestamp field on every record in my data as well but even ordering by that does not solve the problem. Has anybody had any experience building this successfully?
EDIT:
The timestamp is gotten with the following code:
var timestamp = Firebase.ServerValue.TIMESTAMP;
And the database architecture is structured like so:
If you want to order your posts from newest to oldest you can do the following:
1/ Store a field in your post that is the inverse of the TimeStamp as follows:
var tDate = new Date().getTime();
var postData = {
//.....
timestampInverted: (0 - tDate),
//.....
};
2/ Query your posts ordered by this field as follows:
theDataRef.orderByChild("timestampInverted").limitToLast(25).once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
displaytableRow(childSnapshot.val().name, childSnapshot.val().text);
});
});
It is important to note that theDataRef.orderByChild("timestampInverted").limitToLast(25) returns a Query, which returns a DataSnapshot : Therefore you need to use snapshot.forEach() (see doc here) to iterate over the different posts items.
Also note that "even when there is only a single match for the query, the snapshot is still a list; it just contains a single item. To access the item, you always need to loop over the snapshot".

Firebase pushing array - Javascript

I am using Firebase to store information for a workout application.
I user adds a workout name and then I push it to the database. I can continue pushing these but my issue is that it does not seem to be pushing as an array just an object. See the screen shots below...
As you can see in the console log picture the workouts property is an object not an array like I expect.
The code I'm using to push it:
let newWorkout = {
title: 'title',
exercises: [{
name: 'pulldownsnsn',
sets: 4
}]}
let ref = firebase.database().ref("/userProfile/"+this.userId);
ref.child("workouts").push(newWorkout);
The Firebase Database stores lists of data in a different format, to cater for the multi-user and offline aspects of modern web. The -K... are called push IDs and are the expected behavior when you call push() on a database reference.
See this blog post on how Firebase handles arrays, this blog post on the format of those keys, and the Firebase documentation on adding data to lists.
Arrays are handy, but they are a distributed database nightmare for one simple reason: index element identification is not reliable when elements get pushed or deleted. Firebase database instead uses keys for element identification:
// javascript object
['hello', 'world']
// database object
{ -PKQdFz22Yu: 'hello', -VxzzHd1Umr: 'world' }
It gets tricky when using push(), because it does not actually behaves like a normal push, but rather as a key generation followed by object modification.
Example usage
firebase.database().ref('/uri/to/list').push(
newElement,
err => console.log(err ? 'error while pushing' : 'successful push')
)
Heres an example from firebase documentation:
const admin = require('firebase-admin');
// ...
const washingtonRef = db.collection('cities').doc('DC');
// Atomically add a new region to the "regions" array field.
const unionRes = await washingtonRef.update({
regions: admin.firestore.FieldValue.arrayUnion('greater_virginia')
});
// Atomically remove a region from the "regions" array field.
const removeRes = await washingtonRef.update({
regions: admin.firestore.FieldValue.arrayRemove('east_coast')
});
More info on this firebase documentation.

Querying a parse table and eagerly fetching Relations for matching

Currently, I have a table named Appointments- on appointments, I have a Relation of Clients.
In searching the parse documentation, I haven't found a ton of help on how to eagerly fetch all of the child collection of Clients when retrieving the Appointments. I have attempted a standard query, which looked like this:
var Appointment = Parse.Object.extend("Appointment");
var query = new Parse.Query(Appointment);
query.equalTo("User",Parse.User.current());
query.include('Rate'); // a pointer object
query.find().then(function(appointments){
let appointmentItems =[];
for(var i=0; i < appointments.length;i++){
var appt = appointments[i];
var clientRelation = appt.relation('Client');
clientRelation.query().find().then(function(clients){
appointmentItems.push(
{
objectId: appt.id,
startDate : appt.get("Start"),
endDate: appt.get("End"),
clients: clients, //should be a Parse object collection
rate : appt.get("Rate"),
type: appt.get("Type"),
notes : appt.get("Notes"),
scheduledDate: appt.get("ScheduledDate"),
confirmed:appt.get("Confirmed"),
parseAppointment:appt
}
);//add to appointmentitems
}); //query.find
}
});
This does not return a correct Clients collection-
I then switched over to attempt to do this in cloud code- as I was assuming the issue was on my side for whatever reason, I thought I'd create a function that did the same thing, only on their server to reduce the amount of network calls.
Here is what that function was defined as:
Parse.Cloud.define("GetAllAppointmentsWithClients",function(request,response){
var Appointment = Parse.Object.extend("Appointment");
var query = new Parse.Query(Appointment);
query.equalTo("User", request.user);
query.include('Rate');
query.find().then(function(appointments){
//for each appointment, get all client items
var apptItems = appointments.map(function(appointment){
var ClientRelation = appointment.get("Clients");
console.log(ClientRelation);
return {
objectId: appointment.id,
startDate : appointment.get("Start"),
endDate: appointment.get("End"),
clients: ClientRelation.query().find(),
rate : appointment.get("Rate"),
type: appointment.get("Type"),
notes : appointment.get("Notes"),
scheduledDate: appointment.get("ScheduledDate"),
confirmed:appointment.get("Confirmed"),
parseAppointment:appointment
};
});
console.log('apptItems Count is ' + apptItems.length);
response.success(apptItems);
})
});
and the resulting "Clients" returned look nothing like the actual object class:
clients: {_rejected: false, _rejectedCallbacks: [], _resolved: false, _resolvedCallbacks: []}
When I browse the data, I see the related objects just fine. The fact that Parse cannot eagerly fetch relational queries within the same call seems a bit odd coming from other data providers, but at this point I'd take the overhead of additional calls if the data was retrieved properly.
Any help would be beneficial, thank you.
Well, in your Cloud code example - ClientRelation.query().find() will return a Parse.Promise. So the output clients: {_rejected: false, _rejectedCallbacks: [], _resolved: false, _resolvedCallbacks: []} makes sense - that's what a promise looks like in console. The ClientRelation.query().find() will be an async call so your response.success(apptItems) is going to be happen before you're done anyway.
Your first example as far as I can see looks good though. What do you see as your clients response if you just output it like the following? Are you sure you're getting an array of Parse.Objects? Are you getting an empty []? (Meaning, do the objects with client relations you're querying actually have clients added?)
clientRelation.query().find().then(function(clients){
console.log(clients); // Check what you're actually getting here.
});
Also, one more helpful thing. Are you going to have more than 100 clients in any given appointment object? Parse.Relation is really meant for very large related collection of other objects. If you know that your appointments aren't going to have more than 100 (rule of thumb) related objects - a much easier way of doing this is to store your client objects in an Array within your Appointment objects.
With a Parse.Relation, you can't get around having to make that second query to get that related collection (client or cloud). But with a datatype Array you could do the following.
var query = new Parse.Query(Appointment);
query.equalTo("User", request.user);
query.include('Rate');
query.include('Clients'); // Assumes Client column is now an Array of Client Parse.Objects
query.find().then(function(appointments){
// You'll find Client Parse.Objects already nested and provided for you in the appointments.
console.log(appointments[0].get('Clients'));
});
I ended up solving this using "Promises in Series"
the final code looked something like this:
var Appointment = Parse.Object.extend("Appointment");
var query = new Parse.Query(Appointment);
query.equalTo("User",Parse.User.current());
query.include('Rate');
var appointmentItems = [];
query.find().then(function(appointments){
var promise = Parse.Promise.as();
_.each(appointments,function(appointment){
promise = promise.then(function(){
var clientRelation = appointment.relation('Clients');
return clientRelation.query().find().then(function(clients){
appointmentItems.push(
{
//...object details
}
);
})
});
});
return promise;
}).then(function(result){
// return/use appointmentItems with the sub-collection of clients that were fetched within the subquery.
});
You can apparently do this in parallel, but that was really not needed for me, as the query I'm using seems to return instantaniously. I got rid of the cloud code- as it didnt seem to provide any performance boost. I will say, the fact that you cannot debug cloud code seems truly limiting and I wasted a bit of time waiting for console.log statements to show themselves on the log of the cloud code panel- overall the Parse.Promise object was the key to getting this to work properly.

JSPlumb diagram to JSON

I've been developing a diagramming tool, I used JSPlumb.
I made shapes using css and connections are made through JSplumb.
I need to save the diagram as json or xml format. But I am having a hard time.
For example, this is the function for saving the diagram
$(function save() {
//$("#editor").resizable("destroy");
Objs = [];
$('#editor').each(function(){
Objs.push({id:$(this).attr('id'), html:$(this).html(), left:$(this).css('left'), top:$(this).css('top'), width:$(this).css('width'), height:$(this).css('height')});
});
console.log(Objs);
});
Also, I've been trying the stringify for getting the data and parse for loading but I still can't figure it out.
Is there a way that I can save jsplumb to json or xml?
Whenever a connection is established, "connection" event is triggered. You need to store the connection endpoints details in that triggered function so that you can retrieve them later.
First make sure that you have set proper id for your endpoints. You can manually set at time of endpoint creation as:
var e0 = jsPlumb.addEndpoint("div1",{uuid:"div1_ep1"}), // You can also set uuid based on element it is placed on
e1 = jsPlumb.addEndpoint("div2",{uuid:"div2_ep1"});
Now bind the connection event where you will store the established connections info:
var uuid, index=0; // Array to store the endpoint sets.
jsPlumb.bind("connection", function(ci) {
var eps = ci.connection.endpoints;
console.log(eps[0].getUuid() +"->"+ eps[1].getUuid()); // store this information in 2d-Array or any other format you wish
uuid[index][0]=eps[0].getUuid(); // source endpoint id
uuid[index++][1]=eps[1].getUuid(); // target endpoint id
}
});
You can convert the array information to JSON format and store it. On restoring, connect the endpoints based on uuid. code:
jsPlumb.connect({ uuids:["div1_ep1","div2_ep1"] });
Here is the jsFiddle for making connections based on endpoints.
NOTE: The above code is only for restoring the connection and endpoints information after you have restored the div's css. You can store the css properties of all div's by using the same method which you wrote in your question.
I just recently tied this and its working
function createJSON(){
var data = new Object();
$("input[class = process]").each(function(){
data[$(this).attr("name")] = $(this).val();
jsonString = JSON.stringify(data);
});
console.log(jsonString);
}

Saving a model in local storage

I'm using Jerome's localStorage adapter with Backbone and it works great for collections.
But, now I have a single model that I need to save. So in my model I set:
localStorage: new Store("msg")
I then do my saves and fetch. My problem is that everytime I do a refresh and initialize my app a new representation of my model is added to localStorage, see below.
What am I doing wrong?
window.localStorage.msg = {
// Created after first run
"1de5770c-1431-3b15-539b-695cedf3a415":{
"title":"First run",
"id":"1de5770c-1431-3b15-539b-695cedf3a415"
},
// Created after second run
"26c1fdb7-5803-a61f-ca12-2701dba9a09e":{
"0":{
"title":"First run",
"id":"1de5770c-1431-3b15-539b-695cedf3a415"
},
"title":"Second run",
"id":"26c1fdb7-5803-a61f-ca12-2701dba9a09e"
}
}
I ran into same issue. Maybe you have something similar to this
var Settings = Backbone.Model.extend({
localStorage: new Store("Settings"),
defaults: { a: 1 }
});
var s = new Settings;
s.fetch();
I changed to
var s = new Settings({ id: 1 });
localStorage adapter check for id like
case "read": resp = model.id ? store.find(model) : store.findAll(); break;
so 0 or "" for id wont work and it will return all models in one
I'm new to backbone.js too, but it looks like the persistence model is analogous to database tables. That is to say, it's designed to create/delete/read records from a table. The localStorage adapter does the same, so what you are doing there is creating a Msg "table"
in localStorage, and creating a new Msg "record" each time, and the adapter gives each new Msg a unique id.
If you just have one object, it's probably easier to just use localStorage directly. The API is really straight forward:
localStorage.setItem("key","value");
Keep in mind that localStorage only deals with key/value pairs as strings, so you'd need to convert to/from string format.
Take a look a this question for more on doing that:
Storing Objects in HTML5 localStorage

Categories

Resources