Accessing Firebase data in a node with JS - javascript

So I have an object being returned from Firebase that looks like this:
{key: {name: "test", email: "test", id: "test"}}
How can I get the id out of this object?
If I do returnItem I get that object, so I tried to do returnItem[0] but it's not an array, and I've tried (Object.keys(tempSnap) but that just gives me the key not the object inside it.
This is my current code:
export function sendInvitation(email) {
firebaseRef.database().ref().child('users').orderByChild('email').equalTo(email).on("value", function(snapshot) {
let tempSnap = snapshot.val();
if(tempSnap != null) {
console.log(tempSnap);
}
});
return dispatch => firebaseRef.database().ref(`${userID}/invites`).push("This is a test Message!");
}
This is what it outputs:
Help would be awesome :D

If you already know id and it's a literal, then it's a matter of returnItem.id.
If you already know id and it's a variable, then it's returnItem[id].
If you don't know the keys and want to print all keys and their values, it's:
Object.keys(returnItem).forEach(function(key) {
console.log(key, returnItem[key]);
});
Update
Your new code shows the problem. When you execute a query against the Firebase Database, there will potentially be 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. Your callback needs to handle the fact that it gets a list by looping over the results with snapshot.forEach():
firebaseRef.database().ref().child('users').orderByChild('email').equalTo(email).on("value", function(snapshot) {
snapshot.forEach(function(child) {
let tempSnap = child.val();
console.log(tempSnap);
});
});

Try this:
firebaseRef.database().ref().child('users').orderByChild('email').equalTo(email).on("value", function(snapshot) {
snapshot.forEach(function(child) {
let keys=child.key;
let ids=child.val().id;
)};
)};
you have:
users
keyid
email:email
name:yourname
id: test

Related

How to push an item to the array inside JSON Object?

I am trying to make inventory functionality using Discord.js and struggling on how to push an item to the array inside JSON Object.
Inside the JSON, every user with unique 'userID' has their own array 'inventory'.
The thing I want to achieve is:
After user types 'get' command in the chat, the item is pushed to the inventory array and the JSON file is updated.
.json file:
{
"userID": {
"inventory": []
}
}
.js file:
const item = itemName
inventory[userID] = {
inventory: inventory[userID].inventory + item,
}
fs.writeFile('./data/inventory.json', JSON.stringify(inventory), err => {
if (err) console.log(err)
})
Output (after using command twice):
{
"userID": {
"inventory": ["itemNameitemName"]
}
}
Expected output (after using command twice):
{
"userID": {
"inventory": ["itemName", "itemName"]
}
}
The thing I want to achieve is: After user types 'get' command in the chat, the item is pushed to the inventory array and the JSON file is updated. I suppose I need to use .push() somewhere, but I tried it million times in all configurations I could think of and it always throws an error, that .push() is not a function.
Instead of making a new object for the user every time you want to update the inventory, it would be much easier if you can just push the item to the inventory instead of reassigning. #DanielAWhite wrote the correct solution but I think you misunderstood where to put that particular piece of code. What you might have tried is this:
const inventory = {
"userID": {
"inventory": ["testOne"]
}
}
const item = "test"
const userID = "userID"
inventory[userID] = {
inventory: inventory[userID].inventory.push(item),
}
console.log(inventory)
Instead, what the correct way was to do away with the inventory[userID] = {} part and just directly push the item to the inventory by doing this:
const inventory = {
"userID": {
"inventory": ["testOne"]
}
}
const item = "test"
const userID = "userID"
inventory[userID].inventory.push(item)
console.log(inventory)
(Note: I edited the code a little bit so that you could try to run this code right here, but this should work with your fs.writeFile as well
Try this :
let rawdata = fs.readFileSync('inventory.json');
let inventory = JSON.parse(rawdata);
inventory["userID"] = {
inventory: [...inventory["userID"].inventory, item],
}
fs.writeFile('./inventory.json', JSON.stringify(inventory), err => {
if (err) console.log(err)
})

mongoosejs - find() using nested objects

question is possibly a duplicate but I haven't found anything that provides an appropriate answer to my issue.
I have an ExpressJS server which is used to provide API requests to retrieve data from a MongoDB database. I am using mongoosejs for the MongoDB connection to query/save data.
I am building a route that will allow me to find all data that matches some user input but I am having trouble when doing the query. I have spent a long while looking online for someone with a similar issue but coming up blank.
I will leave example of the code I have at the minute below.
code for route
// -- return matched data (GET)
router.get('/match', async (req, res) => {
const style_data = req.query.style; // grab url param for style scores ** this comes in as a string **
const character_data = req.query.character; // grab url param for character scores ** this comes in as a string **
// run matcher systems
const style_matches = style_match(style_data);
res.send({
response: 200,
data: style_matches
}); // return data
});
code for the query
// ---(Build the finder)
const fetch_matches_using = async function(body, richness, smoke, sweetness) {
return await WhiskyModel.find({
'attributes.body': body,
'attributes.richness': richness,
'attributes.smoke': smoke,
'attributes.sweetness': sweetness
});
}
// ---(Start match function)---
const style_match = async function (scores_as_string) {
// ---(extract data)---
const body = scores_as_string[0];
const richness = scores_as_string[1];
const smoke = scores_as_string[2];
const sweetness = scores_as_string[3];
const matched = [];
// ---(initialise variables)---
let match_count = matched.length;
let first_run; // -> exact matches
let second_run; // -> +- 1
let third_run; // -> +- 2
let fourth_run; // -> +- 3
// ---(begin db find loop)---
first_run = fetch_matches_using(body, richness, smoke, sweetness).then((result) => {return result});
matched.push(first_run);
// ---(return final data)---
return matched
}
example of db object
{
_id: mongoid,
meta-data: {
pagemd:{some data},
name: whiskyname
age: whiskyage,
price: price
},
attributes: {
body: "3",
richness: "3",
smoke: "0",
sweetness: "3",
some other data ...
}
}
When I hit the route in postman the JSON data looks like:
{
response: 200,
data: {}
}
and when I console.log() out matched from within the style match function after I have pushed the it prints [ Promise(pending) ] which I don't understand.
if I console.log() the result from within the .then() I get an empty array.
I have tried using the populate() method after running the find which does technically work, but instead of only returning data that matches it returns every entry in the collection so I think I am doing something wrong there, but I also don't see why I would need to use the .populate() function to access the nested object.
Am I doing something totally wrong here?
I should also mention that the route and the matching functions are in different files just to try and keep things simple.
Thanks for any answers.
just posting an answer as I seem to have fixed this.
Issue was with my .find() function, needed to pass in the items to search by and then also a call back within the function to return error/data. I'll leave the changed code below.
new function
const fetch_matches_using = async function(body, richness, smoke, sweetness) {
const data = await WhiskyModel.find({
'attributes.body': body,
'attributes.richness': richness,
'attributes.smoke': smoke,
'attributes.sweetness': sweetness
}, (error, data) => { // new ¬
if (error) {
return error;
}
if (data) {
console.log(data)
return data
}
});
return data; //new
}
There is still an issue with sending the found results back to the route but this is a different issue I believe. If its connected I'll edit this answer with the fix for that.

React, Firebase: Access values of JSON and also get key value

I am beginner working with firebase, react. I am able to get the required data from firebase based on userEmail. But I am very confused in accessing the data.
firebase.database().ref('/users').orderByChild('email').equalTo(userEmail).on('value', data => {
console.log('data: ', data);
})
I get the following output:
data: Object {
"-Lhdfgkjd6fn3AA-": Object {
"email": "t5#gmail.com",
"favQuote": "this is it",
"firstName": "t5",
"lastName": "l5",
},
}
Please help me how to access all values ("-Lhdfgkjd6fn3AA-" , firstname, lastname, email and favQuote) into variables like: data.firstName, data.lastName, data.key, etc . Thank you.
let data = {
"-Lhdfgkjd6fn3AA-": {
"email": "t5#gmail.com",
"favQuote": "this is it",
"firstName": "t5",
"lastName": "l5",
},
};
console.log(Object.keys(data))//returning an array of keys, in this case ["-Lhdfgkjd6fn3AA-"]
console.log(Object.keys(data)[0])
console.log(Object.values(data))//returning an array of values of property
console.log(Object.values(data)[0].email)
Do need to be careful that the above code with the hardcoded "0" as index because it assumed that your data object has only one key. If you have more key, you can't simply replace index either because property of object has no predictable sequence
It's really a JavaScript question. I had to figure this out too. ...this works.
var p;
var thisLine;
p = docu.data();
for (var k in p) {
if (p.hasOwnProperty(k)) {
if (isObject(p[k])) {
thisLine = p[k];
Object.keys(thisLine).forEach(function (key, index) {
console.log(key, index);
});
}
}
}
function isObject(obj) {
return obj === Object(obj);
}
When you execute a query against the Firebase Database, there will potentially be 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 your first step is that you need to loop over the snapshot in your on() callback.
The second step is that you need to call Snapshot.val() to get the JSON data from the snapshot. From there you can get the individual properties.
firebase.database().ref('/users').orderByChild('email').equalTo(userEmail).on('value', snapshot => {
snapshot.forEach(userSnapshot => {
let data = userSnapshot.val();
console.log('data: ', data);
console.log(data.email, data.firstname);
});
})

How to update Array field?

Im using Firebase Firestore and want to update an array field under a userprofile with the latest chat thread's id.. Im guessing that I have to pull the entire array (if it exists) from the chat node under that user, then I need to append the new id (if it doesnt exist) and update the array.. It works when theres only 1 value in the array then it fails after that with the following error:
Transaction failed: { Error: Cannot convert an array value in an array value.
at /user_code/node_modules/firebase-admin/node_modules/grpc/src/node/src/client.js:554:15 code: 3, metadata: Metadata { _internal_repr: {} } }
and here is my firebase cloud function, can anyone tell me where im going wrong ?
exports.updateMessages = functions.firestore.document('messages/{messageId}/conversation/{msgkey}').onCreate( (event) => {
/// console.log('function started');
const messagePayload = event.data.data();
const userA = messagePayload.userA;
const userB = messagePayload.userB;
// console.log("userA " + userA);
// console.log("userB " + userB);
// console.log("messagePayload " + JSON.stringify(messagePayload, null, 2) );
const sfDocRef = admin.firestore().doc(`users/${userB}`);
return admin.firestore().runTransaction( (transaction) => {
return transaction.get(sfDocRef).then( (sfDoc) => {
const array = [];
array.push(...[event.params.messageId, sfDoc.get('chats') ]);
transaction.update(sfDocRef, { chats: array } );
});
}).then( () => {
console.log("Transaction successfully committed!");
}).catch( (error) => {
console.log("Transaction failed: ", error);
});
});
You're nesting arrays in your code here:
const array = [];
array.push(...[event.params.messageId, sfDoc.get('chats') ]);
This leads to an array with two values, the first one being the new messageId and the second value contains an array all of your previous values, e.g.
[ "new message id", ["previous id", "older id"] ]
This type of nested array is something that Firestore (apparently) doesn't allow to be stored.
The solution is simple:
const array = [event.params.messageId, ...sfDoc.get('chats')];
The fact that you have to first load the array to then add a single element to it is one of reasons Firebasers recommend not storing data in arrays. Your current data looks like it'd be better off as a set, as shown in the Firestore documenation:
{
"new message id": true,
"previous id": true,
"older id": true
}
That way adding a chat ID is as simple as:
sfDocRef.update({ "chats."+event.params.messageId, true })
I have looked further into the matter, and I would follow the advice that Frank gave you in his post; allocate the data in collections rather than with arrays as they have greater versatility for Firebase 1. Researching under the examples listed in the Firebase website looking for anything related to a chat, I’ve found the data structure and code for messages that are used by Firechat as they might be of use for you.
In the source code, they use a collection for the their message-id -userId pair with the following topology 2 :
The exact way how the saving is executed at the repository is 3 :
It executes an append of the message into the Room-id collection. Instead of this structure, you could use an userID - messageID pair as it might fit you better.

Look up an object by the key in Firebase

I'm using the following data structure in my application:
var users = {
"tom": { conversations: ["fake-uuid-v4"] },
"bob": { conversations: ["fake-uuid-v4"] }
};
var conversations = {
"fake-uuid-v4": {
user_one: "tom",
user_two: "bob"
}
}
Each user has a collection of keys mapping to the conversation which contains data for the conversation, such as the last messages sent, if a user is typing, etc. The issue is I'm having a really hard time looking up the conversation.
Here's what I've tried, but it doesn't yield any results. (Note: I have this exact data in my firebase application right now, so this is technically a runnable example)
var conversation_id = 'fake-uuid-v4';
firebase.database().ref('/conversations')
.startAt(conversation_id)
.endAt(conversation_id)
.on('child_added', function(snapshot, prevKey) {
if(snapshot.val()) console.log(snapshot);
});
However, it's not pulling anything from the database, if I change the code to
firebase.database().ref('/conversations/'+conversation_id).on('child_added', function(snapshot, prevKey) {
});
Then it prints out each key/value for the conversations added, in this case:
tom
bob
How can I monitor all conversations with a key that's stored in the user's conversations array?
Quick "answer" on why your first snippet won't work:
var conversation_id = 'fake-uuid-v4';
firebase.database().ref('/conversations')
.startAt(conversation_id)
.endAt(conversation_id)
.on('child_added', function(snapshot, prevKey) {
if(snapshot.val()) console.log(snapshot);
});
You're not specifying a order, which means that the data is likely being order by priority. But I'd recommend against this approach anyway, since you're building a query, while you can directly access the child (which will be faster at scale):
var conversation_id = 'fake-uuid-v4';
firebase.database().ref('/conversations')
.child(conversation_id)
.on('child_added', function(snapshot, prevKey) {
if(snapshot.val()) console.log(snapshot);
});

Categories

Resources