Result of Mongodb aggregation operation

I've created a Property controller :

//Retrieve Properties By Type
const getPropertiesByType = async (req: Request, res: Response) => {
    const { cities, type } = req.query;
    const citiesArr = typeof cities === 'string' ? cities.split(',') : [];
    try {
        const properties = await Promise.all(
            citiesArr?.map((item) => {
                return PropertyModel.aggregate([
                    {
                        $match: { city: item, propertyType: type },
                    },
                    {
                        $project: {
                            _id: 0,
                            city: 1,
                            country: 1,
                            cityPhoto: 1,
                        },
                    },
                    {
                        $group: {
                            _id: '$city',
                            country: { $first: '$country' },
                            totalProperties: { $sum: 1 },
                            cityPhoto: { $first: '$cityPhoto' },
                        },
                    },
                ]);
            })
        );
        res.status(201).json(properties.flat());
    } catch (error) {
        console.log(error);
        res.status(400).json(error);
    }
} 

When using Postman, the response I'm receiving looks like this :

[
    {
        "_id": "Davenport",
        "country": "United States",
        "totalProperties": 1,
        "cityPhoto": "https://"
    },
    {
        "_id": "Destin",
        "country": "United States",
        "totalProperties": 1,
        "cityPhoto": "https://"
    }
] 

The issue I'm facing is that all objects are nested within arrays, but I would prefer to have them in a single main array. Is there a way to achieve this without using the aggregation pipeline?

Answer №1

To utilize the array.flatMap() method, simply apply it after receiving the aggregation result:

const property = [
    [
        {
            "_id": "Davenport",
            "country": "United States",
            "totalProperties": 1,
            "cityPhoto": "https://"
        }
    ],
    [
        {
            "_id": "Destin",
            "country": "United States",
            "totalProperties": 1,
            "cityPhoto": "https://"
        }
    ],
] ; // your aggregation output

const response = property.flatMap(x => x);
console.log(response);

The reason you can't directly perform this operation in the aggregation pipeline is due to using Promise.all, which returns an array. Additionally, each .aggregate() call also returns an array, resulting in a nested structure of arrays.

Answer №2

It seems that @mickl has given a solution on how to structure the response using flatMap() after the database completes its processing, which appears to be a valid approach. However, there is an alternative method I would like to explore in response to a question raised in the comments.

From what I understand in the code, you are examining the cities query parameter and expecting a string with values separated by commas, such as "A,B,C". After splitting this string into an array named citiesArr, you proceed to send individual aggregate() requests to the database for each entry in the array (using the map function where each city becomes an item).

I believe it is possible (and advisable) to consolidate these requests into a single call to the database. In terms of the aggregation process itself, it would involve altering

                    {
                        $match: { city: item, propertyType: type },
                    }

To something like

                    {
                        $match: { city: { $in: citiesArr }, propertyType: type },
                    }

If you also modify the code structure surrounding this database query (eliminating the need for .all() and .map()), then the database's direct response should align more closely with your desired outcome.

Two other points to consider:

  1. The $project stage in the middle may not be necessary. The database can determine the appropriate stages for the $group operation and retrieve them automatically. Removing $project could streamline the process.
  2. Given this approach, I recommend verifying that citiesArr contains elements before initiating the aggregation. If the array is empty, there is no need for a database query since no results will be returned.

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

Create a dynamic Prisma data call by using the syntax: this.prisma['dataType'].count()

I'm currently working on implementing a counting function that can be utilized in all of my objects. In my 'core' file, Prisma is involved in this process. This allows me to execute commands like this.user.count() or this.company.count() I ...

Increasing several array elements within a MongoDB object

I have been struggling with this problem for some time now. My goal is to update multiple array values in the same object with a single query. The data in the database appears as follows: id: 616f5aca5f60da8bb5870e36 title: "title" recommendations: ...

Restrict the number of items in each list to just one

I'm trying to customize a query that displays a list of numbers. My goal is to only display each unique number once. For example, if there are three instances of the number 18 in the database, I want it to show as 18, 18, 18. If there are two occurre ...

Error Detected: An unhandled error occurred, triggering a promise rejection: TypeError: The super expression must be either null or a function in Angular version 6

Upon deploying the application on AWS Elastic Beanstalk, an error has surfaced. While the build and deployment processes were successful, one module is giving a Super Expression error. The other modules are functioning correctly, and everything works fine ...

