I'm having trouble figuring out how to target a single object in the firebase database. For example, I want to have a specific word/definition shown when I click an index card. I'm using this to store the data:
wordVal = $("#word").val();
defVal = $("#def").val();
data = firebase.database().ref("indexCards");
data.push( { 'word': wordVal, 'definition': defVal } );
and this to retrieve it:
data.on("child_added", function(snapshot){
console.log(snapshot.val().word);
console.log(snapshot.val().definition);
});
This gives me the whole list of words and definitions. I want to refer to specific words and specific definitions, separately. The docs say that I can reference the specific values by doing this - firebase.database().ref("child/path").
But my question is...how can I reference the path when the parents are those random numbers and letters (see below)? I know that these are unique IDs generated by firebase, but I don't know how to access them like I'd access ordinary objects.
{
"-KQIOHLNsruyrrnAhqis" : {
"definition" : "person, place, thing",
"word" : "noun"
},
"-KQIOO7Wtp2d5v2VorqL" : {
"definition" : "device for photos",
"word" : "camera"
},
"-KQISp4WMnjABxQayToD" : {
"definition" : "circus act",
"word" : "clown"
},
"-KQITC9W1lapBkMyiL7n" : {
"definition" : "device used for cutting",
"word" : "scissors"
}
}
You can use a query like this:
data = firebase.database().ref('indexCards').orderByChild('word').equalTo('noun')
It is self-explanatory, we get reference to indexCards where value of key word is equal noun, so it will return object with key -KQHZ3xCHTQjuTvonSwj
Link to Firebase docs: Retrieve data - Sorting and Filtering data
You need to put the initial push into an object then call the object later. ie
To PUSH data:
firebase.database().ref().push( { 'word': wordVal, 'definition': defVal } )
To UPDATE data or call it later:
firebase.database().ref("indexCards").set({})
or in this case:
data.set({})
Related
This is a simplified version of the DB structure that I'm working with:
"user" : {
"nhbAQ9p8BrMoAIbJNKvLlXTdiNz2" : {
"log" : {
"-LhMVugmjmIdqwrJSURp" : {
"a" : 25120,
"timeStamp" : 1560312000000,
},
"-Lh_Z9GsJJvlMOpVV9jU" : {
"a" : 19033,
"timeStamp" : 1564718400000,
}
}
}
}
I'm having issues filtering and retrieving the value of "a" with a given user id (e.g. nhbAQ9p8BrMoAIbJNKvLlXTdiNz2) and timeStamp (e.g.1560312000000).
I've tried combinations of orderByChild(), equalTo(), and adding a once() listener to do the task but they've only returned null so far.
The code that I have:
firebase.database().ref('user/' + userID + + '/log').orderByChild('timeStamp').equalTo(targetTimeStamp).once('value').then(function(snapshot){
let userLog = snapshot.val().a
})
where userID is a string and targetTimeStamp is a number.
I checked the doc and a post about orderByChild() but I'm still not sure what is causing it to return null.
This is my first time posting a question, please comment if there's anyway I can make this clearer and any help is much appreciated!
where userID and targetTimeStamp are both strings.
That is the reason nothing is returned. In the database the values of the timeStamp property is a number, and comparing a number to a string never returns a match.
To make the query work, convert the string to a number:
...equalTo(parseInt(targetTimeStamp)).once(...
Aside from that a query against the Firebase Database may potentially have multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
So you need to handle that case too:
firebase.database().ref('user/' + userID + + '/log').orderByChild('timeStamp').equalTo(targetTimeStamp).once('value').then(function(results){
results.forEach(function(snapshot) {
let userLog = snapshot.val().a
})
})
Introduction
I'm learning JavaScript on my own and JSON its something along the path. I'm working on a JavaScript WebScraper and I want, for now, load my results in JSON format.
I know I can use data base, server-client stuff, etc to work with data. But I want to take this approach as learning JSON and how to parse/create/format it's my main goal for today.
Explaining variables
As you may have guessed the data stored in the fore mentioned variables comes from an html file. So an example of the content in:
users[] -> "Egypt"
GDP[] -> "<td> $2,971</td>"
Regions[] -> "<td> Egypt </td>"
Align[] -> "<td> Eastern Bloc </td>"
Code
let countries = [];
for(let i = 0; i < users.length; i++)
{
countries.push( {
'country' : [{
'name' : users[i],
'GDP' : GDP[i],
'Region' : regions[i],
'Align' : align[i]
}]})
};
let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);
Code explanation
I have previously loaded into arrays (users, GDP, regionsm align) those store the data (String format) I had extracted from a website.
My idea was to then "dump" it into an object with which the stringify() function format would format it into JSON.
I have tested it without the loop (static data just for testing) and it works.
Type of error
let obj_data = JSON.stringify(countries, null, 2);
^
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Node'
| property 'children' -> object with constructor 'Array'
| index 0 -> object with constructor 'Node'
--- property 'parent' closes the circle
What I want from this question
I want to know what makes this JSON format "Circular" and how to make this code work for my goals.
Notes
I am working with Node.js and Visual Studio Code
EDIT
This is further explanation for those who were interested and thought it was not a good question.
Test code that works
let countries;
console.log(users.length)
for(let i = 0; i < users.length; i++)
{
countries = {
country : [
{
"name" : 'CountryTest'
}
]
}
};
let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);
});
Notice in comparison to the previous code, right now I am inputing "manually" the name of the country object.
This way absolutely works as you can see below:
Now, if I change 'CountryTest' to into a users[i] where I store country names (Forget about why countries are tagged users, it is out of the scope of this question)
It shows me the previous circular error.
A "Partial Solution" for this was to add +"" which, as I said, partially solved the problem as now there is not "Circular Error"
Example:
for(let i = 0; i < users.length; i++)
{
countries = {
country : [
{
"name" : users[i]+''
}
]
}
};
Resulting in:
Another bug, which I do not know why is that only shows 1 country when there are 32 in the array users[]
This makes me think that the answers provided are not correct so far.
Desired JSON format
{
"countries": {
"country": [
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
},
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
},
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
}
]}
}
Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a) or indirectly (a -> b -> a).
To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference. For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:
JSON.stringify( that.person, function( key, value) {
if( key == 'parent') { return value.id;}
else {return value;}
})
The second parameter to stringify is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.
You can test the above code with the following:
function Person( params) {
this.id = params['id'];
this.name = params['name'];
this.father = null;
this.fingers = [];
// etc.
}
var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him;
JSON.stringify(me); // so far so good
him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
if(key == 'father') {
return value.id;
} else {
return value;
};
})
The answer is from StackOverflow question,
Stringify (convert to JSON) a JavaScript object with circular reference
From your output, it looks as though users is a list of DOM nodes. Rather than referring to these directly (where there are all sort of possible cyclical structures), if you just want their text, instead of using users directly, try something like
country : [
{
"name" : users[i].textContent // maybe also followed by `.trim()
}
]
Or you could do this up front to your whole list:
const usersText = [...users].map(node => node.textContent)
and then use usersText in place of users as you build your object.
If GDP, regions and align are also references to your HTML, then you might have to do the same with them.
EUREKA!
As some of you have mentioned above, let me tell you it is not a problem of circularity, at first..., in the JSON design. It is an error of the data itself.
When I scraped the data it came in html format i.e <td>whatever</td>, I did not care about that as I could simply take it away later. I was way too focused in having the JSON well formatted and learning.
As #VLAZ and #Scott Sauyezt mentioned above, it could be that some of the data, if it is not well formatted into string, it might be referring to itself somehow as so I started to work on that.
Lets have a look at this assumption...
To extract the data I used the cheerio.js which gives you a kind of jquery thing to parse html.
To extract the name of the country I used:
nullTest = ($('table').eq(2).find('tr').eq(i).find('td').find('a').last());
//"Partial solution" for the OutOfIndex nulls
if (nullTest != null)
{
users.push(nullTest);
}
(nullTest helps me avoid nulls, I will implement some RegEx when everything works to polish the code a bit)
This "query" would output me something like:
whatEverIsInHereIfThereIsAny
or else.
to get rid off this html thing just add .html() at the end of the "jquery" such as:
($('table').eq(2).find('tr').eq(i).find('td').find('a').last().html());
That way you are now working with String and avoiding any error and thus solves this question.
I have data like the one below in my mongoDB and I retrieve calling the service and later subscribing to it. But I want to filter the before subcribing to it in a way that i just subscribe to the filtered data base on my condition.
I want to filtered verifying that one of the camps in the data from the backend matches the "this.idcalbuscador". (See the .filter()). I haven't been able to achieve this, could anyone help? Just new to observables
Data
{
"_id" : ObjectId("588850b746f8ce140c1fe8cf"),
"idpertenalcalendario" : ObjectId("5885bfe452c6ba1d50f37f19"),
"enabled" : true,
"forma" : "Rombo",
"color" : "Red",
"type" : "point",
"descrip" : "ghghghgh",
"startDate" : "2017-01-15",
"nameHito" : "gjgjgjgg",
}
Code
//retrieve the datas
this._hitoService.getHitos()
.filter(resp => resp.idpertenalcalendario === this.idcalbuscador )
.subscribe(hito1 =>{
if (typeof this.nom_cal1 === "undefined"){
swal("Atencion!", "Busca un calendario con el buscador del Side Menu")
}else {
drawtimeline1_1(this.hito1, this.nom_cal1);
}
});
The filter function is not called for every item in your array, like it is for instance in Java's stream API. It is called for a single emittance of the Observable. That means the resp you work with in the filter function contains the array and not a single hito. That's why the following comparison will always return false:
resp.idpertenalcalendario === this.idcalbuscador
This is, at least, what I'd expect according to the names: getHitos returns an array of Hito. But Pierre Duc is right, it depends on your actual implementation.
In local storage I have an object named favourites and it contains this..
"{
"id3333":{
"URL":"somewhere.comm/page1/",
"TITLE":"Page 1 Title",
},
"id4444":{
"URL":"somewhere.comm/page2/",
"TITLE":"Page 2 Title",
}
}"
How can I delete an object based on its ID (id3333 & id4444 for examples)
I have tried the following along with some other voodoo..
localStorage.removeItem('id3333'); // no errors, no removal
localStorage.removeItem('favourites':'id3333'); // SyntaxError: missing ) after argument list
localStorage.removeItem('favourites[id3333]'); // no errors, no removal
localStorage.removeItem('id3333', JSON.stringify('id3333')); // no errors, no removal
Also, I will need to get the key name to delete based on a variable, so like this..
var postID = 'id3333';
localStorage.removeItem(postID);
or
var objectName = 'favourites';
var postID = 'id3333';
localStorage.removeItem(objectName[postID]);
Is it possible to remove a nested item directly or do I need to retrieve the full object and then delete the item and then set the object back to local storage again?
The closest I can get to deleting anything directly so far is..
localStorage.removeItem('favourites');
But that of course removes the entire object.
You have a a single key and you are acting like there are multiple keys
var obj = {
"id3333":{
"URL":"somewhere.comm/page1/",
"TITLE":"Page 1 Title",
},
"id4444":{
"URL":"somewhere.comm/page2/",
"TITLE":"Page 2 Title",
}
};
window.localStorage.favs = JSON.stringify(obj); //store object to local storage
console.log("before : ", window.localStorage.favs); //display it
var favs = JSON.parse(window.localStorage.favs || {}); //read and convert to object
var delKey = "id3333"; //key to remove
if (favs[delKey]) { //check if key exists
delete favs[delKey]; //remove the key from object
}
window.localStorage.favs = JSON.stringify(favs); //save it back
console.log("after : ", window.localStorage.favs); //display object with item removed
With localStorage.removeItem you can only remove top level keys, i.e. keys directly on localStorage.
Because id3333 is on localStorage.favourites you cannot remove it using localStorage.removeItem.
Instead try delete localStorage.favourties['id3333']
Simple, actually: you just delete it. :)
x = {
"id3333":{
"URL":"somewhere.comm/page1/",
"TITLE":"Page 1 Title",
},
"id4444":{
"URL":"somewhere.comm/page2/",
"TITLE":"Page 2 Title",
}
};
console.log(x);
delete x.id3333;
console.log(x);
delete does what you're looking for. You could also do something like delete x.id3333.TITLE if you were so inclined. Note also that delete returns true if successful and false if not.
Suppose you set a nested object in localStorage like that
const dataObj = {
uid: {
name: 'robin',
age: 24,
}
}
window.localStorage.setItem('users', JSON.stringify(dataObj));
Now you want to delete the age property. You can't remove it with removeItem native function since it allows to delete from top level.
So you need to get the data first and delete the property you want and set the data again to localStorage with updated value like that
const existingLocalStorage = JSON.parse(window.localStorage.getItem('users') || {});
if(existingLocalStorage['uid']['age']) { // if throws any error, use lodash get fucntion for getting value
delete existingLocalStorage['uid']['age'];
}
window.localStorage.setItem('users', JSON.stringify(existingLocalStorage));
So after building a chat app with angularjs and PHP I realized it was horrible for server performance and decided to give firebase a try using angularjs to talk with firebase(angularfire) right now I have hit a little roadblock and can't seem to figure out how to accomplish displaying a users chat rooms he's apart of. Please note this is my FIRST time using NoSql structure.
Currently my structure is like so:
{
"-K4KXS4k3mftFMe7jy_g" : {
"members" : {
"guest:Aaaa1aa" : {
"user1" : "Aaaa1aa",
"user2" : "guest"
}
},
"messages" : {
"guest:Aaaa1aa" : {
"-K4LdBwkMe7dcshqCXxW" : {
"content" : "gg",
"from" : "Aaaa1aa"
}
}
},
"rooms" : {
"guest:Aaaa1aa" : {
"roomname" : "guestAaaa1aa",
"type" : "private"
}
}
}
}
I want to check if
members->'key'->user1 == 'Aaaa1aa'
but the way I construct the key for each members data(from room key) is passed two parameters when the user clicks on 'message'(creates new room or opens existing room) in another function and that is their user name and the users profile name they clicked on. hence the keys with the delimiter ':' (guest:Aaaa1aa).
So my question is can I check if the members key contains a substring value ? sort of like explode in PHP.
What I want my query to be like:
select uniqueid(room_name) from members where user1 = 'passed value'
and if above is possible would the below be possible as well ?
select uniqueid(room_name) from members where user1 = 'passed value' || user2 = 'passed value'
thanks for any help, if I am structuring this wrong please let me know and point me into the right direction.