Combine multiple string values into a single field within an array in MongoDB

Imagine I have a collection of documents in the following structure:

{
    "_id": "3_0",
    "values": ["1", "2"]
}

I want to create a projection where the values from the array are concatenated into a single field like this:

{
    "_id": "3_0",
    "values": "1_2"
}

Is there a way to achieve this? I attempted using $concat, but it seems using $values as the array for $concat is not working.

Answer №1

In the latest MongoDB versions, you have the ability to manipulate arrays using the $reduce operator with documentation on reduce. Here is an example of how you can achieve this:

db.collection.aggregate([
  { "$addFields": {
    "values": { 
      "$reduce": {
        "input": "$values",
        "initialValue": "",
        "in": {
          "$cond": {
            "if": { "$eq": [ { "$indexOfArray": [ "$values", "$$this" ] }, 0 ] },
            "then": { "$concat": [ "$$value", "$$this" ] },
            "else": { "$concat": [ "$$value", "_", "$$this" ] }
          }    
        }
      }        
    }
  }}
])

You can enhance this functionality by combining it with $indexOfArray to avoid concatenating with an underscore when at the first index.

Another useful operator that has been introduced in MongoDB is $sum:

db.collection.aggregate([
  { "$addFields": {
    "total": { "$sum": "$items.value" }
  }}
])

When working with aggregation operators that take an array of items, keep in mind the difference between an "array of arguments" and an "array element" within a document.

If you need to concatenate items within an array present in a document, one approach is to use JavaScript as demonstrated in the following mapReduce example:

db.collection.mapReduce(
    function() {
        emit( this._id, { "values": this.values.join("_") } );
    },
    function() {},
    { "out": { "inline": 1 } }
)

For scenarios where post-processing is possible outside of aggregation, consider performing join operations in client code. However, if such operations are required across documents, mapReduce remains the suitable option.


It would be ideal for functionalities like below to work seamlessly:

{
    "items": [
        { "product": "A", "value": 1 },
        { "product": "B", "value": 2 },
        { "product": "C", "value": 3 }
    ]
}

As seen in this aggregation snippet:

db.collection.aggregate([
    { "$project": {
        "total": { "$add": [
            { "$map": {
                "input": "$items",
                "as": "i",
                "in": "$$i.value"
            }}
        ]}
    }}
])

However, current limitations do not support this method due to expectations from $add operator arguments. An alternate solution involves unwinding and grouping the data to calculate totals.

While we may wish for advancements in these areas, existing methods require us to stick with the available options until further updates are made.

Answer №2

Combine the reduce operator with the substr operator for effective data manipulation.

db.collection.aggregate([
{
    $project: {
        values: {
            $reduce: {
              input: '$values',
              initialValue: '',
              in: {
                $concat: ['$$value', '_', '$$this']
              }
            }
        }   
    }       
},
{
    $project: {
        values: { $substr: ['$values', 1 , -1]}
    }       
}])

Answer №3

Introduced in Mongo 4.4, the $function aggregation operator enables the use of custom JavaScript functions to implement functionalities not supported by MongoDB's Query Language.

For example, to concatenate an array of strings:

// { "_id" : "3_0", "values" : [ "1", "2" ] }
db.collection.aggregate(
  { $set:
    { "values":
      { $function: {
          body: function(values) { return values.join('_'); },
          args: ["$values"],
          lang: "js"
      }}
    }
  }
)
// { "_id" : "3_0", "values" : "1_2" }

The $function operator requires 3 parameters:

  • body, which is the function to be applied and takes the array to join as a parameter.
  • args, containing the fields from the record that the body function uses as parameters. In this case, "$values".
  • lang, specifying the language in which the body function is written. Currently, only js is supported.

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

Leveraging the power of Webpack 2 in conjunction with the extract-text-webpack

