简体   繁体   中英

MongoDB filter docs on dynamic key and value using regex

Suppose I have multiple fields in a document whose key value I don't know(only the user who has added the keys know that)

Now suppose user wants to finds a document specifying the key value, but he forgot what his key value was EXACTLY

So say I have this document:

name: "John Doe"
class: 5
MisChief: "Bullying"

where the MisChief key was custom created.

Suppose user wants to search for 'mischief: bullying'

I can use $regex operator to search for the value, but how can I specify the key as a regex expression ?

Another way to do this is to return all documents, and doing a case insensitive search for the keys from all those documents which is very inefficient.

So with unknown/dynamic/random key names, one way to do it using aggregation operator $objectToArray :

db.collection.aggregate([
  /** Add a new array field to all docs which contains each field as {k:...,v:...} */
  {
    $addFields: { data: { $objectToArray: "$$ROOT" } }
  },
  /** Match docs that has an object in `data` array which matches with input */
  {
    $match: { "data": { "$elemMatch": { "k": "MisChief", "v": "Bullying" } } } // can be a regex /MisChief/i
  },
  /** Remove added array field from output */
  {
    $project: { "data": 0 }
  }
])

Test: mongoplayground

Ref:aggregation

From your statement:

but he forgot what his key value was EXACTLY

If he vaguely remembers Key name/value but doesn't remember it completely - You can do it using regex as you wanted ! But if he forgets it entirely then you can't do much just get all docs where data.v: 'Bullying' & use $match stage to filter further on name of user.

db.collection.aggregate([
  {
    $addFields: { data: { $objectToArray: "$$ROOT" } }
  },
  {
    $match: { "data": { "$elemMatch": { "v": "Bullying" } } } 
  },
  {
    $project: { "data": 0 }
  }
])

Test: mongoplayground

Note:

For one single element { "v": "Bullying" } we don't need to use $elemMatch but to keep syntax consistent we're using it, otherwise you can just use data.v: 'Bullying' in $match stage.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM