Troublication inquiry for retrieving the latest messages to and from User A experiencing issues with functionality

In my project, I have defined a model called MostRecentMessage, which looks like this:

const MostRecentMessage = new Schema({
  to: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "user"
  },
  from: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "user"
  },
  conversation: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "conversation"
  },
  date: {
    type: Date,
    default: Date.now
  }
});

Whenever User A sends a message to User B, a document is created if it doesn't exist. This document gets updated each time User A sends a new message to User B with the latest conversation and date. Here's an example of how a document looks like:

_id: ObjectId(5dc46521cf670a0017d2434d)
to: ObjectId(5dc464ce2fd75700178c1ad4) // User B
from: ObjectId(5dc464fc2fd75700178c1ad5) // User A
conversation: ObjectId(5dc465c6cf670a0017d24363)
date: 2019-11-07T18:40:33.242+00:00
__v: 0

The purpose of this setup is to keep track of all recent messages sent to specific users.

If User B replies to User A, a similar document is created as shown above, and it also gets updated when User B sends more messages to User A.

Now, let's take a look at my aggregation query, but there seems to be an issue where it only returns one conversation even if multiple users are talking to User A.

  const { id } = req.user;

  try {
    await MostRecentMessages.aggregate(
      [
        {
          $match: {
            $or: [
              { from: mongoose.Types.ObjectId(id) },
              { to: mongoose.Types.ObjectId(id) }
            ]
          }
        },
        { $project: { _id: 1, from: 1, to: 1, conversation: 1, date: 1 } },
        { $sort: { date: -1 } },
        {
          $group: {
            _id: null,
            from: { $first: "$from" },
            to: { $first: "$to" },
            date: { $first: "$date" },
            conversation: { $first: "$conversation" }
          }
        },
        {
          $lookup: {
            from: "conversations",
            localField: "conversation",
            foreignField: "_id",
            as: "conversation"
          }
        },
        { $unwind: { path: "$conversation" } },
        {
          $lookup: {
            from: "users",
            localField: "to",
            foreignField: "_id",
            as: "to"
          }
        },
        { $unwind: { path: "$to" } },
        {
          $lookup: {
            from: "users",
            localField: "from",
            foreignField: "_id",
            as: "from"
          }
        },
        { $unwind: { path: "$from" } }
      ],
      function(err, docs) {
        if (err) {
          console.log(err);
        } else {
          return res.json(docs);
        }
      }
    );
  } catch (err) {
    console.log(err);

    return res.status(500).send("Server error");
  }

However, the current implementation of the code displays only the last message exchanged between User A and User B. How can we modify the query to show all messages for both users?


Any thoughts on what might be going wrong here or suggestions for improvement would be much appreciated!

Answer №1

My comment emphasizes the crucial role of the group stage in determining the unique output you receive. The key is to establish 2 fields, either 'from' or 'to' (based on the objectId specified in the parameter), that represent the user you provide and their conversation partner. It doesn't matter whether it's 'from' or 'to'. Here's the concept, although I'm unable to test the solution at the moment.

...

