MongoDB Realm Functions: How to query the document count of a collection - javascript

I tried implementing using this:
const mongodb = context.services.get("mongodb-atlas");
const itemsCollection = mongodb.db("natcocuDB").collection("members");
And I tried to put it inside an object
let memberToInsert = arg;
memberToInsert.memberID = itemsCollection.count({}) + 1;
Then the result is this:
memberID : [object Promise]1"
So the count function is a Promise. I tried to "await" the count but the function editor of realm produces an error.
The error says it's missing some ";".
So I tried so separate it by creating an async function for the count.
async function getDocumentCount(collection) {
return await collection.count({}) + 1;
}
But the result is the same only an object:
memberID : Object
Do you have any idea how can I get the document count? Thanks!

Solved it already. I just made my parent function async. And the 'await' worked. Thanks.

use await
Db query is an async operation that returns a promise. So in order to get a response from it use await or a callback.
let memberToInsert = arg;
const count = await itemsCollection.count({});
memberToInsert.memberID = count + 1;
https://docs.mongodb.com/realm/functions/#behavior

Related

How to call a variable which is declared inside firebase firestore

I have some values inside my Firebase > Firestore > Collection > Document.
i can acces them by,
db.collection("Fund").doc("Status").get().then((doc)=>{
let MTBNAV = doc.data().SPMTB
}
Now, I want to Access my MTBNAV outside the function without calling another function and setting an argument
Use the await to get MTBNAV. like this:
let MTBNAV = (await db.collection('Fund').doc('Status').get()).data().SPMTB
Try this.
much easier to understand code should be:
const myFunc = async () => {
const collectionRef = db.collection("Fund")
const doc = await collectionRef.doc("Status").get()
let MTBNAV = doc.data().SPMTB
}
}

Running two functions in parallel and then calling another function with result of prev functions in javascript

