How I make a list of documents with mongoose? (Schema) - javascript

I don't know how to make a list of documents with mongoose (Node JS), someone know's how to make that?
new mongoose.Schema({
first_name: String,
last_name: String,
companies: [
{
name_company:String,
post:String,
time_in_post:String,
}
]
});
I need to insert many documents with companies schema at different times but I don't know how to make that with mongoose.
Can someone help me?

Seems like splitting this into different schemas might be a good idea. Especially if other people will be apart of the same company.
For instance, maybe you could try this:
const CompanySchema = new mongoose.Schema({
name: String,
// ... other company specific attributes
});
const Company = mongoose.model("Company", CompanySchema);
const UserSchema = new mongoose.Schema({
firstName: String,
lastName: String,
companies: [
{
company: { type: mongoose.Schema.Types.ObjectId, ref: 'Company' },
post: String,
timeInPost: String,
}
]
});
const User = mongoose.model("User", UserSchema);
And the interaction with the models could look like this:
(async () => {
try {
const company1 = await Company.create({ name: "Company 1" });
const company2 = await Company.create({ name: "Company 2" });
const user1 = await User.create({
firstName: "first",
lastName: "last",
companies: [
{
company: company1._id,
post: "....",
timeInPost: "....",
},
{
company: company2._id,
post: "....",
timeInPost: "....",
},
],
});
const users = await User.find({}).populate("companies.company"); // in order to populate the company with the document from the company collection
// users with companies info
} catch (error) {
console.log(error);
}
})();
Referenced from the mongoose documentation: https://alexanderzeitler.com/articles/mongoose-referencing-schema-in-properties-and-arrays/

You could use this approach, with this way you avoid data duplication:
const companySchema = new mongoose.Schema({
name_company: String,
post: String,
time_in_post: String
});
new mongoose.Schema({
firstName: String,
lastName: String,
companies: [companySchema] // Array of subdocuments
});
See full documentation here: https://mongoosejs.com/docs/guide.html

Related

Mongoose is not populating the fields in MongoDB

When I run the following code, I get the object along with the populated fields logged on the console.
Screenshot
But, the fields have not been populated in the books collection. Can someone please help me figure this out?
const bookSchema = new Schema({
title: String,
genre: { type: Schema.Types.ObjectId, ref: "genre" },
author: { type: Schema.Types.ObjectId, ref: "author" },
numberInStock: { type: Number, default: 0 },
rating: Number,
yearPublished: Number,
dateAdded: { type: Date, default: Date.now },
liked: { type: Boolean, default: false },
});
const genreSchema = new Schema({ name: String });
const authorSchema = new Schema({ name: String });
const Book = model("book", bookSchema);
const Genre = model("genre", genreSchema);
const Author = model("author", authorSchema);
const books = [
{
title: "Sapiens",
genre: "632873144b0bbfc10ae1942d",
author: "632873e706fe265eaee77de3",
numberInStock: 6,
rating: 4.4,
yearPublished: 2011,
},
];
async function saveBook(b) {
let book = new Book(b);
book
.save()
.then((result) => {
populateBook(result._id);
})
.catch((err) => console.log("Error: ", err));
}
function populateBook(id) {
Book.findById(id)
.populate("genre")
.populate("author")
.exec((err, book) => {
if (err) {
console.log("Error: ", err);
return;
}
console.log(book);
});
}
books.forEach((b) => {
saveBook(b);
});
That's how population works, it only stores references to other documents in the database. At query time, and if you ask for it (using .populate()), Mongoose will retrieve the referenced documents and insert them into the "parent" document.
If you want the referenced documents to be stored in the database, you can't use population but have to use subdocuments.
However, this will limit the flexibility of your database, because if for example an author name needs to be changed, you need to change all the Book documents in your database to update the author's name. With population, you only need to change the Author document.

Mongoose filter by nested reference

I have 3 mongoose schemas Employee, Team and Project. Employee has reference to the team and Team has reference to the Project. Is it possible to get all employees by project Id? I don't want to change schema or use Team model with populate.
const employeeSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
team: { type: mongoose.Schema.Types.ObjectId, ref: "Team" },
});
const teamSchema = mongoose.Schema({
name: { type: String, required: true },
employees: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
project: { type: mongoose.Schema.Types.ObjectId, ref: "Project" },
});
Below code throws cast error, id is a valid project id.
router.get("/:id/employees", checkAuth, (req, res, next) => {
const id = req.params.id;
console.log(id);
Employee.find({ team:{project:id}}).then((employees) => {
console.log(employees);
});
});
Yes it is possible to get all employees using project Id.but not using single query so you have to modify your function like this
const id = mongoose.Types.ObjectId(req.params.id);
Team.findOne({ project: id }, { _id: 1 }, function (err, docs) {
// Get the Team which match with project ID
Employee.find({ team: docs._id }, function (err, docs1) {
//Get all employee belongs to that team and project
console.log(docs1);
});
});

how do I query from parent model a array of other model in Mongoose?

