본문 바로가기
Infra/MongoDB

MongoDB - (3) - CRUD 실습

by Inventer 2023. 4. 19.

디비 확인

show dbs

 

컬렉션 확인

show collections

 

데이터 생성

db.movies.insertOne({"title" : "Stand by Me"})

 

데이터 확인

db.moives.find()

 

컬렉션 삭제

db.movies.drop()

 

다중 데이터 생성

db.movies.insertMany([{"title" : "Ghostbuster"}, {"title" : "E.T."}, {"title" : "Blade Runner"}]);

 

조회 결과

 

  • 여러 도큐먼트를 단일 컬렉션에 삽입하는데 매우 유용
  • 얼마까지 데이터를 입력할 수 있는가? - 책 필자는 48MB 라고 언급
  • 하지만 현재 실습환경 MongoDB 6.X 버전은 아래와 같음

 

MongoDB 6.X 버전의 임계 값

 

현재는 해당링크 에 100,000개의 임계값을 가진다고 나와있고,

해당 숫자는 한번에 넣을 수 있는 _id의 개수이다.

다만, 용량에 대한 언급은 별도로 존재하지 않았다.

 

20만 개 인 경우, mongoDB에서 자체적으로 대기열을 생성하여 데이터를 삽입한다.

하지만 단일 용량을 여러번 호출 하는 것이 대기열을 이용하는 것 보다 빠르다고 한다.

 

 

insert() 명령 미지원

 

3.0 이전 버전에서는 주로 insert로 사용했는데,

CRUD 작업을 명확하고 일관된다는 MongoDB의 미션에 따라

해당 insert() 대신 insertOne(), insertMany()를 사용한다.

 

 

단일 삭제

db.movies.deleteOne({"_id" : 4})

MongoDB의 필터 특성상, 위와 같은 연산식을 주더라도 여러 값이 등장할 수 있고

deleteOne은 그 중에서 가장 먼저 일치하는 데이터를 삭제한다.

 

 

다중 삭제

db.movies.deleteMany({"year" : 1984})

위 명령을 통해 year가 1984인 모든 도큐먼트를 삭제할 수 있다.

 

 

다중 삭제 2

db.movies.deleteMany({})

movies 컬렉션안에 모든 데이터가 날라간다.

 

 

 

remove() 미지원

마찬가지로 deleteOne()과 deleteMany()를 쓴다.

 

 

 

도큐먼트 갱신

갱신은 Atomic한 특성을 갖고 있어, 하나의 도큐먼트에 대해

update 요청이 2번 발생할 수 있다. 이 경우에는 맨 마지막 요청이 최후의 승리자가 된다.

 

 

 

데이터 치환

{
    _id: ObjectId("643ee230f5de6c870d83313d"),
    name: 'joe',
    friends: 32,
    enemies: 2
}

 

friends와 enemies 필드를 relationship 이라는 서브 도큐먼트로 옮길 것 이다.

var joe = db.user.findOne({"name" : "joe"});

joe.relationship = {"friends" : joe.friends, "enemies" : joe.enemies};

joe.username = joe.name;

delete joe.friends;

delete joe.enemies;

delete joe.name;

db.user.replaceOne({"name" : "joe"}, joe);

 

findOne()으로 확인해보면 아래와 같은 결과를 볼 수 있다.

{
  _id: ObjectId("643ee230f5de6c870d83313d"),
  relationship: { friends: 32, enemies: 2 },
  username: 'joe'
}

 

치환은 스키마 마이그레이션을 진행할 때 유용히 사용된다. 

 

 

데이터 갱신 - $inc

{
  _id: ObjectId("643ee4d4f5de6c870d83313f"),
  url: 'www.example.com',
  pageview: 52
}

 

페이지를 조회할 때마다 pageView를 1씩 증가하도록 구성하자.

db.analytics.updateOne({"url" : "www.example.com"}, {"$inc" : {"pageview" : 1}})

 

데이터 갱신 - $set

