Keystonejs: custom names to defaultColumns of Admin UI - javascript

I use keystonejs as Node.js CMS
Model look like this:
Message.add({
uId: { type: String, initial: true, required: true },
title: { type: String, initial: true, required: true },
createdDate: { type: Date, default: Date.now, required: true },
user: {
name: { type: Types.Relationship, ref: 'User', initial: true, required: true },
email: { type: Types.Relationship, ref: 'User', initial: true, required: true }
},
status: {
display_name: { type: String, initial: false, required: true },
state: { type: String, initial: false, required: true }
}
})
Message.defaultColumns = 'user.name, title, status.display_name'
Message.register();
Titles of the columns in the generated Admin UI looks like this:
User Name,
Title
Status Display_name
Is it possible to set custom names to defaultColumns to make it look better?

You can add the label property to your field options. The label is used as label for the field and as column name.
For example:
display_name: { type: String, initial: false, required: true, label: 'Whatever you like' }

Related

MongoDB (mongoose) filter with value in array with reference

I am trying to filter an array in a document in mongoose.
The problem i am having is trying to filter with a value in the array that is in the reference.
To clarify, i have a document containg all the information about a course. In that course i have a array of objects that contains information about students. An object containts a status and also a refrence to the actual user object. I would like filter the students array with a value found in the refrence.
The way i have tested this is as following:
courseModel.findOne({ _id: courseId, 'students.user.startDate': { $lte: startDate } });
My models look like this:
CourseModel:
{
name: {
type: String,
required: true,
maxlength: 50,
minlength: 2,
trim: true
},
description: {
type: String,
required: false,
maxlength: 500,
trim: true
},
type: {
type: String,
required: true,
enum: ['physical', 'online', 'quiz']
},
color: {
type: String,
required: true,
match: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
},
events: [
{
type: Schema.Types.ObjectId,
ref: 'event'
}
],
questions: [
{
type: Schema.Types.ObjectId,
ref: 'question'
}
],
educators: [
{
type: Schema.Types.ObjectId,
ref: 'user'
}
],
students: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
status: {
type: String,
enum: ['notBooked', 'booked', 'attended', 'completed']
},
lastSlackMessage: {
ts: {
type: String
},
channel: {
type: String
}
},
events: [
{
type: Schema.Types.ObjectId,
ref: 'event'
}
]
}
],
teams: [
{
type: Schema.Types.ObjectId,
ref: 'team'
}
],
createdBy: {
type: Schema.Types.ObjectId,
ref: 'user'
},
updatedBy: {
type: Schema.Types.ObjectId,
ref: 'user'
}
}
UserModel:
{
name: {
type: String,
required: true,
maxlength: 100,
trim: true
},
email: {
type: String,
required: true,
minlength: 5,
match: /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
},
employeeId: {
type: String,
required: true
},
slackId: {
type: String,
default: ''
},
teams: [
{
type: Schema.Types.ObjectId,
ref: 'team'
}
],
questions: [
{
question: {
type: Schema.Types.ObjectId,
ref: 'question'
},
status: {
type: String,
enum: ['answered', 'pending', 'notSent']
},
tries: {
type: Number,
default: 0
}
}
],
startDate: {
type: Date,
required: true
}
}
I appreciate any help i can get, thank you!

How to get only matched data in mongoose (node.js)?

