I have this code:
const project = await Project.findOne({"code":currentUser.groupcode}); // this works
const card = await Card.findOne({"id":req.body.id}); // this works
card.panel = req.body.newSection;
card.save(); // this works
project.cards[`${req.body.id}`].panel = req.body.newSection;
project.save(); // this does not work
I'm trying to update the panel field in both the cards collection and projects collection.
When I log project.cards[`${req.body.id}`].panel, it is the correct value, so it is the correct routing.
What's wrong here?
Try putting await before your save statements and see if it resolves the issue.
If I have guessed your schemas correctly this is the answer:
const project = await Project.findOne({ code: currentUser.groupcode }).populate("cards");
const card = await Card.findOne({ id: req.body.id }); // this works
card.panel = req.body.newSection;
await card.save(); // this works
const cardIndex = project.cards.findIndex(card => card._id.toString() === req.body.id);
project.cards[cardIndex].panel = req.body.newSection;
await project.save(); // this does not work
Ok
I needed to add
project.markModified(`cards.${req.body.id}.panel`)
before project.save();
Related
I am trying to make barbershop web app where costumer can see list of free appointments and when they reserve free appointment I want to delete that field from firebase.
I have a collection which represents one barber.
This is how it looks in firebase.
As you see radno_vrijeme is object or map in firebase which contains 6 arrays, and in each array there is list of free working hours.
In my function I am able to do everthing except last line where I need to update firebase collection.
const finishReservation = async () => {
try {
const freeTimeRef = collection(db, `${barber}`);
const q = query(freeTimeRef);
const querySnap = await getDoc(q);
querySnap.forEach(async (doc) => {
const radnoVrijeme = doc.data().radno_vrijeme;
// Find the index of the hour you want to delete
const index = radnoVrijeme["Mon"].indexOf(hour);
// Remove the hour from the array
radnoVrijeme["Mon"].splice(index, 1);
// Update the document in the collection
console.log(radnoVrijeme);
const radnoVrijemeMap = new Map(Object.entries(radnoVrijeme));
await freeTimeRef.update({ radno_vrijeme: radnoVrijemeMap });
});
} catch (error) {
console.log(error);
}
};
I tried to pass it as JSON stringified object, but it didn't work. I always get this error :
"FirebaseError: Expected type 'ya', but it was: a custom Ia object"
When you are trying to fetch multiple documents using a collection reference or query, then you must use getDocs():
const finishReservation = async () => {
try {
const freeTimeRef = collection(db, `${barber}`);
const q = query(freeTimeRef);
const querySnap = await getDocs(q);
const updates = [];
querySnap.forEach((d) => {
const radnoVrijeme = d.data().radno_vrijeme;
const index = radnoVrijeme["Mon"].indexOf(hour);
radnoVrijeme["Mon"].splice(index, 1);
const radnoVrijemeMap = new Map(Object.entries(radnoVrijeme));
updates.push(updateDoc(d.ref, { radno_vrijeme: radnoVrijemeMap }))
});
await Promise.all(updates);
console.log("Documents updated")
} catch (error) {
console.log(error);
}
};
getDoc() is used to fetch a single document using a document reference.
Hi I have exported using data (hawkers collection) using getDocs() from Firebase.
After that I put each hawker data as an object in an array called allStall as shown in the screenshot of the console log below.
Question 1 - How do I access each individual object in my allStall array. I try to use .map() to access each of it, but i am getting nothing.
Do note that I already have data inside my allStall array, see screenshot above.
[Update] map doesn't work in code below because field is stallname not stallName. However, it needs to be async + await if using/call in/from other function.
Question 2 - Why is there [[Prototype]]: Array(0) in my allStall array
export /*Soln add async*/function getAllStall(){
var allStall = [];
try
{
/*Soln add await */getDocs(collection(db, "hawkers")).then((querySnapshot) =>
{
querySnapshot.forEach((doc) =>
{
var stall = doc.data();
var name = stall.stallname;
var category = stall.category;
var description = stall.description;
var stallData = {
stallName:name,
stallCategory:category,
stallDescription:description
};
allStall.push(stallData);
});});
console.log(allStall);
//Unable to access individual object in Array of objects
allStall.map(stall =>{console.log(stall.stallName);});}
catch (e) {console.error("Error get all document: ", e);}
return allStall;
}
In my main js file, i did the following:
useEffect(/*Soln add await*/() =>
{
getAllStall();
/*Soln:replace the statement above with the code below
const allStall = await getAllStall();
allStall.map((stall)=>console.log(stall.stallname));
*/
}
);
You are getting nothing because allStall is empty since you are not waiting for the promise to be fullfilled
try this
export const getAllStall = () => getDocs(collection(db, "hawkers"))
.then((querySnapshot) =>
querySnapshot.map((doc) =>
{
const {stallName, category, description} = doc.data();
return {
stallName:name,
stallCategory:category,
stallDescription:description
};
});
)
try to change use effect like this
useEffect(async () =>
{
const allStats = await getAllStall();
console.log(allStats)
allStats.forEach(console.log)
}
);
A very big thanks to R4ncid, you have been an inspiration!
And thank you all who commented below!
I managed to get it done with async and await. Latest update, I figure out what's wrong with my previous code too. I commented the solution in my question, which is adding the async to the function and await to getDocs.
Also map doesn't work in code above because field is stallname not stallName. However, it needs to be async + await if using in/calling from other function.
Helper function
export async function getAllStall(){
const querySnapshot = await getDocs(collection(db, "hawkers"));
var allStall = [];
querySnapshot.forEach(doc =>
{
var stall = doc.data();
var name = stall.stallname;
var category = stall.category;
var description = stall.description;
var stallData = {
stallName:name,
stallCategory:category,
stallDescription:description
};
allStall.push(stall);
}
);
return allStall;
}
Main JS file
useEffect(async () =>
{
const allStall = await getAllStall();
allStall.map((stall)=>console.log(stall.stallname));
}
);
Hurray
So I'm working on a project where I'm making a call to a database to retrieve the data stored there. This data comes as an array. here is the code:
const allLogins = await Login.find().sort("name");
const token = req.header("x-auth-token");
const user = jwt.verify(token, config.get("jwtPrivateKey"));
const logins = allLogins
.filter((login) => login.userId === user._id)
.map((login) => {
login.password = decrypt(login.password);
});
If I call a console.log after the decrypt has been run I see that it has been completed correctly. The issue I have is if I console.log(logins) it says it is an array of two items that are both undefined. If instead I run it like this...
const allLogins = await Login.find().sort("name");
const token = req.header("x-auth-token");
const user = jwt.verify(token, config.get("jwtPrivateKey"));
let logins = allLogins.filter((login) => login.userId === user._id);
logins.map((login) => {
login.password = decrypt(login.password);
});
Then it works as it should. I'm not sure why the first set of code doesn't work and why the second set does work.
Any help would be appreciated!
Basic :
array. filter - accept a callback and call back return boolean (that match our criteria)
array.map - accept a callback and call back return transformed object
In the second working example:
logins.map((login) => {
// note: logins is iterated but not assigned to logins back
// so accessing login is working
login.password = decrypt(login.password); // map should return data
+ return login; // if we update all code will work
});
Now coming to first example:
const logins = allLogins
.filter((login) => login.userId === user._id)
.map((login) => {
login.password = decrypt(login.password);
+ return login; // this will fix the issue
});
I am trying to create a higher order selector which I can reuse by changing a text parameter. In the snippet below, when I am trying to perform t.click using actualSelector, it's not working as expected. When I console log the value for the actualSelector, i see whole item values are printed.
Seems I am not using it right way. Can you please help me with this.
e.g
const testItemNameGenericSelector = (itemName) =>
Selector(
".ms-Callout-container .ms-Callout-main div div"
)
.withText(itemName);
...
const itemNameToSelect = "Test Item-8ab1ec12-e719-4ab6-a0a3-ed538143d6d3";
const actualSelector = testItemNameGenericSelector(itemNameToSelect)
...
console.log(`selecting ${await actualSelector().textContent}`)
Below is full testcafe code for this test.
fixture`Getting Started`
.page // declare the fixture
`https://hasans30.github.io/testpage/dropdown.html`; // specify the start page
//then create a test and place your code there
test("My first test", async (t) => {
const testItemNameGenericSelector = (itemName) =>
Selector(
".ms-Callout-container .ms-Callout-main div div"
)
.withText(itemName);
const buttonSelector = Selector('.ms-Button-label');
const selectedValue = Selector('.ms-Dropdown-title');
const itemNameToSelect = "Test Item-8ab1ec12-e719-4ab6-a0a3-ed538143d6d3";
const actualSelector = testItemNameGenericSelector(itemNameToSelect);
await t.click(buttonSelector,{speed:0.51})
console.log(`selecting ${await actualSelector().textContent}`)
await t.click(actualSelector,{speed:0.51})
await t.expect(await selectedValue().textContent).eql(itemNameToSelect);
});
I have a collection of users which I'd like to update regularly using several different APIs (where each has its own rate limits etc).
So I have a few cron jobs with the following similar structure:
const cursor_i = db.collection('users').find();
while(await cursor_i.hasNext()){
let user = await cursor_i.next();
user.field_1 = 'Some New Stuff';
const write_result = await db.collection('newusers').save(user);
if(!write_result.result.ok){
console.log(write_result);
}
}
The problem is when a document is being updated at the same time, by more than one updater, only the last save() call would matter.
To clarify, consider the following code:
const cursor_1 = db.collection('users').find();
const cursor_2 = db.collection('users').find();
let user_cursor_1 = await cursor_1.next(); // user_cursor_1 has the first user in the collection
let user_cursor_2 = await cursor_2.next(); // user_cursor_2 has the first user in the collection
user_cursor_1.new_field_1 = 'ok';
const write_result = await db.collection('users').save(user_cursor_1);
if(!write_result.result.ok){
console.log(write_result);
}
// first user in collection now has a new field named new_field_1 with the value 'ok'
user_cursor_2.new_field_2 = 'ok';
const write_result_2 = await db.collection('newusers').save(user_cursor_2);
if(!write_result_2.result.ok){
console.log(write_result);
}
// first user in collection now has a new field named new_field_2 with the value 'ok' but DOES NOT have new_field_1 anymore
And so, the first user in the collection has been updated twice, but eventually will only have the effect of the second update.
I can think of a few ways to avoid it by implementing locks myself, but I'd guess MongoDB must have something to handle these cases.
you should find users after updating the first cursor, like this :
const cursor_1 = db.collection("users").find();
let user_cursor_1 = await cursor_1.next(); // user_cursor_1 has the first user in the collection
user_cursor_1.new_field_1 = "ok";
const write_result = await db.collection("users").save(user_cursor_1);
if (!write_result.result.ok) {
console.log(write_result);
}
const cursor_2 = db.collection("users").find();
let user_cursor_2 = await cursor_2.next(); // user_cursor_2 has the first user in the collection
user_cursor_2.new_field_2 = "ok";
const write_result_2 = await db.collection("newusers").save(user_cursor_2);
if (!write_result_2.result.ok) {
console.log(write_result);
}