Finding a specific element in nested Array MongoDB

Question:

DB Schema

[{
  "_id": 1,
  "name": "city1",
  "districts": [
    {
      "id": 5,
      "name": "district 1",
      "neighborhoods": [
        {
          "id": 309,
          "name": "neighborhood 1"
        }
      ]
    },
    {
      "id": 6,
      "name": "district 2",
      "neighborhoods": [
        {
          "id": 52280,
          "name": "neighborhood 2"
        }
      ]
    }
},
{
  "_id": 1,
  "name": "city2",
  "districts": [
    {
      "id": 5,
      "name": "district 3",
      "neighborhoods": [
        {
          "id": 309,
          "name": "neighborhood 3"
        }
      ]
    },
    {
      "id": 6,
      "name": "district 4",
      "neighborhoods": [
        {
          "id": 52280,
          "name": "neighborhood 4"
        },
        {
          "id": 52287,
          "name": "neighborhood 5"
        }
      ]
    }
}]

Goal

I would like to be able to check whether a 3-tuple combination is valid. Given some values for name, districts.name, and district.neighborhoods.name; I would like to check if those 3 values do indeed represent a valid combination. By valid I mean that they are nested in each other.

Example 1

If I am given city1, district 1, and neighborhood 1 as input, this is a valid combination (Because they are nested inside each other)

Example 2

If I am given city2, district 4, and neighborhood 4 as input, this is a valid combination

Example 3

If I am given city1, district 1, and neighborhood 2 as input, this is NOT a valid combination (because they are not nested inside each other)

Example 4

If I am given city1, district 3, and neighborhood 3 as input, this is NOT a valid combination

Expected Output

Assuming I am given city1, district 1, and neighborhood 1 (a valid combination) for name, districts.name, and districts.neighborhoods.name respectively. The output should be:

{
  "_id": 1,
  "name": "city1",
  "districts": [
    {
      "id": 5,
      "name": "district 1",
      "neighborhoods": [
        {
          "id": 309,
          "name": "neighborhood 1"
        }
      ]
    }
}

Assuming I am given city1, district 1, and neighborhood 2 (NOT a valid combination) for name, districts.name, and districts.neighborhoods.name respectively. The output should be empty or null or something indicating that an array element with these values does not exist.

Current Approach

doesLocationExist = await locationDbConnection.find_one(
        { "location" : {
            "$elemMatch" :  
                {"name" : city, "districts.name" : district, "districts.neighborhoods.name": neighborhood}
            }
        }
    )

I was hoping this would return a document if the combination is valid, but it always returns None even when the combination is valid.
Essentially what I am trying to do is retrieve a double-nested array element using the "path" (the 3-tuple input mentioned earlier); if that element exists, that means it is a valid combination, otherwise, it is not.

Previous Questions That Did Not Help

P.S: the neighborhood and district names are not unique, so I cannot use projection to display only the array element of interest

Asked By: Ahmet-Salman

||

Answers:

A nested $elemMatch to check if the given combination exists. It will give a result if it does.

db.collection.aggregate([
  {
    $match: {
      name: city,
      districts: {
        $elemMatch: {
          name: district,
          neighborhoods: {
            $elemMatch: {
              name: neighborhood
            }
          }
        }
      }
    }
  }
])

playground

if you actually want the correct result you can keep doing $match,$unwind until you get the result. This is assuming if there is only 1 unique combination of city,district and neighborhood

db.collection.aggregate([
  { $match: { name: city } },
  { $unwind: "$districts" },
  { $match: { "districts.name": district } },
  { $unwind: "$districts.neighborhoods" },
  { $match: { "districts.neighborhoods.name": neighborhood } }
])

playground

if there is more than 1 unique combination a more complex grouping will be needed
playground

Answered By: cmgchess
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.