{
  _id: ObjectId("643ee677f5de6c870d833140"),
  name: 'joe',
  age: 30,
  sex: 'male',
  location: 'Wisconsin'
}

 

필드 값을 변경할 수 있는데, 해당 필드가 존재하지 않으면 생성하여 추가한다.

db.users.updateOne({"name":"joe"}, {"$set" : {"favorite book" : "War and Peace"}})

추가된 모습이다.

하지만 favorite book만 별도 문자열 처리가 된 것을 볼 수 있다.

해당 이유는 찾지 못하였다.

 

또한, 이를 찾고자 공식문서를 살피는 와중

$set 부분은 "" 더블 쿼테이션을 포함하지 않아도 된다는 것을 확인했다.

 

 

 

데이터 갱신 - $unset

db.users.updateOne({"name" : "joe"},
... {$unset : {"favorite book" : 1}})

(... 은 쉘 개행시 자동으로 생긴다.)

{
  _id: ObjectId("643ee677f5de6c870d833140"),
  name: 'joe',
  age: 30,
  sex: 'male',
  location: 'Wisconsin'
}

favorite book이 없어진 것을 볼 수 있다.

 

 

 

내장 데이터 갱신

db.blog.posts.updateOne({"author.name" : "joe"}, {$set : {"author.name" : "joe schmoe"}})

서브 도큐먼트로 author를 갖고

author는 name이라는 필드가 있는데

해당 name 필드를 "joe"에서 "joe schmoe"로 바꾼 것

 

 

제한자는 왜쓰는 것?

db.blog.posts.updateOne({"author.name" : "joe"}, {"author.name" : "joe schmoe"})

제한자 없이 명령을 치면 다큐먼트를 통으로 바꿔버린다고 한다.

하지만 현재는 제한자라는 개념을 통해 이를 보완했다고 한다.

 

배열 연산자 - $push

db.blog.posts.insertOne({"title" : "A blog post", "content" : "..."});

 

db.blog.posts.updateOne({"title" : "A blog post"}, {$push : {"comment" : {"name" : "joe", "email" : "joe@example.com", "content" : "nice post."}}})

 

코멘트가 배열형태로 추가된 것을 볼 수 있다.

{
  _id: ObjectId("643eeba9f5de6c870d833141"),
  title: 'A blog post',
  content: '...',
  comment: [ { name: 'joe', email: 'joe@example.com', content: 'nice post.' } ]
}

 

