유데미 몽고DB 수업을 듣고 정리한 내용입니다.
최초 발행일 2019-12-10
몽고DB 쉘 실행 후 아래의 명령어를 통해 데이터베이스 목록을 확인할 수 있다.
>show dbs;
admin 0.000GB
class101 0.001GB
config 0.000GB
jumsul 0.000GB
local 0.000GB
task-manager 0.000GB
test 0.000GB
다음 명령어를 통해 특정 데이터베이스를 사용한다. 기존에 있는 데이터베이스라면 기존의 데이터베이스를 사용하고 없다면 새로운 데이터베이스를 생성한다. 아래의 예시에서는 기존에 없던 새로운 flight라는 데이터베이스를 생성했다.
>use flight
switched to db flight
> show dbs;
admin 0.000GB
class101 0.001GB
config 0.000GB
flight 0.000GB
jumsul 0.000GB
local 0.000GB
task-manager 0.000GB
test 0.000GB
> use test
switched to db test
> db.dropDatabase()
{ "dropped" : "test", "ok" : 1 }
터미널에서 다음의 명령어로 mongoDB에 곧바로 데이터를 import 할 수 있다. 현재 경로는 persons.json 파일이 있는 경로여야 한다. 이 명령은 contactsData 데이터베이스를 생성하고 contacts 컬렉션에 persons.json의 데이터를 넣는다.
mongoimport persons.json -d contactsData -c contacts --jsonArray
다음은 flightData라는 컬렉션을 만들어 새로운 도큐먼트를 입력하는 명령어이다. 마찬가지로 이미 이 데이터베이스에 있는 컬렉션이라면 해당 컬렉션에 도큐먼트를 추가하고, 그렇지 않다면 새로운 컬렉션을 만들고 도큐먼트를 입력한다.
> db.flightData.insertOne({departure: "MUC"})
{
"acknowledged" : true,
"insertedId" : ObjectId("5def61e6a71650b73644582f")
}
다음 명령어를 통해 새로 만든 컬렉션을 확인해보자.
> show collections
flightData
그리고 이 컬렉션에 방금 입력한 데이터를 확인해보자.
> db.flightData.find()
{ "_id" : ObjectId("5def61e6a71650b73644582f"), "departure" : "MUC" }
다음 명령어를 통해 도큐먼트를 업데이트 할 수 있다. flightData 컬렉션에 있는 도큐먼트 중에 departure 프로퍼티가 "MUC"인 것을 찾아 marker라는 프로퍼티를 추가했다.
> db.flightData.updateOne({departure: "MUC"}, {$set : {marker:"delete"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
다음 명령어를 통해 업데이트가 잘 되었는지 확인해본다.
> db.flightData.find().pretty()
{
"_id" : ObjectId("5def61e6a71650b73644582f"),
"departure" : "MUC",
"marker" : "delete"
}
여러개의 도큐먼트를 한번에 업데이트 할 수도 있다. 이를 위해 새로운 도큐먼트 하나를 추가로 입력하고 확인한다.
> db.flightData.insertOne({departure: "TXL", arrivalAirport: "LHR"})
{
"acknowledged" : true,
"insertedId" : ObjectId("5def620ba71650b736445830")
}
> db.flightData.find().pretty()
{
"_id" : ObjectId("5def61e6a71650b73644582f"),
"departure" : "MUC",
"marker" : "delete"
}
{
"_id" : ObjectId("5def620ba71650b736445830"),
"departure" : "TXL",
"arrivalAirport" : "LHR"
}
다음의 명령어를 통해 이 컬렉션에 있는 모든 도큐먼트를 업데이트 할 수 있다. updatedMany의 첫번째 인자에 빈 객체를 넣음으로서 이 컬렉션에 있는 모든 도큐먼트를 선택하여 업데이트를 할 수 있다.
> db.flightData.updateMany({}, {$set : {marker:"toDelete"}})
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
업데이트 된 것을 확인해보자.
> db.flightData.find().pretty()
{
"_id" : ObjectId("5def61e6a71650b73644582f"),
"departure" : "MUC",
"marker" : "toDelete"
}
{
"_id" : ObjectId("5def620ba71650b736445830"),
"departure" : "TXL",
"arrivalAirport" : "LHR",
"marker" : "toDelete"
}
다음 명령어를 통해 컬렉션에 있는 모든 도큐먼트를 한번에 삭제할 수도 있다. 이 컬렉션에 있는 모든 도큐먼트 중 marker 프로퍼티의 값이 "toDelete"인 모든 도큐먼트를 삭제한다.
> db.flightData.deleteMany({marker: "toDelete"})
{ "acknowledged" : true, "deletedCount" : 2 }
이를 확인해보면 다음 명령어를 쳤을 때 아무 도큐먼트가 뜨지 않는 것을 보니 컬렉션에 있는 모든 도큐먼트가 잘 지워졌다.
> db.flightData.find()
다음의 명령어를 통해 컬렉션에 여러 개의 도큐먼트를 한번에 입력할 수 있다. insertMany에는 입력하고자 하는 여러개의 객체를 배열로 넣어야 한다.
> db.flightData.insertMany([
... {
... "departureAirport": "MUC",
... "arrivalAirport": "SFO",
... "aircraft": "Airbus A380",
... "distance": 12000,
... "intercontinental": true
... },
... {
... "departureAirport": "LHR",
... "arrivalAirport": "TXL",
... "aircraft": "Airbus A320",
... "distance": 950,
... "intercontinental": false
... }])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5defbde2a71650b736445834"),
ObjectId("5defbde2a71650b736445835")
]
}
데이터가 잘 들어갔음을 확인해볼 수 있다.
> db.flightData.find().pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true
}
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false
}
다음 명령어를 통해 컬렉션에서 distance 프로퍼티가 900 이상인 도큐먼트만을 쿼리할 수 있다. $gt의 gt는 greater than의 이니셜이다.
> db.flightData.find({distance: {$gt : 900}}).pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true
}
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false
}
기준을 1000으로 줬을 때는 위의 결과와 달리 1개의 도큐먼트만 나타난다.
> db.flightData.find({distance: {$gt : 1000}}).pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true
}
다음 명령어 findOne은 특정 기준을 만족하는 단 하나의 도큐먼트만을 쿼리한다.
> db.flightData.findOne({distance: {$gt : 900}})
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true
}
updateOne과 updateMany는 기존의 도큐먼트에 새로운 프로퍼티가 추가된다. 예를들어 _id가 ObjectId("5defbde2a71650b736445834") 인 도큐먼트를 다음과 같이 업데이트를 하면 새로 업데이트한 delayed 프로퍼티가 기존의 도큐먼트에 추가되었다.
> db.flightData.updateOne({_id: ObjectId("5defbde2a71650b736445834")},
{$set : {delayed: false}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.flightData.find().pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true,
"delayed" : false
}
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false
}
하지만 update 함수는 어떨까? 아래의 결과를 보면 도큐먼트에 기존에 있던 프로퍼티를 모두 삭제하고 새로 업데이트한 프로퍼티만 추가되었다. 주의할 점은 update 함수의 두번째 인자이다. update 함수의 두번째 인자에는 {$set } 부분이 빠져있다. updateOne과 updateMany의 두번째 인자에 {$set }를 빼면 에러가 난다. 그런데 update 함수에 {$set }를 넣으면 updateOne과 마찬가지로 기존의 프로퍼티에 새로운 프로퍼티가 추가가 된다. 헷갈린다..
> db.flightData.update({_id: ObjectId("5defbde2a71650b736445834")},
{delayed: true})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.flightData.find().pretty()
{ "_id" : ObjectId("5defbde2a71650b736445834"), "delayed" : true }
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false
}
그래서 위 경우에는 update 보다는 replaceOne 함수를 사용하는 것이 좋다. replaceOne은 함수 이름에서 유추해볼 수 있듯이 업데이트 내용이 기존의 내용을 대체한다. 다음과 같다.
> db.flightData.replaceOne({_id: ObjectId("5defbde2a71650b736445834")}, {
... "departureAirport": "MUC",
... "arrivalAirport": "SFO",
... "aircraft": "Airbus A380",
... "distance": 12000,
... "intercontinental": true
... })
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
기존에 있던 delayed 프로퍼티는 없어지고 새로 추가한 프로퍼티들만 도큐먼트에 추가된 것을 확인할 수 있다.
> db.flightData.find().pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true
}
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false
}
몽고DB에서 컬렉션의 도큐먼트를 쿼리 할 때는 find 함수를 사용한다. find 함수는 도큐먼트를 곧바로 리턴하지 않고 커서(Cursor) 객체를 리턴한다. 만약 컬렉션에 20개 이상의 도큐먼트가 있을때 find 함수로 모든 도큐먼트를 찾으면 20개의 도큐먼트가 나오고 맨 아래에 다음과 같이 나타난다.
...
{ "_id" : ObjectId("5defd370c79996355df1cbad"), "name" : "Klaus Arber", "age" : 53 }
{ "_id" : ObjectId("5defd370c79996355df1cbae"), "name" : "Albert Twostone", "age" : 68 }
Type "it" for more
그리고 몽고 쉘에 it을 입력하면 그 다음 도큐먼트가 나온다. it을 입력함으로써 위의 find 함수에서 리턴된 커서 객체를 사용하여 다음 도큐먼트들을 가져온것이다.
> it
{ "_id" : ObjectId("5defd370c79996355df1cbaf"), "name" : "Gordon Black", "age" : 38 }
...
몽고DB는 커서 객체에 사용할 수 있는 toArray(), forEach()와 같은 여러가지 함수들을 제공한다. toArray()는 도큐먼트의 배열을 리턴한다.
> db.passengers.find().toArray()
[
{
"_id" : ObjectId("5defd370c79996355df1cb9b"),
"name" : "Max Schwarzmueller",
"age" : 29
},
{
"_id" : ObjectId("5defd370c79996355df1cb9c"),
"name" : "Manu Lorenz",
"age" : 30
}
...
]
forEach() 함수는 다음과 같이 사용할 수 있다. 마치 자바스크립트 배열의 forEach 함수와 같이 작동한다. passengers 컬렉션의 모든 도큐먼트에 각각 printjson 함수를 호출하여 결과를 출력하고 있다. 너무 신기해서 mongodb shell language 로 검색을 해보니.. The mongo shell is an interactive JavaScript interface to MongoDB라고 한다. 몽고 쉘이 몽고DB에서 자바스크립트를 사용할 수 있게 해주는 인터페이스가 된다고 한다.
> db.passengers.find().forEach(doc => printjson(doc))
{
"_id" : ObjectId("5defd370c79996355df1cb9b"),
"name" : "Max",
"age" : 29
}
{
"_id" : ObjectId("5defd370c79996355df1cb9c"),
"name" : "Manu Lorenz",
"age" : 30
}
{
"_id" : ObjectId("5defd370c79996355df1cb9d"),
"name" : "Chris Hayton",
"age" : 35
}
...
컬렉션의 도큐먼트 쿼리는 다음과 같이 할 수 있다.
> db.passengers.find().pretty()
{
"_id" : ObjectId("5defd370c79996355df1cb9b"),
"name" : "Max Schwarzmueller",
"age" : 29
}
{
"_id" : ObjectId("5defd370c79996355df1cb9c"),
"name" : "Manu Lorenz",
"age" : 30
}
만약 도큐먼트의 모든 프로퍼티가 아니라 특정 프로퍼티만을 쿼리하고 싶을 때는 다음과 같이 하면 된다. {name: 1} 객체의 1은 name 프로퍼티를 쿼리하라는 뜻이다. _id 프로퍼티는 디폴트로 무조건 쿼리된다.
> db.passengers.find({}, {name: 1}).pretty()
{
"_id" : ObjectId("5defd370c79996355df1cb9b"),
"name" : "Max Schwarzmueller"
}
{ "_id" : ObjectId("5defd370c79996355df1cb9c"), "name" : "Manu Lorenz" }
만약 _id도 빼고 name 프로퍼티만 보고 싶다면 다음과 같이 쿼리하면된다.
> db.passengers.find({}, {name: 1, _id:0}).pretty()
{ "name" : "Max Schwarzmueller" }
{ "name" : "Manu Lorenz" }
다음과 같이 passengers 컬렉션의 도큐먼트 하나에 hobbies 프로퍼티를 추가하여 string 배열을 준다.
> db.passengers.updateOne({name: "Albert Twostone"},
{$set : {hobbies: ["sports", "cooking"] }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.passengers.find({name: "Albert Twostone"}).pretty()
{
"_id" : ObjectId("5defd370c79996355df1cbae"),
"name" : "Albert Twostone",
"age" : 68,
"hobbies" : [
"sports",
"cooking"
]
}```
방금 추가한 hobbies 프로퍼티에 다음과 같이 접근할 수 있다.
> db.passengers.findOne({name: "Albert Twostone"}).hobbies
[ "sports", "cooking" ]
다음의 쿼리는 좀 신기한데.. hobbies 프로퍼티의 값은 배열이다. 하지만 아래와 같이 쿼리해도 몽고DB는 hobbies 프로퍼티의 값이 배열임을 알고 배열을 순회하여 sports를 찾는다. 해당 값이 배열 안에 있다면 그 도큐먼트를 리턴한다.
> db.passengers.find({hobbies: "sports"}).pretty()
{
"_id" : ObjectId("5defd370c79996355df1cbae"),
"name" : "Albert Twostone",
"age" : 68,
"hobbies" : [
"sports",
"cooking"
]
}
위 예시의 flightData 컬렉션에 다음과 같이 프로퍼티를 추가하였다.
> db.flightData.updateMany({}, {$set : {status:
{description: "on-time", lastUpdated: "1 hour ago", details: {responsible: "louieslee"}}}})
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
> db.flightData.find().pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true,
"status" : {
"description" : "on-time",
"lastUpdated" : "1 hour ago",
"details" : {
"responsible" : "louieslee"
}
}
}
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false,
"status" : {
"description" : "on-time",
"lastUpdated" : "1 hour ago",
"details" : {
"responsible" : "louieslee"
}
}
}
이 때 쿼리를 다음과 같이 할 수 있다. 쿼리할 때 "status.details.responsible" 에는 반드시 쌍따옴표를 붙여야 한다.
> db.flightData.find({"status.details.responsible" : "louieslee"}).pretty()
{
"_id" : ObjectId("5defbde2a71650b736445834"),
"departureAirport" : "MUC",
"arrivalAirport" : "SFO",
"aircraft" : "Airbus A380",
"distance" : 12000,
"intercontinental" : true,
"status" : {
"description" : "on-time",
"lastUpdated" : "1 hour ago",
"details" : {
"responsible" : "louieslee"
}
}
}
{
"_id" : ObjectId("5defbde2a71650b736445835"),
"departureAirport" : "LHR",
"arrivalAirport" : "TXL",
"aircraft" : "Airbus A320",
"distance" : 950,
"intercontinental" : false,
"status" : {
"description" : "on-time",
"lastUpdated" : "1 hour ago",
"details" : {
"responsible" : "louieslee"
}
}
}