How to insert array in MongoDB? Node Js - node.js

I'm working on Node js server and use the mongoDB with driver mongoose. So, how can I insert an array in database. Here is my Schema:
const SubjectsSchema = new Schema(
{
id: {
type: String,
required: true,
},
subjects: [
{
id: { type: Number, required: true },
subject: { type: String, required: true },
},
],
},
{ versionKey: false }
);
And here how I add new element:
let subjects = new Subjects({
id: req.params.class,
subjects: { id: 0, subject: "Maths"},
subjects: {id: 1, subject: "IT"},
subjects: {id: 2, subject: "Physics"},
});
subjects.save();
But in db created only last element. So how can create a correct array?

You are supposed to pass it as an array, like your model definition
let subjects = new Subjects({
id: req.params.class,
subjects: [{ id: 0, subject: "Maths"},
{id: 1, subject: "IT"},
{id: 2, subject: "Physics"}
]
});
subjects.save();

Related

add pagination on result of two query. (first query result is used in second query). mongodb, nodejs

result data should look like this:
[
{
Feed_id:
Feed_title:
User_Name:
project_title:
event_object: { // all event data }
},
...
]
==> feed contains project, user and taskIdsList,
===> after fetching filtered feed take all the taskList and find events.
===> Here pagination is applied to second query of events, so if data set is large and many feeds (like 1000) are fetched, it will slow down the process and use more memory.? is there any way to go around it may be event architectural changes
model and query code:
same event can be in multiple feeds. as the same task can be in multiple events.
feed model
const feedSchema = new Schema({
title: {
type: String,
required: [true, 'Please enter title.']
},
project: {
type: Schema.Types.ObjectId,
ref: 'project',
required: [true, 'Please enter project.']
},
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
task: [{
type: Schema.Types.ObjectId,
ref: 'task',
}],
usersSharedFeed: [{
type: Schema.Types.ObjectId,
ref: 'user',
default: []
}],
}, {
timestamps: true,
});
event model
const eventSchema = new Schema({
title: {
type: String,
},
taskId: {
type: Schema.Types.ObjectId,
},
description: {
type: String,
default: ''
},
endDateTime: {
type: Date,
}
}, {
timestamps: true,
});
this is the relation between feed and event through task ID.
fetch feed data where the feed is shared with user.
const feedFetched = await feedModel.find({ usersSharedFeed: { $in: req.user._id }, isArchived: false })
.populate({
path: 'user',
select: { fullName: 1, profileImage: 1 }
})
.populate({ path: 'project', select: { title: 1 } })
.select({ project: 1, task: 1, usersSharedFeed: 1, user: 1, title: 1 });
from feed data create taskIDList. and fetch events.
const events = await eventModel.find({ taskId: { $in: taskIdList }, isArchived: false })
.select({ taskId: 1, timeSpent: 1, endDateTime: 1, title: 1, imageUrl: 1, description: 1 })
.sort({ endDateTime: -1 })
.limit(parseInt(req.query.perPage) * parseInt(req.query.pageNo))
.skip(parseInt(req.query.perPage) * parseInt(req.query.pageNo) - parseInt(req.query.perPage))
and now map events data to feed by matching taskId to get desired result. which runs nested for loop, which again increases cost as fetched feed data will increse.
events.forEach((event) => {
for (let i = 0; i < feed.length; i++) {
if (feed[i].task && feed[i].task.includes(event.taskId)) {
combineFeed.push({
_id: feed[i]._id,
title: feed[i].title,
project: feed[i].project,
user: feed[i].user,
event,
});
}
}
});
Here I have not added all the fields in schema as to not increase unnecessary data.
Any kind of feedback is appreciated.
Using aggregation to make query then you add pagination easily

find and update data of a certain user's nested data in MongoDB Mongoose

I have a database of users and their info of the places they checked. Each time an user clicks on a particular place, I want to check in the data base if he hasn't yet clicked on that place. User's schema:
const userSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Įveskite el. paštą'],
unique: true,
lowercase : true,
validate: [isEmail, 'Įveskite tinkamą el. paštą']
},
password: {
type: String,
required: [true, 'Įveskite slaptažodį'],
minlength: [6, 'Minimalus simbolių skaičius – 6']
},
placeinfo: [
{
title: String,
score: String
}
]
});
const User = mongoose.model('user', userSchema);
If I search for a place title, it searches in all database for all users, but I want it to search for a particular user, for example testuser#test.com and if he has "Kalnaberžės piliakalnis" in his placeInfo array.
{
_id: 60d2eecea704c60a705ef3fb,
email: 'testuser#test.com',
password: '$2a$10$PN3krKgwsdtQV1Y/Z.wQ7eeJbQ9GIrOEjHcpGlYCQR33Oxub5bJ4a',
placeinfo: [
{ _id: 60d2eefba704c60a705ef3fe, title: 'Kalnaberžės piliakalnis' },
{ _id: 60d2ef10ea1c3437a4e47c31, title: 'Pakalniškių piliakalnis' },
],
__v: 0
}
You can use this aggregation:
db.collection.aggregate([
{
"$match": {
"email": "testuser#test.com",
"placeinfo.title": "Kalnaberžės piliakalnis"
}
}
])
Or basicly find:
db.collection.find({
"email": "testuser#test.com",
"placeinfo.title": "Kalnaberžės piliakalnis"
})
Playground

