Cloud Functions & Firestore: Iterate over document.data - node.js

The database structure looks like this:
User {id}
Settings (Collection)
device_uids(document)
{device_uid_1}: Boolean
(...)
{device_uid_n}: Boolean
I want to get the document and access all of the device_uids within that document.
I tried like this, however the console logs, that forEach is not definded:
const settings_ref = admin.firestore().collection('User').doc(uid).collection('Settings').doc('device_uids');
settings_ref.get()
.then(snap =>{
let uids = snap.data();
uids.array.forEach(element => {
let device = element.key;
if(device != device_uid){
//GO ON
}
});
})
How can I access the values individually?

You don't have a field called array in your document, so uids.array will always be undefined. If you just want to iterate all the properties of the document, it's just like iterating all the properties of a plain old JavaScript object:
const data = snap.data();
for (const key in data) {
const value = data[key];
// now key and value are the property name and value
}

Related

Google Apps Script: How to retrieve values from deeply nested object having nulls and empty elements?

Trying to retrieve {raw} values from all {type} keys in the object of this URL. #Tanaike made this code which worked well when all of {type} keys have clean data without any missing or null. But it didn't work when some of {type} keys have null elements or are empty, getting an error:
TypeError: Cannot read properties of null (reading 'reportedValue')
In #Tanaike's code below, I like to achieve something like if {type} key doesn't have {raw} value, array = [[type, ''], ....], and remove any elements of null. What should be changed in this line? Thank you!
var array = obj.timeseries.result.map(o => types.flatMap(type => o[type] ? [type, ...o[type].map(({ reportedValue: { raw } }) => raw)] : []));
function test() {
var url = 'https://query2.finance.yahoo.com/ws/fundamentals-timeseries/v1/finance/timeseries/CRWD?lang=en-US&region=US&symbol=CRWD&padTimeSeries=true&type=annualTaxProvision,trailingTaxProvision,annualPretaxIncome,trailingPretaxIncome,annualInterestExpenseNonOperating,trailingInterestExpenseNonOperating,annualLongTermDebt,quarterlyLongTermDebt,annualCurrentDebt,quarterlyCurrentDebt,annualCashCashEquivalentsAndShortTermInvestments,quarterlyCashCashEquivalentsAndShortTermInvestments,annualFreeCashFlow,trailingFreeCashFlow&merge=false&period1=493590046&period2=1672980169&corsDomain=finance.yahoo.com'
var obj = UrlFetchApp.fetch(url, { muteHttpExceptions: true }).getContentText();
obj = JSON.parse(obj); //Convert strings to object
var types = obj.timeseries.result.flatMap(({ meta: { type } }) => type);
var array = obj.timeseries.result.map(o => types.flatMap(type => o[type] ? [type, ...o[type].map(({ reportedValue: { raw } }) => raw)] : []));
array = Object.keys(array).map(k => [...array[k]]); // Convert object to array
console.log(array)
}
Looks like there's two different errors that could occur. One for a series missing all of its values and one where the series has null entries.
// A pull of the data at asker's url
var obj = '{"timeseries":{"result":[{"meta":{"symbol":["CRWD"],"type":["annualLongTermDebt"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"annualLongTermDebt":[null,null,{"dataId":23123,"asOfDate":"2021-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":7.38029E8,"fmt":"738.03M"}},null,{"dataId":23123,"asOfDate":"2022-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":7.39517E8,"fmt":"739.52M"}},null,null,null]},{"meta":{"symbol":["CRWD"],"type":["trailingFreeCashFlow"]},"timestamp":[1667174400],"trailingFreeCashFlow":[{"dataId":26185,"asOfDate":"2022-10-31","periodType":"TTM","currencyCode":"USD","reportedValue":{"raw":5.93996E8,"fmt":"594.00M"}}]},{"meta":{"symbol":["CRWD"],"type":["trailingInterestExpenseNonOperating"]},"timestamp":[1667174400],"trailingInterestExpenseNonOperating":[{"dataId":20064,"asOfDate":"2022-10-31","periodType":"TTM","currencyCode":"USD","reportedValue":{"raw":2.5269E7,"fmt":"25.27M"}}]},{"meta":{"symbol":["CRWD"],"type":["annualFreeCashFlow"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"annualFreeCashFlow":[{"dataId":26185,"asOfDate":"2019-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":-6.5613E7,"fmt":"-65.61M"}},{"dataId":26185,"asOfDate":"2020-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1.2456E7,"fmt":"12.46M"}},{"dataId":26185,"asOfDate":"2021-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":2.92723E8,"fmt":"292.72M"}},null,{"dataId":26185,"asOfDate":"2022-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":4.41095E8,"fmt":"441.10M"}},null,null,null]},{"meta":{"symbol":["CRWD"],"type":["trailingTaxProvision"]},"timestamp":[1667174400],"trailingTaxProvision":[{"dataId":20145,"asOfDate":"2022-10-31","periodType":"TTM","currencyCode":"USD","reportedValue":{"raw":3.067E7,"fmt":"30.67M"}}]},{"meta":{"symbol":["CRWD"],"type":["trailingPretaxIncome"]},"timestamp":[1667174400],"trailingPretaxIncome":[{"dataId":20136,"asOfDate":"2022-10-31","periodType":"TTM","currencyCode":"USD","reportedValue":{"raw":-1.44422E8,"fmt":"-144.42M"}}]},{"meta":{"symbol":["CRWD"],"type":["annualTaxProvision"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"annualTaxProvision":[{"dataId":20145,"asOfDate":"2019-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1367000.0,"fmt":"1.37M"}},{"dataId":20145,"asOfDate":"2020-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1997000.0,"fmt":"2.00M"}},{"dataId":20145,"asOfDate":"2021-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":4760000.0,"fmt":"4.76M"}},null,{"dataId":20145,"asOfDate":"2022-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":7.2355E7,"fmt":"72.36M"}},null,null,null]},{"meta":{"symbol":["CRWD"],"type":["annualPretaxIncome"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"annualPretaxIncome":[{"dataId":20136,"asOfDate":"2019-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":-1.3871E8,"fmt":"-138.71M"}},{"dataId":20136,"asOfDate":"2020-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":-1.39782E8,"fmt":"-139.78M"}},{"dataId":20136,"asOfDate":"2021-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":-8.7869E7,"fmt":"-87.87M"}},null,{"dataId":20136,"asOfDate":"2022-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":-1.60023E8,"fmt":"-160.02M"}},null,null,null]},{"meta":{"symbol":["CRWD"],"type":["quarterlyCashCashEquivalentsAndShortTermInvestments"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"quarterlyCashCashEquivalentsAndShortTermInvestments":[null,null,null,{"dataId":23033,"asOfDate":"2021-10-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":1.907508E9,"fmt":"1.91B"}},{"dataId":23033,"asOfDate":"2022-01-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":1.996633E9,"fmt":"2.00B"}},{"dataId":23033,"asOfDate":"2022-04-30","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":2.152736E9,"fmt":"2.15B"}},{"dataId":23033,"asOfDate":"2022-07-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":2.318858E9,"fmt":"2.32B"}},{"dataId":23033,"asOfDate":"2022-10-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":2.466551E9,"fmt":"2.47B"}}]},{"meta":{"symbol":["CRWD"],"type":["annualCashCashEquivalentsAndShortTermInvestments"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"annualCashCashEquivalentsAndShortTermInvestments":[{"dataId":23033,"asOfDate":"2019-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1.91655E8,"fmt":"191.66M"}},{"dataId":23033,"asOfDate":"2020-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":9.12064E8,"fmt":"912.06M"}},{"dataId":23033,"asOfDate":"2021-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1.918608E9,"fmt":"1.92B"}},null,{"dataId":23033,"asOfDate":"2022-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1.996633E9,"fmt":"2.00B"}},null,null,null]},{"meta":{"symbol":["CRWD"],"type":["quarterlyLongTermDebt"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"quarterlyLongTermDebt":[null,null,null,{"dataId":23123,"asOfDate":"2021-10-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":7.39145E8,"fmt":"739.14M"}},{"dataId":23123,"asOfDate":"2022-01-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":7.39517E8,"fmt":"739.52M"}},{"dataId":23123,"asOfDate":"2022-04-30","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":7.39889E8,"fmt":"739.89M"}},{"dataId":23123,"asOfDate":"2022-07-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":7.40261E8,"fmt":"740.26M"}},{"dataId":23123,"asOfDate":"2022-10-31","periodType":"3M","currencyCode":"USD","reportedValue":{"raw":7.40633E8,"fmt":"740.63M"}}]},{"meta":{"symbol":["CRWD"],"type":["annualInterestExpenseNonOperating"]},"timestamp":[1548892800,1580428800,1612051200,1635638400,1643587200,1651276800,1659225600,1667174400],"annualInterestExpenseNonOperating":[{"dataId":20064,"asOfDate":"2019-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":428000.0,"fmt":"428.00k"}},{"dataId":20064,"asOfDate":"2020-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":442000.0,"fmt":"442.00k"}},{"dataId":20064,"asOfDate":"2021-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":1559000.0,"fmt":"1.56M"}},null,{"dataId":20064,"asOfDate":"2022-01-31","periodType":"12M","currencyCode":"USD","reportedValue":{"raw":2.5231E7,"fmt":"25.23M"}},null,null,null]},{"meta":{"symbol":["CRWD"],"type":["quarterlyCurrentDebt"]}},{"meta":{"symbol":["CRWD"],"type":["annualCurrentDebt"]}}],"error":null}}'
obj = JSON.parse(obj); //Convert strings to object
// for each object in `obj.timeseries.result`, `.meta.type` names a key in
// that object that contains the data array. That key may not exist. Some
// entries in the data array may be null.
var mangled = obj.timeseries.result.map(o => {
// pull the key
const type = o.meta.type[0];
// if there's no attribute of that name, return an empty array of values
if (!(type in o)) return [type, []];
// otherwise return an array of values, being careful of `null`s
return [
type,
o[type].map(value => value == null ? null : value.reportedValue.raw),
];
});
console.log(mangled)

