Post same objectID in to different table - node.js

I'm trying to post a data in my user then at the same time, post the _id of my user as a reference id in my donation table.
After I posted my data in the users table like this:
var User = require('../models/user');
var Blooddonation = require('../models/blooddonation');
router.post('/createBlooduser',function(req, res) {
var user = new User();
user.user_lastname = req.body.user_lastname;
user.status= "initial";
user.save(function(err) {});
});
How can I get the _id of the posted data and make a reference id in my donation table? Something like this:
**users.json**
{
_id:ObjectId("5c7e591eee959272cc5768cb"),
user_lastname:"Jhonson",
status:"initial"
}
**blooddonations.json**
{
donor_id:ObjectId("5c7e591eee959272cc5768cb")
}

The _id property is actually created as soon as you create new instance with a statement like new User(). So you can actually access that value before it's even stored in the collection, or at any time after instance creation really:
router.post('/createBlooduser',function(req, res) {
var user = new User();
user.user_lastname = req.body.user_lastname;
user.status= "initial";
user.save(function(err) {
if (err) throw err; // or really handle better
// You can also just create() rather than new Blooddonation({ donor_id: user._id })
Blooddonation.create({ donor_id: user._id }, function(err, donor) {
// check for errors and/or respond
})
});
});
Of if you might just want access to other properties that might "default on save", then you can access in the callback from save() or create():
router.post('/createBlooduser',function(req, res) {
User.create({
user_lastname: req.body.user_lastname;
status: "initial"
}, function(err, user) { // this time we pass from the callback
if (err) throw err; // or really handle better
Blooddonation.create({ donor_id: user._id }, function(err, donor) {
// check for errors and/or respond
});
});
});

Related

node.js and mongodb increment _id sequentially in existing database

Good morning everyone.
So I'm doing a class assignment wherein I'm connecting to an existing mongoDB database (via a node.js server), and I'm adding a bunch of data to it from a form on an HTML site. I've got the form information adding correctly, but there's two fields server side that aren't responding to new data. There is the primary key (_id) which instead of incrementing from the current last number, get's incremented by ObjectId('longnumericvale'), and CustomerID which get's populated by an undefined value. The last record existing in the database has both _id and CustomerId as the same number. How can I get node.js to look at this number and auto increment it when it's adding my form data as a new document in the mongodb DB. Code below:
app.post("/orderform", (req, res) => { //This takes post action from html and stores it
console.log("successfully posted")
var item = {
CustFirstName: req.body.CustFirstName,
CustLastName: req.body.CustLastName,
CustAddress: req.body.CustAddress,
CustCity: req.body.CustCity,
CustProv: req.body.CustProv,
CustPostal: req.body.CustPostal,
CustCountry: req.body.CustCountry,
CustHomePhone: req.body.CustHomePhone,
CustBusPhone: req.body.CustBusPhone,
CustEmail: req.body.CustEmail,
userid: req.body.userid,
passwd: req.body.passwd,
};
console.log("Customer information stored as:");//this is just a debug to the console to make sure it's grabbing the info
console.log(item);
//here we connect to the datbase, and insert every item above to its corresponding position in the "customers" collection of "travelexperts" database
mongo.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true },
(err, client) => {
if (err) throw err;
//select database
const db = client.db("travelexperts");
//grab a collection
const collection = db.collection("customers");
collection.insertOne(item, (err, res) => {
if (err) throw err;
console.log("Items inserted");
db.close;
});
});//endconnection
res.redirect('/thanks');
console.log("finished, redirected")
});
//render thank you page for after submitting order
app.get('/thanks', (req, res) =>{
res.render("thanks");
});
I've read the documentation for mongodb on autoincrementing, but it's a bit beyond me how to implement it in my specific example.
UPDATE
So maybe I didn't explain the problem really well. I'm trying to log into two separate collections now, and I have that working. with this code below:
app.post("/orderform", (req, res) => { //This takes post action from Order.html form and stores all form inputs with corresponding names in a variable called item
console.log("successfully posted")
var item = {
CustFirstName: req.body.CustFirstName,
CustLastName: req.body.CustLastName,
CustAddress: req.body.CustAddress,
CustCity: req.body.CustCity,
CustProv: req.body.CustProv,
CustPostal: req.body.CustPostal,
CustCountry: req.body.CustCountry,
CustHomePhone: req.body.CustHomePhone,
CustBusPhone: req.body.CustBusPhone,
CustEmail: req.body.CustEmail,
userid: req.body.userid,
passwd: req.body.passwd,
};
console.log("This should be an array of all entered customer info:");//this is just a debug to the console to make sure it's grabbing the info
console.log(item);
var book = {
BookingId: "",
BookingDate: new Date(),
BookingNo: "",
TravelerCount:"",
CustomerId: "",
TripTypeId:"",
PackageId: Number(req.query.packId),
};
console.log(book);
//here we connect to the datbase, and insert every item/booking above to its corresponding position in the "customers" collection of "travelexperts" database
mongo.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true },
(err, client) => {
if (err) throw err;
const db = client.db("travelexperts");
const collection = db.collection("customers");
const booking = db.collection("bookings");
collection.insertOne(item, (err, res) => {
if (err) throw err;
console.log("Items inserted");
});
booking.insertOne(book, (err, res) => {
if (err) throw err;
console.log("Items inserted");
});
db.close;
});//endconnection
res.redirect('/thanks');
console.log("finished, redirected")
});
So the issue is that for both collections and bookings, they have incomplete records. collections is 26 documents long, and the last _id is 144. So that's why I need to read that _id and increment it +1 for each new record. There's an _id field for each collection and then a customerId and BookinbId that should match it. Really appreciate all the help so far, but neither of these solutions seems to work. I tried both just before the collections.insertone line, and i tried console logging them and they just return [object Object] in the console instead of the _id value.
To insert a custom ID field for your documents, you should append the _id field with your item object.
The simplest wayc can be to create a global id_counter variable that you increment everytime you execute the /orderform API.
let idCounter = 1;
.
.
.
const itemDoc = {_id: idCounter++, ...item}
collection.insertOne(itemDoc, (err, res) => {
if (err) throw err;
console.log("Items inserted");
db.close;
});
.
.
.
You could also fetch the last inserted Item's id and simply increment it and it could save a lot of effort to keep the ids of the documents in sync incase the server restarts or something.
In that case, you could do something as below using collection.countDocuments() method:
let docLength = 0 // global variable
.
.
.
// inside your api endpoint controller...
collection.countDocuments({}, {}, (err, res)=> {
docLength = res;
})
const itemDoc = {_id: docLength++, ...item}
collection.insertOne(itemDoc, (err, res) => {
if (err) throw err;
console.log("Items inserted");
db.close;
});