I am building a bus ticket booking app in node.js. I want to fetch only related data about queries not all the data But I am getting all the data about Bus.
Here is the location model. only admin can enter data about locations.
const locationSchema = new mongoose.Schema(
{
departureLocation: {
name: {
type: String,
required: true,
lowercase: true
},
time: {
type: String,
required: true,
},
subLocations: { type: [String], lowercase: true },
},
arrivalLocation: {
name: {
type: String,
required: true,
lowercase: true
},
time: {
type: String,
required: true,
},
subLocations: { type: [String], lowercase: true },
},
},
{
timestamps: true,
}
);
Here is the route table. Again admin...
const routeSchema = new mongoose.Schema({
location:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Location',
required: true
},
duration: {
type: Number,
required: true
},
date: {
type:String,
required: true
},
},
{
timestamps: true,
});
Bus model: Admin...
const busSchema = new mongoose.Schema({
busNumber: {
type: String,
unique: true,
required: true,
},
seats: {
type: Number,
},
route: {
type: mongoose.Schema.Types.ObjectId,
ref: "Route",
required: true,
},
},
{
timestamps: true,
});
and here finally the booking table:
const bookingSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
required: true,
},
passengers: [
{
name: { type: String, required: true, trim: true },
gender: { type: String, required: true, trim: true },
age: { type: Number, required: true, trim: true },
}],
phone: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
bookingDate: {
type: String,
required: true,
},
fare: {
type: Number,
required: true,
},
seats: {
required: true,
type: [Number],
},
departureDetails: [
{
city: { type: String, required: true, trim: true },
location: { type: String, required: true, trim: true },
time: { type: String, required: true, trim: true },
date: { type: String, required: true, trim: true },
},
],
arrivalDetails: [
{
city: { type: String, required: true, trim: true },
location: { type: String, required: true, trim: true },
time: { type: String, required: true, trim: true },
date: { type: String, required: true, trim: true },
},
],
},{
timestamps:true
});
Whenever an authorized user enters the booking data It is getting saved to the database. No problem whatsoever
Now I want to show every user(Non-authorized as well) of my app about trips(routes), the bus which will run on that particular trip and reserved and available seats in that particular bus which is currently stored.
But the problem is that I am getting all the buses even if it is not on that trip.
here is the query:
router.get("/trip/single", async (req, res) => {
if (!req.query.departure || !req.query.arrival || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { departure, arrival, date } = req.query;
let locations = await Location.find({
'departureLocation.name': departure,
'arrivalLocation.name': arrival,
});
const ids = locations.map(location => location._id)
const routes = await Route.find({$and: [{location : {$in: ids}},{date}]});
const route = routes.find(()=>{
return ([{ date }, { routes }])
});
let buses = await Bus.find({})
let matchedBuses = buses.filter((bus)=> {
return bus.routes === locations._id
})
const bookings = await Booking.find({})
const busIdWithSeatsObj = {}
for(let i = 0; i < matchedBuses.length; i++){
let currentBusSeats = []
const busBookings = bookings.filter((booking) => {
return (booking.departureDetails.date === date &&
booking.busId.toString() === matchedBuses[i]._id.toString()
)
})
busBookings.forEach((booking) => {
currentBusSeats = [...currentBusSeats, ...booking.seats]
})
busIdWithSeatsObj[matchedBuses[i].seats] = currentBusSeats
}
res.status(200).send({route, matchedBuses, busIdWithSeatsObj});
});
Now I also want to fetch details by Id(only single bus).
How to do that?
Can anyone help me out here?
here's the input data image with result for date: 2022-06-02 which is actually available in the database : https://i.stack.imgur.com/FlfaG.png
This is the second query with result for date: 2022-06-01. It is not available in the database still showing matchedBus.: https://i.stack.imgur.com/xY5pW.png Now route data is gone but matched buses still shows.

can't get the user's address in mongoose / nodejs

When the app loads it fetches initialData Array of objects from the backend where I have all the info I need, like categories,orders,products etc. Inside the orders array i have all the info about the users ordered items, status etc. I want to load the users address, when he filled up the address form that address.I have that address stored inside address.js-> UserAddress model/schema. So I want to load the users address inside orders array.
plz help me get the users address inside the orders array so that i can display the users address inside my admin-app->orders card, i'm new at this so I'm unable to figure it out on my own.
here is my orderSchema
const orderSchema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
addressId: {
type: mongoose.Schema.Types.ObjectId,
ref: "UserAddress.address",
required: true,
},
totalAmount: {
type: Number,
required: true,
},
items: [
{
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Product",
},
payablePrice: {
type: Number,
required: true,
},
purchasedQty: {
type: Number,
required: true,
},
},
],
paymentStatus: {
type: String,
enum: ["pending", "completed", "cancelled", "refund"],
required: true,
},
paymentType: {
type: String,
enum: ["cod", "card"],
required: true,
},
orderStatus: [
{
type: {
type: String,
enum: ["ordered", "packed", "shipped", "delivered"],
default: "ordered",
},
date: {
type: Date,
},
isCompleted: {
type: Boolean,
default: false,
},
},
],
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", orderSchema);
here is my address schema:
const addressSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
min: 3,
max: 50,
},
mobileNumber: {
type: String,
required: true,
trim: true,
},
pinCode: {
type: String,
required: true,
trim: true,
},
locality: {
type: String,
required: true,
trim: true,
min: 10,
max: 100,
},
address: {
type: String,
required: true,
trim: true,
min: 10,
max: 100,
},
cityDistrictTown: {
type: String,
required: true,
trim: true,
},
state: {
type: String,
required: true,
required: true,
},
landmark: {
type: String,
min: 10,
max: 100,
},
alternatePhone: {
type: String,
},
addressType: {
type: String,
required: true,
enum: ["home", "work"],
required: true,
},
});
// B
const userAddressSchema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
address: [addressSchema],
},
{ timestamps: true }
);
mongoose.model("Address", addressSchema);
module.exports = mongoose.model("UserAddress", userAddressSchema);
here is the get initial data where i get all the data/response:
exports.initialData = async (req, res) => {
const categories = await Category.find({}).exec();
const products = await Product.find({ createdBy: req.user._id })
.select("_id name price quantity slug description productPictures category")
.populate({ path: "category", select: "_id name" })
.exec();
const orders = await Order.find({})
.populate("items.productId", "name")
.exec();
res.status(200).json({
categories: createCategories(categories),
products,
orders,
});
};
here is the response of initial data:
You can simply use the $lookup aggregation from the order schema to the address schema to fetch the address of the user via the user field.
More info on MongoDb $lookup aggregation here

