0

In MongoDB i have documents with the following structure:

{
  "_id": {
    "$oid": "570794ee453b02a0001000001"
  },
  "fields_data": {
    "572999c241f1590001000005": "Chicago",
    "572999c241f1590001000007": "Male",
    "572999c241f1590001000013": "Dr.",
    "57299c0741f1590001000023": null,
    "572999c241f1590001000017": "",
    "589886d48570e90001000111": true,
    "58762ac58570e9000100006a": true
  }
}

fields_data object is very dynamic; the <field> of the object is not static.

Is it possible to search or filter only the values of the fields_data object?.

Something like:

$filter: {
    input: "$fields_data",
    as: "field",
    cond: { $eq: [ "$$field.???", "Male" ] }
}

I'm using MongoDB 5.0.4 Community

EDIT/SOLUTION:

Thanks for the reply and help. The following worked for me.

<used within node>

[
    {
        '$project': {
            'array': {
            '$objectToArray': '$fields_data'
            }, 
            'doc': '$$ROOT'
        }
        }, {
        '$match': {
            'array.v': 'Male'
        }
        }, {
        '$replaceRoot': {
            'newRoot': '$doc'
        }
    }
]
Luc
  • 365
  • 4
  • 22

2 Answers2

1

I think this is the answer you looking for basically you can use $where. I also agree with the comment that you might reconsider to have your fields_data be an array of objects with "name" and "value" fields so you can have straight normal queries.

Carlo Capuano
  • 382
  • 3
  • 6
0

Query1

  • filter the object and keep the field that is "Male"
  • we cant construct paths dynamically, so the only way is to convert the object to array and filter.
  • objectToArray to convert the embeded document to an array in the form
    [{"k" : "key1", "v" : "value1"} ....]
  • filter and keep only if "value"="Male"
  • arrayToObject to convert back to object like it was

*i think you should change your schema, fields are for the schema, not for saving data in general, if you do this queries become much more complicated and slower

Test code here

aggregate(
[{"$set":
  {"fields_data":
   {"$filter":
    {"input":{"$objectToArray":"$fields_data"},
     "cond":{"$eq":["$$this.v", "Male"]}}}}},
 {"$set":{"fields_data":{"$arrayToObject":["$fields_data"]}}}])

Query2

  • filter the documents and keep those that have the "Male"
  • works like the above but only to filter

Test code here

aggregate(
[{"$match":
  {"$expr":
   {"$ne":
    [{"$filter":
      {"input":{"$objectToArray":"$fields_data"},
       "cond":{"$eq":["$$this.v", "Male"]}}},
     []]}}}])
Takis
  • 8,314
  • 2
  • 14
  • 25