Updating a retrieved Firestore document? - node.js

I'm stumbling onto an issue which I find silly, but can't seem to get around:
I'm not directly able to update the documents which I retrieve from Firestore. For example, when I try the deploy the following code within a onWrite trigger to a different node:
admin.firestore().collection("user-data").doc('someUserId').get().then(doc => {
const profile = doc.data()
if (profile.foo != 'bar') {
return 0
}
return doc.update({
objectToUpdate: {
fieldToUpdate: 'Foo is not bar!'}
})
I get the error that doc.update is not a function
I've also tried doc.ref.update, and doc.data.ref.update, but no dice.
I can achieve what I want with admin.firestore().collection("user-data').doc('someUserId').update({...}), but that just feels so clunky...
What am I missing here?

Related

result prints undefined after invoking a new method

I am trying to loop though all users data in my mongo database and check and see if an email is in the database. The loop currently works and correctly identifies if an email is in a database but the problem is once I verify the email exist I get the id of the same object and use findById() to find the specific object the email was found in then update it. Once I find the object when I try and print the result I got from the first find() it logs undefined but when I log it before the findById() method it logs the result without no problem. Why is this happening and how can I log the previous result after invoking findById(). Take a look at the comments on my code to understand the question better. Thanks in advance.
const Users = require('pathToSchema')
const email = 'test#gmail.com'
Users.find()
.then(async(result) => {
for (var i = 0; i < result.length; i++) {
if (result[i].email == email) {
//this prints result successfully
console.log(result[i])
Users.findById(result[i].id)
.then((result2) => {
//this prints undefiend
console.log(result[i])
})
.catch((err) => {
console.log(err)
})
} else {
if (i === result.length - 1) {
console.log('email not found')
}
}
}
})
.catch((err) => {
console.log(err)
})
From the code snippet it looks like you are trying to print a value from result and not result2. result is not available inside the findById() method callback handler.
Continuing the discussion from the comments, you can use the findOneAndUpdate method in mongodb to find a user with a given email and update. With this, you will not have to find the user before you update. You can do that in a single DB command.
Users.findOneAndUpdate({email: 'test#gmail.com'},{updates},{options});
This will return the original document before update. If you need the updated document in the response, pass returnNewDocument: true in the options.
Link to the documentation for this function
https://www.mongodb.com/docs/manual/reference/method/db.collection.findOneAndUpdate/

Proper way to delete-if-exists?

I have a use case where I need to delete a document that may or may not exist. I delete like this
db.collection('cities').doc('DC').delete();
It works fine, but when the document doesn't exist, I get an error in the log, which I'd rather not see. I could read the document first to ensure it exists, but that seems wasteful. What's the proper delete-if-exists approach?
EDIT I'm performing this operation using Cloud Functions (JS)
db.collection('cities').doc('DC').get().then(
doc => {
if (doc.exists) {
db.collection('cities').doc('DC').delete().then(() => {
console.log("Doc deleted!")
})
}
}
);
You can also use async/await and reuse the same doc for both actions
const doc = db.collection('cities').doc('DC')
const snapshot = await doc.get()
if (snapshot.exists) await doc.delete()

"array.forEach is not a fuction" after firebase deploy but works on firebase serve

After deployment my array does not seem to be defined and I get a "forEach is not a function" error:
textPayload: "TypeError: currencies.forEach is not a function
at currenciesMenuConfiguration (/srv/menu/currencies-menu.js:22:16)
Here's the code for the currencies array:
async function currenciesMenuConfiguration() {
currencies = await getCol("currencies")
currencies.forEach(element => {
return currenciesList[element[Object.keys(element)].id] = element[Object.keys(element)].current
});
}
This gets called right after being defined with currenciesMenuConfiguration()
getCol is defined as:
// Get all documents in collection from Firestore
async function getCol(colName) {
return fs.collection(colName).get()
.then(res => {
return res.docs.map(doc => {
var rObj = {};
rObj[doc.id] = doc.data();
return rObj;
})
})
.catch(err => {
return `Error getting collection: ${err}`;
});
}
As mentioned on firebase serve locally this works without an issue. After deployment, I get this error. Am I missing something about asynchronous code in the cloud?
Also, any tips on how I would go about debugging this myself would be much appreciated. #BeginngersLife.
// I have checked the questions on so about firebase serve vs deployment but they mostly deal with issues around deployment or don't address the issue I am facing. One question that might help me get further in this is: firebase serve and debugging functions?.
See comment below question: I did indeed not return an array but an object. Closing. Thanks for the hint #Frank van Puffelen.

Meteor ReactiveDict MongoDB Find onCreate

I'm trying to use a mongodb find items and stored in ReactiveDict, but I'm just getting the error:
{{#each}} currently only accepts arrays, cursors or falsey...
What am I doing wrong here?
Template.body.onCreated(function(){
Meteor.subscribe('itemFind');
this.global = new ReactiveDict();
this.global.set('items',Items.find());
});
Template.body.helpers({
items(){
console.log(Template.instance().global.get('items'));
return Template.instance().global.get('items');
}
});
Further, I figured if I added a .fetch() to the original find statement this would be fixed, but apparently not.
I'm new to Meteor, so what am I doing wrong here?
On the onCreated the subscription is not ready yet. A good practice is to define your Reactive vars on onCreated and assign them on onRendered.
In any case, you need to wait for the subscription to be ready. To do so you can use an autorun(). The autorun() will rerun every time its dependencies are updated.
Template.body.onCreated(function() {
this.global = new ReactiveDict({});
});
Template.body.onRendered(function()
this.autorun(() => {
const subs = Meteor.subscribe('itemFind');
if(subs.ready()) {
this.global.set('items', Items.find({}));
}
});
});

Model.create retrive how many documents have been created

I am using Model.create(Array) in Mongoose.
I want to provide user a feedback about how many documents have been created and how many of them haven't (i.e. they didn't validate).
I created a callback like this
User.create(usersToImport, function(err, docs) {
console.log(err);
console.log(docs);
}
The problem is that if any document does not validate, I only receive a validation error on the single non-valid document, while I cannot retrieve any information about the inserted documents.
Is there any way to get this information?
I think, you need something like .settle() method from when.js module.
Here is an example of doing it using when.js with mongoose 3.8.x:
when = require('when');
promises = usersToImport.map(function(user) {
return User.create(user); // returns Promise
});
when.settle(promises).then(function(results) {
// results is an array, containing following elements:
// { state: 'fulfilled', value: <document> }
// { state: 'rejected', value: <error> }
});
It's possible to do it without Promises (e.g. using async module), but the code will be much more complicated.
Model.create() isn't going to return that information for you. The best option would be to roll your own version of Model.create(), which is essentially a convenience method for calling Model.save() multiple times, and collate the information yourself. A good way to get started is the code for Model.create().

Resources