Mongoose sort and get only one per field - node.js

I need to get a list of item using the mongoose, however, i need select only one item of any type (i've 5 possible values), and always the last inserted item of this type.
for example, to the list below, not ordered (i know, here it's ordered).
[
{
"_id": "5b226abab64b2309de01bfd5",
"documentType": "type3",
"createdAt": "2018-06-14T13:16:42.321Z"
},
{
"_id": "5b226a5da93b0e09b8aee447",
"documentType": "type3",
"createdAt": "2018-06-14T13:15:09.458Z"
},
{
"_id": "5b226a21f454d6097ffa461c",
"documentType": "type2",
"createdAt": "2018-06-14T13:14:09.159Z"
},
{
"_id": "5b2267fb445d7709590e1695",
"documentType": "type1",
"createdAt": "2018-06-14T13:04:59.742Z"
},
{
"_id": "5b2267de76708b094696b0fe",
"documentType": "type3",
"createdAt": "2018-06-14T13:04:30.349Z"
},
{
"_id": "5b2267ce2f3724092b1a14a3",
"documentType": "type2",
"createdAt": "2018-06-14T13:04:14.410Z"
},
{
"_id": "5b2267a92f3724092b1a14a2",
"documentType": "type4",
"createdAt": "2018-06-14T13:03:37.079Z"
},
{
"_id": "5b22647b63017e08a69a3043",
"documentType": "type5",
"createdAt": "2018-06-14T12:50:03.999Z"
},
{
"_id": "5b2264471778a20880d4ba64",
"documentType": "type5",
"createdAt": "2018-06-14T12:49:11.773Z"
}
]
the expected result is something like this:
[
{
"_id": "5b226abab64b2309de01bfd5",
"documentType": "type3",
"createdAt": "2018-06-14T13:16:42.321Z"
},
{
"_id": "5b226a21f454d6097ffa461c",
"documentType": "type2",
"createdAt": "2018-06-14T13:14:09.159Z"
},
{
"_id": "5b2267fb445d7709590e1695",
"documentType": "type1",
"createdAt": "2018-06-14T13:04:59.742Z"
},
{
"_id": "5b2267a92f3724092b1a14a2",
"documentType": "type4",
"createdAt": "2018-06-14T13:03:37.079Z"
},
{
"_id": "5b22647b63017e08a69a3043",
"documentType": "type5",
"createdAt": "2018-06-14T12:50:03.999Z"
}
]
Basicly only one per type, sort desc by id
How can i do this?

You can use $group by in mongodb to distinct the documentType
db.collection.aggregate([
{ "$group": {
"_id": "$documentType",
"createdAt": { "$first": "$createdAt" },
"id": { "$first": "$_id" }
}},
{ "$project": {
"_id": "$id",
"createdAt": 1,
"documentType": "$_id"
}}
])
The output will be
[
{
"_id": "5b226abab64b2309de01bfd5",
"createdAt": "2018-06-14T13:16:42.321Z",
"documentType": "type3"
},
{
"_id": "5b2267fb445d7709590e1695",
"createdAt": "2018-06-14T13:04:59.742Z",
"documentType": "type1"
},
{
"_id": "5b22647b63017e08a69a3043",
"createdAt": "2018-06-14T12:50:03.999Z",
"documentType": "type5"
},
{
"_id": "5b2267a92f3724092b1a14a2",
"createdAt": "2018-06-14T13:03:37.079Z",
"documentType": "type4"
},
{
"_id": "5b226a21f454d6097ffa461c",
"createdAt": "2018-06-14T13:14:09.159Z",
"documentType": "type2"
}
]

Related

How to set up aggregation pipeline for specific use case in MongoDB

`I have two collections in MongoDB. One is users and the other is companies. I need to be able to populate the users.endpoints with the endpoints from companies that match ObjectID's which are in the user.endPoints property. It is a bit hard for me to wrap my head around considering there are two steps.
This is the companies collection.
{
"_id": {
"$oid": "63ed39162bfc2cf8065b76cf"
{
"_id": {
"$oid": "63ed39162bfc2cf8065b76cf"
},
"companyName": "Sowegatel",
"amount": 0,
"signalwireSid": "id",
"numbers": [
{
"number": "+12068133580",
"_id": {
"$oid": "63ed39c72bfc2cf8065b76f0"
},
"createdAt": {
"$date": {
"$numberLong": "1676491207931"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1676491207931"
}
}
}
],
"endPoints": [
{
"userName": "4009",
"_id": "fb1d0ef9-c713-400e-a3c9-cbc6823aaf57"
},
{
"userName": "4019",
"_id": "506e710d-14a6-4345-bc89-8488af4cabe4"
},
{
"userName": "4020",
"_id": "c80bd1ab-ca8d-4649-9d35-56d64ef8fab5",
"type": "sip_endpoint"
}
],
"__v": 6
} },
"companyName": "Sowegatel",
"amount": 0,
"signalwireSid": "id",
"numbers": [
{
"number": "+12068133580",
"_id": {
"$oid": "63ed39c72bfc2cf8065b76f0"
},
"createdAt": {
"$date": {
"$numberLong": "1676491207931"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1676491207931"
}
}
}
],
"endPoints": [
{
"userName": "4009",
"_id": "fb1d0ef9-c713-400e-a3c9-cbc6823aaf57"
},
{
"userName": "4019",
"_id": "506e710d-14a6-4345-bc89-8488af4cabe4"
},
{
"userName": "4020",
"_id": "c80bd1ab-ca8d-4649-9d35-56d64ef8fab5",
"type": "sip_endpoint"
}
],
"__v": 6
}
This is the users collection.
{
"_id": {
"$oid": "63ed39162bfc2cf8065b76d2"
},
"firstName": "mark",
"lastName": "thomas",
"email": "mt#st.com",
"password": "",
"companyId": {
"$oid": "63ed39162bfc2cf8065b76cf"
},
"active": true,
"role": "companyAdmin",
"tokens": [],
"__v": 2,
"endpoints": [
// I need to populate to endpoints here!!!! //
"c80bd1ab-ca8d-4649-9d35-56d64ef8fab5"
]
}
I can do a single step aggregation, but this is a little complicated for me.`

$lookup and $group on Mongodb Aggregation

So i have an document of answers from user with structure like this:
[{
"_id": {
"$oid": "636e685d1e1b4aa82f7e87c7"
},
"userId": {
"$oid": "6369b17b11e02557349d8e37"
},
"formId": {
"$oid": "6361d3bf914c7e5a21efa190"
},
"title": "Order Kerja Produksi (KSNI)",
"username": "22000510",
"date": "2022-11-11",
"createdAt": 1668180061,
"updatedAt": 1668180061,
"__v": 0,
"position": "Foreman",
"department": "Production"
},
{
"_id": {
"$oid": "636e699c1e1b4aa82f7e87cb"
},
"userId": {
"$oid": "6369b17b11e02557349d8e37"
},
"formId": {
"$oid": "6361d3bf914c7e5a21efa190"
},
"title": "Order Kerja Produksi (KSNI)",
"username": "22000510",
"date": "2022-11-11",
"createdAt": 1668180380,
"updatedAt": 1668180380,
"__v": 0,
"department": "Production",
"position": "Foreman"
},
{
"_id": {
"$oid": "636e6ace1e1b4aa82f7e87cf"
},
"userId": {
"$oid": "6369b17b11e02557349d8e37"
},
"formId": {
"$oid": "6361d3bf914c7e5a21efa190"
},
"title": "Order Kerja Produksi (KSNI)",
"username": "22000510",
"date": "2022-11-11",
"createdAt": 1668180686,
"updatedAt": 1668180686,
"__v": 0,
"department": "Production",
"position": "Foreman"
}
]
each NIK has assigned with SPV on the Users document, that have structure like this:
{
"_id": {
"$oid": "6369b17b11e02557349d8de6"
},
"password": "$2b$10$whBbgZRMsIMCgKy/EJAwXefSdZNnrK5b.cSOYXTqu7g5a2uwCddKm",
"NIK": "19000298",
"department": "Production",
"__v": 0,
"createdAt": 1667871099,
"updatedAt": 1667871099,
"plant": "RANC",
"Gedung_Zona": "No Status",
"SPV": "JAMJAM J",
"Sector": "2"
},
{
"_id": {
"$oid": "6369b17b11e02557349d8de7"
},
"password": "$2b$10$whBbgZRMsIMCgKy/EJAwXefSdZNnrK5b.cSOYXTqu7g5a2uwCddKm",
"NIK": "20000100",
"Group_Shift": "R1",
"role": "user",
"__v": 0,
"createdAt": 1667871099,
"updatedAt": 1670974129,
"plant": "RANC",
"Gedung_Zona": "No Status",
"SPV": "JAMJAM J",
"Sector": "3"
},
]
I want to aggregate the answers from answers document with condition from users document where condition like this:
{$match:{SPV:"SPV_name"}}
Is that a possible way to produce it into this kind of response with condition above using $lookup and $group?
If thats possible any help on how to produce that?
any help will be very thankful
Here is what i want the response from the query..
{
_id:1243135421412,
formId:123123123123,
title:"title of the question",
username:22004627,
date:2022-10-10,
createdAt:1234125525,
SPV:"SPV_NAME",
},
{
_id:1243135421412,
formId:123123123123,
title:"title of the question",
username:22004777,
date:2022-10-12,
createdAt:1234125525,
SPV:"SPV_NAME",
}
here is my try but it keeps returning error :
MongoServerError: Expression $arrayElemAt takes exactly 2 arguments. 1 were passed in.
Here is my try:
db.answers.aggregate([{$lookup:{from:"users",pipeline:[{$match:{SPV:"JAMJAM JAMALUDIN"}}],as:"data"}}])

Aggregation query

Node js using mongoose as ORM. I have set of documents like below
I want to calculate the average time for createdAt in ISO String(format) field in duration of hours on
grouping the category field. I have tried many ways to use aggregate but couldn't get the result.
[{
"_id": {
"$oid": "62dfc2cf25735e8b1b475ff1"
},
"numLikes": 0,
"numViews": 0,
"numShares": 0,
"hasUserLiked": false,
"title": "sample-broadcast",
"description": "broadcast-dewscription",
"projectId": {
"$oid": "62d903a5dade1714382b27af"
},
"content": [
{
"_id": {
"$oid": "62dfc2cf25735ee18d475ff2"
},
"downloadLink": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/51daead4-1134-4921-a544-fea845f03d1c/uploadbroadcast/1658831544",
"label": "lance-anderson-QdAAasrZhdk-unsplash (1).jpg",
"contentType": "jpeg"
}
],
"delivery": "scheduleBroadcast",
"category": "GENERAL_UPDATES",
"groupId": "51daead4-1134-4921-a544-fea845f03d1c",
"author": {
"userId": "83314517-9326-430f-9c4e-8fedb050e6b0",
"profilePic": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/4f670832-dfd7-43ee-a6ad-e2f43f48df6a/uploadprofilepic/1658239806",
"name": "Biswajit Rout"
},
"projectLogo": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/4f670832-dfd7-43ee-a6ad-e2f43f48df6a/uploadcompanylogo%2A/1658239764",
"createdAt": {
"$date": {
"$numberLong": "1658831567577"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1658831567577"
}
},
"__v": 0
},{
"_id": {
"$oid": "62dfebae25735e015f476dfb"
},
"numLikes": 0,
"numViews": 0,
"numShares": 0,
"hasUserLiked": false,
"title": "testing-broadcast",
"description": "testing-description",
"projectId": {
"$oid": "62d903a5dade1714382b27af"
},
"content": [
{
"_id": {
"$oid": "62dfebae25735e291c476dfc"
},
"downloadLink": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/51daead4-1134-4921-a544-fea845f03d1c/projectimages0/1658842001",
"label": "lance-anderson-QdAAasrZhdk-unsplash (1).jpg",
"contentType": "jpeg"
},
{
"_id": {
"$oid": "62dfebae25735e0321476dfd"
},
"downloadLink": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/51daead4-1134-4921-a544-fea845f03d1c/projectimages1/1658842024",
"label": "Get_Started_With_Smallpdf.pdf",
"contentType": "pdf"
}
],
"delivery": "immediate",
"link": "http://localhost:3000",
"category": "GENERAL_UPDATES",
"groupId": "51daead4-1134-4921-a544-fea845f03d1c",
"author": {
"userId": "83314517-9326-430f-9c4e-8fedb050e6b0",
"profilePic": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/4f670832-dfd7-43ee-a6ad-e2f43f48df6a/uploadprofilepic/1658239806",
"name": "Biswajit Rout"
},
"projectLogo": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/4f670832-dfd7-43ee-a6ad-e2f43f48df6a/uploadcompanylogo%2A/1658239764",
"createdAt": {
"$date": {
"$numberLong": "1658842030827"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1658842030827"
}
},
"__v": 0
},{
"_id": {
"$oid": "62e144677fc76b0373f40152"
},
"numLikes": 0,
"numViews": 0,
"numShares": 0,
"hasUserLiked": false,
"title": "Broker Offer-1",
"description": "50% off on the membership for early birds. \n\nOffer Applied to first fifty users only",
"projectId": {
"$oid": "62d903a5dade1714382b27af"
},
"content": [
{
"_id": {
"$oid": "62e144677fc76b2b79f40153"
},
"downloadLink": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/51daead4-1134-4921-a544-fea845f03d1c/projectimages0/1658930275",
"label": "50-off-PNG-Picture.png",
"contentType": "png"
}
],
"delivery": "immediate",
"link": "",
"category": "OFFER_BROKERS",
"groupId": "51daead4-1134-4921-a544-fea845f03d1c",
"author": {
"userId": "83314517-9326-430f-9c4e-8fedb050e6b0",
"profilePic": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/4f670832-dfd7-43ee-a6ad-e2f43f48df6a/uploadprofilepic/1658239806",
"name": "Biswajit Rout"
},
"projectLogo": "https://builder-broadcast-media.s3.ap-south-1.amazonaws.com/builder-broadcast-media/4f670832-dfd7-43ee-a6ad-e2f43f48df6a/uploadcompanylogo%2A/1658239764",
"createdAt": {
"$date": {
"$numberLong": "1658930279871"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1658930279871"
}
},
"__v": 0
}]
My expected result should be like this
{
OFFER_BROKERS: 5 <hrs>,
GENERAL_UPDATES : 4 <hrs>
}
Do you want to convert milliseconds to real time and give it to orm

Joining only matching elements

I want to join more than two collections in MongoDB . Is it possible to join?
I have 2 collections and I want to join them based by their ids
news collection
{
"lang": "ru",
"news": [{
"title": "title",
"content": "desc",
"image": "path",
"categoryId": {
"$oid": "6171499e0ba3d75082823c9a"
},
"createdAt": {
"$date": "2021-10-21T12:30:33.215Z"
},
"_id": {
"$oid": "61715d7990905adefcf314d1"
}
}]
}
and I have got newscategory collection like that
[
{
"lang": "ru",
"categories": [{
"name": "sdfsdsdcsdf",
"_id": {
"$oid": "6171499e0ba3d75082823c9a"
}
}]
},
{
"lang": "en",
"categories": [{
"name": "ooo",
"_id": {
"$oid": "61712980f8ee795c6a569dcb"
}
}, {
"name": "yuy",
"_id": {
"$oid": "61712980f8ee795c6a569dcc"
}
}, {
"name": "rtyrty",
"_id": {
"$oid": "61712980f8ee795c6a569dcd"
}
}]
}
]
Expected Output:
[
{
"_id": "61715d7990905adefcf314d0",
"lang": "ru",
"news": [
{
"title": "sdf",
"content": "sdf",
"image": "asdas",
"categoryId": "6171499e0ba3d75082823c9a",
"caregory": [
{
"name": "sdfsdsdcsdf",
"_id": "6171499e0ba3d75082823c9a"
},
]
"createdAt": "2021-10-21T12:30:33.215Z",
"_id": "61715d7990905adefcf314d1"
}
],
Match is based on both "category_id" and "categories._id".
How can I achieve result like that ?

mongodb $addfields conditions is not working

i have used lookup for join 2 tables and i need to create 2 custom column so i have used the $addfields.
In $addfields, Member is not working but pqr is working.
I have a array of objects as a given below :
await mongoose.models.abc.aggregate([
{
$lookup:
{`enter code here`
from: 'xyz',
localField: 'id',
foreignField: '_id',
as: 'my'
}
},
{
$match: {
"my": { $ne: [] }
}
},
{
$addFields: {
pqr: { $cond: [{ $gte: ["$my.request", 1] }, { $sum: "$my.request" }, 0] },
Member: { $cond: [{ $eq: ["$myClub.request", 0] }, { $sum: "$myClub.request" }, 0] },
}
},
]);
[
{
"_id": "5ef05f650e26a40cb44a68d6",
"createdAt": "2020-06-22T07:36:05.640Z",
"updatedAt": "2020-06-22T07:36:05.640Z",
"__v": 0,
"my": [
{
"_id": "5eecc3c961767f21c8d694e0",
"request": 1,
"createdAt": "2020-06-19T13:55:21.573Z",
"updatedAt": "2020-06-19T13:55:21.573Z",
"__v": 0
},
{
"_id": "5ef1b8f2c3d54e21f4d6b332",
"request": 0,
"createdAt": "2020-06-23T08:10:26.036Z",
"updatedAt": "2020-06-23T08:10:26.036Z",
"__v": 0
}
]
}
]
i need a output like this:
[
{
"_id": "5ef05f650e26a40cb44a68d6",
"createdAt": "2020-06-22T07:36:05.640Z",
"updatedAt": "2020-06-22T07:36:05.640Z",
"__v": 0,
"my": [
{
"_id": "5eecc3c961767f21c8d694e0",
"request": 1,
"createdAt": "2020-06-19T13:55:21.573Z",
"updatedAt": "2020-06-19T13:55:21.573Z",
"__v": 0
},
{
"_id": "5ef1b8f2c3d54e21f4d6b332",
"request": 0,
"createdAt": "2020-06-23T08:10:26.036Z",
"updatedAt": "2020-06-23T08:10:26.036Z",
"__v": 0
}
],
"pqr":1, // for greater than eqaul to request=1
"Member":1 // // for eqaul to request=0
}
]

Resources