MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Zapytania hierarchiczne z Mongo za pomocą $graphLookup

Wierzę, że mając poziom pole możemy zbudować hierarchiczną strukturę z tablicy używając $reduce. Aby to osiągnąć, musimy pozyskać reportees uporządkowane według poziomu malejąco po $graphLookup . Niestety obecnie jedynym sposobem na to jest użycie $unwind + $sort + $group, co sprawia, że ​​agregacja jest dość długa.

Następnie możemy przetworzyć zamówioną tablicę za pomocą $reduce . Na każdym kroku wystarczy dodać pracownika do zbioru wyników, w tym jego reportees z poprzedniego poziomu. Dodatkowo musimy wykryć kiedy level w takim przypadku zmiany podczas przetwarzania i zmiany kolejności tablic pomocniczych.

$addFields po prostu zastępuje istniejących reportees w tym przypadku. $concatArrays pozwala nam dołączyć aktualnego pracownika ($$this ) do wyniku. Używając $filter możemy pozyskać reportees z niższego poziomu.

db.getCollection('employees').aggregate([
    {
        $match: {
            empId : "10"
        }
    },
    {
        $graphLookup: {
            from: "employees",
            startWith: "$empId",
            connectFromField: "empId",
            connectToField: "managerId",
            as: "reportees",
            maxDepth: 4,
            depthField: "level"
        }
    },
    {
        $project: {
            "empId":1,
            "managerId":1,
            "reportees.empId":1,
            "reportees.name":1,
            "reportees.managerId":1,
            "reportees.level":1
        }
    },
    {
        $unwind: "$reportees"
    },
    {
        $sort: { "reportees.level": -1 }
    },
    {
        $group: {
            _id: "$_id",
            empId: { $first: "$empId" },
            managerId: { $first: "$managerId" },
            reportees: { $push: "$reportees" }
        }
    },
    {
        $addFields: {
            reportees: {
                $reduce: {
                    input: "$reportees",
                    initialValue: {
                        currentLevel: -1,
                        currentLevelEmployees: [],
                        previousLevelEmployees: []
                    },
                    in: {
                        $let: {
                            vars: {
                                prev: { 
                                    $cond: [ 
                                        { $eq: [ "$$value.currentLevel", "$$this.level" ] }, 
                                        "$$value.previousLevelEmployees", 
                                        "$$value.currentLevelEmployees" 
                                    ] 
                                },
                                current: { 
                                    $cond: [ 
                                        { $eq: [ "$$value.currentLevel", "$$this.level" ] }, 
                                        "$$value.currentLevelEmployees", 
                                        [] 
                                    ] 
                                }
                            },
                            in: {
                                currentLevel: "$$this.level",
                                previousLevelEmployees: "$$prev",
                                currentLevelEmployees: {
                                    $concatArrays: [
                                        "$$current", 
                                        [
                                            { $mergeObjects: [ 
                                                "$$this", 
                                                { reportees: { $filter: { input: "$$prev", as: "e", cond: { $eq: [ "$$e.managerId", "$$this.empId"  ] } } } } 
                                            ] }
                                        ]
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $addFields: { reportees: "$reportees.currentLevelEmployees" }
    }
]).pretty()

Powyższe rozwiązanie powinno działać na wielu poziomach. Wyjścia:

{
    "_id" : "10",
    "empId" : "10",
    "managerId" : "15",
    "reportees" : [
        {
            "empId" : "6",
            "name" : "Employee6",
            "managerId" : "10",
            "level" : NumberLong(0),
            "reportees" : [
                {
                        "empId" : "1",
                        "name" : "Employee1",
                        "managerId" : "6",
                        "level" : NumberLong(1),
                        "reportees" : [ ]
                },
                {
                        "empId" : "2",
                        "name" : "Employee2",
                        "managerId" : "6",
                        "level" : NumberLong(1),
                        "reportees" : [ ]
                }
            ]
        },
        {
            "empId" : "8",
            "name" : "Employee8",
            "managerId" : "10",
            "level" : NumberLong(0),
            "reportees" : [
                {
                    "empId" : "5",
                    "name" : "Employee5",
                    "managerId" : "8",
                    "level" : NumberLong(1),
                    "reportees" : [ ]
                },
                {
                    "empId" : "4",
                    "name" : "Employee4",
                    "managerId" : "8",
                    "level" : NumberLong(1),
                    "reportees" : [ ]
                }
            ]
        }
    ]
}


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Wiele warunków przyłączenia za pomocą operatora $lookup

  2. Jak mogę pobrać dokumenty podrzędne z tablicy?

  3. Jak sprawdzić typ danych kolumny w SQL?

  4. Przechowywanie plików w MongoDB za pomocą GridFS

  5. Jak przejść do produkcji z MongoDB — dziesięć najważniejszych wskazówek