How to create a document with the data from another collection? - node.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CompanySchema = new Schema(
{
companyName: {
type: String,
required: true,
unique: true
},
taxOffice: {
type: String
},
taxNumber: {
type: String
},
},
{
timestamps: true
}
);
const Company = mongoose.model('Company', CompanySchema);
module.exports = Company;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const DateSchema = new Schema({
name: {
type: String,
unique: true,
required: true
},
companies: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Company' }]
});
const Date = mongoose.model('Date', DateSchema, 'dates');
module.exports = Date;
const router = require('express').Router();
const Date = require('../models/date');
router.route('/').get((req, res) => {
Date.find()
.then(dates => res.json(dates))
.catch(err => res.status(400).json('Error: ' + err));
});
router.route('/add').post((req, res) => {
const name = req.body.name;
const newDate = new Date({ name });
newDate
.save()
.then(() => res.json('Date added!'))
.catch(err => res.status(400).json('Error: ' + err));
});
module.exports = router;
I have 2 collections called Company and Date.
I inserted many data to Company Collection.
But I want that Company data(companies) to copied into Date Collection whenever I create a Date document.
I want to store company data as an array for each Date.
By the way don't know that my schema design is correct for the purpose. What should I do?
I want to have a Date document like:
{
name: "DECEMBER-2019",
companies: ['5e2076236664640d22515f7b', '5e2076236664640d22515f7a']
}

It sounds like you want to take an action whenever you create a new document in the Date collection. If you are using Atlas (MongoDB's fully managed database as a service), you can configure a Trigger to fire whenever a new document is inserted into the Date collection. Another option (regardless of whether you are using Atlas or not) is to use Change Streams to monitor changes in the Date collection. For more on how to configure these, see https://www.mongodb.com/blog/post/node-js-change-streams-and-triggers.

Assuming that only companies present at the time of Date Object creation should be added in Date's companies field, Then you can maintain a cache of companies ObjectIds at any point of time which will be updated for every delete/insert in Company Collection.
You can write your own function of creating a date object which will have parameter name which add the current companies ObjectIds.
Date.statics.getNewDateObject = function(name) {
let companyIds = await getCachedCompanyIds();
return new Date({name: name, companies: companyIds});
}
This will have a document like:
{
name: "TODAY'S DATE",
companies: ['5e2076236664640d22515f7b', '5e2076236664640d22515f7a']
}
If you want to populate the Date object with complete Company Information, You can use the populate method present in mongoose which populates the complete company information into the Date Object.
https://mongoosejs.com/docs/populate.html

I solved it:
router.route('/add').post((req, res) => {
const name = req.body.name;
Company.find().then(companies => {
const newDate = new Date({ name, companies });
newDate
.save()
.then(() => res.json('Date added!'))
.catch(err => res.status(400).json('Error: ' + err));
});
});

Related

Nodejs: not getting any data while fetching data from MongoDB?

I am trying to fetch data from MongoDB by a field name - pubdate, but data is not showing neither I am getting any error!
I have field in the collection - _id, article, headline, pubdate all are String type except _id which is Objectid.
When I tried this query in Mongo query browser like - compass and studio 3t I got data -
{ pubdate: { '$gte': '2022-12-01', '$lte': '2022-12-31' } }
I am using postman to fetch data, in raw option sending POST request in JSON form.
{"fdate":"2022-12-31","tdate":"2022-12-31"}
const express = require("express");
const app = express();
const port = 3005;
const mongoose = require("mongoose");
// Connect to MongoDB using Mongoose
const url =
"mongodb://localhost:2701/db";
mongoose.connect(url, { useUnifiedTopology: true, useNewUrlParser: true });
const db = mongoose.connection;
db.on("error", console.error.bind(console, "MongoDB connection error:"));
// Define the Article schema
const articleSchema = new mongoose.Schema({
headline: String,
fulltext: String,
pubdate: String,
article_type: String,
});
const Article = mongoose.model("collectioname", articleSchema);
// Route for retrieving articles based on fromdate and todate
app.post("/articles2", (req, res) => {
let _fDate = req.body.fdate;
let _tDate = req.body.tdate;
Article.find({
pubdate: { $gte: _fDate, $lte: _tDate },
}).exec((err, articles) => {
if (err) {
console.error(err);
res.status(500).send("Error retrieving articles");
return;
}
res.send(articles);
});
});
// Start the server
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
});
How Will I pass the value in Postman to get the record, I am clueless as of now?
I tried map function too but no output-
let _articles = articles.map((x) => x.articleid); res.send(_articles);
Your issue is caused by Mongoose, by default, lowercasing and pluralizing the name that you pass when creating the model to determine the name of the collection it will use for the model.
In other words, when you use mongoose.model('User', UserSchema), Mongoose will take the name (User) and lowercase and pluralize it, so the collection becomes users.
If you want Mongoose to use an existing collection, or if you want to have full control of the collection name, you need to use the collection option in your schema:
const articleSchema = new mongoose.Schema({
headline: String,
fulltext: String,
pubdate: String,
article_type: String,
}, {
collection : 'article_fulltext' // the collection to use for this schema
});
const Article = mongoose.model("Article", articleSchema);
Without this option, and assume that you used article_fulltext as the model name, Mongoose would have used a collection named article_fulltexts.
Can you try logging what articles return in exec callback?
One possible issue could be that variables _fDate and _tDate are not seen as Dates by mongoose.So try wrapping them with new Date?
Article.find({
pubdate: { $gte: new Date(_fDate), $lte: new Date(_tDate) },
})

