Retrieve two foreign keys nodejs sequelize - javascript

I have a route and I want it to send two primary keys as foreign keys to my orderline table. I have three tables a customer, address and orderline table. an orderline has one customer and one address as foreign keys. I´m really struggling to figure it out. My route looks like this:
import express from "express";
import expressAsyncHandler from 'express-async-handler';
import { isAuth } from '../utlis';
import {Orderline, Address} from '../models';
const orderRouter = express.Router();
orderRouter.post(
'/',
isAuth,
expressAsyncHandler(async (req, res) => {
const customerId = req.customer.id;
const addresss = Address.findOne({where: {CustomerId: customerId}})
const addressId = addresss.id
const createdOrder = ({
totalPrice: req.body.totalPrice,
itemsPrice: req.body.itemsPrice,
taxPrice: req.body.taxPrice,
shippingPrice: req.body.shippingPrice,
AddressId: addressId,
CustomerId: customerId
});
Orderline.create(createdOrder);
res.status(201).send({ message: 'New Order Created', data: createdOrder});
})
);
export default orderRouter;
As seen in the code I have attempted to retrieve the address that has the id of the user logged in and then gett the ID and send that as the value. I would ideally like to find the postcode,address and customerID in the address table and Any help/guidance is much appreciated.

First, you need to indicate await to the left from 'findOne' and create because they are async functions and you want to get the result in the calling code:
const customerId = req.customer.id;
const address = req.address;
const postcode = req.postcode;
const addresss = await Address.findOne({
where: {
CustomerId: customerId,
address: address,
postcode: postcode
}
})
const addressId = addresss.id
const createdOrder = ({
totalPrice: req.body.totalPrice,
itemsPrice: req.body.itemsPrice,
taxPrice: req.body.taxPrice,
shippingPrice: req.body.shippingPrice,
AddressId: addressId,
CustomerId: customerId
});
const newOrder = await Orderline.create(createdOrder);
// in case you want to send the whole orderline object along with its generated ID
res.status(201).send({ message: 'New Order Created', data: newOrder});
And if you don't indicate attributes option in findOne you will get all attributes of Address.

Related

.findByIdAndUpdate is not a function error - coming from controller where the model has been required?

I'm working on a web application for my company to view a database of customers and their data using MongoDB, Mongoose, and Express. Our company resells used copiers/printers and also provides maintenance contracts for machines. I want to save each customer as a document, with machines as separate linked documents.
I have models, controllers, and routes set up for customers and machines. I am getting the following error when trying to delete a machine from it's customer:
Customer.findByIdAndUpdate is not a function
TypeError: Customer.findByIdAndUpdate is not a function at module.exports.deleteMachine (C:\controllers\machines.js:21:20) at C:\utils\catchAsync.js:3:9 at Layer.handle [as handle_request] (C:\node_modules\express\lib\router\layer.js:95:5) at next (C:\node_modules\express\lib\router\route.js:144:13) at module.exports.getCustomer (C:\middleware.js:15:5) at processTicksAndRejections (node:internal/process/task_queues:96:5)
My code is as follows:
Controller for Machines:
const Customer = require('../models/customer');
const Machine = require('../models/machine');
module.exports.deleteMachine = async (req, res) => {
const { id, machineId } = req.params;
await Customer.findByIdAndUpdate(id, { $pull: { machines: machineId } });
await Machine.findByIdAndDelete(machineId);
req.flash('success', 'Machine has been deleted');
res.redirect(`/customers/${id}`);
};
Route for Machines:
router.delete('/:machineId', getCustomer, catchAsync(machines.deleteMachine));
the "getCustomer" middleware is as follows - its only purpose is to ensure a valid customer is being requested and to set the "foundCustomer" to make my life easier elsewhere. I don't think it is the issue, but I'm including it just for clarity:
module.exports.getCustomer = async (req, res, next) => {
const { id } = req.params;
const customer = await Customer.findById(id).populate({ path: 'machines' });
if (!customer) {
req.flash('error', 'Sorry, that customer cannot be found!');
return res.redirect('/customers');
}
res.locals.foundCustomer = customer;
next();
};
The relevant routes have been set as follows in my app.js:
const customerRoutes = require('./routes/customers');
const machineRoutes = require('./routes/machines');
app.use('/customers', customerRoutes);
app.use('/customers/:id/machines', machineRoutes);
I haven't run into any issues with other machine routes, so I'm not sure why this one is throwing an error. This application is actually the second version that I've made, and the first version uses the exact same code, with no issue. So I'm super stumped.
Any help is greatly appreciated!
Customer Model -
const customerSchema = new Schema({
customer: String,
customerID: String,
category: {
type: String,
enum: ['contracted', 'billable']
},
contacts: [contactSchema],
address: String,
city: String,
state: String,
zip: String,
county: String,
machines: [
{
type: Schema.Types.ObjectId,
ref: 'Machine'
}
],
notes: [noteSchema]
});
I'm a dummy. I exported the Customer model as part of an array of exports like this:
const Customer = mongoose.model('Customer', customerSchema);
module.exports = {
Customer: Customer,
Note: Note,
Contact: Contact
};
When requiring the model in my Machine controller I had it formatted as:
const Customer = require('../models/customer');
To get it working correctly I needed to require it like this:
const { Customer } = require('../models/customer');
After making that change everything is working correctly, and I can move on with my life/application.

