Firebase Firestore can't save document - javascript

Summary
I have a node server that is getting a document from MongoDB and then saving it to Firestore. I have Firestore setup properly and I can save variables I create in node as a document but I can't save the document I get back from MongoDB. Does anyone know how to solve this problem? Your help would be greatly appreciated!
Error
"Value for argument "data" is not a valid Firestore document. Couldn't serialize object of type "model" (found in field event.data). Firestore doesn't support JavaScript objects with custom prototypes (i.e. objects that were created via the "new" operator)."
Code
Get stats from MongoDB & send to firebase
const objectFromMongoDb = await InstantComp.findOneAndUpdate(
{
_id: compId,
"competitors.userId": userObj._id,
inProgress: true
},
{ $set: { "competitors.$.stats": lifeStats } },
{ new: true }
);
addToFirestoreFunction(userObj._id, "NEW_COMP_DATA", objectFromMongoDb);
addToFirestoreFunction
async function addToFirestoreFunction(userId, eventType, data) {
try {
//read database
//if userId contains eventType singleEntry then remove from database
const timeStamp = new Date();
userId = userId.toString();
const userDoc = db.collection("pushData").doc(userId);
const pushData = await userDoc.set(
{
event: {
eventType,
data,
timeStamp
}
},
{ merge: true }
);
console.log("Document set in FireStore", pushData);
} catch (err) {
console.log("errpr pushing to firebase", err);
}
}
Object from MongoDB
This is the object returned from MongoDB which I copied from a console log.
{
inProgress: true,
_id: "5d63ffd3c364351ce81a230b", //an objectId from MongoDB
userId: "5cca01eb8c481129d711f479", //an objectId from MongoDB
compName: "Benji's Daily MuckShow",
competitors: [
{
inProgress: true,
_id: "5d63ffd3c364351ce81a230c", //an objectId from MongoDB
userId: "5cd65533c2e8700024309e6d", //an objectId from MongoDB
startingLifeTimeStats: [{kills: 0, wins: 10}],
stats: [{kills: 0, wins: 10}]
}
]
};``

async function addToFirestoreFunction(userId, eventType, data) {
try {
//read database
//if userId contains eventType singleEntry then remove from database
// Convert mongoose object to normal json object
data = JSON.parse(JSON.stringify(data));
const timeStamp = new Date();
userId = userId.toString();
const userDoc = db.collection("pushData").doc(userId);
const pushData = await userDoc.set(
{
event: {
eventType,
data,
timeStamp
}
},
{ merge: true }
);
console.log("Document set in FireStore", pushData);
} catch (err) {
console.log("errpr pushing to firebase", err);
}
}

Related

backend node js with mongoDB, patch request does not update date type value

