Related
Node.js:
how to create api for list ordered product count based on date .this order model and how to i create the controller for that...
const mongoose = require('mongoose')
const schema = mongoose.Schema
const orderSchema = new schema({
orderID:{type:String,required:true},
customer: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'userdatas',
},
orderItems:
{
// productName: { type: String, required: true },
// qty: { type: Number, required: true },
// amount: { type: String, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'productsdatas',
},
},
shippingAddress : {
address: { type: String, required: true },
city: { type: String, required: true },
postalCode : { type: String, required: true },
country: { type: String, required: true },
},
orderDate:{type: String,
required: true},
totalAmount: {
type: Number,
required: true,
default: 0.0,
},
},
{
timestamps: true,
}
)
const Order = mongoose.model('Order', orderSchema)
module.exports = Order
mongoDB:
this is mongoDB data for order i should already created and customer and product details i populateded to show the output that time..
{
"_id": {
"$oid": "630f47d44a772822d2370794"
},
"orderID": "1",
"customerName": "vikiram",
"customer": {
"$oid": "630ccd62121a7425d6918e95"
},
"orderItems": {
"product": {
"$oid": "630d95d659998496b12f4f36"
}
},
"shippingAddress": {
"address": "123 IT street",
"city": "chennai",
"postalCode": "6000100",
"country": "india"
},
"orderDate": "25/04/2022",
"totalAmount": 11700000,
"createdAt": {
"$date": {
"$numberLong": "1650886612732"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1661945812732"
}
},
"__v": 0
}
json:
i want json output in postman like this..
{
"data" : {
"May-2019" : 1,
"January-2020" : 1,
"February-2020" : 2,
"April-2020" : 1
}
}
You can achieve it by using aggregation. https://www.mongodb.com/docs/manual/aggregation/
Employee Schema
const employeeSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid');
}
},
},
password: {
type: String,
required: true,
trim: true,
minLength: 6,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error("Password can not contain a word 'password'.");
}
},
},
birthdate: {
type: Date,
required: true,
},
cellphone: {
type: String,
required: true,
trim: true,
},
gender: {
type: String,
enum: ['남성', '여성'],
required: true,
},
hourly_wage: {
type: Number,
trim: true,
default: 0,
},
timeClocks: [
{
type: new mongoose.Schema({
start_time: {
type: Date,
required: true,
},
end_time: {
type: Date,
},
wage: {
type: Number,
required: true,
},
total: {
type: Number,
},
totalWorkTime: {
type: Number
}
}),
},
],
role: {
type: String,
enum: ['staff'],
default: 'staff',
},
stores: [
{
location: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Location',
},
},
],
status: {
//현재 재직상태
type: String,
enum: ['재직자', '퇴직자'],
default: '재직자',
},
tokens: [
{
token: {
type: String,
required: true,
},
},
],
},
{
timestamps: true,
}
);
What I have done so far
const employees = shifts.map((d) => d.owner._id);
//timeclock
const temp = await Employee.aggregate([
{
$match: {
_id: { $in: employees },
},
},
{
$sort: { 'timeClocks.start_time': 1 },
},
{
$unwind: { path: '$timeClocks', preserveNullAndEmptyArrays: true },
},
{
$group: {
_id: '$_id',
name: { $first: '$name' },
timeClock: {
$push: '$timeClocks',
},
},
},
]);
My result
{
"shifts": [
{
"_id": "60e05b188be53900280bcdf2",
"date": "2021-07-09T00:00:00.000Z",
"day": "Fri",
"start": "2021-07-09T09:41:00.000Z",
"end": "2021-07-09T21:42:00.000Z",
"owner": {
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd"
},
"location": "60cd99b1b4ddcc00285b0df3",
"__v": 0
}
],
"timeClock": [
{
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd",
"timeClock": [
{
"_id": "60def63d19648a00286f0539",
"start_time": "2021-05-04T02:19:00.000Z",
"end_time": "2021-05-04T14:42:00.000Z",
"wage": 8720,
"total": 107735,
"totalWorkTime": 743
},
{
"_id": "60def63f19648a00286f053d",
"start_time": "2021-05-02T08:12:00.000Z",
"end_time": "2021-05-02T22:24:00.000Z",
"wage": 8720,
"total": 123540,
"totalWorkTime": 852
},
{
"_id": "60def64119648a00286f0541",
"start_time": "2021-05-10T20:14:00.000Z",
"end_time": "2021-05-10T22:17:00.000Z",
"wage": 8720,
"total": 17835,
"totalWorkTime": 123
},
}
]
Expected Result(2021-05-10)
{
"shifts": [
{
"_id": "60e05b188be53900280bcdf2",
"date": "2021-07-09T00:00:00.000Z",
"day": "Fri",
"start": "2021-07-09T09:41:00.000Z",
"end": "2021-07-09T21:42:00.000Z",
"owner": {
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd"
},
"location": "60cd99b1b4ddcc00285b0df3",
"__v": 0
}
],
"timeClock": [
{
"_id": "60cd9a3cb4ddcc00285b0df9",
"name": "Dr. dd",
"timeClock": {
"_id": "60def64119648a00286f0541",
"start_time": "2021-05-10T20:14:00.000Z",
"end_time": "2021-05-10T22:17:00.000Z",
"wage": 8720,
"total": 17835,
"totalWorkTime": 123
},
}
]
I am receiving the 'date string' example('URL/2021-05-10') via params and trying to query all employees that have the same date timeClocks.
also trying to send back everything I queried without different dates from timeClocks.
How can I filter out non-same dates?
You have string 2021-05-10 now you need a $match stage before your group so you can filter out timeClock. Something like:
{ $match: { 'timeClocks.start_time': new Date('2021-05-10') } }
Modify the match stage to your requirements like maybe add $gte or $lte or something like that.
I have a model which has a field with nested fields, when I try to update the field it doesn't work. it still remail=ns the same. Below is the code with further explanations.
i have a model below
const mongoose = require('mongoose')
const placeSchema = new mongoose.Schema({
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
typeof: {
type: String,
required: true,
enum: ["studio", "hall",
"house", "mansion",
"field", "room",
"restaurant", "school",
"church", "beach", "warehouse",
"others"
]
},
location: {
type: String,
required: true,
trim: true
},
time: {
alwaysopen: {
type: Boolean,
required: true,
default: false
},
open: {
type: String
},
close: {
type: String
}
},
idealfor: [{
type: String,
required: false,
enum: ["reception", "production",
"meeting", "performance",
"dinner", "wedding",
"party", "conference"
]
}],
rooms: {
type: Number,
required: false,
trim: true
},
toilet: {
type: Number,
required: false,
trim: true
},
price: {
type: Number,
required: true,
trim: true
},
amenities: [{
type: String,
required: false,
enum: ["electricity", "a/c",
"wifi", "sound system",
"private entrance",
"kitchen", "large table", "tv",
"green screen", "Stage",
"changing room", "makeup room",
"lounge", "soundproof"
]
}],
accessibility: [{
type: String,
required: false,
enum: ["wheelchair", "Elevator",
"on-site parking", "parking near by",
"Stairs"
]
}],
isOpen: {
type: Boolean,
required: false,
default: true
},
phonenumber: {
type: String,
required: true,
trim: true
},
}, {
timestamps: true
})
the problem is that when i try to update the time.alwaysopen field from false to true, id doesn't work.
below is the update route
// Edit a place
router.patch('/api/place/:id', isVerified, async (req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ["title", "description", "maxguest", "size", "isOpen", "rules", "rooms", "toilet", "price", "phonenumber", "location", "typeof", "time", "time.alwaysopen", "time.open", "time.close"]
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(404).send({ error: 'Invalid updates!' })
}
try {
const place = await Place.findOne({ _id: req.params.id, owner: req.user._id })
if (!place) {
return res.status(404).send({ "message": "place does not exist" })
}
updates.forEach((update) => place[update] = req.body[update])
await place.save()
res.status(201).send({place, "message": "successfully updated" })
} catch (e) {
res.status(400).send({ "message": "failed to update" })
}
})
and below is the patch json request i make
{
"time.alwaysopen": false
}
after sending the patch request, i still get the vaue of the time.alwaysopen to be true, but updating the field is fine.
below is the response i get
{
"place": {
"time": {
"alwaysopen": true
},
"idealfor": [
"production",
"wedding"
],
"amenities": [
"electricity",
"a/c",
"Stage"
],
"accessibility": [],
"unavailabledate": [],
"isOpen": true,
"img": true,
"_id": "604028e717314039402c2c10",
"typeof": "studio",
"location": "good news church, olufemi street, surulere, Lagos, Nigeria",
"rooms": 2,
"toilet": 2,
"price": 1000,
"phonenumber": "+2348125580085",
"owner": "603e6b494e0df045745066a7",
"createdAt": "2021-03-04T00:25:11.413Z",
"updatedAt": "2021-03-04T01:19:14.867Z",
"__v": 0,
"description": "the famous hotel",
"title": "Royal habiscus edited"
},
"message": "successfully updated"
}
Please, what could be the problem?
I making an API using MongoDB, Nodejs and ExpressJS.I have a collection called membership
const membershipSchema = new Schema(
{
membership_id: {
type: Number,
required: [true, "ID is required"],
unique: true,
},
member_detail: [{ type: Schema.Types.ObjectId, ref: "user" }],
validity: {
type: Number,
enum: [30, 90, 180, 365],
required: true,
},
fee: {
type: Number,
required: [true, "fee is required"],
},
registration_fee: {
type: Number,
required: [true, "registration fee is required"],
},
total_fee: {
type: Number,
required: [true, "total_fee fee is required"],
},
// status: {
// type: Boolean,
// required: [true, "status fee is required"],
// },
startDate: {
type: Date,
required: [true, "Start date is required"],
},
endDate: {
type: Date,
required: [true, "End date is required"],
},
added_by: { type: String, required: true },
last_update: {
type: Date,
default: Date.now,
},
}
);
After adding membership and requesting with GET, I get the following response
{
"member_detail": [
{
"_id": "5ea1e43dd401c828f4d1cf7d",
"name": "member421"
}
],
"_id": "5ea1e4a3d401c828f4d1cf7f",
"last_update": "2020-04-23T18:55:31.311Z",
"membership_id": 421,
"added_by": "admin",
"validity": 30,
"fee": 3500,
"registration_fee": 500,
"total_fee": 4000,
"startDate": "2020-04-18T06:21:04.869Z",
"endDate": "2020-07-18T06:21:04.869Z",
"createdAt": "2020-04-23T18:55:31.313Z",
"updatedAt": "2020-04-23T18:55:31.313Z",
"__v": 0
}
Now I am sending another GET request to membership collection with a query to test and to get the difference between two date (endDate - Current Date(24/04/2020)) and its working fine and gives following response
router.route("/alert").get((req, res) => {
Membership.aggregate(
[
{
$project: {
dayssince: {
$trunc: {
$divide: [
{ $subtract: ["$endDate", new Date()] },
1000 * 60 * 60 * 24,
],
},
},
},
},
],
(err, document) => {
if (err) {
return res.status(404).json({ error: true, message: err });
}
res.status(200).json({ data: document });
}
);
});
the above code returns me this result
{
"data": [
{
"_id": "5ea1e4a3d401c828f4d1cf7f",
"dayssince": 85
}
]
}
Now I want to merge the above result for every membership that I create
Expected output
{
"member_detail": [
{
"_id": "5ea1e43dd401c828f4d1cf7d",
"name": "member421"
}
],
"_id": "5ea1e4a3d401c828f4d1cf7f",
"last_update": "2020-04-23T18:55:31.311Z",
"membership_id": 421,
"added_by": "admin",
"validity": 30,
"fee": 3500,
"registration_fee": 500,
"total_fee": 4000,
"startDate": "2020-04-18T06:21:04.869Z",
"endDate": "2020-07-18T06:21:04.869Z",
"createdAt": "2020-04-23T18:55:31.313Z",
"updatedAt": "2020-04-23T18:55:31.313Z",
"__v": 0
**"dayssince": 85**
}
I've come accross aggregate function but I dont know how to implement with my query.If you need any other code from my project, feel free to comment.
Why request the DB just to calculate a time difference?
Once you have your first result... Why not just do the math right away?
// The result of the first query to DB
let firstResult = {
"member_detail": [
{
"_id": "5ea1e43dd401c828f4d1cf7d",
"name": "member421"
}
],
"_id": "5ea1e4a3d401c828f4d1cf7f",
"last_update": "2020-04-23T18:55:31.311Z",
"membership_id": 421,
"added_by": "admin",
"validity": 30,
"fee": 3500,
"registration_fee": 500,
"total_fee": 4000,
"startDate": "2020-04-18T06:21:04.869Z",
"endDate": "2020-07-18T06:21:04.869Z",
"createdAt": "2020-04-23T18:55:31.313Z",
"updatedAt": "2020-04-23T18:55:31.313Z",
"__v": 0
}
// NOW
let now = new Date();
// Create a date object from the endDate found in the DB result
let endDate = new Date(firstResult.endDate);
// Calculate the difference in rounded days
let result = Math.round((endDate-now) / (1000*60*60*24));
// Output
console.log(result)
// Then... Yes, you can add this to the initial response object
firstResult.dayssince = result;
console.log(firstResult)
I had a problem with the association of collections.
I spent 2 days and still did not solve the problem, it's new for me.
My models:
// Schema opened cases
const openedSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user',
required: [true, 'user is required'],
index: true
},
weapon: {
type: Schema.Types.ObjectId,
ref: 'cases.weapons',
required: [true, 'weapon is required'],
index: true
},
sellPrice: {
type: Number,
default: null
},
status: {
type: Number,
default: 0
}
}, {
timestamps: true
});
const opened = mongoose.model('opened', openedSchema);
// list cases
const casesSchema = new Schema({
name: {
type: String,
unique: true,
required: [true, 'name is required']
},
price: {
type: Number,
required: [true, 'price is required']
},
weapons: [ {
weapon: {
type: Schema.Types.ObjectId,
ref: 'weapon',
index: true
}
} ]
}, {
timestamps: false
});
const cases = mongoose.model('cases', casesSchema);
// list weapons
const weaponSchema = new Schema({
name: {
type: String,
unique: true,
required: [true, 'name is required']
},
price: {
type: Number,
required: [true, 'price is required']
},
autoship: {
count: Number,
status: Boolean,
price: Number
}
}, {
timestamps: false
});
const weapon = mongoose.model('weapon', weaponSchema);
That's what documents look like
// cases
{
"_id": {
"$oid": "59653bcfa9ac622e1913e10c"
},
"name": "test case #1",
"price": 256,
"weapons": [
{
"weapon": {
"$oid": "59653bcfa9ac622e1913e10b"
},
"_id": {
"$oid": "59653bcfa9ac622e1913e10d"
}
},
{
"_id": {
"$oid": "59653d3279aeda2fda9fb490"
},
"weapon": {
"$oid": "59653c5d069f562eb0ba4ef3"
}
},
{
"_id": {
"$oid": "59653d38ba04de2fdddc459f"
},
"weapon": {
"$oid": "59653c893a772e2ef7b65a29"
}
}
],
"__v": 0
}
// opened
{
"_id": {
"$oid": "5965d134c8c95972a1a498f5"
},
"updatedAt": {
"$date": "2017-07-12T07:35:16.419Z"
},
"createdAt": {
"$date": "2017-07-12T07:35:16.419Z"
},
"user": {
"$oid": "5965d0d6ea9db872360db98b"
},
"weapon": {
"$oid": "59653bcfa9ac622e1913e10d"
},
"status": 0,
"sellPrice": null,
"__v": 0
}
// weapon
{
"_id": {
"$oid": "59653bcfa9ac622e1913e10b"
},
"name": "AWP | Fever Dream",
"price": 300,
"autoship": {
"status": true,
"price": 167,
"count": 5
},
"__v": 0
}
I need to get a list of open cases with weapons data.
opened -> cases -> weapon
So, I do this:
opened.find()
.populate('cases.weapons')
.then(_opened => {
console.log(_opened);
})
.catch(err => {
logger.error(err);
});
But populate does not work.
Unless I am mistaken, there is no relationship between openedSchema and casesSchema.
It is not opened -> cases -> weapon but opened -> weapon as openedSchema has no field called cases -- which means cases will never be populated.
Based on your schema definition, it should be opened.find().populate('weapon').