├── 01.mongodb 구축 ├── Replica_Set.md └── Sharding.md ├── 02.Query 실습 ├── CRUD.md ├── aggregationExamples.md ├── aggregationOptimize.js ├── aggregationProblem.md ├── arrayAndEmbeddedDocuments.md ├── changestream.py ├── explain.js ├── geospatialBasics.js ├── indexBound.js ├── indexOptimize.js ├── lookup.js ├── queryProblems.md └── usefulFunctions.md ├── 03.읽기쓰기제어 ├── causal_consistency.py ├── read_preference.py ├── read_write_concern.py ├── transaction1.py └── transaction2.py ├── 04.Index ├── compoundIndex.js ├── indexProperties.js └── multikeyIndex.js ├── 05.Modeling ├── AttributePattern.js ├── BucketPattern.js ├── ExtendedReferencePattern.js ├── SubsetPattern.js └── TreePattern.js └── README.md /01.mongodb 구축/Replica_Set.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | 이 문서는 local 환경에서 MongoDB를 Replica Set으로 구축하는 방법을 작성한다. 4 | 5 | ## 참고 6 | 7 | - https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/ 8 | - https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set-for-testing/ 9 | 10 | ## 환경 11 | 12 | 해당 실습은 MacOS에서 진행되었으면 MongoDB 5.0.12 버전을 사용한다. 13 | 14 | Window나 Linux 계열의 다른 플랫폼에서 사용하더라도 binary의 옵션은 동일하여, 똑같이 실습 진행이 가능하다. 15 | 16 | ## 실습 17 | 18 | ### Binary 설치 19 | 20 | https://www.mongodb.com/try/download/community 21 | 22 | ### 환경 준비 23 | 24 | ```bash 25 | mkdir -p mongodb/data{1,2,3} 26 | mkdir -p mongodb/config 27 | mkdir -p mongodb/logs 28 | ``` 29 | 30 | ### 실행 방법1. Binary 옵션 이용 31 | 32 | ```bash 33 | cd ~/Downloads 34 | cd mongodb-macos-x86_64-5.0.12 35 | cd bin 36 | 37 | # 각각 다른 터미널에서 실행한다. 38 | mongod --replSet rs1 --port 27017 --bind_ip "0.0.0.0" --dbpath /Users/user/mongodb/data1 --oplogSize 128 39 | mongod --replSet rs1 --port 27018 --bind_ip "0.0.0.0" --dbpath /Users/user/mongodb/data2 --oplogSize 128 40 | mongod --replSet rs1 --port 27019 --bind_ip "0.0.0.0" --dbpath /Users/user/mongodb/data3 --oplogSize 128 41 | ``` 42 | 43 | ### 실행 방법2. Config File 이용 44 | 45 | ```bash 46 | vim mongodb/config/mongod1.conf 47 | vim mongodb/config/mongod2.conf 48 | vim mongodb/config/mongod3.conf 49 | ``` 50 | 51 | #### mongod1.conf 52 | 53 | ```yaml 54 | net: 55 | port: 27017 56 | bindIp: 0.0.0.0 57 | 58 | storage: 59 | dbPath: "/Users/user/mongodb/data1" 60 | directoryPerDB: true 61 | 62 | replication: 63 | oplogSizeMB: 128 64 | replSetName: "rs1" 65 | 66 | systemLog: 67 | path: "/Users/user/mongodb/logs/mongod1.log" 68 | destination: "file" 69 | ``` 70 | 71 | #### mongod2.conf 72 | 73 | ```yaml 74 | net: 75 | port: 27018 76 | bindIp: 0.0.0.0 77 | 78 | storage: 79 | dbPath: "/Users/user/mongodb/data2" 80 | directoryPerDB: true 81 | 82 | replication: 83 | oplogSizeMB: 128 84 | replSetName: "rs1" 85 | 86 | systemLog: 87 | path: "/Users/user/mongodb/logs/mongod2.log" 88 | destination: "file" 89 | ``` 90 | 91 | #### mongod3.conf 92 | 93 | ```yaml 94 | net: 95 | port: 27019 96 | bindIp: 0.0.0.0 97 | 98 | storage: 99 | dbPath: "/Users/user/mongodb/data3" 100 | directoryPerDB: true 101 | 102 | replication: 103 | oplogSizeMB: 128 104 | replSetName: "rs1" 105 | 106 | systemLog: 107 | path: "/Users/user/mongodb/logs/mongod3.log" 108 | destination: "file" 109 | ``` 110 | 111 | ```bash 112 | cd ~/Downloads 113 | cd mongodb-macos-x86_64-5.0.12 114 | cd bin 115 | 116 | # 각각 다른 터미널에서 실행한다. 117 | ./mongod -f /Users/user/mongodb/config/mongod1.conf 118 | ./mongod -f /Users/user/mongodb/config/mongod2.conf 119 | ./mongod -f /Users/user/mongodb/config/mongod3.conf 120 | ``` 121 | 122 | ### Replica Set Initiate 123 | 124 | #### 멤버 접속 125 | 126 | ```bash 127 | cd ~/Downloads 128 | cd mongodb-macos-x86_64-5.0.12 129 | cd bin 130 | 131 | ./mongo "mongodb://localhost:27017" 132 | ``` 133 | 134 | #### Replica Set Initiate and Check 135 | 136 | ```javascript 137 | rs.initiate({ 138 | _id: "rs1", 139 | members: [ 140 | { _id: 0, host: "localhost:27017" }, 141 | { _id: 1, host: "localhost:27018" }, 142 | { _id: 2, host: "localhost:27019" }, 143 | ], 144 | }); 145 | 146 | rs.status; 147 | ``` 148 | -------------------------------------------------------------------------------- /01.mongodb 구축/Sharding.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | mongo --nodb --no rc 3 | ``` 4 | 5 | MongoDB 접속 없이 shell을 실행한다. 6 | 7 | 8 | ```javascript 9 | MongoRunner.dataPath = "/Users/user/fastcampus/mongodb/shardData/" 10 | 11 | st = ShardingTest({ 12 | name: "test-shard", 13 | chunkSize: 1, 14 | shards: 3, 15 | rs: { 16 | nodes: 3, 17 | oplogSize: 10 18 | }, 19 | other: { 20 | enableBalancer: true 21 | } 22 | }) 23 | ``` 24 | Sharded Cluster를 구축한다. 25 | 26 | 27 | 28 | ```javascript 29 | arr = [] 30 | for (i = 0; i < 100000; i++){ 31 | document = { 32 | index: i, 33 | text: "text" + i 34 | } 35 | arr.push(document); 36 | } 37 | 38 | db.testing.insertMany(arr); 39 | 40 | sh.status() 41 | 42 | sh.enableSharding('test') 43 | 44 | db.testing.createIndex({ index: 1 }) 45 | 46 | sh.shardCollection("test.testing", { index: 1 }) 47 | 48 | sh.status() 49 | 50 | 51 | db.testing.createIndex({ text: "hashed" }) 52 | 53 | sh.reshardCollection("test.testing", { text: "hashed" }) 54 | 55 | 56 | sh.status() 57 | ``` 58 | 접속 후 Sharding을 수행한다. 59 | -------------------------------------------------------------------------------- /02.Query 실습/CRUD.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | 이 문서는 CRUD의 기본 사용방법과 주의사항을 확인할 수 있는 실습을 담고 있다. 4 | 5 | ## 환경 6 | 7 | MongoDB Atlas에서 5.0버전을 사용한다. 8 | 9 | ## 실습 10 | 11 | ### Insert One 12 | 13 | ```javascript 14 | db.employees.insertOne({ 15 | name: "lake", 16 | age: 21, 17 | dept: "Database", 18 | joinDate: new ISODate("2022-10-05"), 19 | salary: 400000, 20 | bonus: null 21 | }); 22 | ``` 23 | 24 | ### Insert Many 25 | 26 | ```javascript 27 | db.employees.insertMany([ 28 | { 29 | name: "ocean", 30 | age: 45, 31 | dept: "Network", 32 | joinDate: new ISODate("1999-11-15"), 33 | salary: 10000, 34 | resignationDate: new ISODate("2002-12-23"), 35 | bonus: null 36 | }, 37 | { 38 | name: "river", 39 | age: 34, 40 | dept: "DevOps", 41 | isNegotiating: true, 42 | }, 43 | ]); 44 | ``` 45 | 46 | ### Insert One vs Insert Many 47 | 48 | ```javascript 49 | // insertOne 50 | for (i = 0; i < 300; i++) { 51 | db.insertTest.insertOne({ a: i }); 52 | } 53 | 54 | // insertMany 55 | var docs = []; 56 | for (i = 0; i < 300; i++) { 57 | docs.push({ a: i }); 58 | } 59 | db.insertTest.insertMany(docs); 60 | ``` 61 | 62 | - 2개 이상의 Document를 생성하는 경우 가능하면 insertMany함수를 활용하는 것이 좋다. 63 | - 속도차이가 Document 수에 비례해서 많이난다. 64 | 65 | ### Update One 66 | 67 | ```javascript 68 | db.employees.updateOne( 69 | { name: "river" }, 70 | { 71 | $set: { 72 | salary: 350000, 73 | dept: "Database", 74 | joinDate: new ISODate("2022-12-31"), 75 | }, 76 | $unset: { 77 | isNegotiating: "", 78 | }, 79 | } 80 | ); 81 | ``` 82 | 83 | ### Update Many 84 | 85 | ```javascript 86 | db.employees.updateMany( 87 | { resignationDate: { $exists: false }, joinDate: { $exists: true } }, 88 | { 89 | $mul: { salary: Decimal128("1.1") }, 90 | } 91 | ); 92 | ``` 93 | 94 | ```javascript 95 | db.employees.updateMany( 96 | { resignationDate: { $exists: false }, bonus: null }, 97 | { 98 | $set: { bonus: 100000 }, 99 | } 100 | ); 101 | ``` 102 | 103 | ### Delete One 104 | 105 | ```javascript 106 | db.employees.deleteOne({ name: "river" }); 107 | ``` 108 | 109 | ### Delete Many 110 | 111 | ```javascript 112 | db.employees.deleteMany({}); 113 | ``` 114 | 115 | ### Drop Collection 116 | 117 | ```javascript 118 | db.employees.drop(); 119 | ``` 120 | 121 | ### Find All 122 | ```javascript 123 | use sample_guides 124 | db.planets.find(); 125 | db.planets.find({}); 126 | ``` 127 | 128 | ### Find with Operators 129 | ```javascript 130 | db.planets.find({name: "Mars"}); 131 | 132 | db.planets.find({hasRings: true, orderFromSun: {$lte: 6}}) 133 | db.planets.find({ 134 | $and: [ 135 | {hasRings: true}, 136 | {orderFromSun: {$lte: 6}} 137 | ] 138 | }) 139 | 140 | db.planets.find({ 141 | $or: [ 142 | {hasRings: {$ne: false}}, 143 | {surfaceTempatureC.mean: {$lt: 0}} 144 | ] 145 | }) 146 | 147 | db.planets.find({mainAtmosphere: {$in: ['O2']}}) 148 | ``` 149 | -------------------------------------------------------------------------------- /02.Query 실습/aggregationExamples.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | db.orders.insertMany( [ 3 | { _id: 0, name: "Pepperoni", size: "small", price: 19, 4 | quantity: 10, date: ISODate( "2021-03-13T08:14:30Z" ) }, 5 | { _id: 1, name: "Pepperoni", size: "medium", price: 20, 6 | quantity: 20, date : ISODate( "2021-03-13T09:13:24Z" ) }, 7 | { _id: 2, name: "Pepperoni", size: "large", price: 21, 8 | quantity: 30, date : ISODate( "2021-03-17T09:22:12Z" ) }, 9 | { _id: 3, name: "Cheese", size: "small", price: 12, 10 | quantity: 15, date : ISODate( "2021-03-13T11:21:39.736Z" ) }, 11 | { _id: 4, name: "Cheese", size: "medium", price: 13, 12 | quantity:50, date : ISODate( "2022-01-12T21:23:13.331Z" ) }, 13 | { _id: 5, name: "Cheese", size: "large", price: 14, 14 | quantity: 10, date : ISODate( "2022-01-12T05:08:13Z" ) }, 15 | { _id: 6, name: "Vegan", size: "small", price: 17, 16 | quantity: 10, date : ISODate( "2021-01-13T05:08:13Z" ) }, 17 | { _id: 7, name: "Vegan", size: "medium", price: 18, 18 | quantity: 10, date : ISODate( "2021-01-13T05:10:13Z" ) } 19 | ]) 20 | 21 | db.orders.aggregate([ 22 | { 23 | $match: { 24 | size: "medium" 25 | } 26 | }, 27 | { 28 | $group: { 29 | _id: { $getField: "name" }, 30 | totalQuantity: { 31 | $sum: {$getField: "quantity"} 32 | } 33 | } 34 | } 35 | ]) 36 | 37 | 38 | db.orders.aggregate([ 39 | { 40 | $match: { 41 | size: "medium" 42 | } 43 | }, 44 | { 45 | $group: { 46 | _id: "$name", 47 | totalQuantity: { 48 | $sum: "$quantity" 49 | } 50 | } 51 | } 52 | ]) 53 | 54 | 55 | db.orders.aggregate([ 56 | { 57 | $match: { 58 | date: { 59 | $gte: new ISODate("2020-01-30"), 60 | $lt: new ISODate("2022-01-30") 61 | } 62 | } 63 | }, 64 | { 65 | $group: { 66 | _id: { 67 | $dateToString: { 68 | format: "%Y-%m-%d", date: "$date" 69 | } 70 | }, 71 | totalOrderVaule: { 72 | $sum: { 73 | $multiply: ["$price", "$quantity"] 74 | } 75 | }, 76 | averageOrderQuantity: { 77 | $avg: "$quantity" 78 | } 79 | } 80 | }, 81 | { 82 | $sort: { 83 | totalOrderVaule: -1 84 | } 85 | } 86 | ]) 87 | 88 | 89 | db.books.insertMany([ 90 | { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }, 91 | { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }, 92 | { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }, 93 | { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }, 94 | { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } 95 | ]) 96 | 97 | db.books.aggregate([ 98 | { 99 | $group: { 100 | _id: "$author", 101 | books: { 102 | $push: "$title" 103 | } 104 | } 105 | } 106 | ]) 107 | 108 | 109 | db.books.aggregate([ 110 | { 111 | $group: { 112 | _id: "$author", 113 | books: { 114 | $push: "$$ROOT" 115 | }, 116 | totalCopies: { 117 | $sum: "$copies" 118 | } 119 | } 120 | } 121 | ]) 122 | 123 | 124 | db.books.aggregate([ 125 | { 126 | $group: { 127 | _id: "$author", 128 | books: { 129 | $push: "$$ROOT" 130 | } 131 | } 132 | }, 133 | { 134 | $addFields: { 135 | totalCopies : {$sum: "$books.copies"} 136 | } 137 | } 138 | ]) 139 | 140 | 141 | db.orders.drop() 142 | 143 | db.orders.insertMany([ 144 | { "productId" : 1, "price" : 12, }, 145 | { "productId" : 2, "price" : 20, }, 146 | { "productId" : 3, "price" : 80, } 147 | ]) 148 | 149 | 150 | db.products.insertMany([ 151 | { "id" : 1, "instock" : 120 }, 152 | { "id" : 2, "instock" : 80 }, 153 | { "id" : 3, "instock" : 60 }, 154 | { "id" : 4, "instock" : 70 } 155 | ]) 156 | 157 | 158 | db.orders.aggregate([ 159 | { 160 | $lookup: { 161 | from: 'products', 162 | localField: 'productId', 163 | foreignField: 'id', 164 | as: 'data' 165 | } 166 | }, 167 | { 168 | $match: { 169 | $expr: { 170 | $lt: ['$data.instock', '$price'] 171 | } 172 | } 173 | } 174 | ]) 175 | 176 | db.orders.aggregate([ 177 | { 178 | $lookup: { 179 | from: 'products', 180 | localField: 'productId', 181 | foreignField: 'id', 182 | as: 'data' 183 | } 184 | }, 185 | { 186 | $match: { 187 | $expr: { 188 | $lt: ['$data.instock', '$price'] 189 | } 190 | } 191 | } 192 | ]) 193 | 194 | 195 | db.orders.aggregate([ 196 | { 197 | $lookup: { 198 | from: 'products', 199 | localField: 'productId', 200 | foreignField: 'id', 201 | as: 'data' 202 | } 203 | }, 204 | { 205 | $unwind: '$data' 206 | }, 207 | { 208 | $match: { 209 | $expr: { 210 | $lt: ['$data.instock', '$price'] 211 | } 212 | } 213 | } 214 | ]) 215 | 216 | db.orders.aggregate([ 217 | { 218 | $lookup: { 219 | from: 'products', 220 | localField: 'productId', 221 | foreignField: 'id', 222 | as: 'data' 223 | } 224 | }, 225 | { 226 | $unwind: '$data' 227 | }, 228 | { 229 | $match: { 230 | $expr: { 231 | $gt: ['$data.instock', '$price'] 232 | } 233 | } 234 | } 235 | ]) 236 | 237 | db.orders.aggregate([ 238 | { 239 | $lookup: { 240 | from: 'products', 241 | localField: 'productId', 242 | foreignField: 'id', 243 | as: 'data' 244 | } 245 | }, 246 | { 247 | $unwind: '$data' 248 | } 249 | ]) 250 | 251 | 252 | db.books.aggregate([ 253 | { 254 | $group: { 255 | _id: "$author", 256 | books: { 257 | $push: "$$ROOT" 258 | } 259 | } 260 | }, 261 | { 262 | $addFields: { 263 | totalCopies : {$sum: "$books.copies"} 264 | } 265 | }, 266 | { 267 | $unwind: '$books' 268 | } 269 | ]) 270 | 271 | 272 | db.listingsAndReviews.aggregate([ 273 | { 274 | $sample: {size: 3} 275 | }, 276 | { 277 | $project: { 278 | name: 1, 279 | summary: 1 280 | } 281 | } 282 | ]) 283 | 284 | 285 | db.listingsAndReviews.aggregate([ 286 | { 287 | $match: { 288 | property_type: "Apartment" 289 | } 290 | }, 291 | { 292 | $sort: { 293 | number_of_reviews: -1 294 | } 295 | }, 296 | { 297 | $skip: 0 298 | }, 299 | { 300 | $limit: 5 301 | }, 302 | { 303 | $project: { 304 | name: 1, 305 | number_of_reviews: 1 306 | } 307 | } 308 | ]) 309 | 310 | db.listingsAndReviews.aggregate([ 311 | { 312 | $match: { 313 | property_type: "Apartment" 314 | } 315 | }, 316 | { 317 | $sort: { 318 | number_of_reviews: -1 319 | } 320 | }, 321 | { 322 | $skip: 5 323 | }, 324 | { 325 | $limit: 5 326 | }, 327 | { 328 | $project: { 329 | name: 1, 330 | number_of_reviews: 1 331 | } 332 | } 333 | ]) 334 | 335 | db.books.aggregate([ 336 | { 337 | $group: { 338 | _id: "$author", 339 | books: {$push: "$title"} 340 | } 341 | }, 342 | { 343 | $out: "authors" 344 | } 345 | ]) 346 | ``` 347 | -------------------------------------------------------------------------------- /02.Query 실습/aggregationOptimize.js: -------------------------------------------------------------------------------- 1 | # account에 대해서 symbol로 그룹핑 2 | # 회사 거래별 누적 수량 3 | # 그중에서 상위 3개 4 | # msft에 대한 값만 추출 5 | # customer 정보와 account 정보도 함께 출력 6 | 7 | db.transactions.aggregate([ 8 | { 9 | $unwind: "$transactions" 10 | }, 11 | { 12 | $group: { 13 | _id: { 14 | account_id: "$account_id", 15 | symbol: "$transactions.symbol" 16 | }, 17 | currentHolding: { 18 | $sum: { 19 | $cond: [ 20 | { 21 | $eq: [ 22 | "$transactions.transaction_code", 23 | "buy" 24 | ] 25 | }, 26 | "$transactions.amount", 27 | { 28 | $multiply: [ 29 | "$transactions.amount", 30 | -1 31 | ] 32 | } 33 | ] 34 | } 35 | } 36 | } 37 | }, 38 | { 39 | $match: { 40 | "_id.symbol": 'msft' 41 | } 42 | }, 43 | { 44 | $sort: { 45 | currentHolding: -1 46 | } 47 | }, 48 | { 49 | $limit: 3 50 | }, 51 | { 52 | $lookup: { 53 | from: "accounts", 54 | localField: "_id.account_id", 55 | foreignField: "account_id", 56 | as: "account_info", 57 | pipeline: [ 58 | { 59 | $lookup: { 60 | from: "customers", 61 | localField: "account_id", 62 | foreignField: "accounts", 63 | as: "customer_info", 64 | pipeline: [ 65 | { 66 | $project: { 67 | "username": 1, 68 | "_id": 0 69 | } 70 | } 71 | ] 72 | } 73 | }, 74 | { 75 | $project: { 76 | _id: 0, 77 | account_id: 0 78 | } 79 | }, 80 | { 81 | $unwind: "$customer_info" 82 | } 83 | ] 84 | } 85 | }, 86 | { 87 | $unwind: "$account_info" 88 | }, 89 | { 90 | $project: { 91 | _id: 0, 92 | user: "$account_info.customer_info.username", 93 | account_id: "$_id.account_id", 94 | symbol: "$_id.symbol", 95 | currentHolding: 1, 96 | account_info: { 97 | limit: 1, 98 | products: 1 99 | } 100 | } 101 | } 102 | ]).explain('executionStats') 103 | -------------------------------------------------------------------------------- /02.Query 실습/aggregationProblem.md: -------------------------------------------------------------------------------- 1 | # Problem 2 | sample_traning database의 grades collection을 이용하고 3 | class_id별 exam과 quiz에 대한 평균값을 구한다. 4 | exam과 quiz의 평균값은 배열 필드안에 넣어서 저장한다. 5 | 6 | ## result example 7 | ```javascript 8 | [ 9 | { 10 | _id: 500, 11 | scores: [ 12 | { k: 'exam', v: 45.04082924638036 }, 13 | { k: 'quiz', v: 51.35603805996617 } 14 | ] 15 | }, 16 | { 17 | _id: 499, 18 | scores: [ 19 | { k: 'exam', v: 52.234488613263466 }, 20 | { k: 'quiz', v: 48.96268506750967 } 21 | ] 22 | }, 23 | { 24 | _id: 498, 25 | scores: [ 26 | { k: 'exam', v: 48.51775335555769 }, 27 | { k: 'quiz', v: 53.827492248151465 } 28 | ] 29 | }, 30 | { 31 | _id: 497, 32 | scores: [ 33 | { k: 'exam', v: 50.80561533355925 }, 34 | { k: 'quiz', v: 51.27682967858154 } 35 | ] 36 | }, 37 | { 38 | _id: 496, 39 | scores: [ 40 | { k: 'exam', v: 47.28546854417578 }, 41 | { k: 'quiz', v: 50.30975687853305 } 42 | ] 43 | } 44 | ] 45 | ``` 46 | 47 | 48 | ## solution 1 49 | 50 | 2개 필드를 grouping하고 다시 grouping해서 원하는 결과를 얻는다. 51 | 52 | ```javascript 53 | db.grades.aggregate([ 54 | { 55 | $unwind: "$scores" 56 | }, 57 | { 58 | $match: { 59 | "scores.type": { 60 | $in: ['exam', 'quiz'] 61 | } 62 | } 63 | }, 64 | { 65 | $group: { 66 | _id: { 67 | class_id: "$class_id", 68 | type: "$scores.type" 69 | }, 70 | avg_score: { 71 | $avg: "$scores.score" 72 | } 73 | } 74 | }, 75 | { 76 | $group: { 77 | _id: "$_id.class_id", 78 | scores: { 79 | $push: { 80 | type: "$_id.type", 81 | avg_score: "$avg_score" 82 | } 83 | } 84 | } 85 | }, 86 | { 87 | $sort: { 88 | _id: -1 89 | } 90 | }, 91 | { 92 | $limit: 5 93 | } 94 | ]) 95 | ``` 96 | 97 | ## solution 2 98 | 99 | 미리 원하는 조건으로 배열을 필터링하고 배열필드에 score에대한 모든 값을 넣고 나중에 평균을 구하는 방법 100 | 101 | ```javascript 102 | db.grades.aggregate([ 103 | { 104 | $addFields: { 105 | tmp_scores: { 106 | $filter: { 107 | input: "$scores", 108 | as: "scores_var", 109 | cond: { 110 | $or: [ 111 | {$eq: ["$$scores_var.type", 'exam']}, 112 | {$eq: ["$$scores_var.type", 'quiz']} 113 | ] 114 | } 115 | } 116 | } 117 | } 118 | }, 119 | { 120 | $unset: ["scores", "student_id"] 121 | }, 122 | { 123 | $unwind: "$tmp_scores" 124 | }, 125 | { 126 | $group: { 127 | _id: "$class_id", 128 | exam_scores: { 129 | $push: { 130 | $cond: { 131 | if: { 132 | $eq: ["$tmp_scores.type", 'exam'] 133 | }, 134 | then: "$tmp_scores.score", 135 | else: "$$REMOVE" 136 | } 137 | } 138 | }, 139 | quiz_scores: { 140 | $push: { 141 | $cond: { 142 | if: { 143 | $eq: ["$tmp_scores.type", 'quiz'] 144 | }, 145 | then: "$tmp_scores.score", 146 | else: "$$REMOVE" 147 | } 148 | } 149 | } 150 | } 151 | }, 152 | { 153 | $project: { 154 | _id: 1, 155 | scores: { 156 | $objectToArray: { 157 | exam: { 158 | $avg: "$exam_scores" 159 | }, 160 | quiz: { 161 | $avg: "$quiz_scores" 162 | } 163 | } 164 | } 165 | } 166 | }, 167 | { 168 | $sort: { 169 | _id: -1 170 | } 171 | }, 172 | { 173 | $limit: 5 174 | } 175 | ]) 176 | ``` 177 | -------------------------------------------------------------------------------- /02.Query 실습/arrayAndEmbeddedDocuments.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | db.sales.findOne({ 3 | customer: { 4 | gender: 'M', 5 | age: 50, 6 | email: 'keecade@hem.uy', 7 | satisfaction: 5 8 | } 9 | }) 10 | 11 | db.sales.findOne({ 12 | customer: { 13 | satisfaction: 5, 14 | gender: 'M', 15 | age: 50, 16 | email: 'keecade@hem.uy', 17 | } 18 | }) 19 | 20 | 21 | db.sales.findOne({ 22 | "customer.email": "keecade@hem.uy" 23 | }) 24 | db.sales.findOne({ 25 | "customer.age": {$lt: 20} 26 | }) 27 | 28 | 29 | db.inventory.insertMany([ 30 | { item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] }, 31 | { item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] }, 32 | { item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] }, 33 | { item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] }, 34 | { item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }, 35 | { item: "postcard", qty: 45, tags: ["blue", "red"], dim_cm: [ 13, 14 ] } 36 | ]); 37 | 38 | db.inventory.find({ 39 | tags: ['red', 'blank'] 40 | }) 41 | 42 | 43 | db.inventory.find({ 44 | tags: { $all: ['red', 'blank'] } 45 | }) 46 | 47 | db.inventory.find({ 48 | tags: { $in: ['red', 'blank'] } 49 | }) 50 | 51 | db.inventory.find({ 52 | tags: 'blue' 53 | }) 54 | 55 | db.inventory.find({ 56 | dim_cm: {$gt: 15} 57 | }) 58 | 59 | db.inventory.find({ 60 | dim_cm: {$gt: 15, $lt: 20} 61 | }) 62 | 63 | db.inventory.find({ 64 | dim_cm: {$elemMatch: {$gt: 15, $lt: 20}} 65 | }) 66 | 67 | db.inventory.find({ 68 | "dim_cm.1": {$lt: 20} 69 | }) 70 | 71 | db.inventory.find({ 72 | tags: {$size: 3} 73 | }) 74 | 75 | 76 | db.sales.find({ 77 | "items.name": 'binder', 78 | "items.quantity": {$lte: 6} 79 | }) 80 | 81 | db.sales.find({ 82 | items: { 83 | $elemMatch: { 84 | name: "binder", 85 | quantity: {$lte: 6} 86 | } 87 | } 88 | }) 89 | 90 | db.sales.find( 91 | { 92 | items: { 93 | $elemMatch: { 94 | name: "binder", 95 | quantity: {$lte: 6} 96 | } 97 | } 98 | }, 99 | { 100 | saleDate: 1, 101 | "items.$": 1, 102 | storeLocation: 1, 103 | customer: 1 104 | } 105 | ) 106 | 107 | 108 | 109 | db.students.insertMany([ 110 | {_id: 1, grades: [85, 80, 80]}, 111 | {_id: 2, grades: [88, 90, 92]}, 112 | {_id: 3, grades: [85, 100, 90]} 113 | ]) 114 | 115 | db.students.updateOne( 116 | { _id: 1, grades: 80 }, 117 | {$set: {"grades.$": 82}} 118 | ) 119 | 120 | db.students.updateMany( 121 | {}, 122 | {$inc: {"grades.$[]": 10}} 123 | ) 124 | 125 | 126 | db.students.insertMany([ 127 | { 128 | _id: 4, 129 | grades: [ 130 | { grade: 80, mean: 75, std: 8 }, 131 | { grade: 85, mean: 90, std: 5 }, 132 | { grade: 85, mean: 85, std: 8 }, 133 | ] 134 | } 135 | ]) 136 | 137 | 138 | db.students.updateOne( 139 | { _id: 4, "grades.grade": 85 }, 140 | {$set: {"grades.$.std": 6}} 141 | ) 142 | 143 | db.students.updateOne( 144 | { _id: 4, grades: {$elemMatch: {grade: {$gte: 85}}} }, 145 | {$set: {"grades.$[].grade": 100}} 146 | ) 147 | 148 | 149 | db.students.insertMany([ 150 | { 151 | _id: 6, 152 | grades: [ 153 | { grade: 90, mean: 75, std: 8 }, 154 | { grade: 87, mean: 90, std: 6 }, 155 | { grade: 85, mean: 85, std: 8 }, 156 | ] 157 | } 158 | ]) 159 | 160 | db.students.updateMany( 161 | { _id: 6 }, 162 | { $set: {"grades.$[element].grade": 100}}, 163 | { arrayFilters: [{"element.grade": {$gte: 87}}] } 164 | ) 165 | 166 | 167 | db.students.insertOne( 168 | { 169 | _id: 7, 170 | grades : [ 171 | { type: "quiz", questions: [ 10, 8, 5 ] }, 172 | { type: "quiz", questions: [ 8, 9, 6 ] }, 173 | { type: "hw", questions: [ 5, 4, 3 ] }, 174 | { type: "exam", questions: [ 25, 10, 23, 0 ] }, 175 | ] 176 | } 177 | ) 178 | 179 | db.students.updateOne( 180 | { _id: 7 }, 181 | { $inc: { "grades.$[].questions.$[score]": 2 } }, 182 | {arrayFilters: [{score: {$gte: 8}}]} 183 | ) 184 | 185 | 186 | db.shopping.insertMany([ 187 | { 188 | _id: 1, 189 | cart: ['bannana', 'cheeze', 'milk'], 190 | coupons: ['10%', '20%', '30%'] 191 | }, 192 | { 193 | _id: 2, 194 | cart: [], 195 | coupons: [] 196 | } 197 | ]) 198 | 199 | 200 | db.shopping.updateOne( 201 | { _id: 1 }, 202 | {$addToSet: {cart: 'beer'}} 203 | ) 204 | 205 | db.shopping.updateOne( 206 | { _id: 1 }, 207 | {$addToSet: {cart: ['beer', 'candy']}} 208 | ) 209 | 210 | db.shopping.updateOne( 211 | { _id: 1 }, 212 | { $addToSet: { cart: { $each: ['beer', 'candy'] } } } 213 | ) 214 | 215 | db.shopping.updateOne( 216 | { _id: 1 }, 217 | {$pull: {cart: 'beer'}} 218 | ) 219 | 220 | db.shopping.updateOne( 221 | { _id: 1 }, 222 | {$pull: {cart: {$in: [['beer', 'candy'], 'milk']}}} 223 | ) 224 | 225 | 226 | db.shopping.updateOne( 227 | { _id: 1 }, 228 | {$pop: {cart: -1}} 229 | ) 230 | 231 | 232 | db.shopping.updateOne( 233 | { _id: 1 }, 234 | {$pop: {cart: 1, coupons: -1}} 235 | ) 236 | 237 | 238 | db.shopping.updateOne( 239 | { _id: 1 }, 240 | {$push: {cart: 'popcorn'}} 241 | ) 242 | 243 | db.shopping.updateOne( 244 | { _id: 1 }, 245 | { $push: { coupons: { $each: ['25%', '35%'] } } } 246 | ) 247 | 248 | db.shopping.updateMany( 249 | {}, 250 | { 251 | $push: { 252 | coupons: { 253 | $each: ['90%', '70%'], 254 | $position: 0 255 | } 256 | } 257 | } 258 | ) 259 | 260 | db.shopping.updateMany( 261 | {}, 262 | { 263 | $push: { 264 | coupons: { 265 | $each: ['15%', '20%'], 266 | $position: 0, 267 | $slice: 5 268 | } 269 | } 270 | } 271 | ) 272 | 273 | db.shopping.updateMany( 274 | {}, 275 | { 276 | $push: { 277 | coupons: { 278 | $each: ['90%', '99%'], 279 | $position: -1, 280 | $sort: -1, 281 | $slice: 5 282 | } 283 | } 284 | } 285 | ) 286 | ``` 287 | -------------------------------------------------------------------------------- /02.Query 실습/changestream.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | import certifi 3 | 4 | conn = "mongodb+srv://__USER__:__PWD__@__URI__" 5 | client = pymongo.MongoClient(conn, tlsCAFile=certifi.where()) 6 | db = client.test 7 | 8 | pipeline = [ 9 | {"$match": {"fullDocument.status": "argent"}} 10 | ] 11 | 12 | stream = client.watch(pipeline=pipeline) 13 | for document in stream: 14 | print(document) 15 | -------------------------------------------------------------------------------- /02.Query 실습/explain.js: -------------------------------------------------------------------------------- 1 | db.restaurants.find( 2 | {borough: "Brooklyn"} 3 | ).explain('executionStats') 4 | 5 | 6 | db.restaurants.find( 7 | {borough: "Brooklyn"}, 8 | {name: 1, borough: 1} 9 | ).sort({ name: 1 }).explain('executionStats') 10 | 11 | db.restaurants.createIndex({ borough: -1 }) 12 | 13 | db.restaurants.find( 14 | {borough: "Brooklyn"}, 15 | {name: 1, borough: 1} 16 | ).sort({ name: 1 }).explain('executionStats') 17 | 18 | db.restaurants.createIndex( 19 | { name: 1, borough: -1 } 20 | ) 21 | 22 | db.restaurants.find( 23 | {borough: "Brooklyn"}, 24 | {name: 1, borough: 1} 25 | ).sort({ name: 1 }).explain('executionStats') 26 | 27 | 28 | db.restaurants.find( 29 | {borough: "Brooklyn"}, 30 | {name: 1, borough: 1} 31 | ).sort({ name: 1 }).explain('allPlansExecution') 32 | 33 | 34 | 35 | db.restaurants.aggregate([ 36 | { 37 | $match: {borough: "Brooklyn"} 38 | }, 39 | { 40 | $group: { 41 | _id: "$cuisine", 42 | cnt: {$sum: 1} 43 | } 44 | }, 45 | { 46 | $sort: { 47 | name: 1 48 | } 49 | } 50 | ]).explain('executionStats') 51 | 52 | 53 | db.restaurants.aggregate([ 54 | { 55 | $match: {borough: "Brooklyn", cuisine: "American"} 56 | } 57 | ]).explain('executionStats') 58 | 59 | 60 | 61 | db.restaurants.aggregate([ 62 | { 63 | $group: { 64 | _id: {cuisine: "$cuisine", borough: "$borough"}, 65 | cnt: {$sum: 1} 66 | } 67 | }, 68 | { 69 | $match: {"_id.borough": "Queens"} 70 | }, 71 | { 72 | $sort: { 73 | "_id.borough": 1 74 | } 75 | } 76 | ]).explain('executionStats') 77 | -------------------------------------------------------------------------------- /02.Query 실습/geospatialBasics.js: -------------------------------------------------------------------------------- 1 | db.grids.insertMany([ 2 | { 3 | _id: 1, 4 | loc: [0,0] 5 | }, 6 | { 7 | _id: 2, 8 | loc: [3,4] 9 | }, 10 | { 11 | _id: 3, 12 | loc: [15,2] 13 | }, 14 | { 15 | _id: 4, 16 | loc: [7,8] 17 | }, 18 | { 19 | _id: 5, 20 | loc: { 21 | type: "Point", 22 | coordinates: [5,5] 23 | } 24 | }, 25 | { 26 | _id: 6, 27 | loc: { 28 | type: "Point", 29 | coordinates: [14,8] 30 | } 31 | }, 32 | { 33 | _id: 7, 34 | loc: { 35 | type: "LineString", 36 | coordinates: [ 37 | [6, 6], 38 | [15,13] 39 | ] 40 | } 41 | }, 42 | { 43 | _id: 8, 44 | loc: { 45 | type: "LineString", 46 | coordinates: [ 47 | [0, 12], 48 | [5,12] 49 | ] 50 | } 51 | }, 52 | { 53 | _id: 9, 54 | loc: { 55 | type: "Polygon", 56 | coordinates: [ 57 | [ 58 | [2, 2], 59 | [3,3], 60 | [4,2], 61 | [2,2] 62 | ] 63 | ] 64 | } 65 | }, 66 | { 67 | _id: 10, 68 | loc: { 69 | type: "Polygon", 70 | coordinates: [ 71 | [ 72 | [9, 0], 73 | [5,13], 74 | [14,6], 75 | [9,0] 76 | ] 77 | ] 78 | } 79 | }, 80 | ]) 81 | 82 | db.grids.find({ 83 | loc: { 84 | $geoIntersects: { 85 | $geometry: { 86 | type: "Polygon", 87 | coordinates: [ 88 | [ 89 | [0,0], 90 | [10,0], 91 | [10,10], 92 | [0,10], 93 | [0,0], 94 | ] 95 | ] 96 | } 97 | } 98 | } 99 | }) 100 | 101 | db.grids.find({ 102 | loc: { 103 | $geoWithin: { 104 | $geometry: { 105 | type: "Polygon", 106 | coordinates: [ 107 | [ 108 | [0,0], 109 | [10,0], 110 | [10,10], 111 | [0,10], 112 | [0,0], 113 | ] 114 | ] 115 | } 116 | } 117 | } 118 | }) 119 | 120 | db.grids.find({ 121 | loc: { 122 | $near: { 123 | $geometry: { 124 | type: "Point", 125 | coordinates: [5, 5] 126 | }, 127 | $maxDistance: 1000000000 128 | } 129 | } 130 | }) 131 | 132 | db.grids.createIndex({loc: "2d"}) 133 | db.grids.createIndex({loc: "2dsphere"}) 134 | 135 | db.grids.drop() 136 | 137 | 138 | db.grids.insertMany([ 139 | { 140 | _id: 1, 141 | loc: [0,0] 142 | }, 143 | { 144 | _id: 2, 145 | loc: [3,4] 146 | }, 147 | { 148 | _id: 3, 149 | loc: [15,2] 150 | }, 151 | { 152 | _id: 4, 153 | loc: [7,8] 154 | }, 155 | ]) 156 | 157 | 158 | db.grids.find({ 159 | loc: { 160 | $near: [5,5], 161 | $maxDistance: 10 162 | } 163 | }) 164 | 165 | // 음식점이 있는 동네 166 | var restaurant = db.restaurants.findOne() 167 | db.neighborhoods.find( 168 | { 169 | geometry: { 170 | $geoIntersects: { 171 | $geometry: { 172 | type: "Point", 173 | coordinates: restaurant.address.coord 174 | } 175 | } 176 | } 177 | }, 178 | { 179 | name: 1 180 | } 181 | ) 182 | 183 | var neighborhood = db.neighborhoods.findOne() 184 | db.restaurants.find( 185 | { 186 | "address.coord": { 187 | $geoWithin: { 188 | $geometry: neighborhood.geometry 189 | } 190 | } 191 | }, 192 | { 193 | name: 1, _id: 0 194 | } 195 | ) 196 | 197 | db.restaurants.createIndex({"address.coord": "2dsphere"}) 198 | 199 | db.restaurants.aggregate([ 200 | { 201 | $geoNear: { 202 | near: { 203 | type: "Point", 204 | coordinates: [ -73.8845166, 40.744772 ] 205 | }, 206 | key: "address.coord", 207 | maxDistance: 3000, 208 | query: { 209 | cuisine: "Hamburgers" 210 | }, 211 | distanceField: "dist" 212 | } 213 | }, 214 | { 215 | $project: { 216 | name: 1, 217 | cuisine: 1, 218 | dist: 1 219 | } 220 | }, 221 | { 222 | $count: "cnt" 223 | } 224 | ]) 225 | -------------------------------------------------------------------------------- /02.Query 실습/indexBound.js: -------------------------------------------------------------------------------- 1 | db.survey.insertMany([ 2 | {item: "ABC", ratings: [2, 9], category_id: 10}, 3 | {item: "XYZ", ratings: [4, 3], category_id: 10}, 4 | {item: "ABC", ratings: [9], category_id: 20}, 5 | {item: "ABC", ratings: [9, 10], category_id: 30}, 6 | {item: "ABC", ratings: [2, 4], category_id: 30} 7 | ]) 8 | 9 | for (var i = 0; i < 15; i++){ 10 | arr = [] 11 | db.survey.find({}, { _id: 0 }).forEach(function (document) { 12 | arr.push(document); 13 | }) 14 | db.survey.insertMany(arr) 15 | } 16 | 17 | db.survey.createIndex({ category_id: 1 }) 18 | 19 | db.survey.find({ 20 | category_id: { 21 | $gt: 15, 22 | $lt: 25 23 | } 24 | }).explain('executionStats') 25 | 26 | 27 | db.survey.createIndex({ ratings: 1 }) 28 | 29 | 30 | db.survey.find({ 31 | ratings: { 32 | $gte: 3, 33 | $lte: 6 34 | } 35 | }).explain('executionStats') 36 | 37 | 38 | db.survey.find({ 39 | ratings: { 40 | $elemMatch: { 41 | $gte: 3, 42 | $lte: 6 43 | } 44 | } 45 | }).explain('executionStats') 46 | 47 | db.survey.drop() 48 | 49 | db.survey.createIndex({ ratings: 1 }) 50 | 51 | 52 | db.survey.find({ 53 | ratings: { 54 | $gte: 3, 55 | $lte: 6 56 | } 57 | }) 58 | 59 | db.survey.find({ 60 | ratings: { 61 | $elemMatch: { 62 | $gte: 3, 63 | $lte: 6 64 | } 65 | } 66 | }) 67 | 68 | db.survey.find({ 69 | $and: [ 70 | { ratings: { $not: {$lt: 3} }}, 71 | { ratings: { $not: {$gt: 6} }}, 72 | ] 73 | }).explain('executionStats') 74 | 75 | db.survey.find({ 76 | $and: [ 77 | { ratings: {$elemMatch: {$gte: 3, $lte: 6}} }, 78 | { ratings: { $not: {$lt: 3} }}, 79 | { ratings: { $not: {$gt: 6} }} 80 | ] 81 | }).explain('executionStats') 82 | -------------------------------------------------------------------------------- /02.Query 실습/indexOptimize.js: -------------------------------------------------------------------------------- 1 | db.sales.find( 2 | { 3 | saleDate: { 4 | $gte: ISODate("2015-01-01T00:00:00.000Z") 5 | } 6 | } 7 | ).explain('executionStats') 8 | 9 | db.sales.createIndex({ saleDate: 1 }) 10 | 11 | 12 | db.sales.find( 13 | { 14 | saleDate: { 15 | $gte: ISODate("2015-01-01T00:00:00.000Z") 16 | } 17 | }, 18 | { 19 | saleDate: 1, 20 | _id: 0 21 | } 22 | ).explain('executionStats') 23 | 24 | 25 | 26 | db.sales.find( 27 | { 28 | storeLocation: 'Denver', 29 | "customer.age": 75 30 | } 31 | ).explain('executionStats') 32 | 33 | db.sales.createIndex({ storeLocation: 1 }) 34 | 35 | db.sales.find( 36 | { 37 | storeLocation: 'Denver', 38 | "customer.age": 75 39 | } 40 | ).explain('executionStats') 41 | 42 | db.sales.createIndex( 43 | { 44 | storeLocation: 1, 45 | "customer.age": 1 46 | } 47 | ) 48 | 49 | db.sales.find( 50 | { 51 | storeLocation: 'Denver', 52 | "customer.age": 75 53 | } 54 | ).explain('executionStats') 55 | 56 | 57 | db.sales.dropIndex({ storeLocation: 1 }) 58 | 59 | 60 | 61 | explain = db.restaurants.aggregate([ 62 | { 63 | $geoNear: { 64 | near: { 65 | type: "Point", 66 | coordinates: [-73.98241999999999, 40.579505] 67 | }, 68 | key: "address.coord", 69 | maxDistance: 30000, 70 | query: { 71 | cuisine: "Hamburgers" 72 | }, 73 | distanceField: "dist" 74 | } 75 | }, 76 | { 77 | $project: { 78 | name: 1, 79 | cuisine: 1, 80 | dist: 1 81 | } 82 | } 83 | ]).explain('executionStats') 84 | 85 | 86 | explain.stages 87 | 88 | db.restaurants.createIndex({ 89 | cuisine: 1, 90 | "address.coord": "2dsphere" 91 | }) 92 | 93 | 94 | 95 | explain = db.restaurants.aggregate([ 96 | { 97 | $geoNear: { 98 | near: { 99 | type: "Point", 100 | coordinates: [-73.98241999999999, 40.579505] 101 | }, 102 | key: "address.coord", 103 | maxDistance: 30000, 104 | query: { 105 | cuisine: "Hamburgers" 106 | }, 107 | distanceField: "dist" 108 | } 109 | }, 110 | { 111 | $project: { 112 | name: 1, 113 | cuisine: 1, 114 | dist: 1 115 | } 116 | } 117 | ]).explain('executionStats') 118 | 119 | 120 | explain.stages 121 | -------------------------------------------------------------------------------- /02.Query 실습/lookup.js: -------------------------------------------------------------------------------- 1 | use stores 2 | 3 | db.restaurants.insertMany([ 4 | { 5 | _id: 1, 6 | name: "American Steak House", 7 | food: [ "filet", "sirloin" ], 8 | beverages: [ "beer", "wine" ] 9 | }, 10 | { 11 | _id: 2, 12 | name: "Honest John Pizza", 13 | food: [ "cheese pizza", "pepperoni pizza" ], 14 | beverages: [ "soda" ] 15 | } 16 | ]) 17 | 18 | db.orders.insertMany( [ 19 | { 20 | _id: 1, 21 | item: "filet", 22 | restaurant_name: "American Steak House" 23 | }, 24 | { 25 | _id: 2, 26 | item: "cheese pizza", 27 | restaurant_name: "Honest John Pizza", 28 | drink: "lemonade" 29 | }, 30 | { 31 | _id: 3, 32 | item: "cheese pizza", 33 | restaurant_name: "Honest John Pizza", 34 | drink: "soda" 35 | } 36 | ]) 37 | 38 | 39 | db.restaurants.aggregate([ 40 | { 41 | $lookup: { 42 | from: "orders", 43 | localField: "name", 44 | foreignField: "restaurant_name", 45 | as: "orders" 46 | } 47 | }, 48 | { 49 | $unwind: "$orders" 50 | }, 51 | { 52 | $match: { 53 | $expr: { 54 | $and: [ 55 | {$in: ["$orders.item", "$food"]}, 56 | {$in: ["$orders.drink", "$beverages"]} 57 | ] 58 | } 59 | } 60 | }, 61 | { 62 | $group: { 63 | _id: "$_id", 64 | name: { $first: "$name" }, 65 | food: { $first: "$food" }, 66 | beverages: { $first: "$beverages" }, 67 | orders: { 68 | $push: "$orders" 69 | } 70 | } 71 | } 72 | ]) 73 | 74 | 75 | db.restaurants.aggregate([ 76 | { 77 | $lookup: { 78 | from: "orders", 79 | let: { 80 | name_var: "$name", 81 | beverages_lst: "$beverages", 82 | food_lst: "$food" 83 | }, 84 | pipeline: [ 85 | { 86 | $match: { 87 | $expr: { 88 | $and: [ 89 | { 90 | $eq: [ 91 | "$$name_var", 92 | "$restaurant_name" 93 | ] 94 | }, 95 | { 96 | $in: [ 97 | "$drink", 98 | "$$beverages_lst" 99 | ] 100 | }, 101 | { 102 | $in: [ 103 | "$item", 104 | "$$food_lst" 105 | ] 106 | } 107 | ] 108 | } 109 | } 110 | } 111 | ], 112 | as: "orders" 113 | } 114 | } 115 | ]) 116 | 117 | 118 | db.restaurants.aggregate([ 119 | { 120 | $lookup: { 121 | from: "orders", 122 | localField: "name", 123 | foreignField: "restaurant_name", 124 | let: { 125 | beverages_lst: "$beverages", 126 | food_lst: "$food" 127 | }, 128 | pipeline: [ 129 | { 130 | $match: { 131 | $expr: { 132 | $and: [ 133 | {$in: ["$drink", "$$beverages_lst"]}, 134 | {$in: ["$item", "$$food_lst"]} 135 | ] 136 | } 137 | } 138 | } 139 | ], 140 | as: "orders" 141 | } 142 | } 143 | ]) 144 | -------------------------------------------------------------------------------- /02.Query 실습/queryProblems.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | //1.sample_mflix database의 movies collection 전체를 조회한다. 3 | db.movies.find(); 4 | 5 | 6 | 7 | //2. movies collection의 Document 수를 구한다. 8 | db.movies.countDocuments() 9 | 10 | 11 | 12 | //3. movies collection 전체를 조회하는데, title, year, genres, runtime, rated 필드를 출력하고 _id 필드는 출력하지 않는다. 13 | db.movies.find( 14 | {}, 15 | { 16 | title: 1, 17 | year: 1, 18 | genres: 1, 19 | runtime: 1, 20 | rated: 1, 21 | _id: 0 22 | } 23 | ) 24 | 25 | 26 | 27 | //4. movies collection에서 runtime이 100분 이하인 Document를 조회한다. 28 | db.movies.find( 29 | {runtime: {$lte: 100}} 30 | ) 31 | 32 | 33 | 34 | //5. movies collection에서 runtime이 100분 이하이고 genres에 Drama가 포함되는 Document를 조회한다. 35 | db.movies.find( 36 | { 37 | runtime: {$lte: 100}, 38 | genres: 'Drama' 39 | } 40 | ) 41 | 42 | 43 | 44 | //6. movies collection에서 runtime이 100분 이하이고 genres가 유일하게 Drama인 Document를 조회한다. 45 | db.movies.find( 46 | { 47 | $and: [ 48 | { runtime: { $lte: 100 } }, 49 | { genres: 'Drama' }, 50 | { genres: { $size: 1 } } 51 | ] 52 | }, 53 | {genres: 1} 54 | ) 55 | 56 | 57 | 58 | //7. moveies collection에서 runtime이 100분이하이고 type이 series가 아니고 개봉년도가 2015년 이상이거나 1925년 이하 영화를 찾는다. 59 | db.movies.find( 60 | { 61 | $and: [ 62 | { runtime: { $lte: 100 } }, 63 | { type: { $ne: 'series' } }, 64 | { 65 | $or: [ 66 | {year: {$lte: 1925}}, 67 | { year: { $gte: 2015 } } 68 | ] 69 | } 70 | ] 71 | }, 72 | { 73 | runtime: 1, type: 1, year: 1 74 | } 75 | ).sort({ year: -1 }) 76 | 77 | 78 | 79 | //8. movies collection에서 viewer 평가가 4.5 이상이거나 critic 평가가 9.5 이상인 영화를 찾고 runtime이 가장 긴 순서대로 5개 document를 출력한다. 80 | //필드는 title, runtime, tomatoes, _id 필드를 출력한다. 81 | db.movies.find( 82 | { 83 | $or: [ 84 | { "tomatoes.viewer.rating": { $gte: 4.5 } }, 85 | { "tomatoes.critic.rating": { $gte: 9.5 } }, 86 | ], 87 | } 88 | , { title: 1, runtime: 1, tomatoes: 1 } 89 | ).sort({ runtime: -1 }).limit(5); 90 | 91 | 92 | 93 | //9. sample_restuarants database의 restaurants collection에서 Queens에 있는 음식점 중에, A grade가 없는 음식점을 찾는다. 94 | db.restaurants.find( 95 | { 96 | borough: "Queens", 97 | "grades.grade": { $ne: 'A' }, 98 | grades: {$size: 3} 99 | }, 100 | { 101 | grades: 1, _id: 0 102 | } 103 | ) 104 | 105 | 106 | 107 | //10. restaurants collection에서 Queens에 있는 음식점 중에, A와 Z가 같이 있는 음식점을 찾는다. 108 | db.restaurants.find({ 109 | $and: [ 110 | { borough: "Queens" }, 111 | {grades: {$elemMatch: {grade: 'A'}}}, 112 | {grades: {$elemMatch: {grade: 'Z'}}} 113 | ] 114 | }) 115 | 116 | 117 | 118 | //11. restaurants collection에서 Queens에 있는 음식점 중에, grades의 score가 하나라도 70 이상인 document를 조회하고 grades 배열에는 70이 넘는 document 하나만 출력한다.(나머지 필드는 그대로 출력한다.) 119 | db.restaurants.find( 120 | { 121 | borough: "Queens", 122 | "grades.score": {$gte: 70} 123 | }, 124 | { 125 | address: 1, 126 | borough: 1, 127 | cuisine: 1, 128 | "grades.$": 1, 129 | name: 1, 130 | restaurant_id: 1 131 | } 132 | ) 133 | ``` 134 | -------------------------------------------------------------------------------- /02.Query 실습/usefulFunctions.md: -------------------------------------------------------------------------------- 1 | ### bulkWrite 2 | ```javascript 3 | db.bulk.bulkWrite( 4 | [ 5 | {insertOne: {doc: 1, order: 1}}, 6 | {insertOne: {doc: 2, order: 2}}, 7 | {insertOne: {doc: 3, order: 3}}, 8 | {insertOne: {doc: 4, order: 4}}, 9 | {insertOne: {doc: 4, order: 5}}, 10 | {insertOne: {doc: 5, order: 6}}, 11 | { 12 | deleteOne: { 13 | filter: {doc: 3} 14 | } 15 | }, 16 | { 17 | updateOne: { 18 | filter: { doc: 2 }, 19 | update: { 20 | $set: {doc: 12} 21 | } 22 | } 23 | } 24 | ] 25 | ) 26 | 27 | 28 | db.bulk.bulkWrite( 29 | [ 30 | {insertOne: {doc: 1, order: 1}}, 31 | {insertOne: {doc: 2, order: 2}}, 32 | {insertOne: {doc: 3, order: 3}}, 33 | {insertOne: {doc: 4, order: 4}}, 34 | {insertOne: {doc: 4, order: 5}}, 35 | {insertOne: {doc: 5, order: 6}}, 36 | { 37 | updateOne: { 38 | filter: { doc: 2 }, 39 | update: { 40 | $set: {doc: 3} 41 | } 42 | } 43 | }, 44 | { 45 | deleteMany: { 46 | filter: {doc: 3} 47 | } 48 | }, 49 | ], 50 | {ordered: false} 51 | ) 52 | ``` 53 | 54 | ### Count Documents 55 | ```javascript 56 | db.bulk.countDocuments() 57 | 58 | db.bulk.estimatedDocumentCount() 59 | ``` 60 | 61 | ### Distinct 62 | ```javascript 63 | db.bulk.distinct("doc") 64 | ``` 65 | 66 | ### Find And Modify 67 | ```javascript 68 | db.bulk.findAndModify({ 69 | query: { doc: 4 }, 70 | update: { $inc: {doc: 1} } 71 | }) 72 | 73 | db.bulk.findAndModify({ 74 | query: { doc: 5 }, 75 | sort: {order: -1}, 76 | update: { $inc: {doc: 1} } 77 | }) 78 | 79 | db.sequence.insertOne({ seq: 0 }) 80 | 81 | db.sequence.findAndModify({ 82 | query: {}, 83 | sort: { seq: -1 }, 84 | update: { $inc: {seq: 1}} 85 | }) 86 | ``` 87 | 88 | ### Get Index 89 | ```javascript 90 | db.bulk.createIndex({ doc: 1 }) 91 | 92 | db.bulk.getIndexes() 93 | ``` 94 | 95 | ### Replace One 96 | ```javascript 97 | db.bulk.updateOne({ doc: 1 }, { $set: { _id: 1 } }) 98 | db.bulk.replaceOne({ doc: 1 }, {_id: 1, doc: 13}) 99 | db.bulk.replaceOne({ doc: 1 }, {doc: 13}) 100 | ``` 101 | -------------------------------------------------------------------------------- /03.읽기쓰기제어/causal_consistency.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | from pymongo.read_concern import ReadConcern 3 | from pymongo.write_concern import WriteConcern 4 | 5 | conn = "mongodb://localhost:27017,localhost:27018,localhost:27019/?readPreference=secondary" 6 | 7 | client = MongoClient(conn) 8 | with client.start_session(causal_consistency=True) as session: 9 | db = client.test 10 | db.sales.with_options(write_concern=WriteConcern('majority')).insert_one({ 11 | "name": "lotion", 12 | "price": 20000 13 | }) 14 | 15 | query_filter = {"name": "lotion"} 16 | res = db.sales.with_options(read_concern=ReadConcern('majority')).find_one(query_filter) 17 | print(res) 18 | -------------------------------------------------------------------------------- /03.읽기쓰기제어/read_preference.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | from pymongo.read_preferences import ReadPreference 3 | import certifi 4 | 5 | conn = "mongodb+srv://__USER__:__PWD__@__ENDPOINT__/" 6 | # conn = "mongodb+srv://__USER__:__PWD__@__ENDPOINT__/?readPreference=secondary" 7 | client = MongoClient(conn, tlsCAFile=certifi.where()) 8 | db = client.test 9 | 10 | db.fruits.insert_many([ 11 | { 12 | "name": "melon", 13 | "qty": 1000, 14 | "price": 16000 15 | }, 16 | { 17 | "name": "starberry", 18 | "qty": 100, 19 | "price": 10000 20 | }, 21 | { 22 | "name": "grape", 23 | "qty": 1500, 24 | "price": 5000 25 | }, 26 | ]) 27 | 28 | query_filter = {"name": "melon"} 29 | while True: 30 | res = db.fruits.with_options(read_preference=ReadPreference.SECONDARY).find_one(query_filter) 31 | # res = db.fruits.find_one(query_filter) 32 | print(res) 33 | -------------------------------------------------------------------------------- /03.읽기쓰기제어/read_write_concern.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | from pymongo.read_concern import ReadConcern 3 | from pymongo.write_concern import WriteConcern 4 | 5 | conn = "mongodb://localhost:27017,localhost:27018,localhost:27019/" 6 | # conn = "mongodb://localhost:27017,localhost:27018,localhost:27019/?w=majority&readConcernLevel=linearizable" 7 | 8 | client = MongoClient(conn) 9 | db = client.test 10 | 11 | db.sales.with_options(write_concern=WriteConcern(w='majority')).insert_many([ 12 | { 13 | "name": "pencil", 14 | "price": 10000 15 | }, 16 | { 17 | "name": "paper", 18 | "price": 100 19 | }, 20 | { 21 | "name": "pen", 22 | "price": 2000 23 | } 24 | ]) 25 | 26 | query_filter = {"price": {"$gt": 3000}} 27 | while True: 28 | res = db.sales.with_options(read_concern=ReadConcern('majority')).find_one(query_filter) 29 | print(res) 30 | -------------------------------------------------------------------------------- /03.읽기쓰기제어/transaction1.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | from pymongo.read_concern import ReadConcern 3 | from pymongo.write_concern import WriteConcern 4 | from pymongo.errors import ConnectionFailure, OperationFailure 5 | import certifi 6 | 7 | conn = "mongodb+srv://mongodb_user:__PWD__@cluster0.v6fiw3s.mongodb.net/" 8 | client = MongoClient(conn, tlsCAFile=certifi.where()) 9 | 10 | # client.test.orders.drop() 11 | # client.test.inventory.drop() 12 | # client.test.inventory.insert_one({"name": "pencil", "qty": 1000}) 13 | 14 | def update_orders_and_inventory(session): 15 | orders = session.client.test.orders 16 | inventory = session.client.test.inventory 17 | 18 | with session.start_transaction(read_concern=ReadConcern('majority'), write_concern=WriteConcern(w='majority')): 19 | order = 100 20 | orders.insert_one( 21 | {"name": "pencil", "qty": order}, 22 | session=session 23 | ) 24 | inventory.update_one( 25 | { 26 | "name": "pencil", 27 | "qty": {"$gte": order} 28 | }, 29 | { 30 | "$inc": {"qty": order * -1} 31 | } 32 | ) 33 | commit_with_retry(session) 34 | 35 | def commit_with_retry(session): 36 | while True: 37 | try: 38 | session.commit_transaction() 39 | print("Transaction Commited.") 40 | print(session.client.test.orders.find_one({"name": "pencil"})) 41 | print(session.client.test.inventory.find_one({"name": "pencil"})) 42 | break 43 | except (ConnectionFailure, OperationFailure) as err: 44 | if err.has_error_label("UnknownTransactionCommitResult"): 45 | print("UnknownTransactionCommitResult, retrying commit operation...") 46 | continue 47 | else: 48 | print("Error during commit...") 49 | raise 50 | 51 | def run_transaction_with_retry(transaction_func, session): 52 | while True: 53 | try: 54 | transaction_func(session) 55 | break 56 | except (ConnectionFailure, OperationFailure) as err: 57 | if err.has_error_label("TransientTransactionError"): 58 | print("TransientTransactionError, retryinh transaction...") 59 | continue 60 | else: 61 | raise 62 | 63 | with client.start_session() as session: 64 | try: 65 | run_transaction_with_retry(update_orders_and_inventory, session) 66 | except: 67 | raise 68 | -------------------------------------------------------------------------------- /03.읽기쓰기제어/transaction2.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | from pymongo.read_concern import ReadConcern 3 | from pymongo.write_concern import WriteConcern 4 | import certifi 5 | 6 | conn = "mongodb+srv://mongodb_user:__PWD__@cluster0.v6fiw3s.mongodb.net/" 7 | client = MongoClient(conn, tlsCAFile=certifi.where()) 8 | 9 | # client.test.orders.drop() 10 | # client.test.inventory.drop() 11 | # client.test.inventory.insert_one({"name": "pencil", "qty": 1000}) 12 | 13 | def callback(session): 14 | orders = session.client.test.orders 15 | inventory = session.client.test.inventory 16 | order = 200 17 | 18 | orders.insert_one( 19 | {"name": "pencil", "qty": order}, 20 | session=session 21 | ) 22 | inventory.update_one( 23 | { 24 | "name": "pencil", 25 | "qty": {"$gte": order} 26 | }, 27 | {"$inc": {"qty": order * -1}}, 28 | session=session 29 | ) 30 | 31 | with client.start_session() as session: 32 | session.with_transaction(callback, read_concern=ReadConcern('majority'), write_concern=WriteConcern('majority')) 33 | print(session.client.test.orders.find_one({"name": "pencil"})) 34 | print(session.client.test.inventory.find_one({"name": "pencil"})) 35 | -------------------------------------------------------------------------------- /04.Index/compoundIndex.js: -------------------------------------------------------------------------------- 1 | use sample_training 2 | 3 | show collections 4 | 5 | db.zips.findOne() 6 | 7 | db.zips.getIndexes() 8 | 9 | db.zips.find( 10 | { 11 | state: "LA", 12 | pop: { 13 | $gte: 40000 14 | } 15 | } 16 | ).sort({city: 1}) 17 | 18 | 19 | db.zips.find( 20 | { 21 | state: "LA", 22 | pop: { 23 | $gte: 40000 24 | } 25 | } 26 | ).sort({city: 1}).explain('executionStats') 27 | 28 | db.zips.createIndex({ state: 1 }) 29 | 30 | db.zips.getIndexes() 31 | 32 | db.zips.find( 33 | { 34 | state: "LA", 35 | pop: { 36 | $gte: 40000 37 | } 38 | } 39 | ).sort({ city: 1 }).explain('executionStats') 40 | 41 | 42 | db.zips.createIndex({ state: 1, city: 1, pop: 1 }) 43 | 44 | db.zips.getIndexes() 45 | 46 | 47 | db.zips.find( 48 | { 49 | state: "LA", 50 | pop: { 51 | $gte: 40000 52 | } 53 | } 54 | ).sort({ city: 1 }).explain('executionStats') 55 | 56 | 57 | 58 | db.zips.find( 59 | { 60 | state: "LA", 61 | pop: { 62 | $gte: 40000 63 | } 64 | }, 65 | { 66 | _id: 0, 67 | state: 1, 68 | pop: 1, 69 | city: 1 70 | } 71 | ).sort({ city: 1 }).explain('executionStats') 72 | -------------------------------------------------------------------------------- /04.Index/indexProperties.js: -------------------------------------------------------------------------------- 1 | use test 2 | 3 | db.ttl.insertMany([ 4 | { 5 | msg: "Hello!", 6 | time: new ISODate() 7 | }, 8 | { 9 | msg: "HelloWorld!", 10 | time: new ISODate() 11 | }, 12 | ]) 13 | 14 | db.ttl.find() 15 | 16 | db.ttl.createIndex( 17 | {time: 1}, 18 | {expireAfterSeconds: 60} 19 | ) 20 | 21 | db.ttl.getIndexes() 22 | 23 | db.ttl.find() 24 | 25 | 26 | 27 | db.unique.createIndex( 28 | {name: 1}, 29 | {unique: true} 30 | ) 31 | 32 | 33 | db.unique.insertMany([ 34 | {name: "tom"}, 35 | {name: "john"}, 36 | ]) 37 | 38 | db.unique.insertOne( 39 | {name: "tom"} 40 | ) 41 | 42 | db.unique.dropIndex( 43 | {name: 1} 44 | ) 45 | 46 | db.unique.createIndex( 47 | { 48 | name: 1, 49 | age: 1 50 | }, 51 | {unique: true} 52 | ) 53 | 54 | db.unique.insertOne({ 55 | name: "james", 56 | age: 23 57 | }) 58 | 59 | db.unique.insertOne({ 60 | name: "james", 61 | age: 24 62 | }) 63 | 64 | db.sparse.insertOne({ x: 1 }) 65 | db.sparse.insertOne({ x: 2 }) 66 | db.sparse.insertOne({ y: 1 }) 67 | 68 | db.sparse.createIndex( 69 | { x: 1 }, 70 | {sparse: true} 71 | ) 72 | 73 | db.sparse.find() 74 | 75 | db.sparse.find().hint({x: 1}) 76 | 77 | db.sparse.dropIndex({ x: 1 }) 78 | 79 | db.sparse.createIndex( 80 | { x: 1 }, 81 | { 82 | partialFilterExpression: { 83 | x: {$exists: true} 84 | } 85 | } 86 | ) 87 | 88 | 89 | db.sparse.find().hint({x: 1}) 90 | 91 | db.sparse.dropIndex({ x: 1 }) 92 | 93 | db.sparse.createIndex( 94 | { x: 1 }, 95 | { 96 | partialFilterExpression: { 97 | x: { $exists: true }, 98 | x: {$gte: 2} 99 | } 100 | } 101 | ) 102 | 103 | db.sparse.find().hint({x: 1}) 104 | 105 | 106 | db.hidden.insertOne({ a: 1 }) 107 | db.hidden.insertOne({ a: 2 }) 108 | 109 | db.hidden.createIndex( 110 | { a: 1 }, 111 | {hidden: true} 112 | ) 113 | 114 | db.hidden.find( 115 | {a: 1} 116 | ).explain('executionStats') 117 | 118 | db.hidden.unhideIndex({ a: 1 }) 119 | 120 | 121 | db.hidden.find( 122 | {a: 1} 123 | ).explain('executionStats') 124 | -------------------------------------------------------------------------------- /04.Index/multikeyIndex.js: -------------------------------------------------------------------------------- 1 | use sample_weatherdata 2 | 3 | show collections 4 | 5 | db.data.getIndexes() 6 | 7 | db.data.findOne() 8 | 9 | db.data.createIndex({sections: -1}) 10 | 11 | db.data.getIndexes() 12 | 13 | db.data.find({ sections: 'AG1' }).explain('executionStats') 14 | 15 | 16 | use sample_training 17 | show collections 18 | 19 | db.grades.findOne() 20 | 21 | db.grades.createIndex({"scores.type":1}) 22 | 23 | db.grades.getIndexes() 24 | 25 | db.grades.find( 26 | {"scores.type": "exam"} 27 | ).explain('executionStats') 28 | 29 | 30 | db.grades.dropIndex({"scores.type":1}) 31 | 32 | db.grades.getIndexes() 33 | 34 | db.grades.createIndex( 35 | {class_id: 1, "scores.type": 1} 36 | ) 37 | 38 | db.grades.find( 39 | { 40 | "scores.type": "exam", 41 | class_id: { 42 | $gte: 350 43 | } 44 | } 45 | ).explain("executionStats") 46 | -------------------------------------------------------------------------------- /05.Modeling/AttributePattern.js: -------------------------------------------------------------------------------- 1 | db.users.insertOne({ 2 | _id: "tom", 3 | joinDate: new Date(), 4 | server: "Sevilla", 5 | job: "merchant", 6 | logInfo: [] 7 | }) 8 | 9 | log = { 10 | loginTime: new Date(), 11 | visits: [], 12 | sails: [], 13 | trades: [], 14 | battles: [], 15 | quests: [], 16 | fishings: [], 17 | gambles: [], 18 | castings: [], 19 | farmings: [] 20 | } 21 | 22 | log.visits.push({ 23 | location: "Barcelona", 24 | time: new Date() 25 | }) 26 | log.visits.push({ 27 | location: "Sevilla", 28 | time: new Date() 29 | }) 30 | log.visits.push({ 31 | location: "London", 32 | time: new Date() 33 | }) 34 | 35 | log.trades.push({ 36 | item: "Musket", 37 | qty: 50, 38 | price: 1800 39 | }) 40 | log.trades.push({ 41 | item: "Musket", 42 | qty: -50, 43 | price: 2300 44 | }) 45 | 46 | log.quests.push({ 47 | name: "Cave Invenstigation", 48 | reward: 50000 49 | }) 50 | 51 | db.users.updateOne( 52 | { _id: "tom" }, 53 | { 54 | $addToSet: { 55 | logInfo: log 56 | } 57 | } 58 | ) 59 | 60 | db.users.find() 61 | db.users.drop() 62 | 63 | log.user = "tom" 64 | log.logoutTime = new Date() 65 | db.logs.insertOne(log) 66 | 67 | db.logs.find() 68 | db.logs.drop() 69 | 70 | 71 | 72 | 73 | date = new Date() 74 | log = { 75 | user: 'tom', 76 | loginTime: date, 77 | logoutTime: new Date(), 78 | actions: [ 79 | { action: "visit", value: "Barcelona", time: date }, 80 | { action: "visit", value: "Sevilla", time: date }, 81 | { action: "visit", value: "London", time: date }, 82 | { action: "trade", value: "Musket", type: "buy", qty: 50, price: 1800 }, 83 | { action: "trade", value: "Musket", type: "sell", qty: 50, price: 2300 }, 84 | { action: "quest", value: "Cave Investigation", reward: 50000, status: "In Progress" } 85 | ] 86 | } 87 | 88 | db.logs.insertOne(log); 89 | db.logs.find() 90 | 91 | db.logs.createIndex({"actions.action": 1, "actions.value": 1}) 92 | -------------------------------------------------------------------------------- /05.Modeling/BucketPattern.js: -------------------------------------------------------------------------------- 1 | const addMinutes = (min, date) => { 2 | date.setMinutes(date.getMinutes() + min) 3 | return new Date(date.getTime()) 4 | } 5 | 6 | const getRandomNumber = (min, max) => { 7 | min = Math.ceil(min); 8 | max = Math.floor(max); 9 | return Math.floor(Math.random() * (max - min + 1)) + min; 10 | } 11 | 12 | arr = []; 13 | date = new Date("2022-01-01T00:00:00.000Z"); 14 | for (range = 0; range < 60 * 24 * 30; range++){ 15 | time = addMinutes(1, date) 16 | for (floor = 1; floor < 21; floor++){ 17 | arr.push({ 18 | sensor_id: floor, 19 | timestamp: time, 20 | temparature: getRandomNumber(17, 30) 21 | }) 22 | } 23 | } 24 | 25 | db.sensor1.insertMany(arr) 26 | 27 | 28 | db.sensor1.stats().size / 1024 / 1024 29 | 30 | 31 | arr = []; 32 | date = new Date("2022-01-01T00:00:00.000Z"); 33 | for (hour = 0; hour < 24 * 30; hour++) { 34 | start_date = addMinutes(0, date) 35 | measurement = [] 36 | for (sec = 0; sec < 60; sec++){ 37 | time = addMinutes(1, date) 38 | measurement.push({ 39 | timestamp: time, 40 | temparature: 0 41 | }) 42 | } 43 | for (floor = 1; floor < 21; floor++){ 44 | for (i = 0; i < 60; i++){ 45 | measurement[i].temparature = getRandomNumber(17, 30) 46 | } 47 | arr.push({ 48 | sensor_id: floor, 49 | start_date: start_date, 50 | end_date: addMinutes(0, date), 51 | measurements: measurement 52 | }) 53 | } 54 | } 55 | 56 | db.sensor2.insertMany(arr) 57 | 58 | db.sensor1.stats().size / 1024 / 1024 59 | db.sensor2.stats().size / 1024 / 1024 60 | 61 | 62 | db.createCollection( 63 | "sensor3", 64 | { 65 | timeseries: { 66 | timeField: "timestamp", 67 | metaField: "metadata", 68 | granularity: "minutes" 69 | } 70 | } 71 | ) 72 | 73 | 74 | arr = []; 75 | date = new Date("2022-01-01T00:00:00.000Z"); 76 | for (range = 0; range < 60 * 24 * 30; range++){ 77 | time = addMinutes(1, date) 78 | for (floor = 1; floor < 21; floor++){ 79 | arr.push({ 80 | timestamp: time, 81 | metadata: { 82 | sensor_id: floor, 83 | temparature: getRandomNumber(17, 30) 84 | } 85 | }) 86 | } 87 | } 88 | 89 | db.sensor3.insertMany(arr) 90 | 91 | 92 | db.sensor1.stats().size / 1024 / 1024 93 | db.sensor2.stats().size / 1024 / 1024 94 | db.sensor3.stats().size / 1024 / 1024 95 | -------------------------------------------------------------------------------- /05.Modeling/ExtendedReferencePattern.js: -------------------------------------------------------------------------------- 1 | db.cafe.insertMany([ 2 | { 3 | _id: 1, 4 | name: "IT Community", 5 | desc: "A Cafe where developer's share information.", 6 | created_at: ISODate("2018-08-09"), 7 | last_article: ISODate("2022-06-01T10:56:32.000Z"), 8 | level: 5, 9 | members: [ 10 | { 11 | id: "tom93", 12 | first_name: "Tom", 13 | last_name: "Park", 14 | phone: "000-0000-1234", 15 | joined_at: ISODate("2018-09-12"), 16 | job: "DBA" 17 | }, 18 | { 19 | id: "asddwd12", 20 | first_name: "Jenny", 21 | last_name: "Kim", 22 | phone: "000-0000-1111", 23 | joined_at: ISODate("2018-10-02"), 24 | job: "Frontend Dev" 25 | }, 26 | { 27 | id: "candy12", 28 | first_name: "Zen", 29 | last_name: "Ko", 30 | phone: "000-0000-1233", 31 | joined_at: ISODate("2019-01-01"), 32 | job: "DA" 33 | } 34 | ] 35 | }, 36 | { 37 | _id: 2, 38 | name: "Game Community", 39 | desc: "Share information about games.", 40 | created_at: ISODate("2020-01-23"), 41 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 42 | level: 4, 43 | members: [ 44 | { 45 | id: "tom93", 46 | first_name: "Tom", 47 | last_name: "Park", 48 | phone: "000-0000-1234", 49 | joined_at: ISODate("2020-09-12"), 50 | job: "DBA" 51 | }, 52 | { 53 | id: "asddwd12", 54 | first_name: "Jenny", 55 | last_name: "Kim", 56 | phone: "000-0000-1111", 57 | joined_at: ISODate("2021-10-01"), 58 | job: "Frontend Dev" 59 | }, 60 | { 61 | id: "java1", 62 | first_name: "Kevin", 63 | last_name: "Shin", 64 | phone: "000-0000-1133", 65 | joined_at: ISODate("2022-08-10"), 66 | job: "Game Dev" 67 | } 68 | ] 69 | }, 70 | ]); 71 | 72 | 73 | 74 | const generateRandomString = (num) => { 75 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 76 | let result = ''; 77 | const charactersLength = characters.length; 78 | for (let i = 0; i < num; i++){ 79 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 80 | } 81 | return result; 82 | } 83 | 84 | jobs = ["DBA", "SE", "DA", "FE", "BE"]; 85 | jobs[Math.floor(Math.random()* jobs.length)] 86 | 87 | date = new Date(); 88 | new Date(date - Math.floor(Math.random() * 10000000000)) 89 | 90 | arr = []; 91 | for (i = 0; i < 100000; i++){ 92 | document = { 93 | id: generateRandomString(5), 94 | first_name: generateRandomString(10), 95 | last_name: generateRandomString(15), 96 | phone: "000-0000-1234", 97 | joined_at: new Date(date - Math.floor(Math.random() * 10000000000)), 98 | job: jobs[Math.floor(Math.random()* jobs.length)] 99 | } 100 | arr.push(document) 101 | } 102 | 103 | 104 | db.cafe.updateOne( 105 | { _id: 2 }, 106 | { 107 | $addToSet: { 108 | members: {$each: arr} 109 | } 110 | } 111 | ) 112 | 113 | db.cafe.stats().size / 1024 / 1024 114 | 115 | db.cafe.aggregate([ 116 | { 117 | $project: { 118 | arrSize: { 119 | $size: "$members" 120 | } 121 | } 122 | } 123 | ]) 124 | 125 | 126 | db.members.insertMany([ 127 | { 128 | id: "tom93", 129 | first_name: "Tom", 130 | last_name: "Park", 131 | phone: "000-0000-1234", 132 | job: "DBA", 133 | joined_cafes: [ 134 | { 135 | _id: 1, 136 | name: "IT Community", 137 | desc: "A Cafe where developer's share information.", 138 | created_at: ISODate("2018-08-09"), 139 | last_article: ISODate("2022-06-01T10:56:32.000Z"), 140 | level: 5, 141 | joined_at: ISODate("2018-09-12") 142 | }, 143 | { 144 | _id: 2, 145 | name: "Game Community", 146 | desc: "Share information about games.", 147 | created_at: ISODate("2020-01-23"), 148 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 149 | level: 4, 150 | joined_at: ISODate("2020-09-12") 151 | } 152 | ] 153 | }, 154 | { 155 | id: "asddwd12", 156 | first_name: "Jenny", 157 | last_name: "Kim", 158 | phone: "000-0000-1111", 159 | job: "Frontend Dev", 160 | joined_cafes: [ 161 | { 162 | _id: 1, 163 | name: "IT Community", 164 | desc: "A Cafe where developer's share information.", 165 | created_at: ISODate("2018-08-09"), 166 | last_article: ISODate("2022-06-01T10:56:32.000Z"), 167 | level: 5, 168 | joined_at: ISODate("2018-10-02"), 169 | }, 170 | { 171 | _id: 2, 172 | name: "Game Community", 173 | desc: "Share information about games.", 174 | created_at: ISODate("2020-01-23"), 175 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 176 | level: 4, 177 | joined_at: ISODate("2021-10-01") 178 | } 179 | ] 180 | }, 181 | { 182 | id: "candy12", 183 | first_name: "Zen", 184 | last_name: "Ko", 185 | phone: "000-0000-1233", 186 | job: "DA", 187 | joined_cafes: [ 188 | { 189 | _id: 1, 190 | name: "IT Community", 191 | desc: "A Cafe where developer's share information.", 192 | created_at: ISODate("2018-08-09"), 193 | last_article: ISODate("2022-06-01T10:56:32.000Z"), 194 | level: 5, 195 | joined_at: ISODate("2019-01-01") 196 | } 197 | ] 198 | }, 199 | { 200 | id: "java1", 201 | first_name: "Kevin", 202 | last_name: "Shin", 203 | phone: "000-0000-1133", 204 | job: "Game Dev", 205 | joined_cafes: [ 206 | { 207 | _id: 2, 208 | name: "Game Community", 209 | desc: "Share information about games.", 210 | created_at: ISODate("2020-01-23"), 211 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 212 | level: 4, 213 | joined_at: ISODate("2022-08-10") 214 | } 215 | ] 216 | } 217 | ]) 218 | 219 | 220 | 221 | arr = []; 222 | for (i = 0; i < 300000; i++){ 223 | document = { 224 | id: generateRandomString(5), 225 | first_name: generateRandomString(10), 226 | last_name: generateRandomString(15), 227 | phone: "000-0000-1234", 228 | job: jobs[Math.floor(Math.random() * jobs.length)], 229 | joined_cafes: [ 230 | { 231 | _id: 2, 232 | name: 'Game Community', 233 | desc: 'Share information about games.', 234 | created_at: ISODate("2020-01-23T00:00:00.000Z"), 235 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 236 | level: 4, 237 | joined_at: new Date(date - Math.floor(Math.random() * 10000000000)), 238 | } 239 | ] 240 | } 241 | arr.push(document) 242 | } 243 | 244 | db.members.insertMany(arr) 245 | 246 | 247 | date = new Date() 248 | db.cafe.updateOne( 249 | { _id: 1 }, 250 | {$set: {last_article: date}} 251 | ) 252 | 253 | db.cafe.updateOne( 254 | { _id: 2 }, 255 | {$set: {last_article: date}} 256 | ) 257 | 258 | db.members.updateMany( 259 | { 260 | "joined_cafes._id": 1 261 | }, 262 | { 263 | $set: { 264 | "joined_cafes.$.last_article": date 265 | } 266 | } 267 | ) 268 | 269 | 270 | db.members.updateMany( 271 | { 272 | "joined_cafes._id": 2 273 | }, 274 | { 275 | $set: { 276 | "joined_cafes.$.last_article": date 277 | } 278 | } 279 | ) 280 | 281 | db.cafe.deleteMany({}) 282 | db.members.deleteMany({}) 283 | 284 | 285 | 286 | 287 | db.cafe.insertMany([ 288 | { 289 | _id: 1, 290 | name: "IT Community", 291 | desc: "A Cafe where developer's share information.", 292 | created_at: ISODate("2018-08-09"), 293 | last_article: ISODate("2022-06-01T10:56:32.000Z"), 294 | level: 5 295 | }, 296 | { 297 | _id: 2, 298 | name: "Game Community", 299 | desc: "Share information about games.", 300 | created_at: ISODate("2020-01-23"), 301 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 302 | level: 4 303 | }, 304 | ]); 305 | 306 | 307 | 308 | db.members.insertMany([ 309 | { 310 | id: "tom93", 311 | first_name: "Tom", 312 | last_name: "Park", 313 | phone: "000-0000-1234", 314 | job: "DBA", 315 | joined_cafes: [1, 2] 316 | }, 317 | { 318 | id: "asddwd12", 319 | first_name: "Jenny", 320 | last_name: "Kim", 321 | phone: "000-0000-1111", 322 | job: "Frontend Dev", 323 | joined_cafes: [1,2] 324 | }, 325 | { 326 | id: "candy12", 327 | first_name: "Zen", 328 | last_name: "Ko", 329 | phone: "000-0000-1233", 330 | job: "DA", 331 | joined_cafes: [1] 332 | }, 333 | { 334 | id: "java1", 335 | first_name: "Kevin", 336 | last_name: "Shin", 337 | phone: "000-0000-1133", 338 | job: "Game Dev", 339 | joined_cafes: [2] 340 | } 341 | ]) 342 | 343 | db.cafe.aggregate([ 344 | { 345 | $lookup: { 346 | from: "members", 347 | localField: "_id", 348 | foreignField: "joined_cafes", 349 | as: "members", 350 | pipeline: [ 351 | { 352 | $match: { 353 | job: "DBA" 354 | } 355 | }, 356 | { 357 | $project: { 358 | _id: 0, 359 | id: 1, 360 | job: 1 361 | } 362 | } 363 | ] 364 | } 365 | }, 366 | { 367 | $project: { 368 | name: 1, 369 | desc: 1, 370 | created_at: 1, 371 | joinedMemberJob: { 372 | $first: "$members.job" 373 | }, 374 | cnt: { 375 | $size: "$members" 376 | } 377 | } 378 | } 379 | ]) 380 | 381 | 382 | arr = []; 383 | for (i = 0; i < 300000; i++){ 384 | document = { 385 | id: generateRandomString(5), 386 | first_name: generateRandomString(10), 387 | last_name: generateRandomString(15), 388 | phone: "000-0000-1234", 389 | job: jobs[Math.floor(Math.random() * jobs.length)], 390 | joined_cafes: [2] 391 | } 392 | arr.push(document) 393 | } 394 | 395 | db.members.insertMany(arr) 396 | 397 | 398 | db.cafe.aggregate([ 399 | { 400 | $lookup: { 401 | from: "members", 402 | localField: "_id", 403 | foreignField: "joined_cafes", 404 | as: "members", 405 | pipeline: [ 406 | { 407 | $match: { 408 | job: "DBA" 409 | } 410 | }, 411 | { 412 | $project: { 413 | _id: 0, 414 | id: 1, 415 | job: 1 416 | } 417 | } 418 | ] 419 | } 420 | }, 421 | { 422 | $project: { 423 | name: 1, 424 | desc: 1, 425 | created_at: 1, 426 | joinedMemberJob: { 427 | $first: "$members.job" 428 | }, 429 | cnt: { 430 | $size: "$members" 431 | } 432 | } 433 | } 434 | ]).explain('executionStats') 435 | 436 | 437 | db.members.createIndex({ "joined_cafes": 1 }) 438 | 439 | 440 | db.cafe.aggregate([ 441 | { 442 | $lookup: { 443 | from: "members", 444 | localField: "_id", 445 | foreignField: "joined_cafes", 446 | as: "members", 447 | pipeline: [ 448 | { 449 | $match: { 450 | job: "DBA" 451 | } 452 | }, 453 | { 454 | $project: { 455 | _id: 0, 456 | id: 1, 457 | job: 1 458 | } 459 | } 460 | ] 461 | } 462 | }, 463 | { 464 | $project: { 465 | name: 1, 466 | desc: 1, 467 | created_at: 1, 468 | joinedMemberJob: { 469 | $first: "$members.job" 470 | }, 471 | cnt: { 472 | $size: "$members" 473 | } 474 | } 475 | } 476 | ]).explain('executionStats') 477 | 478 | 479 | 480 | db.cafe.deleteMany({}) 481 | db.members.deleteMany({}) 482 | 483 | 484 | 485 | 486 | db.cafe.insertMany([ 487 | { 488 | _id: 1, 489 | name: "IT Community", 490 | desc: "A Cafe where developer's share information.", 491 | created_at: ISODate("2018-08-09"), 492 | last_article: ISODate("2022-06-01T10:56:32.000Z"), 493 | level: 5 494 | }, 495 | { 496 | _id: 2, 497 | name: "Game Community", 498 | desc: "Share information about games.", 499 | created_at: ISODate("2020-01-23"), 500 | last_article: ISODate("2022-06-02T10:56:32.000Z"), 501 | level: 4 502 | }, 503 | ]); 504 | 505 | 506 | 507 | db.members.insertMany([ 508 | { 509 | id: "tom93", 510 | first_name: "Tom", 511 | last_name: "Park", 512 | phone: "000-0000-1234", 513 | job: "DBA", 514 | joined_cafes: [ 515 | { 516 | _id: 1, 517 | name: "IT Community", 518 | desc: "A Cafe where developer's share information.", 519 | created_at: ISODate("2018-08-09"), 520 | }, 521 | { 522 | _id: 2, 523 | name: "Game Community", 524 | desc: "Share information about games.", 525 | created_at: ISODate("2020-01-23"), 526 | } 527 | ] 528 | }, 529 | { 530 | id: "asddwd12", 531 | first_name: "Jenny", 532 | last_name: "Kim", 533 | phone: "000-0000-1111", 534 | job: "Frontend Dev", 535 | joined_cafes: [ 536 | { 537 | _id: 1, 538 | name: "IT Community", 539 | desc: "A Cafe where developer's share information.", 540 | created_at: ISODate("2018-08-09"), 541 | }, 542 | { 543 | _id: 2, 544 | name: "Game Community", 545 | desc: "Share information about games.", 546 | created_at: ISODate("2020-01-23"), 547 | } 548 | ] 549 | }, 550 | { 551 | id: "candy12", 552 | first_name: "Zen", 553 | last_name: "Ko", 554 | phone: "000-0000-1233", 555 | job: "DA", 556 | joined_cafes: [ 557 | { 558 | _id: 1, 559 | name: "IT Community", 560 | desc: "A Cafe where developer's share information.", 561 | created_at: ISODate("2018-08-09"), 562 | } 563 | ] 564 | }, 565 | { 566 | id: "java1", 567 | first_name: "Kevin", 568 | last_name: "Shin", 569 | phone: "000-0000-1133", 570 | job: "Game Dev", 571 | joined_cafes: [ 572 | { 573 | _id: 2, 574 | name: "Game Community", 575 | desc: "Share information about games.", 576 | created_at: ISODate("2020-01-23"), 577 | } 578 | ] 579 | } 580 | ]) 581 | 582 | 583 | arr = []; 584 | for (i = 0; i < 300000; i++){ 585 | document = { 586 | id: generateRandomString(5), 587 | first_name: generateRandomString(10), 588 | last_name: generateRandomString(15), 589 | phone: "000-0000-1234", 590 | job: jobs[Math.floor(Math.random() * jobs.length)], 591 | joined_cafes: [ 592 | { 593 | _id: 2, 594 | name: 'Game Community', 595 | desc: 'Share information about games.', 596 | created_at: ISODate("2020-01-23T00:00:00.000Z"), 597 | } 598 | ] 599 | } 600 | arr.push(document) 601 | } 602 | 603 | db.members.insertMany(arr) 604 | 605 | db.members.aggregate([ 606 | { 607 | $match: { 608 | job: "DBA" 609 | } 610 | }, 611 | { 612 | $unwind: "$joined_cafes" 613 | }, 614 | { 615 | $group: { 616 | _id: "$joined_cafes._id", 617 | joined_cafes: { 618 | $first: "$joined_cafes" 619 | }, 620 | joinedMemberJob: { 621 | $first: "$job" 622 | }, 623 | cnt: { 624 | $sum: 1 625 | } 626 | } 627 | }, 628 | { 629 | $project: { 630 | _id: 0, 631 | name: "$joined_cafes.name", 632 | desc: "$joined_cafes.desc", 633 | create_at: "$joined_cafes.created_at", 634 | joinedMemberJob: 1, 635 | cnt: 1 636 | } 637 | } 638 | ]).explain('executionStats') 639 | 640 | 641 | db.members.createIndex({job: 1}) 642 | -------------------------------------------------------------------------------- /05.Modeling/SubsetPattern.js: -------------------------------------------------------------------------------- 1 | use delivery 2 | 3 | db.shops.insertOne({ 4 | _id: 1, 5 | name: "Tommy Steak House", 6 | desc: "Greatest Steak House Ever.", 7 | phone: "000-0000-1234", 8 | reviews: [ 9 | { 10 | review_id: 1, 11 | user: "James", 12 | review: "So Good!!", 13 | date: new Date(), 14 | rating: 10 15 | }, 16 | { 17 | review_id: 2, 18 | user: "Tommy", 19 | review: "Not Bad.", 20 | date: new Date(), 21 | rating: 7 22 | }, 23 | { 24 | review_id: 3, 25 | user: "Kevin", 26 | review: "Yummy!!", 27 | date: new Date(), 28 | rating: 5 29 | }, 30 | ] 31 | }) 32 | 33 | 34 | 35 | const generateRandomString = (num) => { 36 | const characters ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 37 | let result = ''; 38 | const charactersLength = characters.length; 39 | for (let i = 0; i < num; i++) { 40 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 41 | } 42 | 43 | return result; 44 | } 45 | 46 | 47 | 48 | 49 | db.shops.insertOne({ 50 | _id: 2, 51 | name: "Kevin's Pizza", 52 | desc: "Italian Style Pizza", 53 | phone: "000-0000-1111", 54 | reviews: [] 55 | }) 56 | 57 | for (i = 0; i < 800; i++){ 58 | review = { 59 | review_id: i, 60 | user: generateRandomString(5), 61 | review: generateRandomString(10), 62 | date: new Date(), 63 | rating: Math.floor(Math.random() * 10) 64 | } 65 | db.shops.updateOne( 66 | { 67 | _id: 2 68 | }, 69 | { 70 | $push: { 71 | reviews: review 72 | } 73 | } 74 | ) 75 | } 76 | 77 | 78 | db.shops.findOne({ _id: 2 }) 79 | 80 | Object.bsonsize(db.shops.findOne({ _id: 2 })) 81 | Object.bsonsize(db.shops.findOne({ _id: 1 })) 82 | 83 | 84 | db.shops.drop() 85 | 86 | 87 | 88 | 89 | db.shops.insertOne({ 90 | _id: 2, 91 | name: "Kevin's Pizza", 92 | desc: "Italian Style Pizza", 93 | phone: "000-0000-1111", 94 | reviews: [] 95 | }) 96 | 97 | for (i = 0; i < 800; i++){ 98 | review = { 99 | review_id: i, 100 | user: generateRandomString(5), 101 | review: generateRandomString(10), 102 | date: new Date(), 103 | rating: Math.floor(Math.random() * 10) 104 | } 105 | db.reviews.insertOne(review) 106 | db.shops.updateOne( 107 | { 108 | _id: 2 109 | }, 110 | { 111 | $push: { 112 | reviews: review 113 | } 114 | } 115 | ) 116 | } 117 | 118 | db.reviews.find() 119 | db.shops.find() 120 | 121 | 122 | 123 | review = { 124 | review_id: 800, 125 | user: generateRandomString(5), 126 | review: generateRandomString(10), 127 | date: new Date(), 128 | rating: Math.floor(Math.random() * 10) 129 | } 130 | db.reviews.insertOne(review) 131 | db.shops.updateOne( 132 | { 133 | _id: 2 134 | }, 135 | { 136 | $push: { 137 | reviews: { 138 | $each: [review], 139 | $slice: -10 140 | } 141 | } 142 | } 143 | ) 144 | 145 | db.reviews.find() 146 | db.shops.find() 147 | 148 | 149 | 150 | for (i = 801; i < 1600; i++){ 151 | review = { 152 | review_id: i, 153 | user: generateRandomString(5), 154 | review: generateRandomString(10), 155 | date: new Date(), 156 | rating: Math.floor(Math.random() * 10) 157 | } 158 | db.reviews.insertOne(review) 159 | db.shops.updateOne( 160 | { 161 | _id: 2 162 | }, 163 | { 164 | $push: { 165 | reviews: { 166 | $each: [review], 167 | $slice: -10 168 | } 169 | } 170 | } 171 | ) 172 | } 173 | 174 | 175 | db.reviews.countDocuments() 176 | db.shops.find() 177 | Object.bsonsize(db.shops.findOne({_id: 2})) 178 | -------------------------------------------------------------------------------- /05.Modeling/TreePattern.js: -------------------------------------------------------------------------------- 1 | use tree 2 | 3 | db.employees.insertMany([ 4 | { 5 | _id: 1, 6 | name: "Eliot", 7 | position: "CEO" 8 | }, 9 | { 10 | _id: 2, 11 | name: "Ron", 12 | position: "Center Lead", 13 | reportsTo: "Eliot" 14 | }, 15 | { 16 | _id: 3, 17 | name: "Tom", 18 | position: "Team Lead", 19 | reportsTo: "Ron" 20 | }, 21 | { 22 | _id: 4, 23 | name: "Bred", 24 | position: "Team Member", 25 | reportsTo: "Tom" 26 | }, 27 | { 28 | _id: 5, 29 | name: "Don", 30 | position: "Team Member", 31 | reportsTo: "Tom" 32 | }, 33 | { 34 | _id: 6, 35 | name: "Carl", 36 | position: "Team Member", 37 | reportsTo: "Tom" 38 | } 39 | ]) 40 | 41 | 42 | db.employees.aggregate([ 43 | { 44 | $graphLookup: { 45 | from: "employees", 46 | startWith: "$reportsTo", 47 | connectFromField: "reportsTo", 48 | connectToField: "name", 49 | depthField: "depth", 50 | as: "reportingHierarchy" 51 | } 52 | } 53 | ]) 54 | 55 | 56 | 57 | db.products.insertMany([ 58 | { 59 | _id: 0, 60 | name: "Yonex ezone", 61 | price: 300000, 62 | category: "Tenis Racket" 63 | }, 64 | { 65 | _id: 1, 66 | name: "Samsung Gaming 24", 67 | price: 260000, 68 | category: "Gaming Monitor" 69 | }, 70 | ]) 71 | 72 | db.categories.insertMany([ 73 | { 74 | category_name: "Tenis Racket", 75 | ancestor_categories: [ 76 | "Tenis", 77 | "Sports", 78 | "Outdoor" 79 | ] 80 | }, 81 | { 82 | category_name: "Gaming Monitor", 83 | ancestor_categories: [ 84 | "Monitor", 85 | "Computer", 86 | "Electronics", 87 | "Home" 88 | ] 89 | }, 90 | ]) 91 | 92 | 93 | db.products.aggregate([ 94 | { 95 | $graphLookup: { 96 | from: "categories", 97 | startWith: "$category", 98 | connectFromField: "ancestor_categories", 99 | connectToField: "category_name", 100 | as: "categories" 101 | } 102 | } 103 | ]) 104 | 105 | 106 | 107 | db.categories.insertMany([ 108 | { 109 | category_name: "Tenis", 110 | ancestor_categories: [ 111 | "Sports", 112 | "Outdoor" 113 | ] 114 | }, 115 | { 116 | category_name: "Sports", 117 | ancestor_categories: [ 118 | "Sports", 119 | ] 120 | }, 121 | { 122 | category_name: "Outdoor", 123 | ancestor_categories: [ 124 | ] 125 | }, 126 | ]) 127 | 128 | 129 | db.products.aggregate([ 130 | { 131 | $graphLookup: { 132 | from: "categories", 133 | startWith: "$category", 134 | connectFromField: "ancestor_categories", 135 | connectToField: "category_name", 136 | as: "categories" 137 | } 138 | } 139 | ]) 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Repository for MongoDB Training Samples. 4 | --------------------------------------------------------------------------------