I'm trying to find all the objects with type==1 (works already) and, then check duplicates from email addresses. (not working)
Output would be something like this:
[ { _id:
{ id: 59d0e3f728150e39b008013f,
firstName: 'pera',
lastName: 'pekko',
phone: '04040404040',
massageType: 'jipii massage',
time: 45,
price: 30,
startsAt: '2017-10-02T11:00:00+03:00',
endsAt: '2017-10-02T11:45:00+03:00' },
email: [ 'gg#gmail.com' ],
{ _id:
{ id: 59ce25975f4d1a096cdd2733,
firstName: 'sdad',
lastName: 'autismus',
phone: '04040404040',
massageType: 'jipii massage',
time: 60,
price: 33,
startsAt: '2017-10-02T12:45:00+03:00',
endsAt: '2017-10-02T13:45:00+03:00' },
email: [ 'YES#hotmail.com' ]
}]
So basically it would check duplicate "email"-values. If there is a duplicate value --> remove WHOLE object from result.
My code so far (result prints all type==1 objects WITH duplicates):
db3.massagerTimes.aggregate(
{$match: {_id: mongo.helper.toObjectID(data.timesData)}},
{$unwind: "$times"},
{$match: {"times.type": 1}},
{
$group: {
_id: {
id: "$times._id",
firstName: "$times.firstName",
lastName: "$times.lastName",
phone: "$times.phone",
massageType: "$times.massageType",
time: "$times.time",
price: "$times.price",
startsAt: "$times.startsAt",
endsAt: "$times.endsAt"
},
email: {$addToSet: "$times.email"},
count: {"$sum": 1}
}
},
{
$match: {
count: {"$lte": 1}
}
},
{$sort: {"times._id": -1}},
function (err, result) {
if (err)
throw err;
if (result) {
console.log(result);
res.json(result);
}
});
}
Collection:
{
"_id": {
"$oid": "59ca4eb610b3be1f8499f6d5"
},
"times": [
{
"_id": {
"$oid": "59ce274f5f4d1a096cdd2745"
},
"type": 0,
"startsAt": "2017-10-02 13:30 +03:00",
"endsAt": "2017-10-02 13:45 +03:00"
},
{
"_id": {
"$oid": "59ce274f5f4d1a096cdd2744"
},
"type": 0,
"startsAt": "2017-10-02 13:15 +03:00",
"endsAt": "2017-10-02 13:30 +03:00"
},
{
"_id": {
"$oid": "59ce28415f4d1a096cdd275b"
},
"title": "sdad autismus",
"firstName": "sdad",
"lastName": "autismus",
"type": 1,
"email": "YES#hotmail.com",
"phone": "04040404040",
"massageType": "jipii massage",
"time": 45,
"price": 30,
"additionalInfo": null,
"startsAt": "2017-10-01T08:30:00+03:00",
"endsAt": "2017-10-01T09:15:00+03:00"
},
{
"_id": {
"$oid": "59ce28665f4d1a096cdd275e"
},
"title": "sdad autismus",
"firstName": "sdad",
"lastName": "autismus",
"type": 1,
"email": "YES#hotmail.com",
"phone": "04040404040",
"massageType": "jipii massage",
"time": 45,
"price": 30,
"additionalInfo": null,
"startsAt": "2017-10-01T09:30:00+03:00",
"endsAt": "2017-10-01T10:15:00+03:00"
},
{
"_id": {
"$oid": "59d0e3f728150e39b008013f"
},
"title": "pera pekko",
"firstName": "pera",
"lastName": "pekko",
"type": 1,
"email": "gg#gmail.com",
"phone": "04040404040",
"massageType": "some massage",
"time": 45,
"price": 30,
"additionalInfo": null,
"startsAt": "2017-10-02T11:00:00+03:00",
"endsAt": "2017-10-02T11:45:00+03:00"
}
]
}
Question: How I check duplicates from value and then drop it from results?
(in this case YES#hotmail.com <-- 2x, remove duplicate object, not just the duplicate value)
The core of what you need would be something like that:
db3.massagerTimes.aggregate({
$unwind: "$times"
}, {
$group: {
_id: "$times.email", // group all items with the same email together
doc: {$first: "$$ROOT"} // keep only the first document for each email address
}
}, {
$replaceRoot: {
newRoot: "$doc" // move the element we remembered during the grouping stage to the top of our document
}
});
Related
With given query I also want to return productId.
I have collection comments that contains documents with data about productId and comments for given product
Example document in this collection:
{
"_id": {
"$oid": "635ee64f55460d1796447662"
},
"productId": "63413800d36ed477adc763d0",
"__v": 0,
"comments": [
{
"userId": "",
"userName": "test",
"date": "2022.12.18.21.51.36",
"confirmed": false,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 6,
"description": "testtesttest"
},
"image": {
"added": false,
"images": []
},
"_id": {
"$oid": "639f7d58b6206a863c4a7aba"
},
"usersWhoLiked": []
},
{
"userId": "",
"userName": "test",
"date": "2022.12.18.21.52.19",
"confirmed": false,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 6,
"description": "testtesttest"
},
"image": {
"added": true,
"images": [
"comments/63413800d36ed477adc763d0/639f7d83b6206a863c4a7ad6/dell.jpg"
]
},
"_id": {
"$oid": "639f7d83b6206a863c4a7ad6"
},
"usersWhoLiked": []
}
]
}
My exmaple query:
db.comments.aggregate([{$match: {"comments._id": {$in: [ObjectId('630b7868f51e10876223b4aa'), ObjectId('630bd277f919a9e9c0e7a559')]}}},
{$project: {comment: {$filter: {input: "$comments", as: "comment", cond: {$in: ["$$comment._id", [ObjectId("630b7868f51e10876223b4aa"), ObjectId("630bd277f919a9e9c0e7a559")]]}}}}}])
With this query I get the result :
{ _id: ObjectId("630b7868f51e10876223b4a6"),
comment:
[ { userId: '62f29c2c324f4778dff443f6',
userName: 'User',
date: '2022.08.19',
confirmed: false,
likes: { up: 3, down: 0 },
content: { rating: 4, description: 'Super laptop <3' },
_id: ObjectId("630b7868f51e10876223b4aa"),
usersWhoLiked:
[ { userId: '62f29c2c324f4778dff443f6',
likeUp: true,
_id: ObjectId("630d2b0494370efb37107983") },
{ userId: '6322434f2b5bbac87f0e7aba',
likeUp: true,
_id: ObjectId("632243702b5bbac87f0e7afa") },
{ userId: '62f2991e324f4778dff443d4',
likeUp: true,
_id: ObjectId("63af4d77c8991b74d6986995") } ] } ] }
{ _id: ObjectId("630bd277f919a9e9c0e7a555"),
comment:
[ { userId: '62f29c2c324f4778dff443f6',
userName: 'User',
date: '2022.08.28',
confirmed: false,
likes: { up: 1, down: 1 },
content:
{ rating: 6,
description: 'Laptop posiada przyjemna klawiature, nie grzeje siÄ™. Do codziennego grania wystarczy.' },
_id: ObjectId("630bd277f919a9e9c0e7a559"),
usersWhoLiked:
[ { userId: '62f29c2c324f4778dff443f6',
likeUp: true,
_id: ObjectId("630d2dfc94370efb37107991") },
{ userId: '62fa2549f029348f75bc9c81',
likeUp: false,
_id: ObjectId("631241fe755c641525dc9cfa") } ] } ] }
As you see in the result, the productId is missing.
I was trying to rebuild query with #group operator but still with out effect...
So my questsion is:
How shall I rewrite that query to get the same result but with productId in it for each returned comment
This is how $project works, if a field is not specified will not be output.
So just add productId: 1 into the $project stage and it will be shown.
Check this example.
I'm a beginner trying to create an API using express ang mongodb and this is my first time posting a question here, so forgive me if my question sounds stupid.
I have this data:
Restaurants
[
{
"_id": "630c0d5e82d52d0852d34b11",
"name": "Restaurant 1",
"type": "Fine Dining",
"cuisine": "Korean",
},
{
"_id": "630c0d5e82d52d0852d34b12",
"name": "Restaurant 2",
"type": "Fine Dining",
"cuisine": "International",
},
{
"_id": "630c0d5e82d52d0852d34b13",
"name": "Restaurant 3",
"type": "Casual Dining",
"cuisine": "Korean",
},
{
"_id": "630c0d5e82d52d0852d34b14",
"name": "Restaurant 4",
"type": "Casual Dining",
"cuisine": "International",
},
...
]
so what I want to achieve is when I create a GET request to this API endpoint http://localhost:8000/api/v1/restaurants/stats is this:
{
"status": "success",
"data": {
"cuisines": [
{
"_id": "Korean",
"restaurants": ["630c0d5e82d52d0852d34b11", "630c0d5e82d52d0852d34b13"],
"quantity": 2
},
{
"_id": "International",
"restaurants": ["630c0d5e82d52d0852d34b12", "630c0d5e82d52d0852d34b14"],
"quantity": 2
}
],
"type": [
{
"_id": "Casual Dining",
"restaurants": ["630c0d5e82d52d0852d34b14", "630c0d5e82d52d0852d34b13"],
"quantity": 2
},
{
"_id": "Fine Dining",
"restaurants": ["630c0d5e82d52d0852d34b11", "630c0d5e82d52d0852d34b12"],
"quantity": 2
}
]
}
}
This is what I have tried so far
restaurantController.js
...
exports.getRestaurantStats = async (req, res) => {
const cuisines = await Restaurant.aggregate([
{
$group: {
_id: '$cuisine',
restaurants: { $push: '$_id' },
quantity: { $sum: 1 },
}
},
]);
res.status(200).json({
status: 'success',
data: {
cuisines,
},
});
};
...
restaurantRoutes.js
...
router.route('/stats').get(restaurantController.getRestaurantStats);
...
The result for calling this endpoint http://localhost:8000/api/v1/restaurants/stats
{
"status": "success",
"data": {
"cuisines": [
{
"_id": "Korean",
"restaurants": ["630c0d5e82d52d0852d34b11", "630c0d5e82d52d0852d34b13"],
"quantity": 2
},
{
"_id": "International",
"restaurants": ["630c0d5e82d52d0852d34b12", "630c0d5e82d52d0852d34b14"],
"quantity": 2
}
]
}
But when I add this another group by
...
$group: {
_id: '$type',
restaurants: { $push: '$_id' },
quantity: { $sum: 1 },
}
...
to restaurantController.js
...
exports.getRestaurantStats = async (req, res) => {
const cuisines = await Restaurant.aggregate([
{
$group: {
_id: '$cuisine',
restaurants: { $push: '$_id' },
quantity: { $sum: 1 },
},
$group: {
_id: '$type',
restaurants: { $push: '$_id' },
quantity: { $sum: 1 },
}
},
]);
res.status(200).json({
status: 'success',
data: {
cuisines,
},
});
};
...
the result is different. Its seems like it overwrote the first group by in the pipeline.
What i want to do is find out which post i have reacted to and return true or false as below result i expect. i know about aggregation in mongodb but i don't know how it works yet. If anyone has study material about it, please comment. thank you.
// user model
{
"_id": "62d0d2e8306367e5162b9c4e",
"fullname": "string",
"username": "string",
"avatar": "string",
"bio": "string",
"tick": true,
"followings_count": 55,
"followers_count": 5,
"likes_count": 0,
"website_url": "",
"social_network": [],
"created_at": "2022-07-15T02:37:28.565Z",
"updated_at": "2022-08-23T08:23:16.611Z",
"__v": 0
}
// post model
{
"_id": "62f0ad6cca2731b7a851b5a5",
"contents": ":>>",
"media_url": "string",
"reaction_count": 1,
"view_count": 0,
"category_id": [],
"created_at": "2022-08-08T06:30:04.137Z",
"updated_at": "2022-08-24T04:10:33.944Z",
"__v": 0,
"comment_count": 9
}
// post_reaction model
{
"user_id": "62d0d2e8306367e5162b9c4e",
"post_id":"62f0ad6cca2731b7a851b5a5",
"type": "Like",
}
This is the result i expect:
{
"data": {
"user": {
"_id": "62d0d2e8306367e5162b9c4e",
...
},
"post": [
{
"_id": "62f0ad6cca2731b7a851b5a5",
...
"is_reaction": true(false)),
},
...
]
}
I found the way resolve this issues:
const result = await PostModel.aggregate([
{
$match: { user_id: ObjectUserId },
},
{
$lookup: {
from: 'post_reaction',
localField: '_id',
foreignField: 'post_id',
as: 'isReaction',
},
},
{
$project: {
_id: 1,
contents: 1,
media_url: 1,
reaction_count: 1,
view_count: 1,
category_id: 1,
created_at: 1,
updated_at: 1,
comment_count: 1,
isReaction: {
$filter: {
input: '$isReaction',
cond: {
$eq: ['$$this.user_id', ObjectUserId],
},
},
},
},
},
{ $sort: { _id: -1 } },
]);
I have a Log collection that is meant to give stats on daily records
[
{
"_id": "5ee4f58be451502a40fb2a83",
"name": "Cement",
"description": "Construction",
"price": 1400,
"quantity": 30,
"quantitySold": -5,
"itemDestination": "Trocadero",
"createdAt": "2020-06-13T15:49:32.684Z",
"updatedAt": "2020-06-13T15:49:32.684Z",
"__v": 0
},
{
"_id": "5eddea221bab5221e4ee2238",
"name": "Pop",
"description": "Construction",
"price": 500,
"quantity": 19,
"quantitySold": -5,
"itemDestination": "Amore",
"createdAt": "2020-06-08T07:34:58.569Z",
"updatedAt": "2020-06-08T07:34:58.569Z",
"__v": 0
},
{
"_id": "5edde9f51bab5221e4ee2237",
"name": "Pop",
"description": "Construction",
"price": 500,
"quantity": 24,
"quantitySold": -6,
"itemDestination": "Trocadero",
"createdAt": "2020-06-08T07:34:13.700Z",
"updatedAt": "2020-06-08T07:34:13.700Z",
"__v": 0
}
]
I would like to get daily records of totalQuantitySold and daily average of quantitySold. But was only able to do the following
//logcontroller.js
Log.aggregate([
{
$group:
{
_id: "$name",
totalAmountSold:{$sum:"$quantitySold" },
avgQuantitySold: { $avg: "$quantitySold" },
}
},
])
output :
{
"results": [
{
"_id": "Cement",
"totalQuantitySold": -5,
"avgQuantitySold": -5
},
{
"_id": "Pop",
"totalQuantitySold": -11,
"avgQuantitySold": -5.5
}
]
}
However, i have the challenge of extracting these stats based on daily entries... would appreciate if anyone can help out. here is my log schema:
{
// _id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
quantity: { type: Number, required: true },
quantitySold: { type: Number, required: true },
supplier: String,
taxable: Boolean,
itemDest: String,
},
{ timestamps: true }
);
// Create model from the schema
const Log = mongoose.model('Log', LogSchema);
// Export model
module.exports = Log;
You need to include date in your grouping key. Since you have ISODate stored as createdAt/updatedAt you can use $dateToString to convert date + into into Y-m-d format:
Log.aggregate([
{
$group: {
_id: { name: "$name", day: { $dateToString: { format: "%Y-%m-%d", date: "$updatedAt" } } },
totalAmountSold:{$sum:"$quantitySold" },
avgQuantitySold: { $avg: "$quantitySold" }
}
},
])
You can also remove the name part from _id if you need to filter by date only.
Mongo Playground
I have a collection with objects like this:
{
"_id": ObjectId("52ed12c144aecc4bf004d0b6"),
"title": "myBook",
"summary": "This is a book summary",
"chapters": [
{
"number": 1
"created_at": ISODate("2013-12-17T23:00:00Z")
},
{
"number": 2
"created_at": ISODate("2014-12-17T23:00:00Z")
}
]
"covers": [
"http://url.com/cover1.jpg",
"http://url.com/cover2.jpg",
],
"urls": [
"http://url.com/myBook",
"http://url.com/myBook/option2"
],
"genres": [
"comedy",
"romantic"
],
"created_at": ISODate("2012-12-17T23:00:00Z"),
"modify_at": ISODate("2014-02-01T15:41:48.149Z")
}
I only want to get books which 'crated_at' >= '2012-12-17T23:00:00Z' with only the chapters which 'created_at' > "2013-12-17T23:00:00Z". (As a filter)
My output json should be something like this:
{
"_id": ObjectId("52ed12c144aecc4bf004d0b6"),
"title": "myBook",
"summary": "This is a book summary",
"chapters": [
{
"number": 2
"created_at": ISODate("2014-12-17T23:00:00Z")
}
]
"covers": [
"http://url.com/cover1.jpg",
"http://url.com/cover2.jpg",
],
"urls": [
"http://url.com/myBook",
"http://url.com/myBook/option2"
],
"genres": [
"comedy",
"romantic"
],
"created_at": ISODate("2012-12-17T23:00:00Z"),
"modify_at": ISODate("2014-02-01T15:41:48.149Z")
}
In the query output could be books without any chapters, others with a subset of all their chapters or books with all their chapters.
For to search books by 'created_at' I query by:
db.books.find({ created_at: {$gte: ISODate("2012-12-17T23:00:00Z")} })
but I don't know what I have to add for to filter the chapters in the output of this result.
You could try to do it with aggregation framework.
db.chapters.aggregate(
{ $match: { created_at: {$gte: ISODate("2012-12-17T23:00:00Z")} } },
{ $unwind: "$chapters" },
{ $match: { "chapters.created_at": {$gte: ISODate("2013-12-17T23:00:00Z")} } },
{ $group:
{
_id:
{
id: "$_id",
title: "$title",
summary: "$summary",
covers: "$covers",
urls: "$urls",
genres: "$genres",
created_at: "$created_at",
modify_at: "$modify_at"
},
chapters: { $push: "$chapters" }
}
},
{ $project:
{
_id: "$_id.id",
title: "$_id.title",
summary: "$_id.summary",
chapters: "$chapters",
covers: "$_id.covers",
urls: "$_id.urls",
genres: "$_id.genres",
created_at: "$_id.created_at",
modify_at: "$_id.modify_at"
}
}
)