Get Firebase Object data based on ID in another ref - javascript

I have this broken CodePen that I am attempting to get the info of an object in another Firebase Ref based on the objects .key or id...
I have to Firebase Refs: The content
[
{
"name": "objecta",
".key": "objecta"
},
{
"name": "objectb",
".key": "objectb"
},
{
"name": "objectc",
".key": "objectc"
}
]
and the Related that lists the object by key and then the key of the ones that are related to that item.
[
{
"objectc": true,
".key": "objectb"
}
]
I am trying to use the following code to go through the relatedRef by key:
var theKey = "objectb"
function getDiscoverBarContent(key, cb) {
relatedRef.child(key).on("child_added", snap => {
let relateRef = relatedRef.child(snap.key);
relateRef.once("value", cb);
console.log('relate:' + relateRef)
});
}
then get the data of the object that it's related to and log it to the console:
getDiscoverBarContent(theKey, snap => {
var snapVal = snap.val();
console.log(snapVal)
});
Currently it is returning null when I need it to return the object info in contentRef referenced in the relatedRef...any ideas?

I was referencing the wrong ref in the JS function. Everything was right except this:
var theKey = "objectb"
function getDiscoverBarContent(key, cb) {
relatedRef.child(key).on("child_added", snap => {
//This should have referenced the contentRef:
let relateRef = relatedRef.child(snap.key);
//like so
let relateRef = contentRef.child(snap.key);
relateRef.once("value", cb);
console.log('relate:' + relateRef)
});
}

Related

How to map this data to reach data property?