I use node.js to build the backend and persist the data in MongoDB. When I do a patch request, I can change the values of all the fields of other types except for the one of date type.
This is the backend code for the patch request.
router.patch('/:id', isLoggedIn, async (req, res) => {
try {
const updatedBooking = await Booking.updateOne(
{_id: req.params.id},
{
$set: {userEmail: req.body.userEmail},
$set: {shiftDate: req.body.shiftDate},
$set: {isMorningShift: req.body.isMorningShift}
}
);
res.json(updatedBooking);
} catch (err) {
res.send({message: err});
}
});
This is the database scheme:
const BookingSchema=mongoose.Schema({
userEmail:{
type:String,
required:true
},
shiftDate:{
type:Date,
required:true
},
isMorningShift:{
type: Boolean,
required: true
}
});
The objects in MongoDB look like this:
{
"_id": "61787183e67b6822180175f9",
"userEmail": "admin2#parantion.nl",
"isMorningShift": false,
"__v": 0,
"shiftDate": "2066-06-23T00:00:00.000Z"
}
What might be the problem?
Instead of multiple $set, update all the keys in one,
const updatedBooking = await Booking.updateOne(
{_id: req.params.id},
{
$set: {
userEmail: req.body.userEmail,
shiftDate: new Date(req.body.shiftDate),
isMorningShift: req.body.isMorningShift
}
}
);
#fractal397's answer will work fine. If you want a more cleaner code, you can use this.
const bookingId = req.params.id;
const payload =
userEmail: req.body.userEmail,
shiftDate: new Date(req.body.shiftDate),
isMorningShift: req.body.isMorningShift
}
const booking = await Booking.findByIdAndUpdate(bookingId, payload);
P.S. - After Mongoose 4.0, new value for findByIdAndUpdate has been changed to false by default. So in this operation, data will be updated in the database but it will return the old value booking. To get updated value in response too, you will have to do -
const booking = await Booking.findByIdAndUpdate(bookingId, payload, { new : true });
Change the line:
$set: {shiftDate: req.body.shiftDate}
to
$set: {shiftDate: new Date(req.body.shiftDate)}
or
$set: {shiftDate: new Date()} //for todays date in your local format
This works:
I tested this with express like so:
app.get('/updateOne', async (req, res) => {
//get data through query params in url
const id = req.query.id;
const date = req.query.date;
//connect to db and collection
//1 connect
//2 set db and collection
const client = await MongoClient.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const collection = client.db("sample_airbnb").collection("listingsAndReviews");
//update function for date field
try {
const updatedBooking = await collection.updateOne(
{_id: id},
{
$set: {name: new Date(date)} //2066-06-23T00:00:00.000Z
}
);
res.json(updatedBooking);
} catch (err) {
res.send({'message': err});
}
})
Response:
{
"acknowledged": true,
"modifiedCount": 1,
"upsertedId": null,
"upsertedCount": 0,
"matchedCount": 1
}
And updated data in Mongoscloud:
_id
:
"100009690"
name
:
2066-06-23T00:00:00.000+00:00
The I called the endpoint like so:
http://localhost:5000/updateOne?id=100009690&date=2066-06-23T00:00:00.000Z and you see it's the same date format you say you expect.
Can you update your OP and show us the exact format you are passing in?? DO a console.log(req.body.shiftDate) on line 7 just before you pass it. I suspect here is where the issue is.
Obviously I shouldn't add dates to names field but this is purely for a quick test.
If updating multiple fields I'd with:
//update function
try {
const updatedBooking = await collection.updateOne(
{_id: id},
{
$set: {
name: name,
email: email,
lastShift: new Date(date)
}
}
);
res.json(updatedBooking);
} catch (err) {
res.send({'message': err});
}

How can I delete an array entry in MongoDB with a delete API?

I am building an application that manages time sensitive tasks. I have APIs to create tasks and retrieve tasks, and I'm currently trying to get my delete API to work.
An employee has an array in MongoDB that contains todo tasks with text and I'm trying to delete the task by ID in SoapUI. With my current code, the delete request just sort of times out after a minute or so.
Here's my current delete API
router.delete("/:empId/tasks/:id", async (req, res) => {
try {
Employee.findByIdAndDelete(
{
empId: req.params.empId,
},
{
$pull: {
todo: {
_id: req.params.id,
},
},
}
);
} catch (e) {
console.log(e);
res.status(500).send({
message: "Internal server error: " + e.message,
});
}
});
Current schema
let itemSchema = new Schema({
text: { type: String },
_id: { type: String },
});
task.service
deleteTask(empId: number, task: string, _id: number): Observable<any> {
return this.http.delete('/api/employees/' + empId + '/tasks/' + _id);
}
and an example of an employee document in MongoDB
{"_id":{"$oid":"61797a51d15ad09b88d167af"},"empId":"1012", "firstName":"web","lastName":"developer","__v":1,"done":[],"todo":[{"_id":"1","text":"test"}]}
When you use findByIDAndDelete, it deletes that entire document. What you need is to update that particular document using update()/findOneAndUpdate()/findByIdAndUpdate(). Also you should either await/use a callback to return the value, like,
collection.findOneAndUpdate({_id:docId },{
$pull: {"todo":{"_id":yourId} },
},
function(error, data){
if(error){ return error}
else {return data}
})

