IT/MongoDB

MONGODB - aggregate

KeepGooing 2020. 6. 13. 14:31
반응형

기본 구조

{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : [ 
        {
            "type1" : "ISTJ",
            "executeInfo" : [ 
                {
                    "check" : "foodTendency",
                    "type2" : "female",
                    "type2Data" : [ 
                        {
                            "searchData" : {
                                "name" : "Jessica",
                                "height" : "165",
                                "weight" : "42"
                            },
                            "returnData" : "파인애플"
                        }, 
                        {
                            "searchData" : {
                                "name" : "Amy",
                                "height" : "165",
                                "weight" : "42"
                            },
                            "returnData" : "사과"
                        }, 
                        {
                            "searchData" : {
                                "name" : "Alice",
                                "height" : "165",
                                "weight" : "42"
                            },
                            "returnData" : "샌드위치"
                        }
                    ]
                }, 
                {
                    "check" : "foodTendency",
                    "type2" : "male",
                    "type2Data" : [ 
                        {
                            "searchData" : {
                                "name" : "john",
                                "height" : "175",
                                "weight" : "72"
                            },
                            "returnData" : "파인애플"
                        }, 
                        {
                            "searchData" : {
                                "name" : "josh",
                                "height" : "190",
                                "weight" : "92"
                            },
                            "returnData" : "사과"
                        }, 
                        {
                            "searchData" : {
                                "name" : "kan",
                                "height" : "185",
                                "weight" : "82"
                            },
                            "returnData" : "샌드위치"
                        }
                    ]
                }
            ]
        }
    ]
}

 

 

aggregate는 일단 배열 형태로 조회를 한다.

 

따라서 

 

db.getCollection('콜렉션 명').aggregate([ {} ]);

 

이런한 형태로 조회를 하고

 

$match

$unwind

$group

$push

$addToSet

$in

$elemMatch

 

...

 

 

등등 다양한 연산자를 갖췄다.

 

이를 기반으로 다양한 함수를 써보자.

 

 

$match를 쓰면 특정 필드의 값이 들어간 도큐먼트 조회를 할 수 있다.

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}}
]);

 

 

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : [ 
        {
            "type1" : "ISTJ",
            "executeInfo" : [ 
                {
                    "check" : "foodTendency",
                    "type2" : "female",
                    "type2Data" : [ 
                        {
                            "searchData" : {
                                "name" : "Jessica",
                                "height" : "165",
                                "weight" : "42"
                            },
                            "returnData" : "파인애플"
                        }, 
                        {
                            "searchData" : {
                                "name" : "Amy",
                                "height" : "165",
                                "weight" : "42"
                            },
                            "returnData" : "사과"
                        }, 
                        {
                            "searchData" : {
                                "name" : "Alice",
                                "height" : "165",
                                "weight" : "42"
                            },
                            "returnData" : "샌드위치"
                        }
                    ]
                }, 
                {
                    "check" : "foodTendency",
                    "type2" : "male",
                    "type2Data" : [ 
                        {
                            "searchData" : {
                                "name" : "john",
                                "height" : "175",
                                "weight" : "72"
                            },
                            "returnData" : "파인애플"
                        }, 
                        {
                            "searchData" : {
                                "name" : "josh",
                                "height" : "190",
                                "weight" : "92"
                            },
                            "returnData" : "사과"
                        }, 
                        {
                            "searchData" : {
                                "name" : "kan",
                                "height" : "185",
                                "weight" : "82"
                            },
                            "returnData" : "샌드위치"
                        }
                    ]
                }
            ]
        }
    ]
}

 

 

하지만 나아가 특정 필드의 값만 조회하고 싶은 경우

예를들어

type2의 값이 male이고  name이 john의 returnData 값을 조회하고 싶다면

어떻게 할까?

 

 

 

이경우에는 $unwind를 써야 한다.

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"}
]);

 

