Firebase query join. Help needed - javascript

Just started with Firebase and loving it.
Was watching this video https://www.youtube.com/watch?v=Idu9EJPSxiY and wanted some help with a particular query. If anyone can help?
In the schema/structure below if i wanted to query all the events that a person named "David" attended, what would it be?
{
"users": {
"key1": {
"name": "David",
"age": 33,
"profileImg": "http/......"
}
"key2": {
"name": "John",
"age": 25,
"profileImg": "http/......"
}
},
"events": {
"fm": {
"name": "event1",
"date": 12332443456
}
},
"eventAttendees": {
"fm": {
"key1": "David",
"key2": "John"
}
}
}
I'm kinda stuck and would like some help. Thanks.
DB structure

You can try something like this (I'm using node.js firebase module to show the example)
firebase.database().ref('eventAttendees').once('value', function (eventAttendeesList) {
var events = []; //array to store the events
eventAttendeesList.forEach(function (eachEvent) { //forEach list of eventAttendees node, Eg: fm
eachEvent.forEach(function (data) { //forEach value of current eventAttendees, Eg: jey1: "David", key2: "John"
if (data.val() == "David") {
firebase.database().ref('events').child(eachEvent.key).once('value', function (snapshot) { // get the event data
events.push(snapshot) // add to array of events David attended
})
} //end of if
})// end of eachEvent.forEach
})// end of eventAttendeesList.forEach
return events;
})
I might have some syntax error somewhere, but you get the idea
First is to query for the list of data under the eventAttendees node ("fm") and loop through each value
In each of your value for the eventAttendees node there are your key1, key2 which we need to do another loop to get the data ("David", "John"). Here we will check if the data matches the person you are looking for
If it matches we will query firebase for the event data under the events node with the key that matches eachEvent.key and add it to our events array

Related

Find specific JSON key and return its value in Javascript

I have some JSON from an API which I am logging in the console.
This is easy for something like the id where I can do this...
let movieID = out.id;
console.log(movieID)
But how can I also return the 'name' of the person whose job is specifically 'Director' from JSON example like this? Basically I need to do something like 'if someone has the JOB of DIRECTOR, log their name to the console.
{
"id": 37291,
"credits": {
"crew": [
{
"name": "John Smith",
"job": "Producer"
},
{
"name": "Mary Jones",
"job": "Director"
}
]
}
}
You can get the list of the crew, like you described above. Then find the first entry in that list where the job equals "Director" and put it in a variable:
let director = out.credits.crew.find(member => member.job == "Director");
You can then log the data, as you did for the movie itself.
Something like this would do literally what you asked which was to console log out the names
credits.crew.foreach((crewMember) => {
if (crewMember.job == 'Director') {
console.log(crewMember.name)
}
})
Use underscore:
_.filter(credits.crew, (key) => key.job === 'Director')
That will give you all the keys with that value. Trust me you should use underscore or lodash because objects can get super tricky and it saves you a ton of time.

Cloud Functions problem, query resulting in an Array?

I need to get inside of itens to go into some item, than into product to get the "ean" field and
check if some product have the "ean" from the body request.
My database is organized like that:
"cart": {
"itens": {
"0": {info here},
"1": {info here}
"2": {
"more info here",
"product": {
"avaliable": true"
"quantity": 231,
"ean": "0000001312"
}
continue listing until 47
But when I execute my cloud function:
exports.getItemByEan = functions.https.onRequest(async (request, response) => {
const db = admin.database();
const itens = db.ref();
const eanRef = itens.child('carrinho').child('itens');
const query = eanRef.orderByKey();
try {
const dataSnapshot = await eanRef.once('value');
response.send(dataSnapshot.val());
} catch (error) {
console.log(error)
}
})
});
But i need to get inside of an iten, and then inside "product" field and than get the "ean", but the result of this is like an Array insted of an object, and without the keys appearing:
[
{,
"product": {
"avaliable": true,
"quantity": 9183
"ean": "0000000000017",
},
{
"product": {
"avaliable": true,
"quantity": 131
"ean": "0000000044790",
},
},
.....continues
I want to things, understand why the result of the query is an Array and not an Object with the Keys before the itens like in the Firebase Database, and then how is the better way to find the specific product by Ean.
I can't even do like
const db = admin.database();
const itens = db.ref();
const eanRef = itens.child('cart').child('itens').child('product'); // This doesnt works, just returns nothing, why ?????
// Isn't "product" field inside the item ?
If your database keys are all numbers, then instead of an object, you will get an array with the same items, where the indexes of the array are the same as the keys of the nodes in the database. Your code needs to be prepared for this. So, if you want the client to receive an object instead of an array, you will have to convert it yourself.

Is this the correct use of the $ operator for findOneAndUpdate?

I would like to update a single value in a mongo document that is an array of arrays of arrays,
Here is the code that I have thus far... but it's not working. I think I need to use the $ operator on the chart to access the currently selected chorePerson... but not sure how that works.
I am really struggling with the mongoDB syntax and updating arrays
This is my data set, I have put in a t1, t2 and t3 in each of the respective arrays...
[
{
"_id": "5e3d891d956bb31c307d8146",
"t1": 0,
"affiliation": "800_800",
"year": 2020,
"month": "February",
"weekNumber": 6,
"weekStart": "02/02/2020",
"weekEnd": "02/08/2020",
"chart": [
{
"t2": 0,
"_id": "5e3d8a6358a3d92448e85aa5",
"ordinal": 5,
"ordinalString": "Friday",
"chorePerson": [
{
"completed": false,
"t3": 0,
"_id": "5e3d8a6358a3d92448e85aa7",
"person": "Frank",
"personID": "5e2891587678601434f6929c",
"phone": "8008008002",
"chore": "Another one",
"choreID": "5e39ca3949acee16fc280c98"
}
]
}
],
"date": "2020-02-07T16:03:47.770Z",
"__v": 0
}
]
I have been able to update t1 and t2 using this query:
{"_id":"5e3d891d956bb31c307d8146","chart._id":"5e3d9260fc365c2d080a32ce"}
and a set call of
{"$set":{"t1":1,"chart.$.t2":2}}
but I cannot figure out how to go down one more level in the arrays
Here is my query: I have hard coded the 'chart[ 1 ]' to try to force it to fetch only that record
{"_id":"5e3d891d956bb31c307d8146","chart._id":"5e3d8a6358a3d92448e85aa5","chart[1].chorePerson._id":"5e3d8a6358a3d92448e85aa7"}
This is my 'set' call
{"$set":{"t1":1,"chart.$.t2":2,"chart.$[].chorePerson.$.t3":3}}
When I run this in my program I get:
error Updating the path 'chart.$[].chorePerson.$.t3' would create a conflict at 'chart'
UPDATE 1
So I tried this:
{"_id":"5e3d93777f099b28b0fff2ae","chart._id":"5e3d953ed92a082738e8e2b9","chart.chorePerson._id":"5e3d953ed92a082738e8e2bb"}
{"$set":{"t1":1,"chart.$.t2":2,"chart.$.chorePerson.$.t3":3}}
which gave me:
error Too many positional (i.e. '$') elements found in path 'chart.$.chorePerson.$.t3
So I thought I would go back to the answer posted by whoami:
{"$set":{"t1":1,"chart.$.t2":2,"chart.$[].chorePerson.$.t3":3}}
Which gave me:
error Updating the path 'chart.$[].chorePerson.$.t3' would create a conflict at 'chart'
UPDATE 2
So I tried moving the [] in my set statement to the chart.$.chorePerson
{"$set":{"t1":1,"chart.$.t2":2,"chart.$.chorePerson.$[].t3":3}}
and selecting only the relevant chorePerson (5e3da771e08e3e31ac420004)
{"_id":"5e3da771e08e3e31ac41fffd","chart._id":"5e3da771e08e3e31ac420002","chart.chorePerson._id":"5e3da771e08e3e31ac420004"}
Which is getting me closer... now the data is being set in the correct chore chart and chart, but ALL of the chorePerson fields are being updated even though my select is supposed to only return the chore person '5e3da771e08e3e31ac420004'
After trial and error and lots of stack overflow articles, I have finally found the code that does what I need it to do:
var query = {"chart.chorePerson._id":idCP};
var update = {$set: {"chart.$.chorePerson.$[elem].completed":true, "chart.$.chorePerson.$[elem].completed_at": Date.now()}};
var options = {new: true, arrayFilters: [ { "elem._id": { $eq: idCP } } ]};
if(debugThis){
console.log("query " + JSON.stringify(query));
console.log("update " + JSON.stringify(update));
console.log("options " + JSON.stringify(options));
}
// see stackoverflow question:
// https://stackoverflow.com/questions/60099719/is-this-the-correct-use-of-the-operator-for-findoneandupdate/60120688#60120688
ChoreChart.findOneAndUpdate( query, update, options)
.then(chart => {
if(debugThis){
console.log('updated chart ' + JSON.stringify(chart));
}
return resolve(msgResponse);
})
.catch(err => {
msgResponse.message('error ' + err.message);
return resolve(msgResponse);
})
Which yields exactly what I want:
Many thanks to the people who wrote these articles:
https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/#behavior
Update nested subdocuments in MongoDB with arrayFilters
Updating a Nested Array with MongoDB
How to Update Multiple Array Elements in mongodb
arrayFilters in mongodb
https://github.com/Automattic/mongoose/issues/6386

Firebase - Is there a way to iterate through all documents in a collection, and find a certain value for a field within each of them

I am trying to find a way to iterate through each document in a collection, and find the value for a certain field each time for my Firebase Database in Node.js
Here is an example of a database structure that has the same structure as mine:
{
"users": {
"tommy": {
"username": "tom",
"points": 3
},
"bryan": {
"username": "bry123",
"points": 7
}
}
}
In this case, I would want it to return the points for each users. Meaning the first time it would return 3, and the second time 7. I tried looking at the Firebase Documentation but couldn't find what I needed. Is anybody able to help?
Sure thing, something like this should do the trick:
let db = firebase.database().ref();
let usersRef = db.child("users");
users.once("value").then(function(snapshot) {
snapshot.forEach(function(userSnapshot) {
console.log(userSnapshot.key); // "tommy", "bryan"
console.log(userSnapshot.val()); // { "username": "tom", "points": 3 }, { "username": "bry123", "points": 7 }
console.log(userSnapshot.child("points").val()); // 3, 7
});
});
I highly recommend spending more time reading the Firebase documentation, some of the tutorials out there, and searching previous questions on the topic.

Looping inside the json in stored proc DocumentDB

I have big json that I pass to stored procedure in Cosmos DB. I need to split the json document and create multiple documents. How do I loop to the json inside the stored procedure.
Example: Using Json below I need to create a separate document for each children and another one without Children nodes. A total of 3 documents. How can I loop and split it inside the stored procedure?
{
"id": "d93af7d3706e4f28882920366c017cd7",
"FamilyId": 989,
"LastName": "Andersen",
"Parents": [
{
"FamilyName": null,
"FirstName": "Thomas"
},
{
"FamilyName": null,
"FirstName": "Mary Kay"
}
],
"Children": [
{
"ChildId":001,
"FamilyName": null,
"FirstName": "Henriette Thaulow",
"Gender": "female",
"Grade": 5,
"Pets": [
{
"GivenName": "Fluffy"
}
]
},
{
"ChildId":002
"FamilyName": null,
"FirstName": "Maria Thaulow",
"Gender": "female",
"Grade": 12,
"Pets": [
{
"GivenName": "Grizzly"
}
]
}
],
"Address": {
"State": "WA",
"County": "King",
"City": "Seattle"
},
"IsRegistered": false
}
Take a look at this sample: https://github.com/Azure/azure-documentdb-js-server/blob/master/samples/stored-procedures/BulkImport.js. Note that currently stored procedure can run within context of one partition key (which is provided in request options to execute the sproc), i.e. if there are multiple PK values in your docs, the docs need to be grouped by PK value.
Actually , you can implement bulk import data via Stored Procedure.
Please refer to the code from official tutorial.
function bulkImport(docs) {
var collection = getContext().getCollection();
var collectionLink = collection.getSelfLink();
// The count of imported docs, also used as current doc index.
var count = 0;
// Validate input.
if (!docs) throw new Error("The array is undefined or null.");
var docsLength = docs.length;
if (docsLength == 0) {
getContext().getResponse().setBody(0);
}
// Call the create API to create a document.
tryCreate(docs[count], callback);
// Note that there are 2 exit conditions:
// 1) The createDocument request was not accepted.
// In this case the callback will not be called, we just call setBody and we are done.
// 2) The callback was called docs.length times.
// In this case all documents were created and we don’t need to call tryCreate anymore. Just call setBody and we are done.
function tryCreate(doc, callback) {
var isAccepted = collection.createDocument(collectionLink, doc, callback);
// If the request was accepted, callback will be called.
// Otherwise report current count back to the client,
// which will call the script again with remaining set of docs.
if (!isAccepted) getContext().getResponse().setBody(count);
}
// This is called when collection.createDocument is done in order to process the result.
function callback(err, doc, options) {
if (err) throw err;
// One more document has been inserted, increment the count.
count++;
if (count >= docsLength) {
// If we created all documents, we are done. Just set the response.
getContext().getResponse().setBody(count);
} else {
// Create next document.
tryCreate(docs[count], callback);
}
}
}
When stored procedure is executed from client, RequestOptions specify the partition key, stored procedure will run in context of this partition and cannot operate (e.g. create) on docs that have different partition key value.
What you can do is to execute the stored procedure from client for each partition key. For instance, if stored procedure is to bulk-create documents, you can group the docs by partition key and send each group (can be done in parallel) to the stored procedure providing partition key value in RequestOptions.
Hope it helps you.

Categories

Resources