Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional field selection with Mongoose

Say I have a collection of users with usernames and email addresses.

{ name: 'John Doe', email: '[email protected]', level: 5 }
{ name: 'Fred Foo', email: '[email protected]', level: 2 }
{ name: 'Jo Green', email: '[email protected]', level: 5 }
{ name: 'Paul Bar', email: '[email protected]', level: 3 }

I want to query this collection, selecting all users' names and levels. In Mongoose, I could do that like this:

User
  .find()
  .select('name level')
  .exec(callback)

This would give me the following:

{ name: 'John Doe', level: 5 }
{ name: 'Fred Foo', level: 2 }
{ name: 'Jo Green', level: 5 }
{ name: 'Paul Bar', level: 3 }

But if a user's level is above 4, I want to also get their email address. This would give me the following:

{ name: 'John Doe', email: '[email protected]', level: 5 }
{ name: 'Fred Foo', level: 2 }
{ name: 'Jo Green', email: '[email protected]', level: 5 }
{ name: 'Paul Bar', level: 3 }

What is the best that with Mongo[ose]?

like image 724
cbnz Avatar asked Mar 21 '23 02:03

cbnz


1 Answers

No, there's not anyway in MongoDb currently to in one query to selectively return different sets of fields depending on conditions. A query in MongoDb and the associated projection applies to all documents.

A map reduce cannot do this (as a map reduce needs to return the same values for each document) and would be a poor fit. An aggregation isn't a general purpose alternative to many queries and returning fields conditionally would be complex.

You have a few options:

  1. Execute multiple queries and merge the results. That would be very simple as each result is an array, so you could just merge the arrays.
  2. Return the superset of all fields and filter in your app code.

I'd test the performance of the options. Neither are complex.

like image 172
WiredPrairie Avatar answered Apr 05 '23 20:04

WiredPrairie