NodeJS : Mongoose findByIdAndUpdate() returns null

Consider the following code on NodeJS for updating a Document By id:
router.put('/:orderId', async(req, res) => {
let update_orderId = req.params.orderId;
let new_item = req.body.item;
let new_item_desc = req.body.item_desc;
let new_quantity = req.body.quantity;
let new_unit_price = req.body.unit_price;
let new_total_cost = new_quantity * new_unit_price;
let new_status = req.body.status;
let new_priority = req.body.priority;
await RequestPermissionOrderSchema.findByIdAndUpdate( update_orderId, {
$set: {
item: new_item,
item_desc: new_item_desc,
quantity: new_quantity,
unit_price: new_unit_price,
total_cost: new_total_cost,
status: new_status,
priority: new_priority,
directOrder: false
}
},
{ new: true, useFindAndModify: false}, function (err, docs) {
if (err) {
console.log(err);
res.send(err);
} else {
console.log("Updated Request Permission Order : ", docs);
res.json(docs);
}
});
});
Everything is according to the latest documentation of Mongoose 5.10.9 and the schema also contains all the properties specified under $set: { ... } . But when I execute, I get the output as follows in the console:
updated Request Permission Order : null
I also make sure of whether the _id is available in the mongoDB database and that object ID is there. I can't seem to find what I did wrong. Really appreciate any help on this !
Also, note that I want to update by the _id auto-generated by MongoDB with each document.
Just pass the JSON object, remove the $set
await RequestPermissionOrderSchema.findByIdAndUpdate( update_orderId, {
$set: { // REMOVE THIS $set
item: new_item,
item_desc: new_item_desc,
quantity: new_quantity,
unit_price: new_unit_price,
total_cost: new_total_cost,
status: new_status,
priority: new_priority,
directOrder: false
} // REMOVE THIS ALSO
},
Only the JSON object.

Mongoose populate method only storing one Object

I'm trying to access the array of Message Models that is stored in my Conversation Model. However, when I use the populate method to try to store the Message models as an array, only the first Message is showing up.
socket.on('connected', function (data) {
//load all messages
const filter = { roomId: data.roomid };
(async () => {
console.log('searching for Schema');
let conversation = await Conversation.findOne(filter)
.populate('messages')
.exec(function (err, message) {
if (err) console.log('no schema found');
var array = message.messages;
console.log(array);
// printing only first Message
});
})();
});
Conversation Schema
const ConversationSchema = new mongoose.Schema(
{
roomId: {
type: String,
required: true
},
messages: {
type: mongoose.Schema.Types.ObjectId, ref: 'Message'
}
},
{
timestamps: true
}
);
populate method not store message as an array.Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s).Refer this for more detail
To solve your problem modify declaration of messages field in Conversation Schema
messages: [{
type: mongoose.Schema.Types.ObjectId, ref: 'Message'
}]

is there a way to prevent duplication of entries in neDB collection's array?

var addNewUser = function (id, chatId) {
db.update({ _id: id }, { $push: { users: chatId } }, {}, function (err, numAffected) {
// code after the record is updated
});
}
in this code
I want to push new Id to the array if it is not in it.
I've read the docs of neDB but it seems there is no way to do that
I'm beginner so I think there is a way to do that but I cant see it.
To push new chatId to users array only if it does not exist, you can use $addToSet. According to the nedb document:
$addToSet adds an element to an array only if it isn't already in it
Here is the example code:
var addNewUser = function (id, chatId) {
db.update({ _id: id }, { $addToSet: { users: chatId } }, {}, function (err, numAffected) {
// code after the record is updated
});
}

Categories