Search code examples
databasemongodbnosqldata-analysis

Is it possible to project fields based on the field name in mongodb?


In a collection, the documents may contains fields like "name", "name:en", "name:de"

{
    _id:123456
    tag:{
        name: HongKong
        name-zh: 香港
        other_tag1: value1
        other_tag2: value2
    }
}
{
    _id:123457
    tag:{
        name-en: Beijing
        other_tag1: value1
        other_tag2: value2
    }
}

What I want is to list out all fields with field name contains "name". I tried with the following codes, but it seems to be stupid, and doesn't list all possible "name"s.

find = {'$or': [{'tag.name': {'$exists': 1}}, {'tag.name:zh': {'$exists': 1}}, {'tag.name:en': {'$exists': 1}}]}
project = {'_id': 0, 'name': '$tag.name', 'name:zh': '$tag.name:zh', 'name:en': '$tag.name:en'}
names = list(db.node.aggregate([{'$match': find}, {'$project': project}]))

And the result I want is:

{
    name: HongKong
    name-zh: 香港
}
{
    name-en: Beijing
}

Solution

  • Its possible to search field names using $objectToArray It may not a optimal solution based on data you need to search.

    $objectToArray to change the tag into array of key value pair followed by $unwind to search the keys for the input pattern and $group + $arrayToObject to return the matching key value pairs.

    db.col.aggregate([
        {$match:{'$or': [{'tag.name': {'$exists': 1}}, {'tag.name-zh': {'$exists': 1}}, {'tag.name-en': {'$exists': 1}}]}}, 
        {$project:{"tagskv":{$objectToArray:"$tag"}}},
        {$unwind:"$tagskv"},
        {$match:{"tagskv.k": { $regex: /name/i }}},
        {$group:{_id:"$_id", names:{$push:"$tagskv"}}},
        {$project:{"names":{$arrayToObject:"$names"}}},
        {$replaceRoot:{newRoot:"$names"}}
    ])