Cosmos DB overwrite existing documents - javascript

Currently, I have this, which works fine.
this.container.items
.create<Session>(data)
.then(() => callback(null))
.catch((error) => {
console.log("error >>>", error)
callback(error)
});
However, if I try to create another document with the same ID, I get the error:
message: 'Entity with the specified id already exists in the system.
Is it possible to make Cosmos ignore it and overwrite the document, or is there a method on the NodeJS SDK for that?

You would need to use Upsert if you want to upadate the entire document , if you need to change few fields then consider using Patch operation
Upsert
const { resource: upsertedPerson1 } = await container.items.upsert(upsertSource);
Patch
const { resource: patchSource1 } = await container.item(patchId!).patch(replaceOperation);
Check the samples here.

You can use UPSERT method of items.
https://learn.microsoft.com/en-us/javascript/api/#azure/cosmos/items?view=azure-node-latest##azure-cosmos-items-upsert-1

Related

Catching Error With Custom Rest API For FireStore Javascript

I have been watching a tutorial on making a Rest API for Firestore which appears to work but I cannot figure out how to catch an error.
The code below basically uses an end point to retrieve a document id from the firestore database.
The client uses javascript fetch to call the API.
I am trying to workout how to return something back to the client from the API if the document id is not there. I thought I might get a 404 status returned but I always get status 200.
This is the API code I used
app.get("/api/read/:id", (req, res) => {
(async () => {
try {
const document = db.collection("users").doc(req.params.id);
let product = await document.get();
let response = product.data();
return res.status(200).send(response);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
})();
})
I'm fairly certain that the 404 message is for the server itself not being found (though I do need to brush up on my error codes).
However, if you're looking to check to see if a document exists there's a command specifically for that demonstrated in the examples in the firebase docs

TypeError: Cannot read property 'rows' of undefined

When following Getting started with Postgres in your React app, at the point where you process and export the getMerchants, createMerchant, and deleteMerchant functions, I am getting this error -- TypeError: Cannot read property 'rows' of undefined, what is going on here?? It is probably something very small I am missing. There error occurs at getMerchants and resolve(results.rows)
const Pool = require('pg').Pool
const pool = new Pool({
user: 'my_user',
host: 'localhost',
database: 'my_database',
password: 'root',
port: 5432,
});
const getMerchants = () => {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM userIds ORDER BY id ASC', (error, results) => {
if (error) {
reject(error)
}
resolve(results.rows);
})
})
}
const createMerchant = (body) => {
return new Promise(function(resolve, reject) {
const { name, email } = body
pool.query('INSERT INTO userIds (name, email) VALUES ($1, $2) RETURNING *', [name, email], (error, results) => {
if (error) {
reject(error)
}
resolve(`A new merchant has been added added: ${results.rows[0]}`)
})
})
}
const deleteMerchant = () => {
return new Promise(function(resolve, reject) {
const id = parseInt(Request.params.id)
pool.query('DELETE FROM userIds WHERE id = $1', [id], (error, results) => {
if (error) {
reject(error)
}
resolve(`Merchant deleted with ID: ${id}`)
})
})
}
module.exports = {
getMerchants,
createMerchant,
deleteMerchant,
}
As per my comment:
Second parameter for query is the query parameters, and not a callback function. Pass in [], if you do not have parameters. Other than that, your code looks largely redundant. You should follow proper async pattern that library offers, and not re-create all those useless promises...
const getMerchants = () => pool.query('SELECT * FROM userIds ORDER BY id ASC');
And then use it like this:
const {rows} = await getMerchants();
Right code, wrong password
The code itself is right! The error is thrown:
if you have not set a password at all, or
if you enter a wrong password. For example, I accidentally copied 'root' as a password from the guide, although I had set the password of my_user to 'postgres'. When everything else was already running and only the password was wrong, you get the same error.
The error in detail:
myuser#mypc:~/project/node-postgres$ node index.js
App running on port 3001.
/home/myuser/myproject/node-postgres/merchant_model.js:17
resolve(results.rows);
^
TypeError: Cannot read property 'rows' of undefined
at pool.query (/home/myuser/myproject/node-postgres/merchant_model.js:17:23)
at PendingItem.connect [as callback] (/home/myuser/myproject/node-postgres/node_modules/pg-pool/index.js:363:16)
at Client.client.connect [as _connectionCallback] (/home/myuser/myproject/node-postgres/node_modules/pg-pool/index.js:246:23)
at Client._handleErrorWhileConnecting (/home/myuser/myproject/node-postgres/node_modules/pg/lib/client.js:305:19)
at Client._handleErrorMessage (/home/myuser/myproject/node-postgres/node_modules/pg/lib/client.js:325:19)
at Connection.emit (events.js:198:13)
at parse (/home/myuser/myproject/node-postgres/node_modules/pg/lib/connection.js:114:12)
at Parser.parse (/home/myuser/myproject/node-postgres/node_modules/pg-protocol/dist/parser.js:40:17)
at Socket.stream.on (/home/myuser/myproject/node-postgres/node_modules/pg-protocol/dist/index.js:11:42)
at Socket.emit (events.js:198:13)
I could find out the solution for this by following the guide at Getting started with Postgres in your React app: an end to end example where you also find more about the code that was used here. For digging deeper into this, How to quickly build an API using Node.js & PostgreSQL might help as well. To test this, you need to install PostgreSQL (or use a Webserver, but then, you will need SSL, see How to create a pool object in javascript that can connect to a database backend using SSL?) and create a "Merchant" table in the database as it is done in the guide.
As the files of the tutorial do not have any error, the problem of the question happens most probably (as in my case) because you have not fully followed the guide about how to set up the database role and password. You can check whether your settings are right by running, depending on whether you have chosen the guide's my_user or the standard postgres user to connect (if the latter, change the pool settings in merchant_model.js to postgres user):
psql -d my_database -U my_user
or:
psql -d my_database -U postgres
It should ask for a password:
Password for user postgres/my_user:
If your password tries are not accepted (standard test password is often postgres or the guide uses root), you probably do not have any password set, so easy. This was in my case, since the fresh install of PostgreSQL does not give the superuser postgres a password, neither has any other role that you create! It just did not catch my attention because I always used
sudo su postgres
to connect, which just asks you for the password of your Linux user, not that of the postgres user.
Thus: you must use a postgres (or my_user) user that has a password. You need to follow Getting error: Peer authentication failed for user "postgres", when trying to get pgsql working with rails in order to give postgres a password, and if you want to use another user like my_user, give it a password as well.
Only then, you get the connection done. And the error will disappear.
Outlook
When you have added the two files from the repository:
merchant_model.js (the one from the guide or the compact version above)
index.js (from the guide)
to the "node-postgres" directory, being in the project directory, you can run it with node index.js.
If that runs, you should see
App running on port 3001.
in the command prompt, with the command still running. Then you open a browser and enter localhost:3001 to see the backend:
When you then follow the guide and add the files from the repository:
App.js
index.js
to the "react-postgres\src" directory, you can run:
npm start
to see the frontend:
Try the Add button:
PS: Bad coding? Probably not!
The first answer is wrong in saying that the alleged "bad coding" is the cause of the error. You can use the full copies of the guide's github repository and everything will work, since the error comes from somthing else in the end. Yet, the code above may be bad coding, at least, count null entries in database column in a RESTfull way also uses the suggested await. I doubt that is that bad since it is working well, and when I later ran the code without the Promises on react-postgres, I vaguely remember having had a sort of message that you should use error handlers. Yet, for anyone interested, here is the advice of the first answer put into practice, it works, the "rows" error disappears, but that is just because the "rows" are not in the code anymore :))).
merchant_model.js:
const Pool = require('pg').Pool
const pool = new Pool({
user: 'my_user',
host: 'localhost',
database: 'my_database',
password: 'postgres',
port: 5432,
});
const getMerchants = () => pool.query('SELECT * FROM Merchants ORDER BY id ASC')
const createMerchant = (body) => {
const { name, email } = body
pool.query('INSERT INTO Merchants (name, email) VALUES ($1, $2) RETURNING *', [name, email])
}
const deleteMerchant = () => {
const id = parseInt(request.params.id)
pool.query('DELETE FROM Merchants WHERE ID = $1', [id])
}
module.exports = {
getMerchants,
createMerchant,
deleteMerchant,
}
Whether you use the code with or without Promises is up to you, perhaps one should rather stick to the guide and use it with Promises.