Retrieving user data from mongoDB

I'm building an app where a user logs in and can create a grocery list on their account (there are more things they can do like create recipes, but this is the example I want to use). Right now I have it so everybody who logs in sees the same list. But I want each user to be able to log in and view their own grocery list that they made. I'm assuming the logic is literally like logging into a social media site and viewing YOUR profile, not somebody else's.
I'm using mongoDB/mongoose and I just read about the populate method as well as referencing other schemas in your current schema. Here is my schema for the list:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create item schema
const GroceryListItemSchema = new Schema({
item: {
type: String,
required: [true, 'Item field is required']
},
userId: {
type: mongoose.Schema.Types.ObjectId, ref: "user",
}
});
// Create an Item model
const GroceryListItem = mongoose.model('groceryListItem', GroceryListItemSchema);
module.exports = GroceryListItem;
And here is the post request to add a list item:
//POST request for shopping list
router.post("/list", checkToken, (req, res, next) => {
// Add an item to the database
const groceryListItem = new GroceryListItem({
item: req.body.item,
userId: ???
})
groceryListItem.save()
.then((groceryListItem) => {
res.send(groceryListItem);
})
.catch(next);
});
Here is my userModel - not sure if this is necessary to show:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
password2: {
type: String,
required: true,
},
});
const User = mongoose.model("users", UserSchema);
module.exports = User;
(in case anyone is wondering why the model is called "users"-- that's what I initially called it on accident and when I changed the name to "user" it errored out...so I changed it back.)
I am not sure how to add the userId when making an instance of the groceryListItem. In the mongoose docs (https://mongoosejs.com/docs/populate.html#saving-refs), they use the example of a Story and Person Schema. They reference each other, and then they create an instance of Person, calling it author. Then they grab the _id from author and reference it in their instance of Story, called story1. So that makes sense to me. But the only way they can do that is because author and story1 are located in the same file.
So it seems like what I should do is grab the user _id by saying userId: users._id. But my new User instance is in my user routes. And I'd rather not combine the two. Because then I'd have another list to combine as well so that would be my user routes, recipe routes, and shopping list routes all in one file and that would be extremely messy.
Anyone have any idea how I can make this work? It seems so simple but for some reason I cannot figure this out.
Thank you!!
EDIT - frontend API call:
handleSubmitItem = (e) => {
e.preventDefault();
const newItem = {
item: this.state.userInput,
};
authAxios
.post(`http://localhost:4000/list/${userId}`, newItem)
.then((res) => {
this.setState({ items: [...this.state.items, newItem] });
newItem._id = res.data._id;
})
.catch((err) => console.log(err));
this.setState({ userInput: "" });
};
Here you can simply pass in the user ID in the POST request params. The POST URL in the frontend should look like this; {localhost:9000/like/${userID}}
You can get the user ID at the express backend like this;
router.post("/list/:id", checkToken, (req, res, next) => {
// Add an item to the database
const groceryListItem = new GroceryListItem({
item: req.body.item,
userId: req.params.id
})
groceryListItem.save()
.then((groceryListItem) => {
res.send(groceryListItem);
}).catch(next);
});

Mongoose find with multiple and optional fields

I am new to mongoose and currently I am coding an app to learn it. I have an Artist Schema and a form that search with multiple and optional fields. For instance the user can put a name, a minimum age and search through the model without filling the other form fields.
On the controller I take all the fields from the form through the req.body object and I have a query object which with multiple if statements I check whether or not the property is not undefined, and if not I put it in the object as a property and the object is passed to the find method.
The problem is when I fill the min age and put to the query object this property query.min_age = { $gte: min_age} the $gte converts into a string and as a result can't run the find method properly.
The Mongoose Model
const mongoose = require("mongoose");
const AlbumSchema = require("./album")
const CompanySchema = require("./company")
const Schema = mongoose.Schema;
const ArtistSchema = new Schema({
name: String,
age: Number,
yearsActive: Number,
albums: [AlbumSchema],
company:[{type: Schema.Types.ObjectId, ref: "Company"}]
});
const Artist = mongoose.model("artist", ArtistSchema);
module.exports = Artist;
The Controller
app.post("/", (req, res, next) => {
const name = req.body.name;
const min_age = req.body.min_age;
const min_active = req.body.min_active;
const sort = req.body.sort;
const query = {};
if(name) {
query.name = name;
}
if(min_age) {
query.min_age = { $gte: min_age};
}
if(min_active) {
qyery.min_active = {gte: min_active};
}
Artist.find(query).
sort(sort)
.then( artists => {
res.render("index", {
artists: artists
})
});
});
The image below is depicting the string $gte when I console it:
Keys in JS objects are always casted to a string, so there is nothing wrong with $gte being a string on a screenshot that you've posted.
As for the min_age value, in your code I cannot see anything that would convert it to a string and mongoose by itself is not doing it as well.
It looks like the problem is in a test request. Please check if you are sending min_age as a number in a POST request, or as a string. It should be a number or else you need to convert it to a number in your controller (with parseInt() for example)
const name = new RegExp(req.body.name, 'i');
const min_age = req.body.min_age;
const min_active = req.body.min_active;
const sort = req.body.sort;
const query = {};
if(req.body.name!=undefined && req.body.name!=''){
query["$and"]=[{name :re}]
}
if(min_age){
query["$and"].push({min_age:{ $gte: parseInt(min_age)}})
}
if(min_active ){
query["$and"].push({min_active:{ $gte: parseInt(min_active)}})
}
let artists=await Artist.find(query).sort(sort)
res.render("index", {
artists: artists
})

How to save array of objects in mongodb with mongoose?

I want to save complex data, ie array of objects to mongoose. I have tried few things but i couldn't save the data.
I defined my schema as above and i want to save array of objects that could have any level of nesting.
Schema
const mongoose = require('mongoose);
const PostSchema = new mongoose.Schema({
post: [{}]
});
let PostModel = mongoose.Model('Post', PostSchema)
The Data:
Here is the code I used to save the data
app.post('/saveData, async (req, res) => {
const response = await Post.create(req.body);
res.json({
data: response
});
});
app.listen(8008, () => {
console.log('server running);
});
The problem is that i cant retrieve the data. it returns array of objects equal to the number of saved array but with no data in it.
How can it be done?
This code works for me.
const PostModel = require('./Post'); //declare your model
app.post('/saveData', async (req, res) => {
const objModel = new PostModel();
objModel.post = req.body; //assign the data post array.
const response = await objModel.save();
res.json({
data: response
});
});
Your post schema looks weird.
You have a collection for Posts and then within a posts schema, you have a posts array.
What is the point of that?
The post collection already is an "array" for posts.
// Perhaps you are looking for something like this.
const PostSchema = new mongoose.Schema({
title: String,
content: String,
level: Number,
footer: String,
author: ObjectId,// who wrote the post
comments: [{
user: ObjectId,
comment: String
}],
... createdAt, updatedAt etc
});
Your data structure doesnt seem to match your schema either.
e.g
await Post.create({posts: req.body});

How can I query a fire store sub-collection with angular?

I am trying to query a Firestore sub collection in an ionic 4 app/angular app. My database looks as follows people(id) ----> tasks(id)
{ description : this is a description about a cat,<br>
title: this is a cat <br>
category: cat }
I am using a Firestore function to query all of the data in the collection. This is what the Firestore function looks like:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'
admin.initializeApp()
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await
admin.firestore().collection('people').limit(5).get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
the typescript home.ts file looks like this :
const getFeed = this.aff.httpsCallable('getFeed')
this.posts = getFeed({}).subscribe(data=> {
console.log(data)
// this.posts = data
})
}
I've tried to use the array-contains option to query, but it doesn't
work. The array shows up empty on the console.
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await
admin.firestore().collection('people').where("category",
"array-
contains", "cat").limit(5).get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
It's not very clear from your question, but it looks like the category field of your database isn't actually a list type field. array-contains only works if the value is a list, not if it's just a single string value. If it's just a string, then use a == filter on it.
I have found workaround by adopting array field type instead of subcollection.
Here is an example of my code:
var coll = this.firestore.collection('credentials', ref => ref.where('tags', 'array-contains-any', ['agile']).orderBy('shortName')); // selects part of collection where roomId = roomStripped, sorted by name
return coll.snapshotChanges();
I have main collection called credentials, and a list of tags in each document.

Categories

Resources