Mongoose - Get and Delete a subrecord

I have a model defined as so:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const feedbackSchema = new Schema({
Name: {
type: String,
required: true,
},
Email: {
type: String,
required: true,
},
Project: {
type: String,
required: true,
},
Wonder: {
type: String,
required: true,
},
Share: {
type: String,
required: true,
},
Delight: {
type: String,
required: true,
},
Suggestions: {
type: String,
required: true,
},
Rating: {
type: String,
required: true,
},
dateCreated: {
type: Date,
default: Date.now(),
},
user: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
const UserSchema = new Schema({
googleId: {
type: String
},
displayName: {
type: String
},
firstName: {
type: String
},
lastName: {
type: String
},
image: {
type: String
},
createdAt: {
type: Date,
default: Date.now(),
},
feedback: [feedbackSchema],
})
module.exports = mongoose.model("User", UserSchema);
An example document:
{
_id: ObjectId('60b9dc728a516a4669b40dbc'),
createdAt: ISODate('2021-06-04T07:42:01.992Z'),
googleId: '2342987239823908423492837',
displayName: 'User Name',
firstName: 'User',
lastName: 'Name',
image: 'https://lh3.googleusercontent.com/a-/89wf323wefiuhh3f9hwerfiu23f29h34f',
feedback: [
{
dateCreated: ISODate('2021-06-04T07:42:01.988Z'),
_id: ObjectId('60b9dc858a516a4669b40dbd'),
Name: 'Joe Bloggs',
Email: 'joe#bloggs.com',
Project: 'Some Project',
Suggestions: 'Here are some suggestions',
Rating: '10'
},
{
dateCreated: ISODate('2021-06-04T08:06:44.625Z'),
_id: ObjectId('60b9df29641ab05db7aa2264'),
Name: 'Mr Bungle',
Email: 'mr#bungle',
Project: 'The Bungle Project',
Suggestions: 'Wharghable',
Rating: '8'
},
{
dateCreated: ISODate('2021-06-04T08:08:30.958Z'),
_id: ObjectId('60b9df917e85eb6066049eed'),
Name: 'Mike Patton',
Email: 'mike#patton.com',
Project: 'No More Faith',
Suggestions: 'Find the faith',
Rating: '10'
},
],
__v: 0
}
I have two routes defined, the first one is called when the user clicked a button on a feedback item on the UI which takes the user to a "are you sure you want to delete this record"-type page displaying some of the information from the selected feedback record.
A second route which, when the user clicks 'confirm' the subrecord is deleted from the document.
The problem I'm having is I can't seem to pull the feedback from the user in order to select the document by id, here's what I have so far for the confirmation route:
router.get('/delete', ensureAuth, async (req, res) => {
try {
var url = require('url');
var url_parts = url.parse(req.url, true);
var feedbackId = url_parts.query.id;
const allFeedback = await User.feedback;
const feedbackToDelete = await allFeedback.find({ _id: feedbackId });
console.log(feedbackToDelete);
res.render('delete', {
imgSrc: user.image,
displayName: user.firstName,
feedbackToDelete
});
} catch (error) {
console.log(error);
}
})
Help much appreciated
Update
You should be able to do just this:
const feedbackToDelete = await User.feedback.find({ _id: feedbackId });
Or if feedbackId is just a string, which is appears to be, you may have to do something like:
// Create an actual _id object
// That is why in your sample doc you see ObjectId('foobarbaz')
const feedbackId = new mongoose.Types.ObjectId(url_parts.query.id);
const feedbackToDelete = await User.feedback.find({ _id: feedbackId });
Original
Shouldn't this:
const allFeedback = await User.feedback; (a field)
be this:
const allFeedback = await User.feedback(); (a method/function)
?

How to get the total number of occurences of a specific item in every document's array element

I am implementing favoriting/unfavoriting functionality to my express app but I have a problem on how to count the the total number the post has been favorited.
Assuming I have this Schema for Recipe
RecipeSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
maxlength: 30
},
description: {
type: String,
default: ''
},
favoritesCount: {
type: Number,
default: 0
}
})
And Schema for User
const UserSchema = new mongoose.Schema({
username: {
type: String,
minlength: 8,
required: true,
unique: true
},
fullname: {
type: String,
maxlength: 40,
minlength: 4,
required: true
},
password: {
type: String,
required: true,
minlength: 8
}
favorites: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Recipe'
}]
}, { timestamps: true });
And now assuming I have this doc of Users,
How can I count the total number the Recipe ID (5daef9a2761d4b1668214dbc) present in each User doc's favorites array?
[{
username: 'john123',
email: 'john#test.com',
favorites: ['5daef9a2761d4b1668214dbc']
}, {
username: 'jane75',
email: 'jane#test.com',
favorites: []
}, {
username: 'johnwick',
email: 'johnwick#test.com',
favorites: ['5daef9a2761d4b1668214dbc']
}]
// Should yield 2
I looked up for answers but I can't find one. I'm new to mongodb and nodejs so please bear with me. Some answers that I saw are related to Aggregation.
So far I have tried this code. But it just return the number of User documents.
const User = require('./User') // the User model
RecipeSchema.methods.updateFavoriteCount = function() {
return User.count({
favorites: {
$in: [this._id]
}
}).then((count) => {
this.favoritesCount = count;
return this.save();
});
};
You can do it with the help of aggregation and with $size. For more detail, refer to this document.
Your query
db.collection.aggregate([
{
$project: {
username: 1,
email: 1,
totalFavritesCount: {
$cond: {
if: {
$isArray: "$favorites"
},
then: {
$size: "$favorites"
},
else: "NA"
}
}
}
}
])
Result
[
{
"_id": ObjectId("5a934e000102030405000000"),
"email": "john#test.com",
"totalFavritesCount": 1,
"username": "john123"
},
{
"_id": ObjectId("5a934e000102030405000001"),
"email": "jane#test.com",
"totalFavritesCount": 0,
"username": "jane75"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"email": "johnwick#test.com",
"totalFavritesCount": 1,
"username": "johnwick"
}
]
You can also check out the running code in this link.

