I am trying to write a transaction that first query documents by documentId from a list of ids, then makes some updates.
I am getting the error:
The corresponding value for FieldPath.documentId() must be a string or a DocumentReference.
For example:
const indexArray = [..list of doc ids...]
const personQueryRef = db.collection("person").where(admin.firestore.FieldPath.documentId(), "in", indexArray)
return db.runTransaction(transaction => {
return transaction.get(personQueryRef).then(personQuery => {
return personQuery.forEach(personRef => {
transaction.update(personRef, { ...update values here })
//more updates etc
})
})
})
I am wanting to do this in an onCreate and onUpdate trigger. Is there another approach I should be taking?
Update
The error still persists when not using a transaction, so this is unrelated to the problem.
The problem does not occur when the query is .where(admin.firestore.FieldPath.documentId(), "==", "just_one_doc_id"). So, the problem is with using FieldPath.documentId() and in.
It sounds like the type of query you're trying to do just isn't supported by the SDK. Whether or not that's intentional, I don't know. But if you want to transact with multiple documents, and you already know all of their IDs, you can use getAll(...) instead:
// build an array of DocumentReference objects
cost refs = indexArray.map(id => db.collection("person").doc(id))
return db.runTransaction(transaction => {
// pass the array to getAll()
return transaction.getAll(refs).then(docs => {
docs.forEach(doc => {
transaction.update(doc.ref, { ...update values here })
})
})
})
Related
Hi I tried to update the element at a particular index in an array but I'm not able to update it. It is updating the entire array. Not able to figure out how to update any particular index. Also tried
{$set:{"Data.1:req.body}}
this is updating at 1st index but I don't want to hardcode the index value. It should take from frontend. Let say I have a schema in which I have Data who's type is array and default value is as shown below or anything in the same format.
Data: {
type: Array,
Default: ["0","1","0"]
}
Whenever I'll create a user then Data field will contain these default values, But now I want to update the value at any index (coming from frontend) of Data array of any user created.
I tried findByIdAndUpdate method but I don't know what to pass in set property. If I'm passing this {$set: req.body} and In postman I'm giving any value of Data then obviously it is updating Data array but I want to update value at any index which I'm passing from frontend, let say the index I'm passing is 2 then it should update the value of array at index 2, similarly I can pass any index from frontend how should I do that. What changes I have to make in {$set : } Thanks in advance.
Waiting for any help or suggestions. Thanks
It appears that you can solve this in backend logic if you are passing the index from the frontend.
You can dynamically specify the index, based on the input from the frontend, before you send a query.
const updateUserData = async (req, res) => {
const { index, user_id, new_value } = req.body;
try {
const update = {};
update[`Data.${index}`] = new_value;
const data = await Users.updateOne(
{ _id: user_id },
{ $set: update }
);
return res.status(200).json({ success: true });
} catch (error) {
return res.status(500).json({ success: false });
}
};
Recently, I changed key of object in MongoDB.
{
links: {
changed: 'value',
notchanged: 'value'
}
}
This is what I get from my MongoDB collection. Data which key is not changed is still readable by links.notchanged but data which key is changed like links.changed is not readable and only outputs undefined. Node.js gets and reads the whole links data correctly but when it comes to links.changed it doesn't. How do I solve this problem? Code below:
scheme.findOne({}, (err, data) => {
if (err) res.send('ERR')
else {
console.log(data) // prints full data, same as JSON above
console.log(data.links.changed) // undefined
}
}
You are matching {class:'210'}.. Is it available in document. Probably Your query returns empty object in data . Confirm the match query... Otherwise your code seems ok.
await db1.findOne({class: "210"}, (err, data) => {
console.log(data.links.changed) // returns value
})
Or Try the code like this
await db1.find({ class: "210" }).toArray()
.then(data => {
console.log(data[0].links.changed) //"value"
});
You should make a variable instead of an object for this. For example: Use changed and assign it value as true or false
I am working on a social network web application I have established a system of following followers with firebase and node js , so I created a collection users and in it two following followers array, I managed to add them
Now I want to issue a condition to check if the user has already made a follow up not to add it a second time to the table how can i access to the tables (following, followers)in order to verify if the user is in
exports.onFollow = (req, res) => {
const followDocument = db.doc(`/users/${req.body.email}`);
const followerDocument = db.doc(`/users/${req.user.email}`);
let followData;
let followerData;
followDocument
.get()
.then((doc) => {
if (doc.exists) {
followData = doc.data();
if ('req.user.email', 'in', followData.followers.docs) {
return res.status(200).json({
error: 'user already follow'
});
} else {
followData.followers.push(req.user.email);
return followDocument.update({
followers: followData.followers
});
}
}
})
.catch((err) => {
console.error(err);
res.status(500).json({
error: err.code
});
});
It sounds like you want followers to be an array with unique values, so that each email address can only occurs once. Firestore has special arrayUnion operation for adding values to such a field.
From the documentation on updating elements in an array:
If your document contains an array field, you can use arrayUnion() and arrayRemove() to add and remove elements. arrayUnion() adds elements to an array but only elements not already present. arrayRemove() removes all instances of each given element.
var washingtonRef = db.collection("cities").doc("DC");
// Atomically add a new region to the "regions" array field.
washingtonRef.update({
regions: admin.firestore.FieldValue.arrayUnion("greater_virginia")
});
// Atomically remove a region from the "regions" array field.
washingtonRef.update({
regions: admin.firestore.FieldValue.arrayRemove("east_coast")
});
I'd recommend switching to using arrayUnion() for your use-case, as it prevents having to do the query to detect if the email address is already in the array.
Product
.findAll()
.then((products) => {
/* Perform operations */
}
The above query returns an array of products. For eg,
[
{
name: Mobile,
price: 10000
},
{
name: Laptop,
price: 20000
},
]
I need to make some changes to the products array (add new fields based on the values of existing fields, and delete those existing fields). I tried few methods, but none are working:
products.forEach((product) => {
product.[updatedPrice] = updatedPrice;
delete product[price];
}
Array.map() is also not working.
The following works, but I don't know the working behind, and why it is happening. Also, how to delete a field using the same.
products.forEach((product) => {
product.set('updatedPrice', updatedPrice, {strict: false})
}
The thing here to note is that in .then((products) products object here is not a JSON object but a Mongoose Document object and the set method you are using is defined by the mongoose. You can refer it from here https://mongoosejs.com/docs/guide.html#strict
We can do 2 things:
use lean() (returns a plain js object)
Product.findAll().lean().then((products) => {
/* Perform operations*/
});
use toJSON() method on products object to convert mongoose object to js object
Product.findAll().then((products) => {
products = products.toJSON();
/* Perform operations*/
});
Thanks
I am executing a mongoose Model.findById() function in order to return a single instance by utilizing an express route.
Model.findById(modelid)
.then(instance => {
if(instance.isOwnedBy(user)) {
return instance.update({$push: {days: req.params.dayid}}, {new: true})
.then(foo => res.send(foo))
} else {
res.status(401).send("Unauthorized")
}
})
the above code returns an object containing the opTime, electionId...etc instead of returning the newly updated document instance. How am I able return the newly updated document after the instance.update() method?
If instance.isOwnedBy(user) and _id: modelid can be merged into one mongo query, it's better to use findOneAndUpdate() but in that way, if it doesn't find any document match, you can not know which part of the query causes the not found.
And because I don't know much about your models, conditions, I can not answer how to do it with findOneAndUpdate() but there is another way that modify the document and call save() method.
Example base on your code:
Model.findById(modelid)
.then(instance => {
if(instance && instance.isOwnedBy(user)) {
if(instance.days) instance.days.push(req.params.dayid);
else instance.days = [req.params.dayid];
instance.save().then(function(instance){
res.send(instance);
})
} else {
res.status(401).send("Unauthorized")
}
})
Note: You should check if the instance exist or not before modify it.