Get a field value on the basis of condition in aggregation

i want to get createdAt field of last message of a specific user in agroup
suppose here userId is any user . i want to fetch his last message in a group which he sent and want to get createdAt field of that message. then i want to compare all documents whose createdAt time is less then this document and want to fetch 1st document in that List.

in below code 1st i sorted documents reversely now i want to get createdAt field of last message of user i put if condition but remain unsuccesfull .try with arrays but still no success.
it returns createdAt field of last document processed. i want createdAt field of that document where senderId field value is equal to userId
I dont want another query .Can anyone help me to get createdAt field of that document?
please dont put simple match condition because match will give one document and all other document doesnt go to next stage . after that i also want compare that createdAt field with other documents createdAt field.

let userId = any userId in this group
let groupId = any groupId
let result = await groupChatModel.aggregate([

    {

        $match: {

            groupId: groupId

        }

    },



    {

        "$sort": {

            "createdAt": -1

        }

    },

    {


        $project: {

            LastmessageCreatedAt: {


                $cond: {



                    if: {

                        $eq: [userId, "$senderId"]

                    },

                    then: $createdAt",
                    else: "$$REMOVE" // i want nothing here but cant get rid of this else condition



                }



            }

        }

    }
]),

Hi @Saad_Tanveer,

It’s really hard to understand your need just based on that pipeline.

Could you please provide a bunch of documents (just the fields we need) that represent your problem and the expected output based on these sample documents?

Cheers,
Maxime.

@MaBeuLux88
Sample documents
My groupchat collection

{
    "_id" : ObjectId("633ebce93642850dfa00dbb7"),
    "messageType" : 0,
    "groupId" : group-A,
    "message" : "my 1st message",
    "senderId" : user-A,
    "createdAt" : ISODate("2022-11-06T16:32:57.000Z"),
    "__v" : 0,
    "updatedAt" : ISODate("2022-11-06T14:28:03.478Z")
}

/* 2 */
{
    "_id" : ObjectId("633ebd553642850dfa00dbb9"),
    "messageType" : 0,
    "groupId" : group-A,
    "message" : "UserB -1st message",
    "senderId" : user-B,
    "createdAt" : ISODate("2022-11-13T16:34:45.000Z"),
    "__v" : 0,
    "updatedAt" : ISODate("2022-11-13T14:28:03.478Z")
}

/* 3 */
{
    "_id" : ObjectId("633fd4b5cdf14144b040d63b"),
    "messageType" : 0,
    "groupId" : group-X,
    "message" : "User x 1st message in X-group",
    "senderId" : User-X,
    "createdAt" : ISODate("2022-11-15T12:26:45.000Z"),
    "__v" : 0,
    "updatedAt" : ISODate("2022-11-15T14:28:03.478Z")
}

/* 4 */
{
    "_id" : ObjectId("6343c6c0dbfa6356d476a642"),
    "messageType" : 0,
    "groupId" : group-A
    "message" : "userA last message in groupA",
    "senderId" : user-A,
    "createdAt" : ISODate("2022-11-19T12:16:16.000Z"),
    "__v" : 0,
    "updatedAt" : ISODate("2022-11-19T14:28:03.478Z")
}

/* 5 */
{
    "_id" : ObjectId("63451926177a364ce8909d33"),
    "messageType" : 0,
    "groupId" : group-A
    "message" : "secong mesage",
    "senderId" : user-B,
    "createdAt" : ISODate("2022-11-23T12:20:06.000Z"),
    "__v" : 0,
    "updatedAt" : ISODate("2022-11-23T14:28:03.478Z")
}

Suppose i want to get last message of any user in group A before user A latest message in group A.
in this case latest message of user A in group A is message: “userA last message in groupA”
so last message in group A before userA latest message is message: “UserB -1st message”

Expected outcome if we pass user A and group A

{
    "_id" : ObjectId("633ebd553642850dfa00dbb9"),
    "messageType" : 0,
    "groupId" : group-A,
    "message" : "UserB -1st message",
    "senderId" : user-B,
    "createdAt" : ISODate("2022-11-13T16:34:45.000Z"),
    "__v" : 0,
    "updatedAt" : ISODate("2022-11-13T14:28:03.478Z")
}

Try to solve in 1 query or 1 aggregation query

I am sorry I couldn’t read your whole post, but deduced a few bit from your example data and output. I don’t have the answer but correct me if I am wrong: get the document with time stamp just below the last document of that user. That seems a “match group, project only required fields, sort all first, maybe put them in an array in a $lookup, find first index of matching user, get post _id from index+1” query.

the reason I quoted your above statement is that the reason we have “aggregation” pipeline is to write many queries but execute them in a single attempt. you just need to ask the right questions for your queries :slight_smile:

Here is my go at it.

user = "user-A" ; 
group = "group-A" ;
_match = { "senderId" : user , "groupId" : group }
_sort = { "$sort" : { "createdAt" : -1 } }
_limit = { "$limit" : 1 }
_lookup = { "$lookup" : {
    "from" : "group_chat" ,
    "localField" : "groupId" ,
    "foreignField" : "groupId" ,
    "as" : "_result" ,
    "let" : { "last_createdAt" : "$createdAt" } ,
    "pipeline" : [
        { "$match" : {
            "senderId" : { "$ne" : user } ,
            "$expr" : { "$lte" : [ "$createdAt" , "$$last_createdAt" ] }
        } } ,
        _sort ,
        _limit
    ]
} }
db.group_chat.aggregate(  [ _match , _sort , _limit , _lookup ] )
/* The above provides the following */
{ _id: ObjectId("6343c6c0dbfa6356d476a642"),
  messageType: 0,
  groupId: 'group-A',
  message: 'userA last message in groupA',
  senderId: 'user-A',
  createdAt: 2022-11-19T12:16:16.000Z,
  __v: 0,
  updatedAt: 2022-11-19T14:28:03.478Z,
  _result: 
   [ { _id: ObjectId("633ebd553642850dfa00dbb9"),
       messageType: 0,
       groupId: 'group-A',
       message: 'UserB -1st message',
       senderId: 'user-B',
       createdAt: 2022-11-13T16:34:45.000Z,
       __v: 0,
       updatedAt: 2022-11-13T14:28:03.478Z } ] }

/* you then may add a cosmetic state such as */
_replace = { "$replaceRoot" : { "newRoot" : { "$arrayElemAt" : [ "$_result" , 0 ] } } }
db.group_chat.aggregate(  [ _match , _sort , _limit , _lookup , _replace ] )

/* to exactly get */
{ _id: ObjectId("633ebd553642850dfa00dbb9"),
  messageType: 0,
  groupId: 'group-A',
  message: 'UserB -1st message',
  senderId: 'user-B',
  createdAt: 2022-11-13T16:34:45.000Z,
  __v: 0,
  updatedAt: 2022-11-13T14:28:03.478Z }
2 Likes

@Yilmaz_Durmaz
My problem is simple.
Suppose you are a part of Digital team whatsapp group. So your latest message in group is “Hy its my last message till now”. I want the latest message in group before your last message sent in group .

I am not sure if you examined @steevej 's answer above. I put it in a playground at this link: Mongo playground.

He uses shell-like commands (adapt and use in any language) and it is better to understand than a bit fat query as used in the playground. if you need a bit of explanation: the first few stages find the last message of a user, and the lookup finds messages older than that one that does not belong to that user, the replaceroot returns the first of those.

@steevej Thanks. That worked. i marked it as solution

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.