I'm trying to clean up the data received from firebase to view them in a FlatList. How can I clean my data to a simple array where I can iterate in FlatList?
EDIT! There are many other coins in my database that I want to pull into the FlatList. So the solution that I'm looking for is to view all these coins in my FlatList and then show their data such as price, market_cap etc.
My data is currently stored in a state and looks like this.
favoriteList data is:
Object {
"bitcoin": Object {
"-MahI1hCDr0CJ_1T_umy": Object {
"data": Object {
"ath": 54205,
"ath_change_percentage": -40.72194,
"ath_date": "2021-04-14T11:54:46.763Z",
"atl": 51.3,
"atl_change_percentage": 62536.71794,
"atl_date": "2013-07-05T00:00:00.000Z",
"circulating_supply": 18719656,
"current_price": 32164,
"fully_diluted_valuation": 674764316483,
"high_24h": 33004,
"id": "bitcoin",
"image": "https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579",
"last_updated": "2021-05-27T10:07:02.525Z",
"low_24h": 30652,
"market_cap": 601493137412,
"market_cap_change_24h": -15118857257.119507,
"market_cap_change_percentage_24h": -2.45192,
"market_cap_rank": 1,
"max_supply": 21000000,
"name": "Bitcoin",
"price_change_24h": -641.85835686,
"price_change_percentage_1h_in_currency": 0.25769270475453127,
"price_change_percentage_24h": -1.95655,
"price_change_percentage_24h_in_currency": -1.9565521832416402,
"price_change_percentage_7d_in_currency": 4.978932125496787,
"symbol": "btc",
"total_supply": 21000000,
"total_volume": 36947814578,
},
},
},
}
The firebase structure is like this where the data above is fetched from:
Object.keys(favourite.bitcoin)[idx] This line gives you the name of key at index 0 into object favourite.bitcoin.
So the variable key will be your firebase key.
let favourite = {
bitcoin: {
"-MahI1hCDr0CJ_1T_umy": {
data: {
ath: 54205,
ath_change_percentage: -40.72194,
ath_date: "2021-04-14T11:54:46.763Z",
atl: 51.3,
atl_change_percentage: 62536.71794,
atl_date: "2013-07-05T00:00:00.000Z",
circulating_supply: 18719656,
current_price: 32164,
fully_diluted_valuation: 674764316483,
high_24h: 33004,
id: "bitcoin",
image:
"https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579",
last_updated: "2021-05-27T10:07:02.525Z",
low_24h: 30652,
market_cap: 601493137412,
market_cap_change_24h: -15118857257.119507,
market_cap_change_percentage_24h: -2.45192,
market_cap_rank: 1,
max_supply: 21000000,
name: "Bitcoin",
price_change_24h: -641.85835686,
price_change_percentage_1h_in_currency: 0.25769270475453127,
price_change_percentage_24h: -1.95655,
price_change_percentage_24h_in_currency: -1.9565521832416402,
price_change_percentage_7d_in_currency: 4.978932125496787,
symbol: "btc",
total_supply: 21000000,
total_volume: 36947814578,
},
},
},
};
let idx = 0; //key at index 0
let key = Object.keys(favourite.bitcoin)[idx];
console.log(key)
let data = favourite.bitcoin[key].data;
console.log(data)
Please let me know if it's works or not !
To get the data from your database, you need to query its parent reference. This will allow you to do things like "find all entries under /favorites/bitcoin that have a current price of over 30000".
Because you want to simply query for all the data under /favorites/bitcoin in your question, you would do the following:
Get a reference for /favorites/bitcoin
Get the data under /favorites/bitcoin
Iterate over the data, and assemble an array
Use this new array for your FlatList
These steps can be made into the following function:
function getDataForFlatlistUnder(databasePath) {
return firebase.database()
.ref(databasePath)
// consider using .limitToFirst(10) or similar queries
.once("value")
.then((listSnapshot) => {
// listSnapshot contains all the data under `${databasePath}`
const arrayOfDataObjects = [];
// For each entry under `listSnapshot`, pull its data into the array
// Note: this is a DataSnapshot#forEach() NOT Array#forEach()
listSnapshot.forEach((entrySnapshot) => {
// entrySnapshot contains all the data under `${databasePath}/${entrySnapshot.key}`
const data = entrySnapshot.child("data").val();
// data is your data object
// i.e. { ath, ath_change_percentage, ath_date, atl, ... }
// add the key into the data for use with the FlatList
data._key = entrySnapshot.key;
arrayOfDataObjects.push(data);
});
return arrayOfDataObjects;
});
}
Which you can use in your component like so:
function renderItem((dataObject) => {
// TODO: render data in dataObject
});
function MyComponent() {
const [listData, setListData] = useState();
const [listDataError, setListDataError] = useState(null);
const [listDataLoading, setListDataLoading] = useState(true);
useEffect(() => {
const disposed = false;
getDataForFlatlistUnder("favorites/bitcoin")
.then((arrayOfDataObjects) => {
if (disposed) return; // component was removed already, do nothing
setListData(arrayOfDataObjects);
setListDataLoading(false);
})
.catch((err) => {
if (disposed) return; // component was removed already, do nothing
// optionally empty data: setListData([]);
setListDataError(err);
setListDataLoading(false);
});
// return a cleanup function to prevent the callbacks above
// trying to update the state of a dead component
return () => disposed = true;
}, []); // <-- run this code once when component is mounted and dispose when unmounted
if (listDataLoading)
return null; // or show loading spinner/throbber/etc
if (listDataError !== null) {
return (
<Text>
{"Error: " + listDataError.message}
</Text>
);
}
return (
<FlatList
data={listData}
renderItem={renderItem}
keyExtractor={item => item._key} // use the key we inserted earlier
/>
);
}
Note: This code is for a one-off grab of the data, if you want realtime updates, you would modify it to use .on("value", callback) instead. Make sure to use .off("value", callback) in the unsubscribe function of the useEffect call to clean it up properly.
It is interesting to see how programmers interpret questions. Or perhaps how beginners fail to articulate clearly what they want to achieve. Here is the answer:
const formatData = (data) => {
let arr = [];
let test = Object.values(data).forEach((o) => {
Object.values(o).forEach((a) =>
Object.values(a).forEach((b) => arr.push(b))
);
setFormattedData(arr);
});

Cannot assign to read only property with .map(). Recoil with NextJs

before I use only nextJs everything is good to go but after I try to use recoil and I try to assign new value to array object by using .map() but the error show up
Cannot assign to read only property
Here is my example Array object
const [allData, setAllData] = useRecoilState(
allDataStatte
);
Here is example state AllData
const allData = [
{
id:1,
value:"test1"
},
{
id:2,
value:"test2"
}
]
Here is my code
const edit = (listId, value) => {
allData.map((data) => {
if (data.id === listId) {
data.value = value;
}
});
};
example I want to call edit funcion like this
edit(1,"newTitle1")
I want my new allData output look like this
const data = [
{
id:1,
value:"newTitle1"
},
{
id:2,
value:"test2"
}
]
I have read someone told that I have to use .slice() to create new object but still not use how to use slice with an array object
Here is what you need to do,
const [allData, setAllData] = useRecoilState(allDataState);
const edit = (listId : number, value : string) => {
let newAllData = allData.map((data) => {
let newData = {...data};
if (data.id === listId) {
newData.value = value;
}
return newData;
});
setAllData (newAllData);
};
edit(1, 'new value 1');
Noticed, newAllData is a new array. Also newData is a new object constructed from data.
it's because of atom in recoil you have to re create object array and then setState again by using _clondeep or slice

How to parse through large JSONL data Node js

I am trying to read through a large JSONL, maybe couple hundreds up to thousands or possibly million line, below is sample of of the data.
{"id":"gid://shopify/Product/1921569226808"}
{"id":"gid://shopify/ProductVariant/19435458986040","__parentId":"gid://shopify/Product/1921569226808"}
{"id":"gid://shopify/Product/1921569259576"}
{"id":"gid://shopify/ProductVariant/19435459018808","__parentId":"gid://shopify/Product/1921569259576"}
{"id":"gid://shopify/Product/1921569292344"}
{"id":"gid://shopify/ProductVariant/19435459051576","__parentId":"gid://shopify/Product/1921569292344"}
{"id":"gid://shopify/Product/1921569325112"}
{"id":"gid://shopify/ProductVariant/19435459084344","__parentId":"gid://shopify/Product/1921569325112"}
{"id":"gid://shopify/Product/1921569357880"}
{"id":"gid://shopify/ProductVariant/19435459117112","__parentId":"gid://shopify/Product/1921569357880"}
{"id":"gid://shopify/ProductVariant/19435458986123","__parentId":"gid://shopify/Product/1921569226808"}
So each line is json object, either its a Product, or a Product Child identified by __parentId, given that the data may contain thousands of lines, what's the best way to read through it and return a regular JSON object, like this.
{
"id": "gid://shopify/Product/1921569226808",
"childrens": {
{"id":"gid://shopify//ProductImage//20771195224224","__parentId":"gid:////shopify//Product//1921569226808"},
{"id":"gid:////shopify//ProductImage//20771195344224","__parentId":"gid:////shopify//Product//1921569226808"}
{"id":"gid:////shopify//ProductImage//20771329344224","__parentId":"gid:////shopify//Product//1921569226808"}
}
}
The data is coming back from Shopify and they advice to:
Because nested connections are no longer nested in the response data
structure, the results contain the __parentId field, which is a
reference to an object's parent. This field doesn’t exist in the API
schema, so you can't explicitly query it. It's included automatically
in bulk operation result.
Read the JSONL file in reverse Reading the JSONL file in reverse makes
it easier to group child nodes and avoids missing any that appear
after the parent node. For example, while collecting variants, there
won't be more variants further up the file when you come to the
product that the variants belong to. After you download the JSONL
file, read it in reverse, and then parse it so that any child nodes
are tracked before the parent node is discovered.
You can look for look here to read more about all of thisenter link description here.
Consider using streams so that you don't have to load the entire file in memory.
You can use readline (a native module) to process each line individually.
I took the line processing part from #terrymorse https://stackoverflow.com/a/65484413/14793527
const readline = require('readline');
const fs = require('fs');
let res = {};
function processLine(line) {
const {id, __parentId} = line;
// if there is no `__parentId`, this is a parent
if (typeof __parentId === 'undefined') {
res[line.id] = {
id,
childrens: []
};
return res;
}
// this is a child, create its parent if necessary
if (typeof res[__parentId] === 'undefined') {
res[__parentId] = {
id: __parentId,
childrens: []
}
}
// add child to parent's children
res[__parentId].childrens.push(line);
return res;
}
const readInterface = readline.createInterface({
input: fs.createReadStream('large.jsonl'),
output: process.stdout,
console: false
});
readInterface.on('line', processLine);
readInterface.on('close', function() {
const resultArray = Object.values(res);
console.log(resultArray);
});
Here's a technique that:
forms an object with properties of the parent ids
converts that object to an array
(input lines converted to an array for simplicity)
const lines = [
{ "id": "gid://shopify/Product/1921569226808" },
{ "id": "gid://shopify/ProductVariant/19435458986040", "__parentId": "gid://shopify/Product/1921569226808" },
{ "id": "gid://shopify/Product/1921569259576" },
{ "id": "gid://shopify/ProductVariant/19435459018808", "__parentId": "gid://shopify/Product/1921569259576" },
{ "id": "gid://shopify/Product/1921569292344" },
{ "id": "gid://shopify/ProductVariant/19435459051576", "__parentId": "gid://shopify/Product/1921569292344" },
{ "id": "gid://shopify/Product/1921569325112" },
{ "id": "gid://shopify/ProductVariant/19435459084344", "__parentId": "gid://shopify/Product/1921569325112" },
{ "id": "gid://shopify/Product/1921569357880" },
{ "id": "gid://shopify/ProductVariant/19435459117112", "__parentId": "gid://shopify/Product/1921569357880" },
{ "id": "gid://shopify/ProductVariant/19435458986123", "__parentId": "gid://shopify/Product/1921569226808" }
];
// form object keyed to parent ids
const result = lines.reduce((res, line) => {
const {id, __parentId} = line;
// if there is no `__parentId`, this is a parent
if (typeof __parentId === 'undefined') {
res[id] = {
id,
childrens: []
};
return res;
}
// this is a child, create its parent if necessary
if (typeof res[__parentId] === 'undefined') {
res[__parentId] = {
id: __parentId,
childrens: []
}
}
// add child to parent's children
res[__parentId].childrens.push(line);
return res;
}, {});
// convert object to array
const resultArray = Object.values(result);
const pre = document.querySelector('pre');
pre.innerText = 'resultArray: ' + JSON.stringify(resultArray, null, 2);
<pre></pre>

Normalizing my nested JSON with normalizr

I'm having the following JSON from my service:
[
{
"name":"Voter1",
"id":1,
"votingCard":{
"verificationCodes":[
"3I08jA",
"3x0eyE",
"2_i69I"
],
"votingCode":"7zCOelDnjfBm7TtFydc4QodgonG",
"finalizationCode":"jyYu",
"confirmationCode":"4ACfcpBVH45iAXqg7hJ0tbEe_tV"
}
},
.....
{
"id":5,
"name":"Voter5",
"votingCard":{
"verificationCodes":[
"2c9I9a",
"3bEeEa",
"1gPKx2"
],
"confirmationCode":"4Z7wNG35VR2UMO6-W-0aZVEhbLM",
"votingCode":"6YQ2x-c8LXJZF05gh3zTajU79ct",
"finalizationCode":"S0CY"
}
}
]
And would like to get it normalized, so a list of votingCards and a list of voters with a "votingCard" property referencing the votingCard by id.
import { normalize, schema } from 'normalizr';
const votingCard = new schema.Entity('votingCard');
const voter = new schema.Entity('voter', {
votingCard: votingCard,
});
const votersSchema = new schema.Array(voter);
const mutations = {
SOCKET_SYNCVOTERS: (state, data) => {
var input = JSON.parse(data);
const normalizedData = normalize(input, votersSchema);
console.log(normalizedData);
},
};
However, I'm not getting what I want:
Why is there an "undefined"?
I think you need to specify an ‘idAttribute’ in the options for the votingCard entity - the problem is that normalizr can’t find an ‘id’ field in those objects so they are all being picked up as id undefined and overwriting each other in entities. See: https://github.com/paularmstrong/normalizr/blob/master/docs/api.md#schema

Cannot read property 'concat' of undefined

to begin with, I have a multilevel of entities as in
country unit ----> customer reporting group ----> customers
each country unit has different customer reporting groups and each of the later has different customers
in the code the variable names are
cu ----> crg ---> customer
this is represented in a multilevel object called menuData:
menuData = {
cu1: {
CRG3: {
Customer1: {},
Customer5: {}
},
CRG7: {
Customer3: {},
Customer2: {},
Customer7: {}
}
},
cu4: {
CRG1: {
Customer2: {},
Customer4: {}
},
CRG3: {
Customer4: {}
}
}
};
what I wanted to do is to construct unique id for each level in a multilevel objects as well as in for example the ids for the customer units will be the same
cu1 and cu2 and so on
for the customer reporting groups the ids will consist of the cu + the crg as in
cu1+crg4
for the customer:
cu1+crg4+customer6;
what I did is a function called getIds
var getIds = function(menuData) {
var ids = {};
for (cu in menuData) {
ids[cu] = cu;
for (crg in menuData[cu]) {
if (!(ids[cu] in ids)) {
ids[cu] = {};
ids[cu][crg] = ids[cu].concat(crg);
} else ids[cu][crg] = ids[cu].concat(crg);
for (customer in menuData[cu][crg]) {
if (!ids[cu][crg]) {
ids[cu][crg] = {};
ids[cu][crg][customer] = ids[cu][crg].concat(customer);
} else ids[cu][crg][customer] = ids[cu][crg].concat(customer);
}
}
}
console.log(ids);
return ids;
};
the error I got is
Cannot read property 'concat' of undefined
what I have tried is that, because it says that it's undefined, I try to define it if its not already defined as in
if (!(ids[cu] in ids)) {
ids[cu] = {};
ids[cu][crg] = ids[cu].concat(crg);
}
if its not defined, define it and insert the value, but if its defined, only assign the value
else ids[cu][crg] = ids[cu].concat (crg );
why do I get this error? and how to get the the ids in multilevel objects ?
edit, excpected output is
ids = {
"cu1": {
"cu1+CRG3": { "cu1+CRG3+Customer1":{}, "cu1+CRG3+Customer5":{} },
"cu1+CRG7": { "cu1+CRG7+Customer3":{}, "cu1+CRG7+Customer2":{}, "cu1+CRG7+Customer7":{} }
},
"cu4": {
"cu4+CRG1": { "cu4+CRG1+Customer2":{}, "cu4+CRG1+Customer4":{} },
"cu4+CRG3": { "cu4+CRG3+Customer4":{}}
}
}
The Problem with your Code is that you are using Objects to store your data and Objects don´t have the Method "concat" only Arrays have the "concat" Method. Your Object must look like these to work:
menuData = [
"cu1": [
"CRG3": [ "Customer1":{}, "Customer5":{} ],
"CRG7": [ "Customer3":{}, "Customer2":{}, "Customer7":{} ]
],
"cu4": [
"CRG1": [ "Customer2":{}, "Customer4":{} ],
"CRG3": [ "Customer4":{}]
]
]
Here´s a reference : MDN Array.concat()
What can be confusing in JS is that an Object Property can be accessed like an Array.
Update after Expected Output was added:
okay than i think concat is not the right solution for your Problem.
Try it with something like this:
var ids = {};
var menuData = {
cu1: {
CRG3: {
Customer1: {},
Customer5: {}
},
CRG7: {
Customer3: {},
Customer2: {},
Customer7: {}
}
},
cu4: {
CRG1: {
Customer2: {},
Customer4: {}
},
CRG3: {
Customer4: {}
}
}
};
for (propKeyLevel1 in menuData){
ids[propKeyLevel1] = {};
var propLevel1 = ids[propKeyLevel1];
for(propKeyLevel2 in menuData[propKeyLevel1]){
propLevel1[propKeyLevel1+"+"+propKeyLevel2] = {};
var propLevel2 = propLevel1[propKeyLevel1+"+"+propKeyLevel2];
for(propKeyLevel3 in menuData[propKeyLevel1][propKeyLevel2]){
propLevel2[propKeyLevel1+"+"+propKeyLevel2+"+"+propKeyLevel3] = {};
}
}
}
console.log(ids);
concat is a method for for a String or an Array, here you call it on an object hence the error.
What you're trying to do is a bit unclear to me, but maybe you could try that :
ids[cu][crg] = crg;
instead of :
ids[cu][crg] = ids[cu].concat (crg );
Because that's what you seem to be trying.
I’d try it this way:
function getIds(dataIn, idsIn) {
idsIn = idsIn || [];
var dataOut = {}, idOut;
for (var idIn in dataIn) {
idsOut = idsIn.concat([idIn]);
dataOut[idsOut.join('+')] = getIds(dataIn[idIn], idsOut);
}
return dataOut;
}
Perfect use case for a recursive function passing down an array (idsOut) of the ids of the previous layers to generate the intended object keys. Pretty straight forward.

Categories

Resources