Why deleteOne & findById of mongoose work on deleted id

Currently developing an API with nodejs that communicates with a MongoDB database, I noticed a special behavior after deleting a document.
Indeed, my API has several endpoints that allow to retrieve all the animals in the database, to retrieve a specific one using the corresponding id or to delete a specific one, again using the id of the document to delete.
The results I don't understand happen once a document is deleted. Indeed, as you can see in the picture below, when I delete the document of the animal called "Johnny" the queries to find it via its id or to delete it via the same ID continue to work, even if the get returns nothing and the deletion indicates that no operation has been performed.
Personally I expected the same behavior as if I passed a wrong id for a deletion (visible below), but if the id has already been assigned in the database the queries work even after a deletion.
Does MongoDB have a "cache" of deleted documents in order to perform a rollback in case of unwanted deletion?
You will find below the different endpoints that use find, deleteOne & findById
exports.getAllAnimal = (req, res, next) => {
Animal.find().sort({'customer' : 1})
.then(animals => res.status(200).send(animals))
.catch(error => res.status(400).send({ error: error.message }));
};
exports.getOneAnimal = (req, res, next) => {
Animal.findOne({ _id: req.params.id })
.then(animal => res.status(200).send(animal))
.catch(error => res.status(400).send({ error: error.message }));
};
exports.deleteAnimal = (req, res, next) => {
Animal.deleteOne({ _id: req.params.id })
.then(thing => res.status(200).send({ message : 'Animal successfully deleted'}))
.catch(error => res.status(400).send({ error: error.message }));
};
MongoDB does not cache deleted id anywhere.
The thing is that when you said I passed a wrong id for a deletion ... you are passing an id with the same length but not in the required format. That's why Mongoose is throwing you an error.
However, if you follow the id structure of MongoDB to create an id that does not exist in the database and run an operation against it, MongoDB will still return you with success and an empty result.
Try using 5ea08034385a46666b05020f and run the .findById() query function against it. It's going to return you with a success an empty result.
The success only means that the operation is successful, but it doesn't necessarily mean that it actually finds something in the database.
I don't have access to your database, so the id is generated randomly but following the MongoDB ObjectId rules below:
The 12-byte ObjectId value consists of:
a 4-byte timestamp value, representing the ObjectId’s creation, measured in
seconds since the Unix epoch
a 5-byte random value
a 3-byte incrementing counter, initialized to a random value
Generate arbitrary MongoDB ObjectId:
https://observablehq.com/#hugodf/mongodb-objectid-generator