NodeJS/Mongoose - How to reference individual models after concatenation?

I am concatenating two models (Blogs and Events) so I can display all records from both collections in a single forEach loop:
const blogs = await Blog.find({});
const events = await Event.find({});
const blogsAndEvents = blogs.concat(events);
blogsAndEvents.forEach(function(blogOrEvent) { etc. etc.
However, within the forEach loop, in some cases, I want to still reference the original model it comes from, e.g. 'if Blog, title equals BLOG, if Event, title equals event). I have a workaround for this where I am using a unique field from each model to determine the underlying model, like this:
if (blogOrEvent.blogPost) {
title = "BLOG"
} elseIf (blogOrEvent.eventDate) {
title = "EVENT"
}
This approach doesn't seem very clean to me though as it relies on their being a unique field in each model. It there a better way I can access the original underlying model within the loop? Thanks.
With mongoose documents it can be distinctly verified which Model they belong to using instance of :
const blogs = await Blog.find({});
const events = await Event.find({});
const blogsAndEvents = blogs.concat(events);
blogsAndEvents.forEach(function (blogOrEvent) {
if (blogOrEvent instanceof Blog) {
title = "BLOG";
} else if (blogOrEvent instanceof Event) {
title = "EVENT";
}
});

Get data by id from firebase

I use firebase on node.js .
My given structure should look like this:
{
...
batch-1:
id-1(suppose):
name:...
phone:...
id-2:
...
id-3:
...
batch-2:
...
batch-3:
...
...
batch-n:
...
}
How can I get an id-1 object by its identifier in such an architecture?
Does the database have to go around all the batches?
Is there a better solution?
The main task: Create a batch with many objects that will have SHORT and a UNIQUE identifier and optimally receive data by this identifier
To search for a particular ID that is a child of a list of unknown IDs, you need to use orderByChild(). In your use case, you are looking for a particular ID in a list of batch IDs. If you used orderByChild() on this list, you would get back results for each and every batch ID, even if it didn't have the ID you wanted. This is because even null (non-existant) values are included (and sorted at the start) in the results. To get the data of the desired ID, you would get the data for the last result of the query, which if it existed, would be sorted to the end of the list. Note that if the desired ID doesn't exist, the last result (if there are any results) would have a null value. To return only the last result of the query, you would use limitToLast(1).
Putting this all together, gives the following code:
let idToFind = "unique-id-1";
let batchesRef = firebase.database().ref(); // parent key of "batch-1", "batch-2", etc.
// assumed to be the database root here
batchesRef.orderByChild(idToFind).limitToLast(1).once('value')
.then((querySnapshot) => {
if (!querySnapshot.numChildren()) { // handle rare no-results case
throw new Error('expected at least one result');
}
let dataSnapshot;
querySnapshot.forEach((snap) => dataSnapshot = snap); // get the snapshot we want out of the query's results list
if (!dataSnapshot.exists()) { // value may be null, meaning idToFind doesn't exist
throw new Error(`Entry ${idToFind} not found.`);
}
// do what you want with dataSnapshot
console.log(`Entry ${idToFind}'s data is:`, dataSnapshot.val());
})
.catch((error) => {
console.log("Unexpected error:", error);
})
For small data sets, the above code will work just fine. But if the list of batches starts growing quite large, you may wish to build an index that maps a particular ID to the batch ID that contains it.
Here is my method which allows you to search by id or to search by key value such as email uniqueemail
// gets primary key
const getSnapshotValKey = snapshot => (Object.keys(snapshot).length > 0 ? Object.keys(snapshot)[0] : null)
const getUser = async ({ id, key, value }) => {
let user = null
const ref = id ? '/users/' + id : 'users'
const userRef = admin.database().ref(ref)
const valueRef = id ? userRef : await userRef.orderByChild(key).equalTo(value)
const snapshot = await valueRef.once('value')
const val = snapshot.val()
if (val) {
const key = id || getSnapshotValKey(val)
user = {
id: key,
...(id ? val : val[key]),
}
}
return user
}

how to pass fieldname dynamically in mogodb

I want to pass field name dynamically in Mondgodb while query the collection. e.g.
emp.ply = function(res,res) {
Employee.find({area: 'Plymouth'}).exec(function(err,PLY) {
res.render("../index", {resultset: PLY})
here I'm doing query on field name area which is hard code. Instead of i want to pass fieldname dynamically. How we can achieve it in nodeJS
So, conceptually you just need to build the query object before sending it to the .find() function. Perhaps something like this:
const query = {}
const fieldname = 'area'
const fieldvalue = 'Plymouth'
query[fieldname] = fieldvalue
Employee.find(query).exec((err, ply) => {
// do whatever
});
You could conceptually extract both fieldname and fielvalue from req.body or req.query depending on what you're doing.
If your code supports ES6 or (any latest browser except IE), we can do this:
emp.ply = function(res,res) {
let searchField = 'area'; // this can be anything dynamically
Employee.find({[searchField]: 'Plymouth'}).exec(function(err,PLY) {
res.render("../index", {resultset: PLY})
})
}
You can refer to MDN docs about Computed property names

Firestore Add value to array field

Im trying to use Firebase cloud functions to add the id of a chatroom to the users document in an array field. I cant seem to figure out the way to write to an array field type. here is my cloud function
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;
return admin.firestore().doc(`users/${userA}/chats`).add({ event.params.messageId }).then( () => {
});
});
here is the way my database looks
any tips greatly appreciated, Im new to firestore.
From the docs, they added a new operation to append or remove elements from arrays. Read more here: https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array
Example:
var admin = require('firebase-admin');
// ...
var washingtonRef = db.collection('cities').doc('DC');
// Atomically add a new region to the "regions" array field.
var arrUnion = washingtonRef.update({
regions: admin.firestore.FieldValue.arrayUnion('greater_virginia')
});
// Atomically remove a region from the "regions" array field.
var arrRm = washingtonRef.update({
regions: admin.firestore.FieldValue.arrayRemove('east_coast')
});
Firestore currently does not allow you to update the individual fields of an array. You can, however, replace the entire contents of an array as such:
admin.firestore().doc(`users/${userA}/chats`).update('array', [...]);
Note that this might override some writes from another client. You can use transactions to lock on the document before you perform the update.
admin.firestore().runTransaction(transaction => {
return transaction.get(docRef).then(snapshot => {
const largerArray = snapshot.get('array');
largerArray.push('newfield');
transaction.update(docRef, 'array', largerArray);
});
});
This is 2021 and after many updates of firebase firestore, the new method to add data in array without removing another data is
var washingtonRef = db.collection("cities").doc("DC");
// Atomically add a new region to the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});
// Atomically remove a region from the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayRemove("east_coast")
});

Resources