Hello I have less idea in express route as I am new in backend with mongodb.
In the route below I am verifying email by resetting a schema value to true. Now I want to copy the new schema details to another existing collection. How can I do that ?
router.get('/:adminId/verifyAdmin',function(req,res){
console.log('request recieved');
Admin.findOne( {_id: req.params.adminId })
.exec()
.then(admin => {
const Thing = mongoose.model(admin.companyName);
const emailTokenn = req.query.id;
//console.log(emailTokenn);
Thing.updateOne( { emailResetTokenn: emailTokenn },{ $set: { verified: true }},(err) =>{
if(!err){
return res.redirect('https://localhost:3000/fw18/index.html');
}
else{
throw err;
}
});
});
});
Here I want to pass/copy/save Thingcollection details to existing collection name users in my db.
EDIT:- Tried this but getting error export :- const User = mongoose.model('User');
Thing.updateOne( { emailResetTokenn: emailTokenn },{ $set: { verified: true }},(err) =>{
if(!err){
//add Thing Schema to Users collection
Thing = mongoose.model(admin);
var copy = mongoose.model('admin', admin,'User');
admin.save(function(err){});
return res.redirect('https://s3.ap-south-1.amazonaws.com/fw18/index.html');
}
Error:-
MissingSchemaError: Schema hasn't been registered for model correct me .
Http is a stateless protocol. To maintain state of the application you can use
1) session
2) cookies and
3) query string.
On your case, you can handle using session.
Store information to the session and get stored information from different routes.
Related
I need to update value in Group db Group_name to the value send in Json payload.
Db schema
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: String,
Group_name: {
type: String,
default: '',
}
});
mongoose.model('User', UserSchema);
And API request
router.put('/join', async(req, res) => {
try {
const data = await User.updateOne(req.params.username, {
Group_name: req.body.Group_name
});
console.log(data)
res.send({ msg: "Group Updated!!!" })
} catch (err) {
console.error(err.message);
res.sendStatus(400).send('Server Error');
}
});
currently its updating only first record which is incorrect , my requirement is to check for all records based on username given and according to username given in request parameters ,i will update value of Group_name to the value sent in request body.
can anyone help me ?
Modify query condition.
const data = await User.updateOne(
{ username: req.params.username },
{ $set: { Group_name: req.body.Group_name } }
);
First of all, understand the difference between req.body & req.params
req.body means hidden parameters sent in request body like in post or put requests.
req.params means defined paramters in URL. For this, you must have it defined in your route like below
router.put('/join/:username', async (req, res) => {
// ^^^^^^^^ here it is defined, now you can access it like
const username = req.params.username;
//or
const {username} = req.params; // destructuring
}
there is one more thing and that is
req.query means undefined paramters attached to URL with ?/&
If you want to give username without pre defining like /join?username=john then use req.query
router.put('/join', async (req, res) => {
const {username} = req.query;
}
Then you should use updateMany() function instead of updateOne()
try {
const {username} = req.params;
const {Group_name} = req.body;
const data = await User.updateMany(
{username}, // find as many users where username matches
{Group_name} // update group name from body
);
console.log(data);
The consoled data would be like { n: 2, nModified: 2, ...} because the update queries don't return updated documents but status of the query. If you want to get updated record set, you have to query again with find().
// after update
const updatedRecord = await User.find({ username });
console.log(updatedRecord);
::POSTMAN::
Postman has two types of parameters
Params
Body
If you add in Params it will be added in URL /join?username=john#email.com&Group_name=GroupB and you have to access it in code with req.query.username or req.query.Group_name
If you add in Body it will be hidden and can be accessed with req.body.Group_name etc
Hope it helps!
router.post('/',auth, async (req, res) => {
const { error } = validate(req.body); //Error Check
if (error) return res.status(400).send(error.details[0].message);
let property = new Property({ //Creating Object: Property as per defined Schema:
title: req.body.title,
description: req.body.description,
price: req.body.price,
user: {
_id: req.user._id, //Getting the ID from auth middleware with JWT Token Authenticared
}
});
console.log({property});
await property.save(); //Saving the Object
res.send(property); //Displaying User with created Object i.e. Property
});
I'm Creating a Property using POST Method.
Now I want to Get the Data from MongoDB, but only for the user who's currently logged in and created that data.
//Writing a GET METHOD to List of Properties with Valid Token:
router.get('/', async (req,res)=>{
try{
//Getting the Information of User by the current user.id loggin in: ... .select('-password') sets it to don't show password
const property = await Property.findById(req.user );
res.send(property);
}
catch (ex){
console.error(ex.message);
}
});
Instead of findByIdtry find({user: req.user._id}).
req.user contains the authenticated user's information so by using _id we can get can the ID which helps us filter the Properties created by a Specific User
My express app tries to record the login time of the user using Mongoose's findOneAndUpdate.
router.post('/login', passport.authenticate('local', {
failureFlash: true,
failureRedirect: '/'
}), async(req, res, next) => {
// if we're at this point in the code, the user has already logged in successfully.
console.log("successful login")
// save login time to database
const result = await User.findOneAndUpdate({ username: req.body.username }, { loginTime: Date.now() }, { new: true });
console.log(result);
return res.redirect('/battle');
})
The user document does not start out with a login time property. I'm expecting this code to insert that property for me.
The actual result is, the console shows the user document being printed out, but without any added login time property. How can I fix this so a login time property is inserted into the document? Is the only way to do it by defining a login time property in the original mongoose schema? And if so, doesn't that nullify the supposed advantage of NoSQL vs SQL in that it's supposed to allow new unexpected property types into your collections and documents?
I've found the answer for anyone who might come across the same problem. It is not at all possible to add a property to a Mongoose collection if it is not already defined in the Schema. So to fix it I added the property in the Schema.
In fact, you can add a new property that isn't defined in the schema, without modifying the schema. You need to set the flag strict to false to enable this mode. See document here.
The code below demonstrates what I said, feel free to runs it:
const mongoose = require('mongoose');
// connect to database
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });
// define the schema
const kittySchema = new mongoose.Schema({
name: String
// this flag indicate that the shema we defined is not fixed,
// document in database can have some fields that are not defined in the schema
// which is very likely
}, { strict: false });
// compile schema to model
const Kitten = mongoose.model('Kitten', kittySchema);
test();
async function test() {
// empty the database
await Kitten.deleteMany({});
// test data
const dataObject = { name: "Kitty 1" };
const firstKitty = new Kitten(dataObject);
// save in database
await firstKitty.save();
// find the kitty from database
const firstKittyDocument = await Kitten.findOne({ name: "Kitty 1" });
console.log("Mongoose document", firstKittyDocument);
// modify the kitty, add new property doesn't exist in the schema
const firstKittyDocumentModified = await Kitten.findOneAndUpdate(
{ _id: firstKittyDocument._id },
{ $set: { age: 1 } },
{ new: true }
);
console.log("Mongoose document updated", firstKittyDocumentModified);
// note : when we log the attribute that isn't in the schema, it is undefined :)
console.log("Age ", firstKittyDocumentModified.age); // undefined
console.log("Name", firstKittyDocumentModified.name); // defined
// for that, use .toObject() method to convert Mongoose document to javascript object
const firstKittyPOJO = firstKittyDocumentModified.toObject();
console.log("Age ", firstKittyPOJO.age); // defined
console.log("Name", firstKittyPOJO.name); // defined
}
The output:
Mongoose document { _id: 60d1fd0ac3b22b4e3c69d4f2, name: 'Kitty 1', __v: 0 }
Mongoose document updated { _id: 60d1fd0ac3b22b4e3c69d4f2, name: 'Kitty 1', __v: 0, age: 1 }
Age undefined
Name Kitty 1
Age 1
Name Kitty 1
I am trying to read from one Mongo collection and then take all that data and save it to a new collection. I am using the same schema, but changing the collection name in two different models :
UserInfo.js :
const mongoose = require('mongoose')
const userSchema = mongoose.Schema({
userID : String,
userName : String
})
let userInfo = mongoose.model('UserInfo', userSchema)
let backUpUserInfo = mongoose.model('BackUpUserInfo', userSchema)
module.exports = {
userInfo : userInfo,
backUpUserInfo : backUpUserInfo
}
I inserted data into the userinfos collection and then I am trying to read that and insert into the backupuserinfos collection :
backup.js :
const UserInfo = require('../Schema/UserInfo').userInfo;
const BackUpUserInfo = require('../Schema/UserInfo').backUpUserInfo;
async function backUp(){
UserInfo.find({}, async function(err1, userInfo){
if (err1) return console.log(err1)
for(let i in userInfo){
try{
let backUpUser = new BackUpUserInfo(userInfo[i])
await backUpUser.save(function (err2, user) {
if (err2) return console.error(err2)
console.log("collection updated")
})
}
catch(err){
console.log(err)
}
}
})
}
I am getting an error that seems to indicate that it is finding a duplicate when trying to save the information, even though the backup collection is empty. This makes me think it is trying to write to the user info collection instead of the back up one. I created the backUp model variable and that is what I run save on, which makes me think it should be specified to run to that collection. Am I doing something wrong here?
Here is the error :
VersionError: No matching document found for id
Easiest way in mongoose would be
UserInfo.aggregate([ { $match: {} }, { $out: "BackupUserInfo" } ])
Else you can use mongodb query OR mongodb copyTo()
db.myoriginal.aggregate([ { $match: {} }, { $out: "mycopy" } ])
//OR
db.source.copyTo("target");
But copyTo() is deprecated since version 3.0.
I'm building an application (MVC) that will use 4 collections in a DB. When I add new clients to the application they will get their separate DB. So if I have 10 customers, there will be 10 DBs and 40 collections (1 db -> 4 collections)
This way each customer data is seperated from other customers, which is crucial here.
So far I've built the app and everything is working nicely, 'cept one thing.
If Company A logs in and start using the app everything works fine. But when Company A is logged in, and Company B logs in, both Company A AND B will be directed towards Company B:s DB.
I've looked trough my code and I guess this is my own fault because I use .connect (mongoose). When a company logs in the route will fire of a controller that will open a new connection (which overrides the old one) which will redirect all open connections towards that specific DB.
controller.dBlogin.js
mongoose.connect(dbConfig.url + id, options)
.then(() => {
console.log("Successfully connected to the database");
next();
}).catch(err => {
console.log('Could not connect to the database. Exiting now...');
process.exit();
});
The id is fetched from req.params.id (example: http://webapp.com/login/:id).
As far as I've figured .connect only allows one connection at a given time so I need something that will, simply, allow many connections. So I'm thinking that I could use .createConnection for this,
https://mongoosejs.com/docs/connections.html#multiple_connections
But i just cant get it to work.
I changed controller.dBlogin.js to
mongoose.createConnection(dbConfig.url + id, options)
.then(() => {
console.log("Successfully connected to the database");
next();
}).catch(err => {
console.log('Could not connect to the database. Exiting now...');
process.exit();
});
but that only leads to a timeout when the company logs in. How do I use the .createConnections? How do you go from .connect to .createConnection?
Heres the examples of routes, controller, and a model (user-schema).
routes.js
// connect to db, check auth
app.post('/login/:id', dbController.connectDB, dbController.login)
controller.dbLogin.js
exports.**connectDB** = (req, res, next) => {
const id = req.params.id;
// Get Mongoose to use the global promise library
mongoose.Promise = global.Promise;
// Options Conncetion mongodb
const options = {
useNewUrlParser: true,
};
// Connecting to the database
mongoose.connect(dbConfig.url + id, options)
.then(() => {
console.log("Successfully connected to the database");
next();
}).catch(err => {
console.log('Could not connect to the database. Exiting now...');
process.exit();
});
};
exports.login = (req, res, next) => {
passport.authenticate('local-login', {
successRedirect: '/start', // redirect to the secure profile section
failureRedirect: '/login', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
})(req, res, next);
};
Example of a model user.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');
const Company = require('../models/company.js');
// define the schema for our user model
const userSchema = mongoose.Schema({
local : {
name : {
type: String,
required : true
},
email : {
type : String,
unique : true,
required : true
},
password : String,
active : Boolean,
company : {
type: mongoose.Schema.Types.ObjectId,
ref: 'Company'
}
}
});
// generating a hash for password
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);
So, for the ones who finds themselves in the same spot:
After reviewing my app and the data it will keep I came to the conclusion that there is no need for splitting multi-tenancy. I reworked the app so when the user fetch or write data they only touch "their" data, and this is controlled backend.
But, I did make a post on mongoose github and got an answer,
See post here: https://github.com/Automattic/mongoose/issues/7386
The author gave a great length which seems to have an actually quite nice implementation of this with express and mongoose: http://nmajor.com/posts/multi-tenancy-with-expressmongoose
I hope this is of any help for you, and if you manage to find a solution or something, where you can show some simple code, please post it as there seems to be a lot of people asking about this.
Cheers.