nodejs passport - use same routes in api but return different sets of data based on permissions

Not sure of a clean way to go about his. Let's say I have this endpoint:
GET /api/Books/
For the user on the webservice, this will return only the user's resources. It might look a little something like this:
exports.getBooks = function(req, res) {
// find all books for user
BookModel.find({ userId: req.user._id }, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
};
The web service using the api needs the user to be logged in first. I can achieve this using a basic passport strategy to ensure authentication. But let's say I have an admin account that needs to see ALL books ever recorded. What's more is that the admin account and user accounts have completely different properties so assigning a Boolean for permissions is not enough. Using the same endpoint:
GET /api/Books
I see no reason to write another endpoint to achieve this. However the difference would look like this:
exports.getBooks = function(req, res) {
// find all books in the database
BookModel.find({}, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
};
However I cannot come up with a clean way to achieve this while also using the passport middlewear as it is intended like so:
router.route('/books')
.post(authController.isAuthenticated, bookController.postBooks)
.get(authController.isAuthenticated, bookController.getBooks);
The function isAuthenticated will will only verify whether or not the user requesting resources has permission and does not change the way the controller behaves. I'm open to ideas.
ANSWER
The user #ZeroCho suggested to check user properties in req.user object to determine what should be sent back. This was more simple than I expected. In my implementation for passport.BasicAuth strategy, I check which table has a matching doc. Once the user is found in the common user or Admin user table all you do is add a property in the isMatch return object.
// Basic strategy for users
passport.use('basic', new BasicStrategy(
function(email, password, done) {
verifyUserPassword(email, password,
function(err, isMatch) {
if(err) { return done(err); }
// Password did not match
if(!isMatch) { return done(null, false); }
// Success
var userInfo = {
email: email,
isAdmin: isMatch.isAdmin || false,
businessID: isMatch.businessID || false
};
return done(null, userInfo);
});
})
);
Then you can check if .isAdmin or .businessID is valid in your requests.
Just separate your controller by if statement
exports.getBooks = function(req, res) {
if (req.user.isAdmin) { // or some other code to check user is admin
// find all books in the database
BookModel.find({}, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
} else {
BookModel.find({ userId: req.user._id }, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
}
};

Node/Mongoose: Synchronous Find/Save/Delete between Collections: collection1.find(collection2.save(collection1.remove()))

I have a database of users and I want to implement deleting a user from one collection (Users). But before that user is deleted, I wanted to save it to another collection for backup/tracking (DeletedUsers).
So the sequence should be:
1) Find user, 2) save user to DeletedUsers, 3) delete user from Users.
Because this needs to be synchronous, I've nested the functions and sequenced through callbacks. The problem is the save to DeletedUsers is not working.
Standalone, the save to DeletedUsers works, just not when it's nested in the User.find().
I have setup two different Schemas for the Users/Deleted Users:
var User = mongoose.model('User', new Schema({data}));
var DeletedUser = mongoose.model('DeletedUser', new Schema({data}));
Implementation of the delete:
exports.postDeleteUser = function(req,res) {
var conditions = { '_id': req.params.user_id };
// Create the new deletedUser object to add to
// the DeletedUsers collection
var deletedUser = new DeletedUser();
User.findOne(conditions, function(err, user) {
if (!user) {console.error(err);
} else {
// Copy over data to the new deletedUser object
for (prop in user) {deletedUser[prop] = user[prop];}
// This is where I save the deletedUser to the
// new collection.
// ** This is not executing ** //
deletedUser.save(function(err) {
if (err) {
console.error(err);
renderViewUser(user['_id'], 0, req, res);
} else {
// However, this delete from Users *is* working
User.find(conditions).remove(function() {
res.redirect('/');
});
};
});
};
});
};
Thanks for your help.
As #RaR pointed out, there are some hidden properties that are keeping the new data object from saving to the new collection, not just _id.
Copying all properties does not work:
for (prop in user) {deletedUser[prop] = user[prop];}
Only specific properties must deliberately copied:
var properties = ['prop1', 'prop2'....];
properties.forEach(function(i) {
deletedUser[i] = user[i];
});

How to send Stripe customer ID to Parse

I've managed to create Stripe customers through Parse using this function:
Parse.Cloud.define("customer", function(request, response){
stripe.customers.create({
email: request.params.useremail
}, function(err, customer) {
if(err){
console.log(err);
response.error(err);
}
else{
console.log(customer);
response.success(customer);
});
});
However, I would like to then be able to send the customer ID that is created to Parse under the current user's data as "cusToken", the same way that "email", "username" and whatnot are stored in the User class.
There are two assumptions that will simplify this code, the first is that the client making the call always does so on behalf of it's logged-in user, not some other user. The second is that stripe create answers a promise. Assuming that:
Parse.Cloud.define("customer", function(request, response) {
var user = request.user;
stripeCreateP({ email: user.email }).then(function(customer) {
user.set("someUserProperty", customer.someStripeProperty); // as an example
return user.save();
}).then(function(result) {
console.log(customer);
response.success(customer);
}, function(err) {
console.log(err);
response.error(err);
});
});
If the stripe api doesn't return a parse Promise, you can "promisify" it as follows...
function stripeCreateP(params) {
var p = new Parse.Promise();
stripe.customers.create(params, function(err, customer) {
if (err) {
p.resolve(customer);
} else {
p.reject(err);
}
});
return p;
}
...and call that with the email param object...
stripeCreateP({ email: user.email }).then( ...
If your app calls this for a user other than the client's logged in user, then you will need to pass user email in request.params as you do in the OP, and furthermore, you'll need to give yourself permission in the code to save a user other than the current one, then you can precede the save with a useMasterKey. See the docs for that.

How to access Mongoose Schema Attributes?

I am fairly new to using Mongoose and MongoDB. I am working on a register / login page. The register function works fine, storing the user account onto the database, but my problem is with logging in. What I am trying to do is get the 'password' attribute from the matching user off of the database, to match against the password that the user enters. This is my login function.
router.post('/logSubmit', function(req, res, next) {
var gusername = req.body.username;
var gpassword = req.body.password;
User.count({
'credentials.username': gusername
}, function(err, count) {
if (err) throw err;
console.log(count);
if (count > 0) {
// Where I need to pull password attribute from the database
} else {
// Wrong username or password
}
});
});
I have looked all over the internet on how to read an attribute from a database entry, but I can't find anything. I feel like it is something very simple, but I guess I don't know the syntax. The name of my model is User. I figured it would be something like:
User.find({ username: gusername }, function(err, user) {
if (err) throw err;
var getpassword = user.password;
console.log(getpassword);
});
I half-thought that would work, but it didn't. How do I access the password attribute from the database?? Thanks.
EDIT:
This is what my user accounts look like stored in my database:
{
"_id": {
"$oid": "569e5344d4355010b63734b7"
},
"credentials": {
"username": "testuser",
"password": "password1234"
},
"__v": 0
}
A find query is sufficient for your purposes. If a non-null user object is retrieved from the find query, you have a guarantee that it is a user with a password.
User.find({ 'credentials.username': gusername }, function(err, users) {
if (err) throw err;
// 'users' is an array of the User objects retrieved.
users.forEach(function(user) {
// Do something with the password.
// The password is stored in user.credentials.password
console.log(user.credentials.password);
});
});

Resources