Node, Express, MongoDB: Creating a schema with an array of objects? - mongodb

Here's my desired schema:
{
username: "taimoor",
pairs: [
{
code: "CA",
site: "google.ca"
},
{
code: "US",
site: "google.com"
},
{
code: "GB",
site: "google.co.uk"
}
]
date: 1574880349,
}
Here's my current schema:
const redirectionSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
pairs: [
// What do I place here?
],
date: {
type: Date,
required: true,
default: Date.now
}
})
I don't know how to proceed and implement this using mongoose. Should I create another schema called Pair? And if so:
How do I ensure the pairs will be valid?
How do I add a Pair to "pairs" programmatically?
Thanks for your time, this is my first time using NoSQL.

You need to have an inner schema for pairs. This way you can apply required or other validations to the pairs.
const mongoose = require("mongoose");
const redirectionSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
pairs: [
new mongoose.Schema({
code: {
type: String,
required: true
},
site: {
type: String,
required: true
}
})
],
date: {
type: Date,
required: true,
default: Date.now
}
});
module.exports = mongoose.model("Redirect", redirectionSchema);
And you can use the following App.js to create a document with username and pairs, or add another pair to an existing document.
App.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const Redirect = require("./models/redirect");
const url = "mongodb://localhost:27017/redirectDB";
const port = process.env.PORT || 3000;
app.use(express.json());
mongoose
.connect(url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
app.listen(port, () => {
console.log(`App running on port ${port}...`);
});
})
.catch(error => console.log(error));
app.post("/redirect", async (req, res) => {
try {
const result = await Redirect.create(req.body);
res.send(result);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
app.post("/redirect/:id/pair", async (req, res) => {
const { code, site } = req.body;
try {
const result = await Redirect.findByIdAndUpdate(
req.params.id,
{
$push: {
pairs: { code, site }
}
},
{ new: true }
);
res.send(result);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
To create username and pairs send a post requrest to the url http://localhost:3000/redirect like this:
{
"username": "taimoor",
"pairs": [
{
"code": "CA",
"site": "google.ca"
},
{
"code": "US",
"site": "google.com"
}
]
}
The response will be like this:
{
"_id": "5ddecfcb3cd5c035b4c31d95",
"username": "taimoor",
"pairs": [
{
"_id": "5ddecfcb3cd5c035b4c31d97",
"code": "CA",
"site": "google.ca"
},
{
"_id": "5ddecfcb3cd5c035b4c31d96",
"code": "US",
"site": "google.com"
}
],
"date": "2019-11-27T19:34:35.781Z",
"__v": 0
}
And later we can add a new pair to this document using a post request to this url http://localhost:3000/redirect/5ddecfcb3cd5c035b4c31d95/pair. The id in the url is the id we previosuly created, and got in the response.
Request:
{
"code": "GB",
"site": "google.co.uk"
}
Response:
{
"_id": "5ddecfcb3cd5c035b4c31d95",
"username": "taimoor",
"pairs": [
{
"_id": "5ddecfcb3cd5c035b4c31d97",
"code": "CA",
"site": "google.ca"
},
{
"_id": "5ddecfcb3cd5c035b4c31d96",
"code": "US",
"site": "google.com"
},
{
"_id": "5dded01693be502168a0f794",
"code": "GB",
"site": "google.co.uk"
}
],
"date": "2019-11-27T19:34:35.781Z",
"__v": 0
}

Model
const redirectionSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
pairs: [
{
_id: false,
code: { type: String },
site: { type: String }
}
],
date: {
type: Date,
required: true,
default: Date.now
}
})
const Redirection = mongoose.model('Redirection', redirectionSchema);
Use
const redirection = new Redirection({
username: "taimoor",
pairs: [
{
code: "CA",
site: "google.ca"
},
{
code: "US",
site: "google.com"
},
{
code: "GB",
site: "google.co.uk"
}
],
date: new Date(1574880349),
})
redirection.save();
Example database output
{
"_id": {
"$oid": "5ddecc4c6dd3760c40ff354b"
},
"username": "taimoor",
"pairs": [
{
"code": "CA",
"site": "google.ca"
},
{
"code": "US",
"site": "google.com"
},
{
"code": "GB",
"site": "google.co.uk"
}
],
"date": {
"$date": "1970-01-19T05:28:00.349Z"
},
"__v": 0
}

Related

Mongodb find by Id in Es6 and moongose doesnt work

SO i try to query data using mongodb on ES6 using this query:
const { title = "", date1 = "", user = "", date2 = "" } = req.query;
const formIds = req.params.formId;
let forms = "";
if (date2 === "undefined") {
console.log(date1, date2, formIds);
}
const form = await Form.findOne({
_id: req.params.formId,
});
if (!form) {
throw { code: 404, message: "FORM_NOT_FOUND" };
}
console.log(form.id);
if (date2 === "undefined") {
forms = await Answer.aggregate([
{
$match: {
$and: [{ date: date1 }, { formId: o_id }],
},
},
{
$group: {
_id: "$title",
title: {
$first: "$title",
},
answer: {
$push: {
username: "$username",
date: "$date",
formId: "$formId",
answers: "$answer",
},
},
},
},
]);
}
but because it using ObjectId on Mongo.., i cannot return the value even though it has the value on the database with format like this:
{
"_id": {
"$oid": "636242358721c33778b16e0f"
},
"userId": {
"$oid": "6355d841bf2fc81f76edfbd9"
},
"formId": {
"$oid": "6361c5aaf7a02c177ebebb27"
},
"title": "Untitled Form",
"username": "jansenstan2410#gmail.com",
"date": "2022-11-02",
"answer": {
"Test": [
"New Option"
],
"Email": "john#nabatisnack.com",
"Dropdown": "New Option",
"Radio": "3",
"Date": "2022-11-01T00:00:00.000Z",
"Time": "17:25"
}
}
can someone tell me where did i do wrong here?i try to find answer all the answer using require while in ES6 i use mongoose

How to find entire records using populated fields in mongoose

This are my schemas
var employeesSchema = new schema({
companyName: { type: String },
employeeName: { type: String },
employeeCode: { type: String, unique: true },
designation: { type: String },
department: { type: String },
officeLocation: { type: String },
workLocation: { type: String },
emailID: { type: String , unique: true},
managerName: { type: String },
managerEmail: { type: String },
countryCode: { type: String },
mobile: { type: String },
password: { type: String },
createdDate: { type: Date, default: new Date() }
})
var leaveRequests = new schema({
leaveRequestID: { type: String, unique: true },
employeeCode: { type: String, required: true },
requestedBy: { type: mongoose.Schema.Types.ObjectId, ref: "employees_master", required: true },
leaveType: { type: mongoose.Schema.Types.ObjectId, ref: "leavetypes", required: true },
startDate: { type: Date },
endDate: { type: Date },
remarks: { type: String },
documentUrl: { type: String },
status: { type: String, enum: ['pending', 'rejected', 'approved'], default: 'pending' },
statusUpdatedBy: { type: mongoose.Schema.Types.ObjectId, ref: "manager_or_lead_master" },
reason: { type: String },
isActive: { type: Boolean, default: true },
createdDate: { type: Date, default: new Date() },
});
Im trying to filter data with managerEmail: req.body.emailID
exports.getTeamLevelLeaveRequest = async (req, res) => {
try {
const getQuery = leaverequests.find({})
.populate('leaveType')
.populate('statusUpdatedBy')
.populate({
path: 'requestedBy',
match: {
managerEmail: req.body.emailID
}
})
.sort({ _id: -1 })
const resp = await getQuery;
const resAfterMap = resp.filter(u => u.requestedBy !== null)
responseHandler.successResponse(res, resAfterMap, "Leave Requests")
} catch (err) {
responseHandler.errorResponse(res, err, commonErrorMessage)
}
}
But Im receiving resp like
[{
"_id": "634e7459f78e446637a70ac6",
"leaveRequestID": "LR10",
"employeeCode": "MLI637",
"requestedBy": null,
"leaveType": {
"_id": "634d8d7ab69f5a80c4c98216",
"leaveType": "Compensatory Off",
"__v": 0,
"name": "Compensatory Off"
},
"startDate": "2022-10-18T18:30:00.000Z",
"endDate": "2022-10-18T18:30:00.000Z",
"remarks": "test",
"status": "pending",
"isActive": true,
"createdDate": "2022-10-18T08:27:42.042Z",
"__v": 0
},
{
"_id": "634e719c71313319a6da2432",
"leaveRequestID": "LR9",
"employeeCode": "MLI699",
"requestedBy": null,
"leaveType": {
"_id": "634d8d7ab69f5a80c4c98216",
"leaveType": "Compensatory Off",
"__v": 0,
"name": "Compensatory Off"
},
"startDate": "2022-10-18T18:30:00.000Z",
"endDate": "2022-10-18T18:30:00.000Z",
"remarks": "test",
"status": "pending",
"isActive": true,
"createdDate": "2022-10-18T08:25:04.220Z",
"__v": 0
},
{
"_id": "634e719c71313319a6da2432",
"leaveRequestID": "LR9",
"employeeCode": "MLI699",
"requestedBy": {
**populated data came ----**
},
"leaveType": {
"_id": "634d8d7ab69f5a80c4c98216",
"leaveType": "Compensatory Off",
"__v": 0,
"name": "Compensatory Off"
},
"startDate": "2022-10-18T18:30:00.000Z",
"endDate": "2022-10-18T18:30:00.000Z",
"remarks": "test",
"status": "pending",
"isActive": true,
"createdDate": "2022-10-18T08:25:04.220Z",
"__v": 0
},
]
I want to get data without filtering requestedBy is not equal to null
Im using filter method to do.
Is there any option to find filter data....

How to query to get all documents referenced to another collection based on one field as username

In my Node API and MongoDB, I'm trying to make an endpoint to get all the posts associated with one username of a profile. In my Profile schema, I have a reference to the Post Schema and in my Post schema, I have a reference to the Username from Profile schema.
My issue I don't know how to get all the posts for that username. I did similarly but with embedded for the Experience schema but I'm not sure how to do that for the referenced collections.
Post model:
const { Connect } = require("../db");
const reactionSchema = {
likedBy: {
type: String,
unique: true,
sparse: true
}
};
const postSchema = {
text: {
type: String,
required: true,
unique: true,
sparse: false
},
username: {
type: Connect.Schema.Types.String,
ref: "Profile"
},
image: {
type: String,
default: "https://via.placeholder.com/150",
required: false
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
reactions: [reactionSchema],
comments: {
type: Connect.Schema.Types.ObjectId,
ref: "Comment",
required: false
}
};
const collectionName = "post";
const postSchemaModel = Connect.Schema(postSchema);
const Post = Connect.model(collectionName, postSchemaModel);
module.exports = Post;
Profile model:
// Here defining profile model
// Embedded we have the Experience as []
const { Connect } = require("../db");
const { isEmail } = require("validator");
const postSchema = {
type: Connect.Schema.Types.ObjectId,
ref: "Post"
};
const experienceSchema = {
role: {
type: String,
required: true
},
company: {
type: String,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date,
required: false
},
description: {
type: String,
required: false
},
area: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
username: {
type: String,
required: false
},
image: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
}
};
const profileSchema = {
firstname: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: [true, "Email is required"],
validate: {
validator: string => isEmail(string),
message: "Provided email is invalid"
}
},
bio: {
type: String,
required: true
},
title: {
type: String,
required: true
},
area: {
type: String,
required: true
},
imageUrl: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
},
username: {
type: String,
required: true,
unique: true
},
experience: [experienceSchema],
posts: [postSchema],
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
}
};
const collectionName = "profile";
const profileSchemaModel = Connect.Schema(profileSchema);
const Profile = Connect.model(collectionName, profileSchemaModel);
module.exports = Profile;
I was able to make this for the embedded experience but not sure that correct for referenced collection:
const profileWithExperiences = await Student.aggregate([
{ $match: { username: res.username.username } },
{
$unwind: "$experience"
},
{
$match: {
"experience._id": new ObjectID(req.params.experienceId)
}
},
{
$project: {
username: 1,
experience: 1,
_id: 0
}
}
]);
I would like to see an example for referenced collections as it is confusing me how should I do that
[EDIT]
JSON for Profiles and Posts
{
"_id": ObjectId("5e2c98fc3d785252ce5b5693"),
"imageUrl": "https://i.pravatar.cc/300",
"firstname": "Jakos",
"surname": "Lemi",
"email": "lemi#email.com",
"bio": "My bio bio",
"title": "Senior IT developer",
"area": "Copenhagen",
"username": "Jakos",
"experience": [
{
"image": "https://via.placeholder.com/150",
"_id": ObjectId("5e3975f95fbeec9095ff3d2f"),
"role": "Developer",
"company": "Google",
"startDate": ISODate("2018-11-09T23:00:00.000Z"),
"endDate": ISODate("2019-01-05T23:00:00.000Z"),
"area": "Copenhagen",
"createdAt": ISODate("2020-02-04T13:47:37.167Z"),
"updatedAt": ISODate("2020-02-04T13:47:37.167Z")
},
{
"image": "https://via.placeholder.com/150",
"_id": ObjectId("5e3978bf5e399698e20c56d4"),
"role": "Developer",
"company": "IBM",
"startDate": ISODate("2018-11-09T23:00:00.000Z"),
"endDate": ISODate("2019-01-05T23:00:00.000Z"),
"area": "Copenhagen",
"createdAt": ISODate("2020-02-04T13:59:27.412Z"),
"updatedAt": ISODate("2020-02-04T13:59:27.412Z")
}
],
"createdAt": ISODate("2020-01-25T19:37:32.727Z"),
"updatedAt": ISODate("2020-02-04T23:14:37.122Z"),
"__v": NumberInt("0")
}
Post
{
"_id": ObjectId("5e3beb639e072afedd19dcef"),
"username": ObjectId("5e2c98fc3d785252ce5b5693"),
"image": "https://via.placeholder.com/150",
"text": "My awesome post",
"createdAt": ISODate("2020-02-06T10:33:07.22Z"),
"updatedAt": ISODate("2020-02-06T10:33:07.22Z"),
"reactions": [ ],
"__v": NumberInt("0")
}
Output expected:
{
"username": "Jakos",
"postsCount": [1],
"posts": [
{
"_id": ObjectId("5e3beb639e072afedd19dcef"),
"image": "https://via.placeholder.com/150",
"text": "My awesome post",
"createdAt": ISODate("2020-02-06T10:33:07.22Z"),
"updatedAt": ISODate("2020-02-06T10:33:07.22Z"),
"reactions": [ ],
"__v": NumberInt("0")
}
]
}
I want to see all the posts related to that username
You can use the $lookup aggregation to join collections.
db.profiles.aggregate([
{
$match: {
username: "Jakos"
}
},
{
$lookup: {
from: "posts", //the name of the posts collection, change this if it is different
localField: "_id",
foreignField: "username",
as: "posts"
}
},
{
$project: {
username: 1,
posts: 1,
postsCount: {
$size: "$posts"
},
_id: 0
}
}
])
Playground
For mongoose it should be like this in your app:
const profileWithExperiences = await Student.aggregate([
{ $match: { username: res.username.username } },
{
$unwind: "$experience"
},
{
$lookup: {
from: "posts", //the name of the posts collection, change this if it is different
localField: "_id",
foreignField: "username",
as: "posts"
}
},
{
$project: {
username: 1,
posts: 1,
postsCount: {
$size: "$posts"
},
_id: 0
}
}
]);
Try to get like this i am getting data from two table with the use of node and mongodb.
var param = {};
param['user_id']=id;
var search={ user_id:param.user_id,status: [ 'Pending', 'Accepted' ] };
var output={};
output = await JobRequest.find(search);
if(output !=0)
{
var JSon=await JobRequest.aggregate([
{$match: { user_id: {$gte:id}} },
{
"$project": {
"employee_id": {
"$toObjectId": "$employee_id"
},
"service_id": {
"$toObjectId": "$service_id"
},
"createdDate": {
"$toString": "$createdDate"
},
"chat_status": {
"$toString": "$chat_status"
},
"status": {
"$toString": "$status"
},
"delivery_address": {
"$toString": "$delivery_address"
},
"delivery_lat": {
"$toString": "$delivery_lat"
},
"delivery_lang": {
"$toString": "$delivery_lang"
},
}
},
{
$lookup:
{
from: "employees",
localField: "employee_id",
foreignField: "_id",
as: "employee_details"
}
},
{
$lookup:
{
from: "services",
localField: "service_id",
foreignField: "_id",
as: "service_details"
}
}
]);

Populate nested ObjectId

My profile document is saved in my DB as the following:
{
"_id": {
"$oid": "5c3aa1de18ad682fb1444138"
},
"user": {
"$oid": "5c318f56e3224b15e0fdbd06"
},
"company": {
"info": {
"$oid": "5c318f56e3224b15e0fdbd07"
},
"position": "Stemuli"
},
"hometown": "Dallas",
"date": {
"$date": "2019-01-13T02:26:38.185Z"
},
"__v": 0
}
I am trying to populate the field company.info within the newly saved Profile.
new Profile(profileFields).save().then(profile => {
Profile.populate(profile, { path: "company.info" }, (err, p) => {
console.log(err);
console.log(p);
});
});
I get the following returned for the company field
company: {id: "5c318f56e3224b15e0fdbd07", position: "Stemuli"}
And the document that this id is linked to is the following:
{
"_id": {
"$oid": "5c318f56e3224b15e0fdbd07"
},
"employees": [
{
"$oid": "5c318f56e3224b15e0fdbd06"
}
],
"name": "Company",
"__v": 14
}
How can I get it to populate the actual company document instead of just the id?
Profile Schema
// Create Schema
const ProfileSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "users"
},
company: {
id: { type: Schema.Types.ObjectId, ref: "industrypartners" },
position: { type: String }
},
work_experience: Array,
hometown: { type: String },
date: {
type: Date,
default: Date.now
}
});
module.exports = Profile = mongoose.model("profile", ProfileSchema);
Industry Partner Schema
// Create Schema
const IndustryPartnerSchema = new Schema({
name: {
type: String,
required: true
},
schools: [{ type: Schema.Types.ObjectId, ref: "schools" }]
});
module.exports = IndustryPartner = mongoose.model(
"industrypartner",
IndustryPartnerSchema
);
Try with this:
new Profile(profileFields).save().then(profile => {
Profile.populate(Profile, {
path: "company.info",
select: {
_id: 1,
employees: 1,
name: 1,
}
}, (err, p) => {
console.log(err);
console.log(p);
});
});