Express mongoose populate array of subdocuments from POST

This is my Mongoose Schema:
const InvoiceSchema = new Schema({
name: { type: String, required: true },
description: { type: String },
items: [{
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product'},
amount: { type: Number },
name: { type: String, required: true },
quantity: { type: Number },
rate: { type: Number, required: true }
}],
createdBy: { type: Schema.ObjectId, ref: 'User', required: true },
}
Now I want to populate my Schema from POST Datas, My problem is I don't Know how to post my items (How do I name my fields)??
I use PostMan to post Datas.
To get post data
To add a new record in mongoose
const {ObjectId} = mongoose.Schema.Types;
const newInvoice = new InvoiceSchema({
name: "John Smith",
description: "This is a description",
items: [{
product: 'THIS_IS_AN_OBJECT_ID_STRINGIFIED',
amount: 2,
quantity: 5,
//name - comes from the product model
//rate - comes from the product model
}]
});
newInvoice.save();
To POST and save it
//Response format
{
name: 'John Smith',
description: 'This is a description',
items: [
{
product: 'THIS_IS_AN_OBJECT_ID',
amount: 2,
quantity: 5
}
]
}
app.post('/yourRoute', (req, res) => {
const {name, description, items} = req.body;
const newInvoice = new InvoiceSchema({name, description, items});
newInvoice.save().then(()=>res.send('success'))
});
To bulk add items
const invoice = new Invoice();
invoice.items = req.body.items;
To add single item
invoice.items.push(item);
To update single item
const item = invoice.items.id(req.params._id);
item.attribute = ...
// Do update

Resources