I'm using Firebase framework to create a WepApp for a Final project that I'm doing. I'm managing small air-line company. I have the database structure below:
{
destination:
{New-York:
{
1:{
person1:"ADAM",
person2:"Joy"}
2...31:
}
Los-Angeles:{
1:{
preson1:"Roy",
person2:"Noy"
}
2..31:
}
}
How can I retrieve only person1 from New-York[1] and Person2 from Los-Angeles[5]? Is it possible? Or anyone else have an other solution the wont kill my Bandwidth credits? Thanks a lot.
**EDIT: I'm using it for a Web App hence I'm writing the code with JavaScript (Using Web-storm IDE).
I tried pulling the whole database , meaning retrieving the whole 'destination' object using:
var ref=firebase.database().ref('/destination/').once("value");
ref.then(function(snapshot){MY-CODE...})
but doing that I'm "eating" my bandwidth allocating
If you want to retrieve the value stored in person1 or person2, then just specify the full path and then call snapshot.val(), it will return the value stored in that location.
firebase.database().ref('destination/New-York/1/person1').on('value', function(snapshot) {
console.log(snapshot.val()); //ADAM
});
firebase.database().ref('destination/Los-Angeles/5/person2').on('value', function(snapshot) {
console.log(snapshot.val()); //Name of Person 2
});
Related
This time I'm facing a problem with formatting data from Firebase. This is how structure in my database looks:
I'm getting it from database using this code:
const preObject = document.getElementById('object')
var parametryObject = firebase.database()
.ref('Parametry_powietrza')
.limitToLast(1)
.once('value').then(function(snapshot) {
var listaParametrow = snapshot.val();
console.log(listaParametrow);
preObject.innerText = JSON.stringify(snapshot.val(), null, 3)
});
And on my webpage it looks like:
My question is - how to properly refer to that data to be able to change its appearance using HTML and CSS?
Thank you! :)
It looks like you're trying to access the data inside your JSON object being returned to you from your FireBase RealTime database (RTDB). But the way you've structured your data makes it near impossible for your javascript to iterate through it.
Some pointers I can give you regarding your data in the Realtime Database atm:
1) Datetime is typically stored in what's called Epoch Time. Which is typically the number of seconds since Jan 1, 1970. The number can easily be converted back into text using various javascript time libraries. An easy one to try out is Luxon. You can see epoch time with this online convertor here.
2) Secondly, RTDB supports the creation of unique, sequential, sortable "push-id" whenever you call the .push({ myDataObject }) function. So there's no need to store the date and the time as the "keys" to your object. More info about the push-id here and here. It's really interesting stuff!
3) I hate to be writing this suggestion because it seems like taking a step back before you can take steps forward, but I feel like you would benefit alot on looking at some articles on designing databases and how to sensibly structure your data. Firebase also has a great introduction here. If it's any help, for your data structure, I suggest modifying your data structure to something like below:
{
Parametry_powietrza: {
[firebase_push_id]: {
timestamp: 726354821,
Cisnienie: 1007.78,
Temperatura: 19.23,
Wilgotnosc: 52.00,
},
[firebase_push_id]: {
timestamp: 726354821,
Cisnienie: 1007.78,
Temperatura: 19.23,
Wilgotnosc: 52.00,
}
}
}
That way, when firebase returns your data, you can iterate through the data much more easily and extract the information you need like:
database
.ref('Parametry_powietrza')
.limitToLast(10)
.once('value', snapshot => {
snapshot.forEach(child => {
// do what you need to do with the data
console.log("firebase push id", child.key);
console.log("data", child.val());
})
});
All the best! BTW are you using any javascript frameworks like React or Vue?
I am storing location data via GeoFire in my database, here is the structure:
geofire
-Ke1uhoT3gpHR_VsehIv
-Kdrel2Z_xWI280XNfGg
-g: "dr5regw90s"
-l
-0: 40.7127837
-1: -74.00594130000002
It is avised to store a location's information and geofire data in separate nodes, however I see an advantage to storing some extra data under these geofire nodes, such as the name of a business. This way I'd only have to make only one call to my Firebase to fetch nearby locations as well as their names.
Is this achievable via the key_entered method? Has anyone created a similar solution? Is this truly that bad of an idea even if the location info is consistently updated?
Any input is appreciated!
Firstly the structure you are using for the app is wrong.
let us take an example of users app
When you use Geofire, you have two lists of data:
a list of user details for each user
a list of latitude and longitude coordinates for each user
You are trying to store both in same structure like this
"users" : {
<userId> : {
"userData" : "userData",
<geofireData>
...
}
}
Trying to store userdata and geofiredata in one node is a bad idea, since you're mixing mostly static data (the properties of your user) with highly volatile data (the geo-location information).Separating the two out leads to better performance, which is why Geofire enforces it.
This is why when you try to add geolocation data to a user node it overwrites previous user details for that node.
Your database structure should be like this.
"Users" : {
<UserId> : {
"UserData" : "UserData",
...
}
}
"Users_location" : {
<UserId> : {
<geofireData> ...
}
}
Hence for the same user Id you create 2 structures one for user details and another for geolocation details of that user.
How to push the user and set the geofire data.
String userId = ref.child("users").push().getKey();
ref.child("users").child(userId).setValue(user);
geoFire = new GeoFire(ref.child("user_location"));
geoFire.setLocation(userId, new GeoLocation(lattitude, longitude));
the userId you use in geolocation is same as the one you got during push().
Hence for each userId you have userdetails in one structure and location details in anotehr structure.
To get the data, first you need to do GeoQuery at users_location node and then get the data on the onKeyEntered method. The parameter key is userId from my example.
geoFire=newGeoFire(FirebaseDatabase.getInstance().getReference().child("users_location");
geoQuery = geoFire.queryAtLocation(geoLocation), radius);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
#Override
public void onKeyEntered(String key, GeoLocation location) {
//retrieve data
//use this key which is userId to fetch user details from user details structure
}
};
Happy coding :)
It might be late but just in case someone else is facing the same issue.
It's very possible to integrate and manipulate GeoFire data with existing data.
The main challenge faced by many developers is the fact that they can't update the GeoFire geolocation without deleting the existing data using geoFire.setLocation("id", location); as reported in this issue geofire-java/issues/134.
This is my solution for that.
1. Setting mixed data with GeoFire on FireBase
Let's consider below Structure:
|-userExtra :
|-userId1 :
|- userId : "userId1",
|- userName : "Name1",
|- <geofireData> (i and g)
|...
|-userId2 :
|- userId : "userId2",
|- userName : "Name2",
|- <geofireData> (i and g)
|...
You can generate the geoHash with GeoHash geoHash = new GeoHash(location) and set the value to the child directly in the firebase.
/*Java Code*/
void setGeoFireMixData(UserExtra user, Location location){
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref = ref.child("users").child(user.userId);
//Setting userData if needed
ref.child("userId").setValue(user.id);
ref.child("Name").setValue(user.name);
// .... other references
//Setting GeoFire Data
GeoHash geoHash = new GeoHash(location);
ref.child("l").setValue(Arrays.asList(location.latitude, location.longitude));
ref.child("g").setValue(geoHash.getGeoHashString());
}
2. Fetching mixed data with GeoFire
About the question:
Is this achievable via the key_entered method? Has anyone created a similar solution? Is this truly that bad of an idea even if the location info is consistently updated?
I'd say, you can't retrieve both extra data and GeoFire using only the GeoQueryEventListener with onKeyEntered. You will need to use GeoQueryDataEventListener. For that, you can define the PoJo of your data considering the structure defined above.
...
GeoQueryDataEventListener geoQueryDataEventListener = new GeoQueryDataEventListener() {
#Override
public void onDataEntered(DataSnapshot dataSnapshot, GeoLocation location) {
UserExtra user = dataSnapshot.getValue(UserExtra.class);
actionOnUser(user);
}
...
};
...
geoQuery = geoFire.queryAtLocation(new GeoLocation(latitude,longitude), 0.5);
geoQuery.addGeoQueryDataEventListener(geoQueryDataEventListener);
...
The class UserExtra can be defined as below:
public class UserExtra implements Serializable {
String userId;
String name;
...
List<Double> l; //GeoLocation
String g;
}
That will give you all the data in your node including the geoFire data.
I had this solution I am using now for Javascript:
Save any extra info with key separated by symbol i.e. underscore
Make sure auth id is in the key, which is used in security rules to ensure only the user can write to their node
"rules": {
"geofire": {
".read":"true",
"$extrainformation_authid":{
".write":"$extrainformation_authid.contains(auth.uid)"
}
}
}
Client-side, separate the information by the underscore
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);
}
I'm working on a web application using node.js that has a form containing basic information about a person. I need to have all records that have been added since the web application was started display on the submit page.
I believe that I need to create an array to store this information but this is where my confusion starts. I'm not sure where to create the array to add information to. I suspect it should be in app.js where I call app.post('/add', routes.add);
I think it should maybe something like this going from an example I found here How do I add a new complex entry to a javascript array?:
// Routes
app.get('/', routes.index);
app.post('/add', routes.add);
var people = [{name, country, date, email, phone}];
people.push({name, country, date, email phone});
However the array looks like it will only hold enough information for 1 person.
Please let me know if my question is not clear enough and I will try to clarify
Thanks in advance!
Edit: I believe that when I am calling routes.add this code is executed from my index.js file
exports.add = function(req, res){
res.render('add', { title: 'Person added',
name: req.body.name,
country: req.body.country,
date: req.body.birthday,
email: req.body.email,
phone: req.body.phone});
};
and in my add.jade file:
h1 Info Added
p Name: #{name}
p Country: #{country}
p Date: #{date}
p Email: #{email}
p Phone: #{phone}
There are a few things to maybe get you started.
Database
I suggest you move the database to another file, that way you may replace it with a 'real' database later. Ie. do something like this:
create a lib directory in app root,
create a db.js in that directory,
put this code in the db.js:
var database = [],
counter = 0;
// add method adds a new object to db.
exports.add = function(person) {
person.id = counter;
counter = counter + 1;
database.push(person);
return id; // we return id, so that we can use it as a reference to this object.
}
// get method retreives the object by id.
exports.get = function(id) {
return database[id]; // this will return undefined if there is no such id
};
exports.list = function(){
return database;
}
Now you have a database.
Controllers
You use the db in other files like this:
var people = require('lib/db');
// or if you're in a routes directory,require('../lib/db') or appropriate path
people.add({name: 'Sarah'}); // returns 0
people.add({name: 'Zlatko'}); // returns 1
people.get(1); // returns {name: 'Zlatko'}
Now in your routes/index.js you can include your database and have this to save or retreive an user or all users. Somehing similar to your exports.add:
var id = people.add({name: req.body.name, email: req.body.email});
res.render('add', people.get(id));
You can also create a 'people' view and just pass it {people: people.list()} object as parameters array.
I didn't include any validation, checking, anything ,to make the example more clear. This db can hold more then one person, and it's enough to get you started. And I think it is clear in what it does.
I hope this helps.
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