xavier.seignard
xavier.seignard

Reputation: 11154

mongodb aggregation with $project to conditionally exclude a field

I would like to exclude a field from a mongo db aggergtion pipeline, after reading the docs, I thought I needed to specify either 1 or 0 to keep the field or not (cf. http://docs.mongodb.org/manual/reference/operator/aggregation/project/)

So I tried the following (using node.js mongoose, but the syntax is quite the same as plain mongo):

aggregate.match({ date: { $gte : today } });
aggregate.sort('-date');
aggregate.group({
    _id: '$name',
    date: { $first: '$date' },
    user: { $first: '$user' },
    app: { $first: '$app' }
});
aggregate.project({
    _id: 1,
    last: { $cond: [ { $eq : [ '$_id', 'undo' ] }, '$date', 0 ] },
    user: { $cond: [ { $eq : [ '$_id', 'undo' ] }, '$user', 0 ] },
    app: { $cond: [ { $eq : [ '$_id', 'undo' ] }, '$app', 0 ] }
});

But doing that, I end with documents like this:

[ 
  {
    _id: 'devices',
    user: 0,
    app: 0,
    last: 0
  },
  { 
    _id: 'undo',
    user: 'test',
    app: 'truc',
    last: Mon Jan 26 2015 16:21:53 GMT+0100 (CET)
  }
]

I want the user, app and date to appear only when _id is undo.

How to achieve it?

Thanks!

Upvotes: 10

Views: 5148

Answers (2)

David
David

Reputation: 336

Starting in mongoDB 3.6, you can use the REMOVE variable to exclude fields conditionally.

In your particular case, the project stage should look like this:

aggregate.project({
    _id: 1,
    last: { $cond: [ { $eq : [ '$_id', 'undo' ] }, '$date', '$$REMOVE' ] },
    user: { $cond: [ { $eq : [ '$_id', 'undo' ] }, '$user', '$$REMOVE' ] },
    app: { $cond: [ { $eq : [ '$_id', 'undo' ] }, '$app', '$$REMOVE' ] }
});

Upvotes: 9

sebprunier
sebprunier

Reputation: 21

I think it's not possible yet.

Error message from the shell when trying to exclude a non-_id field :

The top-level _id field is the only field currently supported for exclusion

Upvotes: 2

Related Questions