How to fetch all data only from mongoose with Nodejs

I am not able to fetch all the data from mongoose. When I tried to fetch data it create new collection name(signins) with empty, but singin collection already exists.
I don't understand what I am doing wrong here
Index.js File
const express = require("express");
const app = express();
const mongoose = require("mongoose");
mongoose
.connect("mongodb://0.0.0.0:27017/signin")
.then(() => console.log("MongoDB Connected"))
.catch((err) => console.log(err));
const User = require("./models/signin");
app.use("/", (req, res) => {
User.find({}, (err, data) => {
if (err) throw new err();
return res.json(data);
});
});
app.listen(5500, () => console.log("Port Started on 5500"));
signin
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const loginSign = new Schema({
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
});
module.exports = Users = mongoose.model("signin", loginSign);
Mongoose will automatically "pluralize" the name of your collection from your model name.
So mongoose.model("signin", loginSign) is creating a collection named "signins".
From the documentation: https://mongoosejs.com/docs/models.html#compiling
The first argument is the singular name of the collection your model is for. Mongoose automatically looks for the plural, lowercased version of your model name.
Providing a third argument will use a collection name you specify, instead of the one mongoose creates. So in your case you could:
mongoose.model("signin", loginSign, "signin");
That said, having plural collection names is the standard, and encouraged.

Saving data to array in mongoose