{
$group: {
_id: {
userConcerned: {
$cond: {
if: {
$eq: [
"$to",
mongoose.Types.ObjectId(id)
]
},
then: "$to",
else: "$from"
}
},
interlocutor: {
$cond: {
if: {
$eq: [
"$to",
mongoose.Types.ObjectId(id)
]
},
then: "$from",
else: "$to"
}
},
from: { $first: "$from" },
to: { $first: "$to" },
date: { $first: "$date" },
conversation: { $first: "$conversation" }
}
}
...

Check out the POC here

(If you're indifferent about 'from' and 'to', you can utilize the newly created fields for your lookup and eliminate from and to from the group stage.

Hope this information proves helpful.

---EDIT--- To elaborate further on my response: Grouping with this computed _id instead of null will aggregate any conversation between A and B (A->B or B->A), A and C, A and D,... A will always be in 'userConcerned', while the other party will be considered the interlocutor. As a result, you will obtain a document for each conversation involving A, featuring the most recent message (thanks to the preceding $sort stage and $first accumulator) exchanged between A and their conversation partner, without distinguishing sender and receiver (from or to).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display symbols based on zoom level using the ArcGIS JavaScript API

I am currently working on creating a map using the ArcGIS JS API. I have added numerous symbols to the graphic layer, but they appear to be too dense and are overlapping with each other. Is there a way for me to display fewer points on the map when zoomed ...

What is the best way to assign an ID to a specific HTML element within NetSuite's Document Object Model

Attempting to utilize jQuery in NetSuite to assign a value to an element for testing purposes, but struggling to locate the HTML DOM ID of certain custom drop-down lists. It's not the internal ID. For example: <input type="text" id="soid"> Wh ...

Events related to SVG elements

I have a unique situation where a div containing multiple SVG elements that act as buttons is added to the page after the user interacts with it. I am trying to add events to these SVG elements using event delegation, where I inspect the target of the even ...

Immersive jQuery slideshow embellished with an interactive counter, captivating thumbnails, dynamic progress bar,

Hey there! I'm currently working on my very first website and I could really use some assistance in creating a slider with images. I've tried searching for a solution to my problem online, but even after attempting to fix the suggested plugin, I ...

Effective Ways to Redirect During or After Executing the onClick Function of Button

I am currently working on implementing a feature for my Next.js website. The functionality involves allowing users to create a new group by clicking a button, and then being redirected to an "Invite members" page with the auto-generated group_id included i ...

Manipulating object properties within an array through iteration

Here is the array I am working with: var data = [ {"firstname":"A","middlename":"B","lastname":"C"}, {"firstname":"L","middlename":"M","lastname":"N"}, {"firstname":"X","middlename":"Y","lastname":"Z"} ]; I need to update the values for all keys - firstn ...

What is the best approach to generate and organize 100 random numbers in a program, ensuring they are sorted in ascending order from 1 to 100?

I have successfully implemented the sorting and printout functionality of the program. However, I am now facing a challenge in generating 100 random numbers between 1 and 100, sorting them. I have created an array to store the generated numbers, and I ha ...

Encountering an issue while setting up the ContextAPI in nextJS, where properties of undefined Provider cannot be read

I'm encountering difficulties in implementing ContextAPI with a nextjs application. The error message I keep receiving is: TypeError: Cannot read properties of undefined (reading 'Provider') This is my approach to creating the context: impo ...

The $firebaseObject variable is not defined

My AngularJs + AngularFire setup includes email/password authentication and a node called "users" to list authenticated users. Here is a snapshot: https://i.sstatic.net/eBz3G.png Within my authentication service, I have an AngularJs factory: .factory(&ap ...

Using Rxjs for MongoDB Document References: A Step-by-Step Guide

Currently, I am working on an app using Ionic2/rc0. In my singleton service, I have a ReplaySubject that maintains the consistency of the current user throughout the entire application. Everything is functioning properly, and I can easily subscribe to it a ...

When using `npm publish`, any files located within the `node_modules

After developing an npm package, I included some modules in the node_modules directory to make them accessible as "modules". For instance, I have a module called my-module.js in node_modules which I require in my code using require('my-module'). ...

The API response in JSON format is displaying as "undefined"

My current code is running as follows: const request = require('request') const apiKey = 'XXXXXXXXXXXXXX' var dat; let url = 'http://api.worldweatheronline.com/premium/v1/marine.ashx' let qs = { q: '-34.48,150.92&ap ...

The continuous resizing of the window is triggering a loop in flexslider when the resize function is called

I am currently working on a website that utilizes the flexslider plugin. My goal is to detect when the browser window is resized, and then reinitialize the slider so that it can adjust its size and other parameters accordingly. Initially, I was able to a ...

Accessing the console output on local server at port 8080

Is there a way to correctly display the console output in the browser https://localhost:8080/? I had no issues with another small spring mvc restful web services project, where I could easily see the data on localhost:8080/. Now, I'm facing difficulti ...

What is the best way to create a jQuery object that encapsulates a snapshot of a DOM element?

Recently, I discovered that a JQuery object retains a reference to a DOM object. As the HTML is modified, the context of the JQuery object also changes. However, my concern now is how to log these changes without altering the history records of the JQuer ...

Delays in running multiple jQuery UI effects at the same time

When I implement a show and hide effect with slide on different divs simultaneously on my page, I encounter some lag in the animation. However, I noticed that if I run the show effect only after the hide effect is completed, the lag disappears. I am curiou ...

The text box isn't displaying the value, even though it was functioning properly just two days back

<html> <head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"> function insertParamIntoField(anchor, param, field) { ...

Retrieve the currently logged-in user whenever the component is rendered using React's Context API

For my small React project, I am utilizing ContextAPI. Whenever I hit the /login endpoint, I store the user's token using an HttpOnly Cookie. Below is the code for UserContext.js, which encapsulates all components (children) within App.js import axio ...

extract information from the request header

One of the functionalities in my application involves making Ajax requests to the server. $.ajax({ type: "get", beforeSend: function (jqXHR) { jqXHR.setRequestHeader(ZO_KEY1, _key1); jqXHR.setReq ...

The npm package for @azure/storage-blob doesn't seem to play nice with the Azure Blob storage modules for IoT Edge

Currently, I am developing an edge module using Node.js to interact with Azure Blob storage modules on IoT Edge platform. To achieve this, I am following the documentation available at https://www.npmjs.com/package/@azure/storage-blob. The npm package ut ...