Learn how to retrieve specific parts of a subdocument in MongoDB using Spring Data

Is there a way to retrieve only the list of "grandSubCategory"? I attempted to use a Query in the repository like this: @Query("{'subCategory.grandSubCategory.grandSubCategoryName':{$regex: '^?0'}}") Category findByName(String n ...

Observe the task while returning - Firebase Functions

I am working on a Firebase Cloud Functions project where I need to run a scraping task within one of the functions. While the scraping is in progress, I also need to provide progress updates to the consumer. For example, informing them when the task is at ...

Using React Query's useMutation hook may result in an error message of "No overload matches this call"

When incorporating react-query into my typescript project, I encountered a perplexing type error while attempting to utilize the useMutation() hook with a graphql query. Here is an example of the code: useMutation( async ( parameter1: string, ...

What is the best way to convert this into a distinct function using typescript?

Is there a way to create a single method in Protractor or Webdriver API that can get the browser width and height? const getWindowWidth = async () => { const size = await browser.manage().window().getSize(); return size.width; }; I need this metho ...

Understanding the infer keyword in Typescript when working with generic type constraints

Exploring a scenario where I have a generic interface that requires a type argument extending another generic type. export interface IPoint<TX, TY> { x: TX; y: TY; } export interface ISeries<TPoint extends IPoint> { points: Array& ...

Storing the Outcome of a mongodb Search in a Variable

I'm encountering an issue where the result of a MongoDB find operation is not being assigned to a variable (specifically, the line var user = db.collection("Users").findOne below), and instead remains undefined. I am aware that the find function retur ...

Is there a way to add a new Date to Spring Data MongoDB easily?

Is there a way to add a new Date using Spring Data MongoDB? Currently, I am using the following: User = new User(); user.setCreationDate(new Date()); mongoOperation.save(user); The issue with this approach is that it saves the user with the current tim ...

Having trouble with Axios PUT request not sending complete data to the server using JavaScript

One issue I'm encountering is that when sending an axios request with specific data, not all of the data gets updated in the user model. Here's a look at my code: Here is the Front-End code with axios request: import axios from "axios" ...

Issue with Mongoose not triggering callback

This particular function is the one that we are discussing function matches_password(password) { var modified = false; var matched = false; User.count({password : password}, function (err, result) { modified = true; console.log('hey& ...

Mongo models failing to react

I'm currently in the process of developing a new application and I am facing difficulties setting up MongoDB locally for storage purposes. Although my API endpoints are being accessed successfully, whenever I attempt to execute a database operation su ...

When attempting to utilize the Next.js Head component in a location other than _document, the page experiences

Currently, I am in the process of integrating Next.js with Typescript and Material UI. Despite the abundance of tutorials available online for setting up Next.js with Material UI, I have encountered a commonality among them where they all provide identical ...

Set the timezone of a Javascript Date to be zero

Is there a way to create a Javascript date without any specific timezone? When I try to do so in Javascript, it automatically sets it to GMT Pacific standard time. let newDate = new Date(new Date().getFullYear(), 0, 2, 0, 0, 0, 0) }, newDate: Sat Feb 01 2 ...

Avoiding the pitfalls of hierarchical dependency injection in Angular 6

Too long; didn't read: How can I ensure that Angular uses the standard implementation of HttpClient in lower level modules instead of injecting a custom one with interceptors? I have developed an Angular 6 library using Angular CLI. This library expo ...

Tips on querying a 3-level nested object in MongoDB

I am having trouble filtering objects by comparing specific fields within the third level of my objects. I am unsure how to properly use the $lte or $gte filter in this case. For instance, I want to filter documents based on the delivery time (delivery_rul ...

Angular 6 - Ensuring all child components are instances of the same component

My issue has been simplified: <div *ngIf="layout1" class="layout1"> <div class="sidebar-layout1"> some items </div> <child-component [something]="sth"></child-component> </div> <div *ngIf="!layout1" class= ...

What is the process for transferring a JWT token between servers to authenticate APIs operating on separate ports in a Node.js and Express environment?

On one server, there are two modules: User and transaction. The User module possesses a Login API that produces a JWT token. I am aiming to transfer this token to the transaction module server for verification in order to secure routes. Can you recommend ...