I have two Schema for user & todo. Every todo has an owner as a user, every user has an array of todos.
// user.js
const TodoSchema = require('./todo').TodoSchema;
var UserSchema = mongoose.Schema({
name: {
type: String,
required: true
},
todos: {
type: [TodoSchema]
}
});
module.exports.UserSchema = UserSchema;
module.exports.UserModel = mongoose.model('UserModel', UserSchema);
// todo.js
var TodoSchema = mongoose.Schema({
body: {
type: String, required: true
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'UserModel',
required: true
}
});
module.exports.TodoSchema = TodoSchema;
module.exports.TodoModel = mongoose.model('TodoModel', TodoSchema);
I entered data like this.
var nUser = new UserModel({
name: "Alex
)};
nUser.save().then(user => {
var t = new TodoModel({
body: "my new todo",
owner: user._id
});
t.save().then();
});
But the problem is I want to get all the todos from a specific user, something like this...What is the correct way?
UserModel.findOne({name: "Alex"})
.then(user => {
// user.todos
});
P.S.
I can do this like TodoModel.find({owner: specific_user._id}), but I want it from UserModel.
Since you're asking for the proper way of doing it, I am gonna start with your User Schema. If you want to find all the todos of a user, then putting the todo documents inside an array in the User document is not required. So you should probably remove that from your schema.
After that you can use a simple aggregation to get your desired outcome.
UserModel.aggregate([
{
$match:{
name:"Alex"
}
},
{
$lookup:{
from:"todomodels",
localField:"$_id",
foreignField:"$owner",
as:"todos"
}
}
])
this will return all the todos for that user in an array of the same name.

Connect mongoose-array-values to a unique ID

This may seem like a vague question, but I'm going to try to explain the best I can. As a side note, I'm quite new to using mongoose :)
I have a mongoose-schema storing different values for each user, like so...
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: String, required: false }],
});
The "files"-key contains an array of values, lets say for example:
userSchema.files = [value1, value2, value3]
And I want each value to be connected to some kind of ID, so that when I call the specified ID, I get the specified value. Just for demonstrating purposes, it could look something like this:
userSchema.files = [{value:value1, id: id1},
{value:value2, id: id2},
{value:value3, id: id3}]
Then I want to find the specified id, and return it's "value"-key in a request:
router.route("/home/:id")
.get(restrict, function(req, res) {
User.findOne({ user: req.session.Auth.username }, function(error, data) {
data.files.forEach(function(file) {
if (file.id === req.params.id) {
response.render("../home", file.value)
}
}
});
});
How can I do this? Tried pushing an object to files, but that didn't work as expected. Read something about ObjectId, but couldn't quite understand it. Any tips?
I think you simply need to create a separate model for File and connect it to your User model using the 'ref' keyword :
let fileSchema = mongoose.Schema({
_id : Number,
value : String
});
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: Number, ref: 'File' }]
});
let User = mongoose.model('User', userSchema);
let File = mongoose.model('File', fileSchema);
let f1 = new File({ _id: 1, value: 'File 1'});
let f2 = new File({ _id: 2, value: 'File 2'});
let f3 = new File({ _id: 3, value: 'File 3'});
let user1 = new User({user:'chuck', pass:'norris'});
user1.files.push(f1);
user1.files.push(f2);
user1.files.push(f3);
user1.save(function(err){ });
Now to get the data back:
User
.findOne({ user: 'chuck' })
.populate('files') // only works if we pushed refs to children
.exec(function (err, user) {
if (err) return handleError(err);
console.log(user);
//you can now loop through user.files and compare _id
user.files.forEach(function(file) {
if (file._id === req.params.id) {
response.render("../home", file.value)
}
}
});
You can read about mongoose reference population here: http://mongoosejs.com/docs/populate.html

Prevent duplicates in an array of objects

I'm learning Node / Mongoose, and trying to figure out how to prevent duplicates in an array of ListItems:
var listitemSchema = new mongoose.Schema({
name: String,
rank: Number
});
...which exist inside a user:
var userSchema = new mongoose.Schema({
username: String,
password: String,
list: [{
type: mongoose.Schema.Types.ObjectId,
ref: "ListItem"
}]
});
...based on whether the user already has the name within his/her list. I was looking into $addtoset but can't really figure out how to put conditions when dealing with an object. The docs weren't very helpful and I can't seem to find similar examples online.
Right now my 'POST' request is a mess and looks like this:
router.post("/editlist", isLoggedIn, function(req,res){
User.findById(req.user._id).populate("list").exec(function(err , user) {
if(err) {
console.log(err);
res.redirect("/editlist");
} else {
//prevent duplicates based on username
User.update(
{ "_id": req.user._id },
{ $addToSet: { "streamName": req.body.listitem.name}
});
res.redirect("/watch");
}
});
});
Can anyone send me on my way? My $addToSet isn't pushing items onto the list array.
According to the $addToSet documentation, the operator is used in this form:
{ $addToSet: { field1: value1, ... } }
where field is an Array.
To add an item to the list array, we do:
User.update({
{ "_id": req.user._id },
{ $addToSet: { list: {"streamName": req.body.listitem.name } }}
});
You'll need to update the userSchema definition:
var userSchema = new mongoose.Schema({
username: String,
password: String,
list: [listitemSchema]
});

Categories