이외에도

  • $push - 한개의 값을 배열로 넣을 때 (
  • $each - 여러개의 배열에 값을 넣을 때
  • $slice - 배열의 개수 제한
  • $sort - 정렬할 수 있는 옵션
  • $addToSet - 중복을 피하며 저장되는 $push (있으면 저장안됨)
  • $ne - not 연산자처럼 동작 (예시 첨부

을 복합적으로 사용한다.

 

$ne

{
  _id: ObjectId("61ba667dfe687fce2f042420"),
  item: 'nuts',
  quantity: 30,
  carrier: { name: 'Shipit', fee: 3 }
},
{
  _id: ObjectId("61ba667dfe687fce2f042421"),
  item: 'bolts',
  quantity: 50,
  carrier: { name: 'Shipit', fee: 4 }
},
{
  _id: ObjectId("61ba667dfe687fce2f042422"),
  item: 'washers',
  quantity: 10,
  carrier: { name: 'Shipit', fee: 1 }
}

 

위 일때 아래와 같은 명령을 실행하면

db.inventory.updateMany( { "carrier.fee": { $ne: 1 } }, { $set: { "price": 9.99 } } )

 

{
  _id: ObjectId("61ba66e2fe687fce2f042423"),
  item: 'nuts',
  quantity: 30,
  carrier: { name: 'Shipit', fee: 3 },
  price: 9.99
},
{
  _id: ObjectId("61ba66e2fe687fce2f042424"),
  item: 'bolts',
  quantity: 50,
  carrier: { name: 'Shipit', fee: 4 },
  price: 9.99
},
{
  _id: ObjectId("61ba66e2fe687fce2f042425"),
  item: 'washers',
  quantity: 10,
  carrier: { name: 'Shipit', fee: 1 }
}

 

fee가 1인 도큐먼트에는 price 라는 필드가 추가되지 않은 것을 확인할 수 있다.

 

 

배열의 삭제 - $pop

db.students.insertOne( { _id: 1, scores: [ 8, 9, 10 ] } )

 

db.students.updateOne( { _id: 1 }, { $pop: { scores: -1 } } )

 

9와 10 값이 남는 것을 확인할 수 있고, STACK, QUEUE 처럼 사용할 수 있는 것이다.

-1은 배열의 처음부터 요소를 제거

1은 배열의 마지막부터 요소를 제거한다.

 

db.lists.updateOne({}, {$pull : {"todo" : "laundry"}})

 

위 명령은 pull 제한자를 사용하고, 조건과 일치하는 요소를 제거한다.

[1, 1, 2, 1] 에서 1을 pull 한다면 2만 남는다.

 

 

배열의 인덱스

"cart" : [
    {
      _id: ObjectId("61ba66e2fe687fce2f042423"),
      item: 'nuts',
      quantity: 30,
      carrier: { name: 'Shipit', fee: 3 },
      price: 9.99
    },
    {
      _id: ObjectId("61ba66e2fe687fce2f042424"),
      item: 'bolts',
      quantity: 50,
      carrier: { name: 'Shipit', fee: 4 },
      price: 9.99
    },
    {
      _id: ObjectId("61ba66e2fe687fce2f042425"),
      item: 'washers',
      quantity: 10,
      carrier: { name: 'Shipit', fee: 1 }
      price: 9.99
    }
]

 

cart 배열을 정의하고 bolts의 fee를 변경하면 아래와 같을 것

 

db.shop.updateOne({"cart" : cart_id},
... {$inc : {"cart.1.fee" : 10}})

 

위 그대로 명령을 치면 좋지만 여기서 cart_id를 모르기 때문에 다른 방법으로 데이터를 찾아와야한다.

db.shop.updateOne({"cart.item" : "bolts"},
... {$inc : {"cart.$.fee" : 10}})

여기서 bolts가 2개 이상이라면 처음 bolts만 변경된다.

 

 

배열 필터를 이용한 갱신

db.blog.updateOne(
	{"post" : post_id},
   	{$set : 
    	{ "comments.$[elem].hidden" : true } },
        {
        	arrayFilters: [ { "elem.votes" : { $lte: -5} } ]
        }
    )

위 명령은 arrayFilters를 도입하여, 반대표가 5표 이상인 댓글을 숨길 수 있다.

comments 배열에 각 요소에 대해 elem을 정의하고, elem의 votes가 -5 이하면 hidden 필드를 추가하여 true로 설정한다.

 

 

갱신입력 - (update + insert) updateOne(), updateMany()의 3번째 parameter

ad.analytics.updateOne({"url : "/blog"}, {"$inc" : {"pagevies" : 1}}, {"upsert" : true})

없으면 만들고, 있으면 업데이트한다.

 

 

다중 도큐먼트 갱신

db.users.insertMany([{birthday: "10/13/1978"},{birthday: "10/13/1978"},{birthday: "10/13/1978"}])
db.users.updateMany({"birthday" : "10/13/1978"}, {$set : {"gift" : "Happy"}})

 

그렇다. 맞다. 컬렉션 자체를 변경하거나 특정 사용자에게 새로운 정보를 추가할 때 쓰기 좋다.

 

 

참 긴 글이다.

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

MongoDB - (6) - 인덱싱2  (0) 2023.04.22
MongoDB - (5) - 인덱싱  (0) 2023.04.21
MongoDB - (4) - 쿼리  (0) 2023.04.20
MongoDB - (2) - CRUD와 데이터타입  (0) 2023.04.18
MongoDB - (1) - MongoDB 소개  (0) 2023.04.18

댓글