Mongoose query - how to create an object for every dataset that is returned - mongodb

I'm query the database and returning an array of objects, which I then want to create an objet for each set of data based on new object properties as well as push each new object into an array. I believe I'm having problems with the promise not resolved, but can't figure out how to resolve it.
The data from the query returns fine, but its when it enter the for-loop, the object isn't created. It goes into the catch statement.
const express = require('express');
const router = express.Router();
const userTxModel = require('../models/userTx.model');
var RecurringTxObj = (name, user_id, next_amt, next_date, transactions) => {
this.name = name;
this.user_id = user_id;
this.next_amt = next_amt;
this.next_date = next_date;
this.transactions = [];
};
router.get('/getRecurringTx', (req, res) => {
const recurringTxArr = [];
userTxModel
.find({ recurring: true })
.exec()
.then((recurringTxData) => {
for (let data of recurringTxData) {
recurringTxArr.push(
new RecurringTxObj(
data.name,
data.user_id,
data.amount,
data.date,
[]
)
);
}
res.status(200).send(recurringTxArr);
})
.catch((err) => {
console.log('Could not find recurring transactions');
res.status(500).send('Could not find recurring transactions');
});
});
router.get('/error', (req, res) => {
throw new Error('Something went wrong');
});
module.exports = router;

Related

Mongoose - MongoDB | "Query was already executed" error on query in loop

I'm trying to collection queries in the while loop. But I'm getting a "Query was already executed" error. How can I do that? I have a custom field and I need to make sure it is unique. I also need to use this function elsewhere.
async function createRandomID() {
let id = Math.random().toString(36).slice(2, 6).toUpperCase();
let unique = false;
while (!unique) {
await Deed.findOne({ deedId: id }, async (err, doc) => {
if (!doc) {
unique = true;
}
else {
id = Math.random().toString(36).slice(2, 6).toUpperCase();
}
})
}
return id;
}
const addNewDeed = asyncErrorWrapper(async (req, res, next) => {
let information = req.body;
const deedId = await createRandomID();
/*Other Operations...*/
});

How to save multiple data on mongoose

Current code can save single data. I have multiple data at incoming request. How can i save the multiple data to mongodb? As you can see in the image there are 3 different objects.
Orders route
router.route("/api/orders").post((req, res) => {
const body = req.body;
console.log(body);
const orderid = req.body.id;
const ordername = req.bodyname;
const orderdescription = req.bodydescription;
const orderquantity = req.bodyquantity;
const ordertotalprice = req.bodytotalPrice;
const newOrder = new Orders({
orderid,
ordername,
orderdescription,
orderquantity,
ordertotalprice
});
newOrder
.save()
.then(() => {
console.log("Order Added!");
res.status(200).json("Order Added!");
})
.catch(err => res.status(400).json("Error: " + err));
});
module.exports = router;
Your request body is an array of objects.
You can use Model.insertMany() method to insert multiple documents.
Before using insertMany be sure, you convert the objects in request body to the mongoose model object correctly. Here I used javascript map method to show a sample, you may need to change that transformation.
router.route("/api/orders").post((req, res) => {
const body = req.body;
console.log(body);
let items = req.body.map(item => {
return {
orderid: item.id,
ordername: item.name,
orderdescription: item.description,
orderquantity: item.quantity,
ordertotalprice: item.totalPrice
};
});
Orders.insertMany(items)
.then(() => {
console.log("Orders Added!");
res.status(200).json("Order Added!");
})
.catch(err => res.status(400).json("Error: " + err));
});
module.exports = router;

Inserting a record from a mongoose model.statics function

