3

My MongoDB stores documents having the following structure:

{
    "application_detail":{},
    "curl_detail":{
        "Curl1":{
            "key1":"value1",
            "key2":"value2"
        },
        "Curl2":{
            "key1":"value1",
            "key2":"value2"        
        },
        "Curl3":{
            "key1":"value1",
            "key2":"value2"
        },
        "Curl4":{
            "key1":"value1",
            "key2":"value2"
        },
        /*total number of curls are unknown*/
    }
}

How can I fetch key1 for all the curls present under curl_detail from mongoDB using express and mongoose?

Expected Output:

{
    "curl_detail": {
        "Curl1": {
            "key1": "value1"
        },
        "Curl2": {
            "key1": "value1"
        },
        "Curl3": {
            "key1": "value1"
        },
        "Curl4": {
            "key1": "value1"
        }
    }
}

NOTE: Total number of curls are unknown.

5
  • What does your expected output from the query look like? Post the expected output you want from the mongoose query. Commented Feb 3, 2020 at 11:44
  • { "curl_detail":{ "Curl1":{ "key1":"value1" }, "Curl2":{ "key1":"value1" }, "Curl3":{ "key1":"value1" }, "Curl4":{ "key1":"value1" } /* so on for all the curls present in that document */ } } @AnkitaKuchhadiya This is the output I expect. Commented Feb 3, 2020 at 12:14
  • Does this result also work for you? "curl_detail": { "Curl1": "value1", "Curl2": "value1", "Curl3": "value1", "Curl4": "value1" } Commented Feb 3, 2020 at 13:06
  • @SuleymanSah This will work for me. Could you please provide an equivalent mongoose code for the same? Commented Feb 3, 2020 at 18:18
  • Please check my updated answer to use aggregation with mongoose. Commented Feb 3, 2020 at 18:21

3 Answers 3

2

I would like to propose you changing data structrure from

"curl_detail": {
    "Curl1": {
        "key1": "value1",
        "key2": "value2"
    },
    "Curl2": {
        "key1": "value1",
        "key2": "value2"
    }
}

to

"curl_detail": [{
        "key1": "value1",
        "key2": "value2"
    },
    {
        "key1": "value1",
        "key2": "value2"
    }
]

Storing data structure in array will allow you to find some data in an easier way. Also there's no need to have object with properties like Curl1, Curl2 etc.

For the new data structure there are already some answers with the explanation:

1) Mongo find value with unknown parent key

2) Query MongoDB by value when parent key is unknown

3) MongoDB: Find document given field values in an object with an unknown key

UPDATE

If there's no possibility to change the data structure please see this solution (trick with use of $arrayToObject / $objectToArray to determine the name of nested key e.g. "Curl1"):

db.collection.aggregate([{
        $addFields: {
            curl_detail: {
                $arrayToObject: {
                    $map: {
                        input: {
                            $objectToArray: "$curl_detail"
                        },
                        as: "details",
                        in: {
                            k: "$$details.k",
                            v: {
                                key1: "$$details.v.key1"
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            curl_detail: 1
        }
    }
])

This outputs the following:

[
  {
    "curl_detail": {
      "Curl1": {
        "key1": "value1"
      },
      "Curl2": {
        "key1": "value1"
      },
      "Curl3": {
        "key1": "value1"
      },
      "Curl4": {
        "key1": "value1"
      }
    }
  }
]

You can check it through Mongo Playground

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Hlib for the recommendation. But this is something out of my scope for now. I am not allowed to make any changes to data. I just need to fetch and populate it on the UI.
@KapilKhandelwal the updated answer is just a revision of my answer. This is not friendly. Please see his edit.
@SuleymanSah in fact I've also used the same operators because there's no other solution for the question. Finally my solution returns the correct data structure. Please be polite and accept others' opinions.
1

You can use projection for the query you are looking for:

collection.find({}, {"curl_detail":1}, (findError, results) => {
  if(findError) { 
    //handle the error
    return;
  }
  // here is the expected result
  console.log();
});

2 Comments

This is giving me this result: { "curl_detail" : { "Curl1" : { "key1" : "value1", "key2" : "value2" }, "Curl2" : { "key1" : "value1", "key2" : "value2" }, "Curl3" : { "key1" : "value1", "key2" : "value2" }, "Curl4" : { "key1" : "value1", "key2" : "value2" } } } How does it work?
@SuleymanSah You are correct. This will return me all the fields of that Curl which is not what I am expecting. I just need key1 for all the Curls. @Shubh @Ankita correct me if I am wrong.
1

If this result also works for you:

[
  {
    "curl_detail": {
      "Curl1": "value1",
      "Curl2": "value1",
      "Curl3": "value1",
      "Curl4": "value1"
    }
  }
]

You can use the following aggregation using the $objectToArray and $arrayToObject

db.collection.aggregate([
  {
    $addFields: {
      curl_detail: {
        $map: {
          "input": {
            "$objectToArray": "$curl_detail"
          },
          "as": "el",
          "in": {
            "k": "$$el.k",
            "v": "$$el.v.key1",

          }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      curl_detail: {
        $arrayToObject: "$curl_detail"
      }
    }
  }
])

Playground

You can use this aggregation with mongoose like this, let's say your model is MyModel:

MyModel.aggregate([
  {
    $addFields: {
      curl_detail: {
        $map: {
          input: {
            $objectToArray: '$curl_detail'
          },
          as: 'el',
          in: {
            k: '$$el.k',
            v: '$$el.v.key1'
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      curl_detail: {
        $arrayToObject: '$curl_detail'
      }
    }
  }
]).then(res => {
  console.log(res);
});

3 Comments

Thanks for your response. @Hlib had provided me the perfect result that I was looking for. "curl_detail": { "Curl1": "value1", "Curl2": "value1", "Curl3": "value1", "Curl4": "value1" } This output would have worked as a workaround for me.
@KapilKhandelwal he just updated his answer after my answer, copied and just edited one line, that is not friendlier. You will see this if you compare his edit history.
@KapilKhandelwal you can at least upvote my answer, but I appreciate if you can also mark it as answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.