[SERVER-50614] JS 'Set' type does not serialize well to BSON Created: 28/Aug/20  Updated: 06/Dec/22

Status: Backlog
Project: Core Server
Component/s: JavaScript
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major - P3
Reporter: Charlie Swanson Assignee: Backlog - Query Optimization
Resolution: Unresolved Votes: 0
Labels: qopt-team
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to DOCS-13861 JS objects like 'Set' do not work wel... Closed
is related to SERVER-34281 ES6 arrow functions (lambdas) do not ... Closed
is related to SERVER-46243 Support ES6 Map object in MongoDB shell Backlog
is related to SERVER-31551 Create a test which enumerates the ob... Closed
is related to SERVER-32665 tojson should print the elements when... Closed
Assigned Teams:
Query Optimization
Participants:

 Description   

As you can see below - it just happens to return an empty object, but proceeds without error. It seems better to either (a) error or (b) return an array. We don't have a 'set' data type in the BSON spec, so I don't see how we could get it to work and round trip seamlessly, but this experience isn't great.

> db.foo.aggregate([{
    $project: {
        js_res: {
            $function: {
                lang: "js",
                body: function() {
                    return new Set([1, 2]);
                },
                args: []
            }
        }
    }
}])
{ "_id" : ObjectId("5f3c24f10efd1cb7f0a88f4a"), "js_res" : {  } }
{ "_id" : ObjectId("5f3c24f60efd1cb7f0a88f4b"), "js_res" : {  } }
{ "_id" : ObjectId("5f47f9411945d1527c6b0368"), "js_res" : {  } }
{ "_id" : ObjectId("5f47f9c71945d1527c6b0369"), "js_res" : {  } }
{ "_id" : ObjectId("5f47fa721945d1527c6b036a"), "js_res" : {  } }

As a workaround, you can use the [...set] syntax to expand the set into an array:

> db.foo.aggregate([{
    $project: {
        js_res: {
            $function: {
                lang: "js",
                body: function() {
                    return [...new Set([1, 2])];
                },
                args: []
            }
        }
    }
}])
{ "_id" : ObjectId("5f3c24f10efd1cb7f0a88f4a"), "js_res" : [ 1, 2 ] }
{ "_id" : ObjectId("5f3c24f60efd1cb7f0a88f4b"), "js_res" : [ 1, 2 ] }
{ "_id" : ObjectId("5f47f9411945d1527c6b0368"), "js_res" : [ 1, 2 ] }
{ "_id" : ObjectId("5f47f9c71945d1527c6b0369"), "js_res" : [ 1, 2 ] }
{ "_id" : ObjectId("5f47fa721945d1527c6b036a"), "js_res" : [ 1, 2 ] }



 Comments   
Comment by Charlie Swanson [ 28/Aug/20 ]

Came up while writing a test using $accumulator, but this is a general problem and the posted example is shorter. Here's why I think this matters and is a poor user experience:

{
                      $group: {
                          _id: null,
                          field: {
                              $accumulator: {
                                  init: function() {
                                      return new Set();
                                  },
                                  accumulate: function acc(state, newObj) {
                                      // Something which wants to call 'state.add(something)';
                                  },
                                  accumulateArgs: ["$$ROOT"],
                                  merge: function merge(state1, state2) {
                                      for (let elem of state2) {
                                          state1.add(elem);
                                      }
                                      return state1;
                                  },
                                  lang: "js"
                              }
                          }
                      }
                  }

Generated at Thu Feb 08 05:23:07 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.