Ignore key if empty value

I'm creating a mongoose entry, and this is my schema:
const OrdersSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "Users",
required: true,
},
currency: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
rate: {
type: Number,
required: true,
},
amount: {
type: Number,
required: true,
},
coupon: {
type: mongoose.Schema.Types.ObjectId,
ref: "Coupons",
},
subtotal: {
type: Number,
required: true,
},
total: {
type: Number,
required: true,
},
recipient: {
type: mongoose.Schema.Types.ObjectId,
required: true,
},
status: {
type: String,
required: true,
default: "On-hold",
},
payment: {
type: Object,
required: true,
},
shortId: {
type: String,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
required: true,
},
});
Coupon is optional. The code to create a new order is:
const order = await Orders.create({
user: req.id,
currency: body.selectedCountry,
country: body.selectedCountry,
rate: rate.rates[body.selectedCountry],
amount: body.amount,
coupon: body.coupon.code,
subtotal: body.subtotal,
total: body.total,
recipient: body.recipient,
payment: body.paymentData,
shortId: shortid.generate(),
});
However, when coupon is an empty string I get a MongooseError [CastError]: Cast to ObjectID failed for value "" at path "coupon"
I need to remove this key and value from the object creation, when creating the order.
How can I remove this key if coupon code is empty?
Thanks in advance
The issue is you are trying to fit an empty string value in the data-type objectID.
A possible solution to this is to use below condition in your code:
coupon: body.coupon.code ? body.coupon.code : null
This will set coupon to null in case body.coupon.code is "".

Validation error while adding new item to MongoDB array

My requirement is to look for an email id in a collection and if it exists, need to add new enquiry details for that user.If user does not exists,then a new document with email id and all other details of user should be created in the collection.
I am able to successfully create user and corresponding details.But when i am trying to add a new item in 'enquiry' array by filtering the collection using email id,its giving a validation error ''validation failed: emailID: Path emailID is required.'
I am not sure why MongoDb is throwing this error.I don't want to update email id.I just want to add a new item under 'enquiry' array
Model is-
var userEenquirySchema = new Schema({
emailID: {
type: String,
required: true, unique: true, trim: true, match: /^([a-zA-Z0-9_.-])+#([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/
},
enquiry: [{
userFullName: { type: String, required: true, unique: false, trim: true},
isdCode: {
type: Number, required: true,
min: [1, 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).'],
max: [200, 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).']
},
primaryPhonenumber: {
type: Number,
validate: {
validator: function (primaryPhonenumber) {
if (isNaN(primaryPhonenumber) || primaryPhonenumber.toString().trim().length != 10) {
return false;
}
},
message: '{VALUE} is not a valid primary phone number!'
},
required: [true, 'User phone number required']
},
procedureName: { type: String, required: true, trim: true },
commuMedium: { type: String, required: false, unique: false, trim: true, default: 'English' },
caseDescription: { type: String, required: true, unique: false, trim: true },
attachmentFlag: { type: String, required: false, enum: ['Y', 'N'], default: 'N' },
attachmentName: { type: String, required: false},
response: [{
mediNovitaResponse: { type: String, required: false, unique: false, trim: true },
respondedBy: { type: String, required: false, unique: false, trim: true },
contactedMethod: { type: String, required: false, enum: ['Phone', 'Email', 'Both']},
emailResponseSent: { type: String, required: false, enum: ['Y', 'N'] },
nextFollowUpDate: { type: Date, required: false, default: Date.now },
followUpAssignee: { type: String, required: false, unique: false, trim: true },
followUpNote: { type: String, required: false, unique: false, trim: true },
respondedAt: { type: Date, required: false, default: Date.now },
}],
updated_at: { type: Date, required: true, default: Date.now }
}]
});
Controller code to add new item to enquiry array -
userEnquiryModel.findOneAndUpdate({ "emailID": req.body['emailID'] }, {"$push": {
enquiry : [{
userFullName: req.body['userFullName'],
isdCode: parseInt(req.body["isdCode"]),
primaryPhonenumber: parseInt(req.body["primaryPhonenumber"]),
procedureName: req.body["procedureName"],
commuMedium: req.body["commuMedium"],
caseDescription: req.body["caseDescription"],
attachmentFlag: req.body["attachment"],
attachmentName: req.body["attachmentName"],
response: []
}]
}
}

Categories