Currently utilizing extract-text-webpack-plugin version 2.0.0-rc.3 with Webpack version 2.2.1 and encountering an error during the build process: /node_modules/extract-text-webpack-plugin/index.js:259 var shouldExtract = !!(options.allChunks || chunk.isIn ...

Is it possible to implement MongoDB in a serverless environment?

Exploring the idea of using MongoDb as a storage solution for my WPF application. I'm eager to dive into NoSQL and thought this would be a great opportunity. My plan is to create a mongodb database, place it in the root folder of my application (or ./ ...

Are you experiencing issues with the cross-origin request failing in react-map-gl?

While setting up a map in react-map-gl and providing my access token, I encountered the following console error: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://events.mapbox.com/events/v2?access_token= ...

Display or conceal all sections based on selected dropdown options within the Elementor plugin

I have a dropdown menu with 9 different sections underneath 1. Section id=Hige x 3 2. Section id=Medium x 3 3. Section id=Low x 3 My goal is to show only the sections that correspond to the selection made in the dropdown menu. I am using jQuery to achi ...

Is there a way to ensure that the result is only sent after the function has been

When trying to send the result from a function after a post request, I'm facing an issue where res.json() seems to execute before I actually receive the result from the function. This results in 'undefined' being returned every time. Game.f ...

The ENOENT error code 4058 occurred while attempting to create a new react application using

Every time I run the command npm create-react-app my-app, I encounter an error like this: npm ERR! code ENOENT npm ERR! syscall spawn C:\Windows\System32; npm ERR! path C:\Users\Administrator\Documents\th-wedding\templa ...

Error in Angular Universal: KeyboardEvent is not defined

I have inserted the word "domino" into the server.ts file and updated the webpack.server.config.js as follows: module: { rules: [ { test: /\.(ts|js)$/, loader: 'regexp-replace-loader', options: { match: { pattern: '&bs ...

Creating search queries using information provided by the user. The correct approach

Currently, I am in the process of developing a web application using Codeigniter and MongoDB. My goal is to create a function that can effectively search the database based on specific criteria. Tags Owner username Status Date range The function must al ...

The onSubmit function fails to run when triggered from a component nested within another component

In my next.js project, I have a component that utilizes the NavbarItem component. The NavbarItem component uses Login to display a login form. This NavbarItem component takes the Login component as a parameter for its function. However, in this configura ...

Execute a function in AngularJS after the HTML has finished loading

Hey guys, I'm facing a problem with this directive: angular.module('blah').directive('someDirective', function () { return { scope: { arrayParam1: '=arrayParam1', arrayParam2: '=ar ...

I'm looking for help on creating a three-column table using javascript/jquery. The table should display Product, Price, and Discount (which is calculated at 20%). Can anyone

Check out this code snippet. var items = ["Laptop", "Tablet", "Smartphone", "Headphones", "Camera"]; var costs = [599.99, 299.99, 799.99, 149.99, 499.99]; displayItems = ""; totalCost = 0; for (var j = 0; j < items.length; j++) { displayItems += " ...

When trying to append data to a datatable, I encountered an error: Uncaught SyntaxError: missing ) after argument

$("#searchresult").append("<tr><td id=''>" + data[i].landarp + "</td>" + "<td id=''>" + data[i].landarp + "</td>" + "<td id=''>" + data[i].landpin + "</td>" + "<td id=''&g ...

Create a new object by mapping values from an array of two objects in Angular using TypeScript, based on the object

Here is a code snippet for a Question and Answer data structure: export class Question { id: string; title: string; description: string; answers: Answer[]; } export class Answer { id: string; text: string; questionId: string; } We have two ...

Removing a Button from a Form Using JavaScript

Here is a snippet of my HTML code: <form id="form"> <input id="deleteNumber" name="del" type="hidden" /> <input id="addAddress" name="addAddress" type="hidden" /> ... ... ... <a href="javascript:deleteAddress();" class="deleteItem" ...

The ultimate tool for creating AJAX applications with minimal effort - a graphical development environment that

Does anyone know of a convenient tool that can help in quickly creating the front-end AJAX for an administrative interface? I'm looking for something like a "Javascript Generator" found in Microsoft Visual development environments. A tool where I can ...

When I utilize $router.push() to navigate to a different page, the back button will take me back to the previous page

Within my Vue project, there is an HTML page that I am working on. Here is the link to the page: https://i.sstatic.net/cbtqM.png Whenever I click on the "+"" button, it redirects me to this specific page: https://i.sstatic.net/0rmMD.png This page funct ...

What is the best way to retrieve multiple variables using Express.js on Node.js?

Trying to fetch Form data from an HTML page to a Node Js server. The HTML file is named index.html <body> <nav> <ul> <li> <a href="#" class="button add">Add Product</a> <div class="dialog" style="displ ...

Submitting data via AJAX using the method parameter

I have a specific ajax form that requires serialization and the manual setting of the _method for the data form. This is how I am currently handling it. $.ajax({ url: http://someposturl.com/object, type: 'POST', ...

Execute a jQuery ajax request to a specific variable

For my Phonegap/Cordova project, I have implemented functions to handle all ajax calls in the following way: function requestData(action, id ) { var data = { user_id: localStorage.getItem('user_id') }; if( action == 'fee ...

Challenge with AngularJS ng-select and ng-switch-when functionality

Struggling with implementing a selection menu on my angular charts, I encountered some challenges. The selection app template I used only displays the selection menu and graph axis on the page. Checking the console log for errors, I noticed one src URL wa ...