Can I use res.send(foo) twice?

I want to send my token and my user's role to my login.component.ts.
When I was trying to find the problem, in my research I came across someone's suggestion to use
res.write(foo1)
res.write(foo2)
res.end
Instead of
res.send(foo1)
res.send(foo2)
But that didn't work.
I then tried using this to test it:
res.write(foo1)
res.end()
But this is giving me an error:
events.js:174
throw er; // Unhandled 'error' event
^
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string or Buffer. Received type object
at write_ (_http_outgoing.js:595:11)
at ServerResponse.write (_http_outgoing.js:567:10)
at User.findOne (C:\Users\notan\GitHub\se3316-notansandwich-lab5\server\controllers\user.controller.js:46:33)
at C:\Users\notan\node_modules\mongoose\lib\model.js:4604:16
at C:\Users\notan\node_modules\mongoose\lib\query.js:4348:12
at process.nextTick (C:\Users\notan\node_modules\mongoose\lib\query.js:2850:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
Emitted 'error' event at:
at C:\Users\notan\node_modules\mongoose\lib\model.js:4606:13
at C:\Users\notan\node_modules\mongoose\lib\query.js:4348:12
at process.nextTick (C:\Users\notan\node_modules\mongoose\lib\query.js:2850:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
This is my user.controller.js, which I use in my route.js which is used in my sever.js
const User = require('../models/user.model')
const jwt = require('jsonwebtoken')
exports.user_create = function (req, res, next) {
let user = new User(
{
_id: Math.random().toString(36).substr(2, 5), // generate a random ID
email: req.body.email,
password: req.body.password,
firstName: req.body.firstName,
lastName: req.body.lastName,
role: "user"
}
);
user.save(function (err, registeredUser) {
if (err) {
return next(err);
}
else {
let payload = { subject: registeredUser._id}
let token = jwt.sign(payload, 'secretKey')
res.status(200).send({token})
}
})
}
exports.user_login = function (req, res, next) {
let userData = req.body
User.findOne({email: userData.email}, (err, user) => {
if (err) {
console.log(err)
}
else {
if (!user) {
res.status(401).send('Invalid email')
}
else if (user.password !== userData.password) {
res.status(401).send('Invalid password')
}
else {
let payload = {subject: user._id}
let token = jwt.sign(payload, 'secretKey')
//res.status(200).send({token})
res.status(200).write({token})
//let role = this.user.role
// res.status(200).write({role})
res.end()
}
}
})
}
Using this works
res.status(200).send({token})
But this does not
res.status(200).write({token})
res.end()
In response to the title of your question:
Can I use res.send(foo) twice?
No, you cannot call that twice for the same request.
See the second part of the answer since the OP changed their question after I wrote this first part
In Express, you can only use res.send() or res.json() or res.end() once per request. When you execute those, it sends the request. If you try to send more on the same request, it will do nothing and will show a warning in Express.
res.write() can be called more than once, then followed by res.end() when you are finally done with the request.
In your example:
res.status(200).send({token})
res.end()
The res.send() already calls .end() for you so trying to call it again is considered an error because the request has already been sent.
FYI, .status(200) is not necessary. The default status is already 200 so res.send({token}) will already have a 200 status.
More Recent Answer for the Modified Question
Now that you've completely changed the question to be about res.write({token}), that does not work because res.write() requires a String or a Buffer as an argument and you were giving it an object. You would have to manually convert the object to JSON yourself:
res.type('application/json');
res.write(JSON.stringify({token}));
res.end();
And note that this also sets the appropriate content type. If your object is large with res.write() you may also have to pay attention to the write buffer being full and listen for the drain event. res.write() is a much lower level facility (it's at the http level, not at the Express level) than the Express functions for sending data.
Built into Express, you can use res.send() or res.json() which are Express methods that will both that you passed an object, automatically convert it to JSON for you and set the content type to JSON also. It will also handle any buffer full issues in the write stream too.
res.send({token});
or, I prefer to be more explicit in my Express code with:
res.json({token});
And, if you're trying to send multiple pieces of data, you can put them into the same object:
res.json({token, role});
Calling res.status(200).send({ token }) ends the request and sends the object back to the client...
Since the request is now ended... Calling res.end() generates the error...
You'd usually use res.end if u were piping some data (usually binary) after several res.write to close the pipe...
For more info... checkout Express' docs in the response object...
https://expressjs.com/en/api.html#res
Also... U can't send an object using res.write...
From your error... it says that it inly accepts a string or buffer. If u want to send plain objects... res.send or res.json would be more appropriate...
I found the solution: I can send multiple things in an res.send(...)
res.status(200).send({token, role})
If you want to use res.write(argument) you have to pass the argument as a string or Buffer, just like the error message says. To get the same effect just convert your response object to a string:
res.status(200).write(JSON.stringify({token}))

firebase SDK error- Cant find variable admin

When i am using the code below, i am getting an error :- cant find variable admin
admin.auth().getUserByEmail('svd#gmail.com')
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
//console.log("Successfully fetched user data:", userRecord.toJSON());
alert(userRecord.toJSON());
})
.catch(function(error) {
console.log("Error fetching user data:", error);
})
Try doing this and tell me whether this works for you or not. I'm also not sure whether it's a fetch issue or DB issue from your firebase JSON data.
As far as this admin variable is concerned, it looks like it is a firebase instance, make sure that you initialize your firebase in your project correctly. Follow this link and add it to your project, then import or initialize it in your particular class where you want to fetch the details.
Add Firebase to your JavaScript Project
Thinking that you might have stored some of the data. Doing code like this would work :
firebase.auth().getUserByEmail('svd#gmail.com')
.then((response) => response.json())
.then((responseJson) => {
/* check the data is it coming in your console or you can simply put it inside the alert() */
console.log(responseJSon);
})
.catch((error) => {
console.log("Error fetching user data:", error);
});
Note: Before implementing that make sure you have initialized the admin variable in your code, else it won't be able to perform an operation on null variable or non-defined variable. Ensure that as well.

Categories