결과

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : {
        "type1" : "ISTJ",
        "executeInfo" : {
            "check" : "foodTendency",
            "type2" : "female",
            "type2Data" : [ 
                {
                    "searchData" : {
                        "name" : "Jessica",
                        "height" : "165",
                        "weight" : "42"
                    },
                    "returnData" : "파인애플"
                }, 
                {
                    "searchData" : {
                        "name" : "Amy",
                        "height" : "165",
                        "weight" : "42"
                    },
                    "returnData" : "사과"
                }, 
                {
                    "searchData" : {
                        "name" : "Alice",
                        "height" : "165",
                        "weight" : "42"
                    },
                    "returnData" : "샌드위치"
                }
            ]
        }
    }
}

/* 2 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : {
        "type1" : "ISTJ",
        "executeInfo" : {
            "check" : "foodTendency",
            "type2" : "male",
            "type2Data" : [ 
                {
                    "searchData" : {
                        "name" : "john",
                        "height" : "175",
                        "weight" : "72"
                    },
                    "returnData" : "파인애플"
                }, 
                {
                    "searchData" : {
                        "name" : "josh",
                        "height" : "190",
                        "weight" : "92"
                    },
                    "returnData" : "사과"
                }, 
                {
                    "searchData" : {
                        "name" : "kan",
                        "height" : "185",
                        "weight" : "82"
                    },
                    "returnData" : "샌드위치"
                }
            ]
        }
    }
}

결과 값을 잘 살펴보면 _id값이 두개가 생겼다. 즉 하나의 document가 document 두개로 나뉘어진 것을 알 수 있다.

 

 

document 단위로 조회되는 몽고디비는 $unwind를 사용했을 때 좀 더 자세하게 조회는 물론 좀 더 구체적인 특정 값만 

뽑을 수 있게 된다.

 

 

 

 

자 이제 

type2의 값이 male이고  name이 john의 returnData 값을 조회해보자.

 

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"},
{$unwind : "$intentArray.executeInfo.type2Data"},
{$match :{"intentArray.executeInfo.type2Data.searchData.name" : "john"}},
]);

 

 

결과

 

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : {
        "type1" : "ISTJ",
        "executeInfo" : {
            "check" : "foodTendency",
            "type2" : "male",
            "type2Data" : {
                "searchData" : {
                    "name" : "john",
                    "height" : "175",
                    "weight" : "72"
                },
                "returnData" : "파인애플"
            }
        }
    }
}

 

앞선 말한 조건의 해당 값만 document로 조회되었다.

 

근데 우리는 returnData의 값 파인애플만 필요하다.

이때는 어떻게 해야할까?

 

그러면 

$project를 쓰면 된다.

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"},
{$unwind : "$intentArray.executeInfo.type2Data"},
{$match :{"intentArray.executeInfo.type2Data.searchData.name" : "john"}},
{$project : {_id: '$_id', "intentArray.executeInfo.type2Data.returnData": 1}},
]);

 

결과

 

/* 1 */
{
    "intentArray" : {
        "executeInfo" : {
            "type2Data" : {
                "returnData" : "파인애플"
            }
        }
    },
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3")
}

끝.

 

 

$sample 

 

이번에는 $sample 연산자를 알아보자

특정 Array에서 특정 객체를 랜덤으로 조회하고 싶을 때 쓴다.

 

type2Data 안의 특정 사람의 신체 특성 그리고 그에 해당하는 returnData값을 

객체 형태로 랜덤 식으로 2개씩 뽑는 것이다.

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"},
{$unwind : "$intentArray.executeInfo.type2Data"},
{$sample : {size : 2}}
]);

 

 

 

결과

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : {
        "type1" : "ISTJ",
        "executeInfo" : {
            "check" : "foodTendency",
            "type2" : "female",
            "type2Data" : {
                "searchData" : {
                    "name" : "Alice",
                    "height" : "165",
                    "weight" : "42"
                },
                "returnData" : "샌드위치"
            }
        }
    }
}