Users are able to post items which other users can request. So, a user creates one item and many users can request it. So, I thought the best way would be to put an array of users into the product schema for who has requested it. And for now I just want to store that users ID and first name. Here is the schema:
const Schema = mongoose.Schema;
const productSchema = new Schema({
title: {
type: String,
required: true
},
category: {
type: String,
required: true
},
description: {
type: String,
required: true
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
requests: [
{
userId: {type: Object},
firstName: {type: String}
}
],
});
module.exports = mongoose.model('Product', productSchema);
In my controller I am first finding the item and then calling save().
exports.postRequest = (req, res, next) => {
const productId = req.body.productId;
const userId = req.body.userId;
const firstName = req.body.firstName;
const data = {userId: userId, firstName: firstName};
Product.findById(productId).then(product => {
product.requests.push(data);
return product
.save()
.then(() => {
res.status(200).json({ message: "success" });
})
.catch(err => {
res.status(500).json({message: 'Something went wrong'});
});
});
};
Firstly, is it okay to do it like this? I found a few posts about this but they don't find and call save, they use findByIdAndUpdate() and $push. Is it 'wrong' to do it how I have done it? This is the second way I tried it and I get the same result in the database:
exports.postRequest = (req, res, next) => {
const productId = req.body.productId;
const userId = req.body.userId;
const firstName = req.body.firstName;
const data = {userId: userId, firstName: firstName};
Product.findByIdAndUpdate(productId, {
$push: {requests: data}
})
.then(() => {
console.log('succes');
})
.catch(err => {
console.log(err);
})
};
And secondly, if you look at the screen shot is the data in the correct format and structure? I don't know why there is _id in there as well instead of just the user ID and first name.
Normally, Developers will save only the reference of other collection(users) in the collection(product). In addition, you had saved username also. Thats fine.
Both of your methods work. But, second method has been added in MongoDB exactly for your specific need. So, no harm in using second method.
There is nothing wrong doing it the way you have done it. using save after querying gives you the chance to validate some things in the data as well for one.
and you can add additional fields as well (if included in the Schema). for an example if your current json return doesn't have a field called last_name then you can add that and save the doc as well so that's a benefit..
When using findById() you don't actually have the power to make a change other than what you program it to do
One thing I noticed.. In your Schema, after you compile it using mongoose.modal()
export the compiled model so that you can use it everywhere it's required using import. like this..
const Product = module.exports = mongoose.model('Product', productSchema);

how to insert multiple JSON objects to one property of a schema?

I have a requirement to store multiple JSON objects in a property of schema.
take this example...
const Schema = require("mongoose").Schema;
const Student= Schema({
student_id: String,
name:String
attendance:[
{
date: Date,
Status: String
}
]
});
I need to insert attendance of individual student which looks like this..
student_id: student_001,
name:'Joe'
attendance:[
{
date: 24-10-2018,
status: 'Present'
},
{
date: 25-10-2018,
status: 'Absent'
},
//list goes on
]
I am using NodeJs as Backend, EJS template as front end and mongodb database. Date and Status comes when user submits data from front end. So I am having hard time writing my post request. Any types of comments / suggestions / change of model structure are welcome. Thank you.
You can create a separate attendance Schema.
const Schema = require("mongoose").Schema;
const AttendanceSchema = new Schema({
date: Date,
status: String
});
const StudentSchema = new Schema({
student_id: String,
name:String
attendance:[AttendanceSchema]
});
const Student = mongoose.model('Student', StudentSchema);
Add a new Student.
let newStudent = new Student({
student_id: student_001,
name:'Joe'
});
newStudent.save();
Update attendance:
let att1 = {
date: 24-10-2018,
status: 'Present'
};
// Here 'id' is id of particular student.
Student.update({ _id: id }, { $push: { attendance: att1 } })
.then(() => console.log("Success"))
.catch(err => console.log(err));
At some point later:
let att2 = {
date: 25-10-2018,
status: 'Absent'
};
// Here 'id' is id of particular student.
Student.update({ _id: id }, { $push: { attendance: att2 } })
.then(() => console.log("Success"))
.catch(err => console.log(err));
I suggest you to change the model structure to be normalized.
This will improve your experience in future statistics querying.
Also, one more suggestion - do not use string indentifiers in mongoDB, this can cause a headache in maintaining their uniqueness. Mongo has automated _id property assigning to each document, you could use it if you need to indentify any object.
Considering my suggestions - the code will look like:
const Schema = require("mongoose").Schema;
const Student = Schema({
name: String
});
const Attendance = Schema({
date: Date,
status: String,
student_id: {
type: Schema.Types.ObjectId,
ref: 'Student'
}
})
Then, you could simply create attendance records assigned to the student :
const attendance = new AttendanceModel({
date: new Date('05/20/2018'),
status: "present",
student_id: "somestudentid"
});

How to add ID of one mongoose collection to an array in another collection?

I'm trying to add the ID of my category documents to my budget documents. Below is the Schema for my budgets.
var {mongoose} = require('../db/mongoose');
var budgetsSchema = new mongoose.Schema({
year: Number,
categoryIDs: [{type:mongoose.Schema.ObjectId,
ref: 'categories'}]
});
var Budgets = mongoose.model('Budgets', budgetsSchema);
module.exports = {
Budgets
};
And here is the Schema for my categories collection.
var {mongoose} = require('../db/mongoose');
var categorySchema = mongoose.Schema({
name: String,
amount: Number,
sub_categories: [{
name: String,
amount: Number
}]
})
var categories = mongoose.model('categories', categorySchema);
module.exports = {
categories
};
To post categories, I use this express post request to add the categories to the category collection and its ID to the Budget collection.
//The ID is the Budget ID
app.post('/categories/:id', (req, res) => {
var id = req.params.id;
var sub_categories = req.body.sub_categories;
var category = new categories({
name: req.body.name,
amount: req.body.amount,
sub_categories
})
category.save().then((docs) => {
res.send(docs);
console.log(docs)
}).catch((e) => res.status(404).send(e));
Budgets.findById(id).then((docs) => {
if(!docs) {
res.status(404).send();
}
docs.categoryIDs.push(category._id);
}).catch((e) => {
res.send(e).status(404);
})
})
When I run this, it does add the category to the collection, but it does not add the ID to the categoryIDs array in the Budget document. Please help
First, change the model name from Plural to Singular as mentioned in the mongoose docs to avoid confusion:
The first argument is the singular name of the collection your model
is for. Mongoose automatically looks for the plural version of your
model name. Thus, for the example above, the model Tank is for the
tanks collection in the database. The .model() function makes a copy
of schema. Make sure that you've added everything you want to schema
before calling .model()!
So categories to Category and Budgets to Budget. Please verify the new before mongoose.model here, Mongoose docs ref.
var categorySchema = new mongoose.Schema({
name: String,
amount: Number,
sub_categories: [{
name: String,
amount: Number
}]
})

Resources