Populate nested ObjectId - mongodb

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);
});
});

Related

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 a document based on a field within a referenced subdocument with Mongoose

Having two models: Supplier and SupplierType - the supplier_type field on the Supplier model holds an ObjectId reference to the relevant supplier_type document.
I need to retrieve all Suppliers where Supplier.supplier_type.name is "Bakers"
Supplier schema (trimmed for brevity):
const supplierSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 255,
},
...
supplier_type: { type: ObjectId, ref: 'SupplierType' },
});
Supplier Type schema:
const supplierTypeSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 50,
},
...
});
A typical Supplier document - where Supplier.supplier_type.populate() has been used:
{
...
"_id": "5e9604d45c18767097e00059",
"name": "Benny's",
"supplier_type": {
"suppliers": [
"5e9604d45c18767097e00059"
],
"_id": "5e8f7e2eca14f14e36785b8d",
"name": "Bakers",
"createdAt": "2020-04-09T19:57:34.731Z",
"updatedAt": "2020-04-14T18:48:21.853Z",
"__v": 0
},
...
},
Query:
const supplier = await SupplierType.aggregate([
{
$match: {
name: 'Bakers',
},
},
{
$lookup: {
from: 'supplier',
localField: 'pk',
foreignField: 'id',
as: 'supplier',
},
},
{
$project: {
supplier: 1,
},
},
])
console.log('LOG: Supplier: ', supplier);
if (!supplier) return res.status(404).send({ error: 'Supplier not found', code: 609 });
res.send({ data: supplier });
Returns:
{
"data": [
{
"_id": "5e8f7e2eca14f14e36785b8d",
"supplier": []
}
]
}

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"
}
}
]);

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

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
}

Query embedded document in mongoDB

I'm trying to query a Group document that has Users sub documents.
But I only want the subdocuments that belong to the user,
but I'm also getting data of other users.
Look at the query result, UserStatus field, only one of them belongs to the user.
The query result -
[
{
"_id": "5b1bcc12d5cdbf2cf78f2133",
"name": "First group ever",
"users": [
{
userId: 1,
"userStatus": "I"
},
{
userId: 2,
"userStatus": "I"
}
]
}
]
Group.js -
const GroupSchema = mongoose.Schema({
name: {
type: String,
required: true
},
users: [{
userId: {
type: mongoose.SchemaTypes.ObjectId,
ref: 'users',
required: true
},
userStatus: {
type: String,
required: true
}
}]
})
Query -
Group.find({
"users": {
$elemMatch: {
userId: req.params.id,
$or: [{
userStatus: "I"
}, {
userStatus: "A"
}]
}
}
}, "_id name users.userStatus",
function (err, groups) {
if (err)
res.send(err)
res.json(groups);
});