Calculating the average value of an attribute in an array using Mongodb (Mongoose)

Seeking assistance with a query to find sellers near users based on location input and sorting them by average rating. Is this achievable? Snippet of the model including an array of reviews:

    const sellerSchema = new mongoose.Schema({
        _id: Mongoose....ObjectId
            //... 
        reviews: [
        {
          by: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "User",
          },
          title: {
            type: String,
          },
          message: {
            type: String,
          },
          rating: Number,
          imagesUri: [{ String }],
          timestamp: {
            type: Date,
            default: Date.now,
          },
        },
      ],
    });

Aggregate function used as follows:

const seller = await Seller.aggregate(
    [
      {
        $geoNear: {
          near: {
            type: "Point",
            coordinates: [longitude, latitude],
          },
          distanceField: "distance",
          spherical: true,
          maxDistance: radius,
        },
      },
      rating_minimum ? { $match: { rating: { $gt: rating_minimum } } } 
       : {},
      {$limit: limit},
    ]);

Consideration for using $group to calculate avgReview and then sort by reviews:

{$group:{averageReviews: { $avg: "$reviews.rating"}},
{$sort: { averageReviews: 1 } },
{$limit: limit}

Answer №1

If you have an array of reviews per document and want to calculate the average rating, consider using $reduce instead of $group:

 {
    $addFields: {
      ratingSum: {
        $reduce: {
          initialValue: 0,
          input: "$reviews",
          in: {$sum: ["$$value", "$$this.rating"]}
        }
      }
    }
  },
  {
    $addFields: {
      "averageReviews": {"$divide": ["$ratingSum", {$size: "$reviews"}]
      }
    }
  },
  {$sort: { averageReviews: 1 } },
  {$limit: limit}

You can check out this example on the playground.

If you are aiming to limit the final results to 3 sellers, then you are doing it correctly.

Also, make sure your seller schema includes the location of the seller for use with $geoNear.

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

Masking the identity of Google Pagespeed

Just starting to learn the ropes of javascript. How can I make Google Pagespeed anonymous? Check out the original code here: http://pastebin.com/xRbTekDA. It's functioning properly when I visit the page. Here is the anonymized version: http://pasteb ...

JavaScript Lightbox for Full Page Content (or near full page)

One option to consider is always jQuery. I am in search of a lightbox that provides a "full screen" effect. Not necessarily filling the entire screen, but rather covering most of the content on the page. The lightboxes I have come across either only displ ...

What could be the reason why my POST endpoint isn't able to receive this AJAX request?

I am currently working on a JavaScript function that is supposed to send JSON data to my escreve POST REST method. $(document).ready(function() { $("#idform").on('submit', function(e) { e.preventDefault(); alert($("#idform"). ...

Conceal the menu when tapping anywhere else

I am working on a project that involves implementing HTML menus that can be shown or hidden when the user interacts with them. Specifically, I want these menus to hide not only when the user clicks on the header again but also when they click outside of th ...

HTML5 failing to load button

<!DOCTYPE html> <html> <head> <title>Greetings Earthlings</title> <script src="HelloWorld.js" /> </head> <body> <button onclick ="pressButton()" >Press Me!</button> ...

Utilizing PHP and Ajax to showcase individual row details within a while loop upon clicking a hyperlink

In the midst of a new project, I find myself faced with a task where the user can log in and view their personal delivery orders. The list of deliveries is generated using a while loop. However, whenever I click on the details button for an item in the lis ...

Transforming HTML features into PHP scripts. (multiplying two selected values)

I am currently working on converting these JavaScript functions into PHP in order to display the correct results. I need guidance on how to use PHP to multiply the values of the NumA and NumB select options, and then show the discount in the discount input ...

Inspecting the Ace Editor within the onbeforeunload event handler to confirm any modifications

I'm attempting to utilize the $(window).on('beforeunload', function(){}); and editor.session.getUndoManager().isClean(); functions within the ace editor to detect whether a user has made modifications to a document without clicking the submi ...

Navigate through JSON data to uncover the tree structure path

In my project, I am working on creating a treeview user interface using the JSON provided below. I have included properties such as node-id and parentId to keep track of the current expanded structure. Next, I am considering adding a breadcrumb UI compone ...

AngularJS expression utilizing unique special character

There are certain special characters (such as '-') in some angular expressions: <tr data-ng-repeat="asset in assets"> <td>{{asset.id}}</td> <td>{{asset.display-name}}</td> <td>{{asset.dns-name}}</td&g ...

Is there a way to implement a targeted hover effect in Vue Js?

I'd like to create a hover button that only affects the nested elements inside it. Right now, when I hover over one button, all the nested elements inside its sibling buttons get styled. Any ideas on how to fix this? <div id="app"> <butto ...

Filter Observable based on object array property

I am trying to filter an Observable and only keep the stream that has a specific property value in an array of objects inside it. For example, consider this Observable: const observable = of({name: 'agency', year: '2010', job: [ ...

Tips for differentiating between elements with identical values in an HTML datalist using Angular

My boss is insisting that I use a datalist in our website interface to select an employee, even though there's no way to determine if the user typed in the name or picked from the list. The challenge is that the list must only display full names, but ...

Observing the Transformation When Employing *ngIf or *ngSwitchCase in Angular 2

Can someone lend a hand? I've run into an issue where my custom JavaScript function is not working after using *ngIf or *ngSwitchCase to change the view. Any suggestions on how to resolve this would be greatly appreciated. ...

There seems to be an issue with byRole as it is failing to return

Currently in the process of migrating my unit test cases from Jest and Enzyme to React Testing Library. I am working with Material UI's Select component and need to trigger the mouseDown event on the corresponding div to open the dropdown. In my previ ...

connecting parameters to functions in javascript

I'm attempting to execute a second query once the first query has been resolved by using the following code: const task1 = nextQuery => $.get('1.json', data => nextQuery()); const task2 = nextQuery => $.get('2.json', ...

Unable to access setRowData() in AgGrid/Angular 2 leads to rendering of the grid without displaying any rowData

Resolved I think my solution is temporarily fixed and it reveals that I may have set up my mongoose model incorrectly. The answer provided did assist me in solving my issue, but ultimately the reason for the empty data rows was due to incorrect identifier ...

The function replace does not exist in t(…)trim

I encountered an error in my code that breaks the functionality when checked using console.log. var map = L.map('map').setView([0, 0], 2); <?php $classesForCountries = []; if (have_posts()) : while (have_posts()) : the_post(); ...

Experiencing memory issues while attempting to slice an extensive buffer in Node.js

Seeking a solution for efficiently processing a very large base64 encoded string by reading it into a byte (Uint8) array, splitting the array into chunks of a specified size, and then encoding those chunks separately. The current function in use works but ...

Confirm that the contents of two Mongodb collections are the same

Is there a simple way to find the equivalent of taking the shasum of the contents of two files? I'm not interested in comparing every item using an eval function as suggested in this post: How to compare 2 mongodb collections? I assume that Mongodb& ...