mongoose populate query doesn't show the desired results

I'm new to MongoDB and Mongoose and I'm having some problems with it, to be more specific I've problems with populate, problem displayed below.
My Schema:
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
/* ------------------------------------- Field config ---------------------------------------- */
const UsersSchema = new Schema({
name: {
type: String,
required: true,
min: 3,
set: str => str.replace(/\b\w/g, l => l.toUpperCase())
},
lastname: {
type: String,
required: true,
min: 3,
set: str => str.replace(/\b\w/g, l => l.toUpperCase())
},
email: {
type: String,
required: true,
unique: true,
validade: {
validator: str => regExp.test(str)
}
},
password: {
type: String,
required: true,
min: 8
},
fcm:{
type: String,
required: true
},
birthDate: {
type: Date,
required: true,
get: convertToBR
},
gender: {
type: String,
enum: ['M', 'F'],
required: true
},
profileImage: {
type: String,
required: false,
get: alterUri
},
aboutMe: {
type: String,
max: 500
},
enabled: {
type: Boolean,
required: true,
default: true
},
createdAt: {
type: Date,
required: true,
default: new Date()
},
token: {
type: String,
required: true,
index: true
},
locations: {
type: [mongoose.Schema.Types.ObjectId],
require: false,
ref: 'Location'
},
lastVisitants: {
type: [{
user: mongoose.Schema.Types.ObjectId,
createAt: {
type: Date,
required: true,
default: new Date()
}
}],
required: false,
ref: 'Users'
}
}, {
toObject: {
virtuals: true,
getters: true,
setters: true
},
toJSON: {
virtuals: true,
getters: true,
setters: true
}
});
//Code bellow removed for make to easy know
Generated doc inside MongoDB:
{
"_id": "589288de533c9555163cf263",
"email": "luiz#sene.com",
"password": "CQziXoB6XrBFBTWe5s/kFsIGYqbtDPBBKQgADUZF9co=",
"name": "luiz Fernando",
"lastname": "Sene",
"birthDate": "1988-08-11T00:00:00.000Z",
"gender": "M",
"fcm": "34567890987654345678",
"token": "58979c08b048917ed8b434ac",
"createdAt": "2017-02-02T01:17:38.168Z",
"enabled": true,
"__v": 0,
"aboutMe": "algo sobre mim aqui mudar",
"locations": [
"5893e2e0c8a01b4ed21c8c39",
"5893e305c8a01b4ed21c8c3a",
"5893e32ac8a01b4ed21c8c3b",
"5893e34dc8a01b4ed21c8c3c",
"5893e92838bd205ba42c2c8a",
"5893ea888628c45d2bc6683a"
],
"profileImage": "images/589288de533c9555163cf263/1486330852976.png",
"lastVisitants": [
{
"createAt": "2017-02-05T19:23:17.697Z",
"_id": "58977ba99fc2b7485dbdbf26",
"user": "589778e22a9dd5449e4f92df"
}
]
}
My problem occurs when I try populate locations and lastVisitants.
My consult is below:
UsersSchema.findOne({_id: data.data.id}, {lastVisitants: true, locations: true})
.populate({
path: 'locations',
model: 'Location',
select: 'description',
options: {
limit: 1,
sort: {
createdAt: -1
}
}
})
.populate({
path: 'lastVisitants.user',
model: 'Users',
select: '_id lastVisitants',
options: {
limit: 5
//TODO: Add sort by createdAt
}
})
.exec((err, result) => {
if (err) {
Utils.callback(err, null, res);
return;
}
Utils.callback(null, result, res);
});
Result of my consult:
{
"_id": "589288de533c9555163cf263",
"lastVisitants": [
{
"_id": "58977c1c9fc2b7485dbdbf27",
"user": {
"_id": "589778e22a9dd5449e4f92df",
"lastVisitants": [
{
"_id": "58977c1c9fc2b7485dbdbf27",
"user": "589288de533c9555163cf263",
"createAt": "2017-02-05T19:23:17.697Z"
}
],
"profileImage": "http://192.168.0.19:3000/undefined",
"birthDate": {
"en": "NaN-NaN-NaN",
"br": "NaN/NaN/NaN"
},
"fullname": "undefined undefined",
"age": null,
"id": "589778e22a9dd5449e4f92df"
},
"createAt": "2017-02-05T19:23:17.697Z"
}
],
"profileImage": "http://192.168.0.19:3000/undefined",
"birthDate": {
"en": "NaN-NaN-NaN",
"br": "NaN/NaN/NaN"
},
"fullname": "undefined undefined",
"age": null,
"id": "589288de533c9555163cf263"
}
Result expected:
{
"_id": "589288de533c9555163cf263",
"locations":[
{
"_id": "5893ea888628c45d2bc6683a",
"description": "Cruzeiro - SP, Brasil"
}
]
"lastVisitants": [
{
_id: ""
user: {
"id": "58977ba99fc2b7485dbdbf26",
"fullname": "Fábio Pereira",
"profileImage": "http://192.168.0.19:3000/images/589288de533c9555163cf263/1486319528451.jpeg",
"gender": "M",
// more fields ...
},
createdAt: ""
}
]
}
My question is how can I make this query bring what I really desire?