36

I am getting an issue for running the following aggregate query:

db.snippets.aggregate([ { '$project': { month: { '$month': '$created_at' }} } ])

The error message for the same is:

assert: command failed: {
        "errmsg" : "exception: can't convert from BSON type EOO to Date",
        "code" : 16006,
        "ok" : 0 } : aggregate failed

How do I get around this issue? I found a related question: MongoDB: can't convert from BSON type EOO to Date.

But it doesn't tell me how to get things done.

ouflak
  • 2,458
  • 10
  • 44
  • 49
jsbisht
  • 9,079
  • 7
  • 50
  • 55
  • In case someone lands here looking for the opposite, eg. all documents have milliseconds in date field, take a look at: http://stackoverflow.com/questions/29892152/convert-miliseconds-to-date-in-mongodb-aggregation-pipeline-for-group-by – Wtower Nov 25 '16 at 11:15

10 Answers10

68

You likely have one or more docs with a created_at value that's not a BSON Date and you'll need to fix that by converting those values to Date or removing them.

You can find those docs with a $not query that uses the $type operator like:

db.snippets.find({created_at: {$not: {$type: 9}}})

If the created_at values are date strings, you can find the docs that need updating and then update them in the shell using code like:

db.snippets.find({created_at: {$not: {$type: 9}}}).forEach(function(doc) {
    // Convert created_at to a Date 
    doc.created_at = new Date(doc.created_at);
    db.snippets.save(doc);
})
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
6

try this one, its help for me above problem.

db.snippets.aggregate([{
'$project': {
    month: { $substr: ["$created_at", 5, 2] }
}
 }]);

above code get month wise

data is entered into the database in ISO format which can then be easily worked with.

Anurag Pandey
  • 744
  • 1
  • 7
  • 14
4

In some situations, some documents are supposed to have empty Date fields. In those cases, you could try this (using your example):

db.snippets.aggregate([ { '$project': { month:  
 { $cond: [{ $ifNull: ['$created_at', 0] }, { $month: '$created_at' }, -1] }} } ])

In this example, we would get -1 in the cases whenever no field '$created_at' is found. For all the other cases, we would get the Date month.

FRocha
  • 942
  • 7
  • 11
3

I had a related issue, but in my case the Date fields were the members of an array, so the error was "can't convert BSON type Object to Date".

I needed to get the day of week from the dates in the possibleTripDateTimes array.

Sample document:

{
"possibleTripDateTimes" : [
    {
        "tripDateTime" : ISODate("2015-08-01T06:00:00.000-0700")
    }
]
}

The fix was simply to use dot notation to address the array member fields.

db.trips.aggregate([
  {
       $project: {
         departTime: {
           $map: {
             input: "$possibleTripDateTimes.tripDateTime",
             as: "dateTime",
             in: { $dayOfWeek: "$$dateTime" }
           }
   }
  }
}
]
);

I hope this helps someone who also gets zero search results on the "BSON type Object" search

Skipwave
  • 603
  • 1
  • 5
  • 7
2

I had a similar problem, and solved it checking if the date existed.

db.users.aggregate([
{$project:{day:  { $cond: ["$bd", { $dayOfMonth: "$bd" }, -1] },
           month:  { $cond: ["$bd", { $month: "$bd" }, -1] },
           year:  { $cond: ["$bd", { $year: "$bd" }, -1] }
           }},
{$match:{"month":1, "day":15}}
])

My date field is bd and with that match I'm getting all users that have their birthday on January 15th.

facumedica
  • 658
  • 1
  • 7
  • 20
2

I had the same problem, I figured that the date field is missing for some of the documents causing the conversion to fail. I just added a match clause to filter these out. But ofcourse i am investigating on my app side why they are not being populated.

db.snippets.aggregate([
  {
    '$match': {
      'created_at': {
        "$exists": true
      }
    }
  },
  {
    '$project': {
      month: {
        '$month': '$created_at'
      }
    }
  }
])
Wolf7176
  • 309
  • 4
  • 7
0

This error can also appear if you have incorrectly named your properties in your aggregation relative to what they are in your database.

For example my code was

$group: {
        _id: {$week: "$projects.timeStamp"},
        total: { $sum: "$projects.hours"  }
    }

But I hadn't camelcased timestamp in my database so simply modifying to projects.timestamp fixed it.

sharkdawg
  • 958
  • 1
  • 8
  • 20
0

First, you need to check whether the data type is in ISODate. IF not you can change the data type as the following example.

db.collectionName.find().forEach(function(each_object_from_collection){each_object_from_collection.your_date_field=new ISODate(each_object_from_collection.your_date_field);db.collectionName.save(each_object_from_collection);})

Now you can find it in two ways

db.collectionName.find({ $expr: {$eq: [{ $year: "$your_date_field" }, 2017]}});

Or by aggregation

db.collectionName.aggregate([{$project: {field1_you_need_in_result: 1,field12_you_need_in_result: 1,your_year_variable: {$year: '$your_date_field'}, your_month_variable: {$month: '$your_date_field'}}},{$match: {your_year_variable:2017, your_month_variable: 3}}])
ABDUL JAMAL
  • 452
  • 7
  • 12
0

First, you can identify the particular field which is causing an issue as follows:


    db.collectionName.find( { 'dateField' : { $type : 2 } } )

The above line checks and finds all the documents with field name 'dateField' having type as String(referred as $type - 2).

Once it is identified and verified, we can modify those records as follows:


    db.collectionName.find( { 'dateField' : { $type : 2 } } ).forEach( function (x) {   
      x.dateField = new ISODate(x.dateField);
      db.collectionName.save(x);
    });

0

In my case I had to use "$toDate" and it worked:

db.snippets.aggregate([ { '$project': { month: { '$month': {$toDate: '$created_at'} }} } ])
Buda Sergiu Flavius
  • 210
  • 1
  • 3
  • 13