I want to create a static function on a mongoose "log" module, which would allow me to write a message as a log entry.
How do I access the model from within the static function? Can I use this.model like below? I don't want to simply use native MongoDB insert command, because I want the model to validate the input, etc.
// ... schema defined above...
var Log = mongoose.model('Log', LogModelSchema)
Log.statics.log = function(message) {
var x = new this.model({message: message})
x.save()
.then(() => { .. do something .. }
.catch((err) => { .. handle err .. }
}
Is this the way it's supposed to be done?
You can make it work like this using this.create:
const mongoose = require("mongoose");
const logSchema = new mongoose.Schema({
message: String
});
logSchema.statics.log = function(message) {
this.create({ message: message })
.then(doc => console.log(doc))
.catch(err => console.log(err));
};
module.exports = mongoose.model("Log", logSchema);
Now you can use this in your routes like this:
Log.log("test");
or just return promise from statics:
logSchema.statics.log = function(message) {
return this.create({ message: message });
};
And use like this:
const Log = require("../models/log");
router.get("/log", (req, res) => {
Log.log("test")
.then(result => {
console.log(result);
res.send("ok");
})
.catch(err => {
console.log(err);
res.status(500).send("not ok");
});
});

How to retrieve currentUser data with Vue.js, AWS Amplify, and MongoDB

I am attempting to build a Vue.js App that synthesizes properties of AWS, MongoDB, and Express. I built an authentication page for the app using aws-amplify and aws-amplify-vue. After logging into the app, metadata containing the username for the logged in AWS user is passed into data object property this.name like so:
async beforeCreate() {
let name = await Auth.currentAuthenticatedUser()
this.name = name.username
}
this.name is then added to MongoDB via Axios:
async addName() {
let uri = 'http://localhost:4000/messages/add';
await this.axios.post(uri, {
name: this.name,
})
this.getMessage()
}
I also have a getName() method that I am using to retrieve that data from MongoDB:
async getData () {
let uri = 'http://localhost:4000/messages';
this.axios.get(uri).then(response => {
this.userData = response.data;
});
},
This method, however, returns data for ALL users. I want to reconfigure this method to ONLY return data for .currentAuthenticatedUser(). In my previous experience with Firebase, I would set up my .getData() method with something like:
let ref = db.collection('users')
let snapshot = await ref.where('user_id', '==', firebase.auth().currentUser.uid).get()
...in order to return currentUser information on the condition that 'user_id' in the collection matches the currently logged-in Firebase user.
To achieve this with MongoDB, I attempted to configure the above method like so:
async getData () {
let uri = 'http://localhost:4000/messages';
let snapshot = await uri.where('name', '==', this.name);
this.axios.get(snapshot).then(response => {
this.userData = response.data;
});
},
My thought here was to try and return current user data by comparing 'name' in the MongoDB collection with the logged-in user stored in this.name...but I understand that this might not work because the .where() method is probably unique to Firebase. Any recommendations on how to configure this .getData() to return ONLY data associated with the currentAuthenticatedUser? Thanks!
EXPRESS ROUTES:
const express = require('express');
const postRoutes = express.Router();
// Require Post model in our routes module
let Post = require('./post.model');
// Defined store route
postRoutes.route('/add').post(function (req, res) {
let post = new Post(req.body);
post.save()
.then(() => {
res.status(200).json({'business': 'business in added successfully'});
})
.catch(() => {
res.status(400).send("unable to save to database");
});
});
// Defined get data(index or listing) route
postRoutes.route('/').get(function (req, res) {
Post.find(function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});
module.exports = postRoutes;
It is not possible to apply a where clause to a uri AFAIK. What you should do is adding a where clause to the actual query you are making in your backend and, to do that, send the username you want to filter the query with through a query parameter like this: /messages?name=JohnDoe.
So basically if you are using a Node/Express backend, as you suggested, and using Mongoose as the ODM for MongoDB your request would probably be looking something like this:
const Users = require('../models/users.model');
Users.find({}, function (e, users) {
if (e) {
return res.status(500).json({
'error': e
})
}
res.status(200).json({
'data': users
});
})
What you should do is getting the username query parameter through req.query and add it to the options in the first parameter of the find function.
const Users = require('../models/users.model');
let params = {},
name = req.query.name;
if (name) {
params.name = name
}
Users.find(params, function (e, users) {
if (e) {
return res.status(500).json({
'error': e
})
}
res.status(200).json({
'data': users.slice
});
})
That way if you point to /messages?name=John you will get the users with "John" as their name.
Edit:
If your backend is configured in the following way
postRoutes.route('/').get(function (req, res) {
Post.find(function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});
what you should do is get the query parameters from inside the get method
postRoutes.route('/').get(function (req, res) {
let params = {},
name = req.query.name
if (name) {
params.name = name
}
Post.find(params, function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});

ES6 Promises in express app not properly resolving data

I'm writing an a async function with ES6 promises, that 1) saves the query parameters for a user 2) fetches data from mongodb using mongoose, 3) manipulates the json into a DSL, 4) and queries another db with it.
mongoose": "^4.7.7"
//myController.js
const myQuery = require('../models/myQuery_model');
require('mongoose').Promise = global.Promise
const uuidV4 = require('uuid/v4');
exports.saveNewQuery = function(req, res, next) {
const rawQuery = req.body;
const queryToStore = new myQuery(rawQuery);
const uid = uuidV4();
const queryToStore.uid = uid
queryToStore.save().then(() => {
fetchQueryFromMongo(uid);
}).then((storedQuery) => {
compileQueryToString(storedQuery);
}).then((queryString) => {
fetchResultsFromOtherDb(queryString);
}).then((results) => {
res.json({ results });
}).catch((error) => {
console.log(error)
})
}
Currently I'm not able to resolve the response from mongodb step 2. Still, the controllter goes on to compileQueryToString rather than catch the error from fetchQueryFromMongo
// fetchQueryFromMongo.js
const myQuery = require('../models/myQuery');
require('mongoose').Promise = global.Promise
module.exports = (uid) => {
return new Promise(
(resolve, reject) => {
myQuery.find({ uid }).then((err, res) => {
if (err) {
reject(err);
}
console.log('response success!')
resolve(res);
});
}
);
};
I'm new to promises so any tips / suggestions would be appreciated!
Make sure to return a value from your then handlers. The code below does this by using the concise body form of arrow functions.
queryToStore.save()
.then(() => fetchQueryFromMongo(uid))
.then(storedQuery => compileQueryToString(storedQuery))
.then(queryString => fetchResultsFromOtherDb(queryString))
.then(results => res.json({ results }))
.catch(console.log);