My javascript code..
function testdata(){
var strtest_data='';
var strtest1_data='';
d3.json("js/test.json").then(function(test_json) {
strtest_data=JSON.stringify(test_json);
console.log(strtest_data);
})
d3.json("js/test.json").then(function(test_json1) {
strtest1_data=JSON.stringify(test_json1);
console.log(strtest_data1);
})
console.log(strtest_data);
var testobj=JSON.parse(strtest_data);
var testobj1=JSON.parse(strtest_data1);
console.log(JSON.stringify({data:testobj.quiz, more:testobj1.maths}));
}
In the above code I'm calling two functions using d3.json (for brevity in this question I'm calling for the same test.json) and then with the results calling another function. Here the function is console.log but in actual scenario could be a ajax POST call using fetch.
The above code does not work as the bottom part of the code gets run prior to d3.json getting finished..
I would sincerely appreciate any help in solving this.
Thanks
d3.json is asynchronous method, so if you want to call it sequentially, use async/await
async function testdata() {
let strtest_data = ""
let strtest1_data = ""
const test_json = await d3.json("js/test.json")
strtest_data = JSON.stringify(test_json)
console.log(strtest_data)
const test_json1 = await d3.json("js/test.json")
strtest1_data = JSON.stringify(test_json1)
console.log(strtest_data1)
var testobj = JSON.parse(strtest_data)
var testobj1 = JSON.parse(strtest_data1)
console.log(JSON.stringify({ data: testobj.quiz, more: testobj1.maths }))
}
or call it concurently using Promise.all
async function testdata() {
let strtest_data = ""
let strtest1_data = ""
const [test_json, test_json1] = await Promise.all([
d3.json("js/test.json"),
d3.json("js/test.json"),
])
strtest_data = JSON.stringify(test_json)
strtest1_data = JSON.stringify(test_json1)
console.log(strtest_data)
console.log(strtest_data1)
var testobj = JSON.parse(strtest_data)
var testobj1 = JSON.parse(strtest_data1)
console.log(JSON.stringify({ data: testobj.quiz, more: testobj1.maths }))
}
Here I think
Promise.all([ d3.json("js/test.json")
d3.json("js/test.json")].then(data =>{
//call your other function and access using data array and make your call
}).catch(e=>console.error("error ",e));
This function is going to execute both calls when they finish then it will put the result in data array. If any error comes in either of the call you will have it in the catch block. You can do whatever you want to in the then block if all calls are completed successfully.

how do I assign a returned value from an async function to a variable

I am new to JavaScript and have been trying to read up a lot on why this is not working. Here is my code. I have also read a number of articles here on stack overflow but still feeling dense
Also if my title does not make sense, please suggest an edit
listRef.listAll()
.then(response => {
let files = []
response.items.forEach(item => {
var text
getText(item.name).then(res=>{text = res});
const id = {uid: guid()}
const url = item.getDownloadURL().then(url => {return url} )
const gsurl = `gs://archivewebsite.appspot.com/${folder}/${item.name}`
files.push({...item, name:item.name, url, gsurl, id:id.uid, text})
});
this.files = files;
})
.catch(error => console.log(error));
async function getText(docID) {
var docRef = firestore.collection("recipes").doc(docID);
let doc = await docRef.get()
if (doc.exists){
return doc.data().text
}
}
that code "works" in that it logs the response to the console but the text variable is a pending promise object.
I understand that async functions return a promise so when I call getText I need to use .then - what I am struggling with and have refactored this code a few times is this:
how can I assign the value of doc.data().text to a variable to be used later in other words, how can var text be an actual string and not a promise object pending
Also for my own learning on javascript inside the async function if I replace
if (doc.exists){
return doc.data().text
}
with
if (doc.exists){
return Promise.resolve(doc.data().text)
}
I get the same result in console.log - is this expected? is return simply short hand for the handler to resolve the promise?
I have also refactored this code to be non async and I get the same result where my var text is basically a pending promise and never the resolved data
Thanks for your help - also any articles to help explain this to me would be great! I have been going through courses on udemy but little confused by this right now
Actually you are assigning the complete promise to the variable text
Replace
var text = getText(item.name).then(res=>console.log(res))
by
var text = await getText(item.name);
OR
var text
getText(item.name).then(res=>{text = res});
Of course text is going to be a Promise. Promise.then() always returns a Promise.
Consider this code:
function doA(n) {
// do something here...
console.log("A" + n);
}
asnyc function doB(n) {
// do something here...
console.log("B" + n);
}
doA(1);
doA(2);
doB(3); // async
doA(4);
doB(5); // async
doB(6); // async
doA(7);
What do you expect the output to be?
1, 2, 4, and 7 will always be in order, because they are executed synchronously.
3 will not ever print before 1 and 2. Likewise, 5 and 6 will not ever print before 1, 2, and 4.
However, 3, 5, and 6 can be printed in any order, because async functions do not guarantee execution order once created.
Also, 4 can print before 3. Likewise, 7 can print before 5 and 6.
Basically, think of async functions as a parallel task that runs independently (although not really; single thread JS only simulates this behavior). It can return (fulfill/reject) at any moment. For this reason, you cannot just simply assign a return value of an async function to a variable using synchronous code - the value is not guaranteed to be (and probably is not) available at the moment of synchronous execution.
Therefore you need to put all the code that requires the value of text to be set into the callback block of the Promise, something like this:
getText(item.name).then((text) => {
// put everything that uses text here
});
This can of course lead to the infamous "callback hell", where you have layers inside layers of async callback. See http://callbackhell.com for details and mitigation techniques.
async/await is just one of the newer ways to do the same thing: MDN has an excellent article here: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
OK I worked with someone at work and found a solution - it was related to this post
https://stackoverflow.com/a/37576787/5991792
I was using async function inside a for each loop
the refactored code is here
async function buildFiles(){
let items = await listRef.listAll()
let files = []
for (const item of item.items){
const text = await getText(item.name)
const url = await item.getDownloadURL()
const gsurl = `gs://archivewebsite.appspot.com/${folder}/${sermon.name}`
files.push({...item, name:item.name, url, gsurl, text})
}
return files
}
async function getText(docID) {
var docRef = firestore.collection("recipies").doc(docID);
let doc = await docRef.get()
if (doc.exists){return await doc.data().text}}
buildFiles().then(res=>this.files = res)
Thanks also to #cyqsimon and #Nav Kumar V

How to use async call inside forEach when using firebase calls

the question that I have is that I can't figure out how to make this code work properly using Firestore (not sure if this is irrelevant).
The actual code is the following:
prestamoItems() {
var myarray = [];
var myobject = {};
//here comes the first async method (works OK)
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
//here comes forEach
val.docs.forEach(doc => {
myobject = doc.data();
myobject.id = doc.id;
console.log("The doc id is " +myobject.id)
//here comes second async call inside the forEach loop, but it doesnt wait for this
//to be finished, and immediately goes to the other step
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
})
myarray.push(myobject)
console.log("myobject pushed to myarray")
});
}
});
}
Please note that I'm calling an async method inside a forEach loop that comes from another async method. In every variation of the code, the output that I'm getting (the console logs) are the following:
11:13:14.999 Prestamos.vue?18d2:71 The doc id is 1yTCUKwBvlopXX2suvVu
11:13:14.999 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is Z5TE15Fj3HFrn1zvceGe
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is JNN9aN65XE1tUTmlzkoJ
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is NF2hHCpM8leZezHbmnJx
11:13:15.001 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.364 Prestamos.vue?18d2:74 The doc id from the other collection is 1yTCUKwBvlopXX2suvVu
11:13:15.368 Prestamos.vue?18d2:74 The doc id from the other collection is Z5TE15Fj3HFrn1zvceGe
11:13:15.374 Prestamos.vue?18d2:74 The doc id from the other collection is JNN9aN65XE1tUTmlzkoJ
11:13:15.379 Prestamos.vue?18d2:74 The doc id from the other collection is NF2hHCpM8leZezHbmnJx
So, the forEach loop is not waiting to the async function inside it (which actually is the expected behavior, AFAIK).
The question is how can I make it wait for the inner call to be finished before adding the obect to the array? Thanks in advance.
either you nest code, which depends on previous results into then() callbacks or you wrap the loop (forEach does not support async) in async block to make use of await inside. eg.:
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
// wrap loop in async function call iife so we can use await inside
(async () => {
for (var i = 0; i < val.docs.length; i++) {
const doc = val.docs[i];
myobject = doc.data();
myobject.id = doc.id;
// this will be synchronous now
let eqp = await fb.equiposCollection.doc(myobject.id).get();
console.log(eqp.id);
myarray.push(myobject)
}
})();
}
});
The root of the problem is that you're trying to turn an asychronous operation (waiting for Firestore to return values) into a synchronous one. This isn't really possible in a meaningful way in JavaScript without causing lots of issues!
You'll need to populate your array inside of the .then() callback and return the promise as a result of the function. Any caller that calls your prestamoItems() function will also have to use .then() callbacks to access the underlying myarray value:
const _ = {
async prestamoItems() {
const val = await fb.prestamosCollection.orderBy("fechaPrestamo", "desc").get();
if (val.empty) {
return myarray
}
// Promise.all() will take a list of promises and will return their results once they have all finished.
return await Promise.all(
// Array.prototype.map() will take an existing array and, for each item, call the given function and return a new array with the return value of each function in that array.
// This is functionally equivalent to making a new array and push()ing to it, but it reads a lot nicer!
val.docs.map(async doc => {
const myobject = doc.data();
const eqp = await fp.equiposCollection.doc(myobject.id).get()
// I presume you want to do something with eqp here
return myobject
})
);
}
}
The above code sample uses Array.prototype.map() to do away with myarray as it's not necessary.
A caller would have to use this code like this:
_.prestamoItems().then((myarray) => {
...
})
Promises are a way of saying that a value may be avaliable at some point in the future. Because of this, you have to make sure that any interaction you have with a promise is written in such a way that assumes the value is not avaliable immediately. The easiest way to do this is by using async/await and ensuring that you return promise objects.
just move the push inside then like this
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
myarray.push(myobject)
console.log("myobject pushed to myarray")
})

How to retrieve the text using protractor's getText API?

I am using protractor for my test framework and I need to get the value by using the getText method and store it in another value. I have problem in extracting the value from getText method. I do understand that I need to resolve the promise but it didn't work for me.
I have the page object like this. (Emp.js)
this.getID = async()=>{
await empID.getText();
}
and in the test.spec.js. This is how I have my test to retrieve the file.
var emp = new emp();
let empID = await emp.getID();
//When I do console.log(empID) it returns undefined. not sure why ?
Please try this:
this.getID = async() => {
return await empID.getText();
}

Categories

Resources