/* 2 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : {
        "type1" : "ISTJ",
        "executeInfo" : {
            "check" : "foodTendency",
            "type2" : "female",
            "type2Data" : {
                "searchData" : {
                    "name" : "Amy",
                    "height" : "165",
                    "weight" : "42"
                },
                "returnData" : "사과"
            }
        }
    }
}

 

 

 

이번에는 $unwind로 나뉘어진 document를 다시 하나의 document로 만드는 방법

정확히는 나뉘어진 Array를 하나의 Array로 합치는 것이다.

 

 

 

$push

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"},
{$unwind : "$intentArray.executeInfo.type2Data"},
{$sample : {size : 2}},
{$group : {'_id' : '$_id', "type2Data" : {$push : "$intentArray.executeInfo.type2Data"}}}
]);

 

결과

 

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "type2Data" : [ 
        {
            "searchData" : {
                "name" : "Amy",
                "height" : "165",
                "weight" : "42"
            },
            "returnData" : "사과"
        }, 
        {
            "searchData" : {
                "name" : "josh",
                "height" : "190",
                "weight" : "92"
            },
            "returnData" : "사과"
        }
    ]
}

 

 

 

 

근데 특정 값만 나오고 다른 필드가 사라진 것을 알 수 있다.

 

이유는 $group 연산자에서 특정 필드만 group했기 때문이다.

 

 

이렇게 $push의  Array 형태를 좀 더 크게 설정하면 원하는 결과를 만들 수 있다.

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"},
{$unwind : "$intentArray.executeInfo.type2Data"},
{$sample : {size : 2}},
{$group : {'_id' : '$_id',  "intentArray" : {  $push :  "$intentArray"}}}
]);

 

 

결과

 

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intentArray" : [ 
        {
            "type1" : "ISTJ",
            "executeInfo" : {
                "check" : "foodTendency",
                "type2" : "male",
                "type2Data" : {
                    "searchData" : {
                        "name" : "kan",
                        "height" : "185",
                        "weight" : "82"
                    },
                    "returnData" : "샌드위치"
                }
            }
        }, 
        {
            "type1" : "ISTJ",
            "executeInfo" : {
                "check" : "foodTendency",
                "type2" : "male",
                "type2Data" : {
                    "searchData" : {
                        "name" : "josh",
                        "height" : "190",
                        "weight" : "92"
                    },
                    "returnData" : "사과"
                }
            }
        }
    ]
}

 

자 이제 여러 연산자를 조합해서 좀더 의미있는 데이터를 조회해보자.

이 때 연산자의 순서 즉 위치가 중요하다.

 

 

type2 필드의 내림차순으로 0번째 값부터 조회하고 값은 1개로 제한

db.getCollection('intent_test').aggregate([
{$match :{"intent" : "MBTI_TYPE"}},
{$unwind : "$intentArray"},
{$unwind : "$intentArray.executeInfo"},
{$sort : {"intentArray.executeInfo.type2" : -1}},
{$skip : 0},
{$limit : 1}
]);

결과

 

/* 1 */
{
    "_id" : ObjectId("5edf2e8ec4130e33cda725b3"),
    "intent" : "MBTI_TYPE",
    "intentArray" : {
        "type1" : "ISTJ",
        "executeInfo" : {
            "check" : "foodTendency",
            "type2" : "male",
            "type2Data" : [ 
                {
                    "searchData" : {
                        "name" : "john",
                        "height" : "175",
                        "weight" : "72"
                    },
                    "returnData" : "파인애플"
                }, 
                {
                    "searchData" : {
                        "name" : "josh",
                        "height" : "190",
                        "weight" : "92"
                    },
                    "returnData" : "사과"
                }, 
                {
                    "searchData" : {
                        "name" : "kan",
                        "height" : "185",
                        "weight" : "82"
                    },
                    "returnData" : "샌드위치"
                }
            ]
        }
    }
}

 

 

 

 

반응형

'IT > MongoDB' 카테고리의 다른 글

JSON.parse() 활용하여 몽고디비 필드 동적 생성  (0) 2021.04.11
몽고디비 - findOneAndUpdate  (0) 2020.06.13
MONGODB - find  (0) 2020.06.13
MONGODB - 기본구조  (0) 2020.06.09
몽고DB 집계 함수  (0) 2019.07.30