[SERVER-13662] Date returned from group command initial object results in error Created: 18/Apr/14  Updated: 06/Dec/22  Resolved: 07/Apr/17

Status: Closed
Project: Core Server
Component/s: JavaScript, MapReduce
Affects Version/s: 2.4.10, 2.6.0
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Kevin Locke Assignee: Backlog - Query Team (Inactive)
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: File 0001-fix-dat-date.patch    
Assigned Teams:
Query
Operating System: ALL
Steps To Reproduce:

Modifying the example from the documentation by adding the field d with a Date value to the initial object, starting with a fresh database:

db.orders.insert({
  _id: ObjectId("5085a95c8fada716c89d0021"),
  ord_dt: ISODate("2012-07-01T04:00:00Z"),
  ship_dt: ISODate("2012-07-02T04:00:00Z"),
  item: { sku: "abc123",
          price: 1.99,
          uom: "pcs",
          qty: 25 }
});
// Next command will cause an error
db.orders.group({
  key: { ord_dt: 1, 'item.sku': 1 },
  cond: { ord_dt: { $gt: new Date( '01/01/2012' ) } },
  reduce: function ( curr, result ) { },
  initial: {d: new Date()}
});

Either removing the property in the finalize function or overwriting it avoids the issue:

// Next command runs without error
db.orders.group({
  key: { ord_dt: 1, 'item.sku': 1 },
  cond: { ord_dt: { $gt: new Date( '01/01/2012' ) } },
  reduce: function ( curr, result ) { },
  initial: {d: new Date()},
  finalize: function(result) { delete result.d; }
});
// As does this one
db.orders.group({
  key: { ord_dt: 1, 'item.sku': 1 },
  cond: { ord_dt: { $gt: new Date( '01/01/2012' ) } },
  reduce: function ( curr, result ) { result.d = new Date() },
  initial: {d: new Date()}
});

Participants:

 Description   

When running a group query where one of the properties of the Object passed as the initial aggregation result is a Date and that property is returned unmodified, the following error occurs:

TypeError: Property 'getUTCFullYear' of object [object Object] is not a function



 Comments   
Comment by Asya Kamsky [ 28/Mar/17 ]

recommend closing won't fix due to deprecation of group command.

Comment by David Storch [ 21/Apr/14 ]

I tracked down the root cause:

https://github.com/mongodb/mongo/blob/e87b42c4f13e48078f5c4aefba3caf18dcfba072/src/mongo/db/commands/group.cpp#L118

This code has been in place for about three years, so this is not a regression.

The group command uses v8 to call the provided reduce function. If nothing is there to reduce, then an object is initialized using the provided "initial" field. This is all fine, but there is a bug in the initialization. It is done by declaring an empty variable, and then doing a deep Object.extend, which looks something like this:

var initial = {d: new Date()};
var toInit = {};
Object.extend(toInit, initial, true); // true means deep

The deep Object.extend is not doing a proper clone. It creates a broken Date object that looks like this in the document returned to the client:

 retval: [ { ord_dt: new Date(1341115200000), item.sku: "abc123", d: { tojson: function (){
    var UTC = 'UTC';
    var year = this['get'+UTC+'FullY... } } ] }

Generated at Thu Feb 08 03:32:28 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.