I'm using node, express, mongoose for my back-end. I created User schema as follows,
const mongoose = require('mongoose');
const addressSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
no: { type: String },
firstStreet: { type: String },
secondStreet: { type: String },
city: { type: String, required: true },
district: { type: String }
})
const contactDetailsSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
landNumber: { type: String },
mobileNumber: { type: String },
momNumber: { type: String },
dadNumber: { type: String },
gardianNumber: { type: String }
})
const userSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
email: {
type: String,
required: true,
unique:true,
lowercase: true,
match: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/
},
password: { type: String, required: true },
role: { type: String, required: true },
fullName: { type: String, required: true },
batch: { type: Number, required: true },
subject: [{
type: String
}],
school: { type: String, required: true },
birthday: { type: String },
address: { type: mongoose.Schema.Types.ObjectId, ref:'User' },
contactDetails: { type: mongoose.Schema.Types.ObjectId, ref:'User' },
stream: { type: String },
});
module.exports = {
user: mongoose.model('User', userSchema),
address: mongoose.model('Address', addressSchema),
contactDetails: mongoose.model('ContactDetails', contactDetailsSchema)
};
and I created a GET route to retrieve data from all users. I store these data in three separate mongoDB collections with same _id. And I want to get those all User data.
my User GET route is like this,
const userModels = require('../models/user');
const User = userModels.user;
const Address = userModels.address;
const ContactDetails = userModels.contactDetails;
router.get('/', (req, res) =>{
User
.find()
.exec()
.then(docs => {
console.log(docs);
const responce1 = {
count: docs.length,
Users: docs.map(doc => {
return {
Message: 'User Details',
Id: doc._id,
Email: doc.email,
Role: doc.role,
Full_Name: doc.fullName,
Batch: doc.batch,
Subject: doc.subject,
School: doc.school,
Birthday: doc.birthday,
Stream: doc.stream,
request: {
type: 'get',
url: 'http://localhost:3000/user/' +doc._id
}
}
})
}
Address
.find()
.exec()
.then(docs => {
console.log(docs)
responce2 = {
count: docs.length,
Address: docs.map(doc => {
return {
Message: 'Address',
_id: doc._id,
Address: doc.city,
First_Street: doc.firstStreet,
Second_Street: doc.secondStreet,
city: doc.city,
District: doc.district,
}
})
}
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
ContactDetails
.find()
.exec()
.then(docs => {
console.log(docs)
responce3 = {
count: docs.length,
ContactDetails: docs.map(doc => {
return {
Message: 'Contact Details',
_id: doc._id,
Land_Number: doc.landNumber,
Mobile_Number: doc.mobileNumber,
Mom_Number: doc.momNumber,
Dad_Number: doc.dadNumber,
Gardian_Number: doc.gardianNumber,
}
})
}
res.status(200).json([responce1,responce2,responce3]);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
I get data like this,
[
{
"count": 3,
"Users": [
{
"Message": "User Details",
"Id": "5b8e68fb9c898543b4970628",
"Email": "new2#gmail.com",
"Role": "student",
"Full_Name": "Dinusha",
"Batch": 16,
"Subject": [
"ICT"
],
"School": "School",
"Birthday": "1996/10/23",
"Stream": "English",
"request": {
"type": "get",
"url": "http://localhost:3000/user/5b8e68fb9c898543b4970628"
}
},
{
"Message": "User Details",
"Id": "5b8e68fd9c898543b4970629",
"Email": "new3#gmail.com",
"Role": "student",
"Full_Name": "Dinusha",
"Batch": 16,
"Subject": [
"ICT"
],
"School": "School",
"Birthday": "1996/10/23",
"Stream": "English",
"request": {
"type": "get",
"url": "http://localhost:3000/user/5b8e68fd9c898543b4970629"
}
},
{
"Message": "User Details",
"Id": "5b8f52e707c299266c0a6b97",
"Email": "new4#gmail.com",
"Role": "student",
"Full_Name": "Dinusha",
"Batch": 16,
"Subject": [
"ICT"
],
"School": "School",
"Birthday": "1996/10/23",
"Stream": "English",
"request": {
"type": "get",
"url": "http://localhost:3000/user/5b8f52e707c299266c0a6b97"
}
}
]
},
{
"count": 3,
"Address": [
{
"Message": "Address",
"_id": "5b8e68fb9c898543b4970628",
"Address": "city",
"city": "city",
"District": "rathnapura"
},
{
"Message": "Address",
"_id": "5b8e68fd9c898543b4970629",
"Address": "city",
"city": "city",
"District": "rathnapura"
},
{
"Message": "Address",
"_id": "5b8f52e707c299266c0a6b97",
"Address": "city",
"city": "city",
"District": "rathnapura"
}
]
},
{
"count": 3,
"ContactDetails": [
{
"Message": "Contact Details",
"_id": "5b8e68fb9c898543b4970628",
"Land_Number": "072846",
"Mobile_Number": "7368438",
"Mom_Number": "7364738",
"Dad_Number": "648364"
},
{
"Message": "Contact Details",
"_id": "5b8e68fd9c898543b4970629",
"Land_Number": "072846",
"Mobile_Number": "7368438",
"Mom_Number": "7364738",
"Dad_Number": "648364"
},
{
"Message": "Contact Details",
"_id": "5b8f52e707c299266c0a6b97",
"Land_Number": "072846",
"Mobile_Number": "7368438",
"Mom_Number": "7364738",
"Dad_Number": "648364"
}
]
}
]
but I need to get data of every User like in this form
[
"Users":
{
"Message": "User Details",
"Id": "5b8e68fb9c898543b4970628",
"Email": "new2#gmail.com",
"Role": "student",
"Full_Name": "Dinusha",
"Batch": 16,
"Subject": [
"ICT"
],
"School": "School",
"Birthday": "1996/10/23",
"Stream": "English",
"request": {
"type": "get",
"url": "http://localhost:3000/user/5b8e68fb9c898543b4970628"
}
},
"Address":
{
"Message": "Address",
"_id": "5b8e68fb9c898543b4970628",
"Address": "city",
"city": "city",
"District": "rathnapura"
},
"ContactDetails":
{
"Message": "Contact Details",
"_id": "5b8e68fb9c898543b4970628",
"Land_Number": "072846",
"Mobile_Number": "7368438",
"Mom_Number": "7364738",
"Dad_Number": "648364"
},
]
can I get those data like that.
how to get data from mongodb as that custom form.
Use aggregate method and $lookup
https://mongoosejs.com/docs/api.html#aggregate_Aggregate-lookup
Related
one collection is carts
[{
"_id": {
"$oid": "633a71cd3a9706174ef57f41"
},
"ProductName": "Natural Blue Sapphire",
"Quantity": 1,
"Price": 20100
},
{
"_id": {
"$oid": "633ae81727e12df99604d9d7"
},
"ProductName": "Natural Blue Sapphire",
"Quantity": 1,
"Price": 20100
}]
`
other collection is orderhistories
`
[{
"_id": {
"$oid": "62f399fc5001311d30680e81"
},
"Address": {
"firstName": "Ronit"
},
"MemberId": {
"$oid": "62e50e29adb262e58ad1f920"
},
"cartItems": [
{
"$oid": "62f399985001311d30680e7e"
}
],
"status": "Delivered"
},{
"_id": {
"$oid": "62ff2b0f0fe010c6e4b0a05d"
},
"Address": {
"firstName": "Ronit"
},
"MemberId": {
"$oid": "62e50e29adb262e58ad1f920"
},
"cartItems": [
{
"$oid": "62f399985001311d30680e7e"
}
],
"status": "Created"
}
`
i want to get cart list using cartItems doc in orderhistories collection
and i am doing this
`
const order = await OrderHistory.find({$or:[{MemberId:Id}] }).sort({"createdAt": -1}).populate('offerCode MemberId cartItems.cart')
res.json(order)
`
my order history model is
`
const orderHistory = new mongoose.Schema({
Address:{
type: mongoose.SchemaTypes.Mixed,
},
MemberId:{
type: mongoose.Schema.Types.ObjectId,
ref:'Member_detail'
},
cartItems:[{
cart:{
type: mongoose.Schema.Types.ObjectId,
ref:'cart'
}
}],
status:{
type:String,
default:"Created"
},
}, {
timestamps: true
})
`
and my cart model schima is
`
const cart_schema = new mongoose.Schema({
Member_Id:{
type: mongoose.Schema.Types.ObjectId,
ref:'Member_detail'
},
ProductId:{
type: mongoose.Schema.Types.ObjectId,
ref:'Product_details'
},
ProductName: {
type: String,
},
status:{type:Number ,
default:1} // 1 = Active 0 = inactive i.e order placed
}, {
timestamps: true
})
`
I need data from carts collection when find ordershistory collection. in orderhistry collection have carts doc. so I need data all data according to id in carts doc
Expected Output
[
{
"_id": "636e73fe398888caca60da16",
"cartItems": [
{
"_id": "6379d76e6274ddb0910f72bc",
"ProductName": "Natural Blue Sapphire",
"Price": 1000,
}
],
"total": 1802.5,
}]
I have two mongoose schema one for keywords :
const keywordSchema = new Schema<keywordI>(
{
sentence: { type: String, required: true },
example: { type: String, required: true },
translate: { type: String, required: true },
imageUrl: { type: String, required: true },
audioUrl: { type: String, required: true },
deletedAt: { type: Date, select: false },
},
{ timestamps: true }
);
and one for keywordsUser :
const keywordUserSchema = new Schema<keywordUserI>(
{
keywordId: {
type: mongoose.Types.ObjectId,
ref: "Keyword",
required: true,
},
userId: {
type: mongoose.Types.ObjectId,
ref: "User",
required: true,
},
isBookMarked: { type: Boolean, default: false },
correctAnswer: { type: Number, default: 0 },
wrongAnswer: { type: Number, default: 0 },
},
{ timestamps: true }
);
I want to get keywords by user grouped by type which I calculate from wrongAnswer and correctAnswer
I try to do this using aggregate
return KeyWordUser.aggregate([
{
$match: { userId },
},
{
$addFields: {
type: {
$function: {
body: getType,
args: ["$correctAnswer", "$wrongAnswer"],
lang: "js",
},
},
},
},
{
$group: {
_id: "$type",
words: {
$push: "$keywordId",
},
isBookMarked: {
$push: { isBookMarked: "$isBookMarked", keywordId: "$keywordId" },
},
},
},
{
$lookup: {
localField: "words",
from: "keywords",
foreignField: "_id",
as: "props",
},
},
{
$addFields: { type: "$_id" },
},
{
$project: {
_id: 0,
words: 0,
},
},
]);
I have this result from aggregate
returned data from. postman
I want to add new aggregate stage to get this result
previous result
[
{
"isBookMarked": [
{
"keywordId": "62e2a0ad3113b8234511cd72"
},
{
"isBookMarked": false,
"keywordId": "62e2a0ba3113b8234511cd74"
}
],
"props": [
{
"_id": "62e2a0ad3113b8234511cd72",
"sentence": "hello",
"example": "Hello , what's your name",
"translate": "مرحبا ما اسمك",
"imageUrl": "src/img/keywords/keyword-A7H_M-1659019437698.png",
"audioUrl": "src/audio/keywords/keyword-YyhUp-1659019437700.mpeg",
"createdAt": "2022-07-28T14:43:57.708Z",
"updatedAt": "2022-07-28T14:43:57.708Z",
"__v": 0
},
{
"_id": "62e2a0ba3113b8234511cd74",
"sentence": "hello 2 ",
"example": "Hello , what's your name 2 ",
"translate": "مرحبا ما اسمك 2",
"imageUrl": "src/img/keywords/keyword-2JO7D-1659019450396.png",
"audioUrl": "src/audio/keywords/keyword-kt5Tc-1659019450397.mpeg",
"createdAt": "2022-07-28T14:44:10.400Z",
"updatedAt": "2022-07-28T14:44:10.400Z",
"__v": 0
}
],
"type": "strong"
}
]
and i want this result :
[
{
"props": [
{
"_id": "62e2a0ad3113b8234511cd72",
"sentence": "hello",
"example": "Hello , what's your name",
"translate": "مرحبا ما اسمك",
"imageUrl": "src/img/keywords/keyword-A7H_M-1659019437698.png",
"audioUrl": "src/audio/keywords/keyword-YyhUp-1659019437700.mpeg",
"createdAt": "2022-07-28T14:43:57.708Z",
"updatedAt": "2022-07-28T14:43:57.708Z",
"__v": 0
},
{
"_id": "62e2a0ba3113b8234511cd74",
"isBookMarked" : false
"sentence": "hello 2 ",
"example": "Hello , what's your name 2 ",
"translate": "مرحبا ما اسمك 2",
"imageUrl": "src/img/keywords/keyword-2JO7D-1659019450396.png",
"audioUrl": "src/audio/keywords/keyword-kt5Tc-1659019450397.mpeg",
"createdAt": "2022-07-28T14:44:10.400Z",
"updatedAt": "2022-07-28T14:44:10.400Z",
"__v": 0
}
],
"type": "strong"
}
]
You can just populate with the keywordId not with aggregate
{
"data": {
"books": [
{
"name": "Himu",
"genre": "novel",
"author": {
"name": "Humayun Ahmed",
"country": "Bangladesh"
}
},
{
"name": "Tatina",
"genre": "novel",
"author": {
"name": "Zafor iqbal",
"country": "Bangladesh"
}
},
{
"name": "Show Me",
"genre": "novel",
"author": {
"name": "Nick Pirog",
"country": "United States"
}
}
]
}
}
I have this data I want to display all the books of authors who live in a specific country
(e.g. all books of all authors living in Bangladesh). I am new to GraphQL and I don't know how to do that. I am using node.js with MongoDB.
const BookType = new GraphQLObjectType({
name: "Book",
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
genre: { type: GraphQLString },
author: {
type: AuthorType,
resolve(parent, args) {
return Author.findById(parent.authorId);
},
},
}),
});
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
books: {
type: new GraphQLList(BookType),
resolve(parent, args) {
return Book.find({});
},
},
},
});
I am building a chat app based on the MERN stack and need to fetch all chats for a specific user.
This is my chat messages schema:
const message = mongoose.Schema({
from: {
type: Schema.Types.ObjectId,
ref: "users",
required: true,
},
to: {
type: Schema.Types.ObjectId,
ref: "users",
required: true,
},
text: { type: String, required: false },
imgLink: { type: String, required: false },
sentAt: { type: Date, required: true },
deliveredAt: { type: Date, required: false },
readAt: { type: Date, required: false },
});
Is there a way to fetch all chats for a user and group them by who sent/recieved these chats.
I used this aggregation pipeline
const fetchChatPipeline = (_id) => {
return [
{
$match: {
$or: [
{
to: mongoose.Types.ObjectId(_id),
},
{
from: mongoose.Types.ObjectId(_id),
},
],
},
},
{
$sort: {
sentAt: 1,
},
},
{
$group: {
_id: "$from",
from: { $first: "$from" },
to: { $first: "$to" },
messages: {
$push: {
text: "$text",
imgLink: "$imgLink",
sentAt: "$sentAt",
deliveredAt: "$deliveredAt",
readAt: "$readAt",
},
},
},
},
{
$lookup: {
from: "users",
localField: "from",
foreignField: "_id",
as: "from",
},
},
{
$unwind: {
path: "$from",
preserveNullAndEmptyArrays: false,
},
},
{
$lookup: {
from: "users",
localField: "to",
foreignField: "_id",
as: "to",
},
},
{
$unwind: {
path: "$to",
preserveNullAndEmptyArrays: false,
},
},
{
$project: {
to: {
_id: 1,
name: 1,
},
from: {
_id: 1,
name: 1,
},
messages: 1,
},
},
];
};
and got the following result:
{
"chats": [
{
"_id": "60368ee8a4e8494c74ccbeec",
"from": {
"_id": "60368ee8a4e8494c74ccbeec",
"name": "Jaivardhan Singh"
},
"to": {
"_id": "603a637ab356a309dcca9099",
"name": "Jai Singh "
},
"messages": [
{
"text": "hello",
"sentAt": "2021-02-27T16:33:40.335Z"
},
{
"text": "What you upto",
"sentAt": "2021-02-27T16:34:16.852Z"
}
]
},
{
"_id": "603a637ab356a309dcca9099",
"from": {
"_id": "603a637ab356a309dcca9099",
"name": "Jai Singh "
},
"to": {
"_id": "60368ee8a4e8494c74ccbeec",
"name": "Jaivardhan Singh"
},
"messages": [
{
"text": "Hi",
"sentAt": "2021-02-27T16:35:32.343Z"
},
{
"text": "Nothing just chilling",
"sentAt": "2021-02-27T16:35:41.720Z"
},
{
"text": "What you upto",
"sentAt": "2021-02-27T16:35:49.662Z"
}
]
}
]
}
Is there a way i can merge these two chats in the results as they have common participants. Thanks.
Just change your $match stage as below and $group it by null
{
$match: {
$or: [
{ to: mongoose.Types.ObjectId(_id) },
{ from: mongoose.Types.ObjectId(_id) }
],
to: { $ne: mongoose.Types.ObjectId(_id) }
}
}
I am use NodeJS, ExpressJS with Mongoose Mongo ORM.
My Schema is as follows.
const chatMessageSchema = new Schema({
_id: {
type: String,
default: () => (uuidV1().replace(/-/g, ''))
},
roomid: String,
message: Schema.Types.Mixed,
type: String, // text, card, qrt, attachment
notes: [notesSchema],
posted_by_user: String,
}, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at'
},
collection: 'ChatMessages'
});
The nested sub schema for notes is as follows;
const notesSchema = new Schema({
_id: {
type: String,
default: () => (uuidV1().replace(/-/g, ''))
},
roomid: String,
messageid: String,
message: Schema.Types.Mixed,
type: String, // text, attachment
posted_by_user: String,
}, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at'
}});
Initially when a user creates a chatMessage the notes is default kept as an empty array initially [].
The user can explicitly create a note message after the message has been created, the notes is an array sub documents.
Now what happens is when I get a list of messages. I need to show posted_by_user which is an id of string. Against that id of string i perform a $lookup which gets the user profile. The aggregation is as follows.
return this.aggregate([
{ $match : {roomid: roomid} },
{ $sort: {created_at: -1} },
{
$lookup: {
from: "RefUserProfiles",
localField: "posted_by_user",
foreignField: "_id",
as: "posted_by_user"
}
},
{ $unwind: "$posted_by_user" },
{ $skip: pageOptions.page * pageOptions.limit },
{ $limit: pageOptions.limit },
{ $sort: {created_at: 1} },
{
$unwind: { path: "$notes", preserveNullAndEmptyArrays: true }
},
{
$lookup: {
from: "RefUserProfiles",
localField: "notes.posted_by_user",
foreignField: "_id",
as: "notes.posted_by_user"
}
},
{
$unwind: { path: "$notes.posted_by_user", preserveNullAndEmptyArrays: true }
},
{
$group: {
_id: "$_id",
created_at: { $last: "$created_at" },
roomid: { $last: "$roomid" },
message: { $last: "$message" },
notes: { $addToSet: "$notes" },
type: { $last: "$type" },
posted_by_user: { $last: "$posted_by_user" },
read_by_recipients: { $last: "$read_by_recipients" },
}
}
]);
Now since in some cases the notes for some messages is an empty array, so for that very particular case the object I get in responses is like [{}]. Is this how it is suppose to be. or is there a better use case involved.
For example the response I get based on this query is as follows.
"conversation": [
{
"_id": "7cdbf630e6ec11e79166559abfb987ac",
"created_at": "2017-12-22T07:48:23.956Z",
"roomid": "aacc6b70e68211e79166559abfb987ac",
"message": {
"text": "message 1"
},
"notes": [{}],
"type": "text",
"posted_by_user": {
"id": "4d6fd5a95d57436d944586a1d5b2b2ff",
"name": "Adeel Imran",
"profilePicture": "",
"phone": "",
"email": "",
"designation": "",
"type": "user"
},
},
{
"_id": "80d91470e6ec11e79166559abfb987ac",
"created_at": "2017-12-22T07:48:30.648Z",
"roomid": "aacc6b70e68211e79166559abfb987ac",
"message": {
"text": "message 4"
},
"notes": [
{
"posted_by_user": {
"id": "86049b3d28f640a8a6722c57b73a292e",
"name": "Paul Johnson",
"profilePicture": "",
"phone": "",
"email": "",
"designation": "",
"type": "sp"
},
"type": "text",
"message": {
"text": "yeah "
},
"messageid": "26401d30e5a511e7acc4c734d11adb25",
"roomid": "27d3ed80e0cc11e78318b3cd036890f2",
"updated_at": "2017-12-20T16:45:44.132Z",
"created_at": "2017-12-20T16:45:44.132Z",
"_id": "38ad3750e5a511e7acc4c734d11adb25"
}
],
"type": "text",
"posted_by_user": {
"id": "4d6fd5a95d57436d944586a1d5b2b2ff",
"name": "Adeel Imran",
"profilePicture":"",
"phone": "",
"email": "",
"designation": "",
"type": "user"
},
}
],
Any suggestions or directions for this will be highly appreciated. Thank you for taking the time out to review this question.
Cheers.