Lsiron

MongoDB 쿼리연산자 본문

데이터베이스/MongoDB

MongoDB 쿼리연산자

Lsiron 2024. 7. 7. 06:25

쿼리?

쿼리(Query)는 데이터베이스에서 데이터를 검색, 삽입, 업데이트, 삭제하기 위해 사용되는 명령문이나 명령어 집합을 의미한다.

 

쿼리를 통해 사용자는 데이터베이스에 저장된 데이터를 조작하고 원하는 정보를 얻을 수 있다.

 

{"age": {"$gte" : 20, "$lte" : 40}, "height": {"gte" : 170}}

 

MongoDB 쿼리는 위 처럼 기본적으로 필드가 가장 바깥에 있고, 안쪽에 연산자가 들어간다.

 

점 표기법?

MongoDB에서 점 표기법(Dot Notation)은 중첩된 문서 또는 배열 내의 특정 필드를 쿼리하거나 업데이트할 때 사용되는 방법이다.

 

점 표기법을 사용하면 객체 내의 특정 필드에 접근할 수 있다.

 

점 표기법은 객체의 계층 구조를 나타내기 위해 점(.)을 사용한다.

 

예를 들어, 객체 person이 address 필드를 포함하고 있고, address 필드가 city 필드를 포함하고 있다면, person.address.city와 같이 점 표기법을 사용할 수 있다.

 

예시를 통해 알아보자.

 

db.people.insertMany([
  {
    name: "Alice",
    age: 25,
    address: {
      city: "New York",
      street: "5th Avenue",
      zip: "10001"
    },
    hobbies: ["reading", "traveling"]
  },
  {
    name: "Bob",
    age: 30,
    address: {
      city: "San Francisco",
      street: "Market Street",
      zip: "94105"
    },
    hobbies: ["sports", "cooking"]
  }
]);

 

1. 특정 필드 조회

중첩된 문서의 특정 필드를 조회할 때 점 표기법을 사용할 수 있다.

// address.city가 "New York"인 사람을 조회
db.people.find({ "address.city": "New York" });

 

2. 특정 필드 업데이트

 

중첩된 문서의 특정 필드를 업데이트할 때도 점 표기법을 사용할 수 있다.

// name이 "Alice"인 사람의 address.city를 "Boston"으로 업데이트
db.people.updateOne(
  { name: "Alice" },
  { $set: { "address.city": "Boston" } }
);

 

3. 배열 요소 조회

점 표기법을 사용하여 배열 내의 특정 요소를 조회할 수 있다.

// hobbies 배열에 "reading"이 포함된 사람을 조회
db.people.find({ "hobbies": "reading" });
// hobbies 배열의 0번 index에 "reading"이 있는 사람을 조회
db.people.find({ "hobbies.0": "reading" });

 

4. 배열 요소 업데이트

배열 내의 특정 요소를 업데이트할 때도 점 표기법을 사용할 수 있다.

// name이 "Alice"인 사람의 hobbies 배열에서 "reading"을 "biking"으로 업데이트
db.people.updateOne(
  { name: "Alice", "hobbies": "reading" },
  { $set: { "hobbies.$": "biking" } }
);
// name이 "Alice"인 사람의 hobbies 배열에서 0번 index에 있는 "reading"을 "biking"으로 업데이트
db.people.updateOne(
  { name: "Alice", "hobbies": "reading" },
  { $set: { "hobbies.0": "biking" } }
);

 

여기서 "hobbies.$" 을 쓰면 조건에 맞는 첫 번째 요소를 찾는다는 것 이고, "hobbies.0" 을 쓰면 특정 index를 지정한다는 뜻이다.

 

즉, "hobbies.$" 은 hobbies 요소중에 아무 자리에 reading이 있으면 첫 번째로 reading이 있는 index를 biking으로 바꿔달라는 뜻이고, ( 0번 index에 reading이 없고 다른 index에 있어도 적용 됨 )

"hobbies.0" 은 hobbies 요소 중에 0번 index 자리에 reading이 있으면 biking으로 바꿔달라는 뜻이다. 

(0번 index에 reading이 없으면 적용안됨)

 

다시말해서, $은 어느 인덱스에 있는지 모를 때 사용, 0은 어느 인덱스에 있는지 알 때 사용한다는 것.

 

비교 연산자?

MongoDB의 비교 연산자는 쿼리에서 데이터를 필터링할 때 조건을 지정하기 위해 사용된다.

 

종류에 대해 하나씩 예제를 통해서 알아보자.

( 단, 대소비교를 할 때 a,b,c,d 순으로 문자 비교 그리고 [ 0, 1, 2, 3 ] < [ 0, 1, 2, 4 ] 배열 비교도 가능하다. )

 

1. $eq (equal)

  • 설명: 지정된 값과 같은 값을 가진 문서를 찾는다.
  • 예시: { age: { $eq: 25 } }는 age 필드가 25인 문서를 찾는다.

2. $ne (not equal)

  • 설명: 지정된 값과 같지 않은 값을 가진 문서를 찾는다.
  • 예시: { age: { $ne: 25 } }는 age 필드가 25가 아닌 문서를 찾는다.

3. $gt (greater than)

  • 설명: 지정된 값보다 큰 값을 가진 문서를 찾는다.
  • 예시: { age: { $gt: 25 } }는 age 필드가 25보다 큰 문서를 찾는다.

4. $gte (greater than or equal)

  • 설명: 지정된 값보다 크거나 같은 값을 가진 문서를 찾는다.
  • 예시: { age: { $gte: 25 } }는 age 필드가 25보다 크거나 같은 문서를 찾는다.

5. $lt (less than)

  • 설명: 지정된 값보다 작은 값을 가진 문서를 찾는다.
  • 예시: { age: { $lt: 25 } }는 age 필드가 25보다 작은 문서를 찾는다.

6. $lte (less than or equal)

  • 설명: 지정된 값보다 작거나 같은 값을 가진 문서를 찾는다.
  • 예시: { age: { $lte: 25 } }는 age 필드가 25보다 작거나 같은 문서를 찾는다.

7. $in (in array)

  • 설명: 지정된 배열 내의 값 중 하나와 일치하는 값을 가진 문서를 찾는다.
  • 예시: { age: { $in: [25, 30, 35] } }는 age 필드가 25, 30 또는 35인 문서를 찾는다.

8. $ne (not equal)

  • 설명: 지정된 값과 같지 않은 값을 가진 문서를 찾는다.
  • 예시: { age: { $ne: 25 } }는 age 필드가 25가 아닌 문서를 찾는다.

9. $nin (not in array)

  • 설명: 지정된 배열 내의 값 중 어느 것도 일치하지 않는 값을 가진 문서를 찾는다.
  • 예시: { age: { $nin: [25, 30, 35] } }는 age 필드가 25, 30, 35가 아닌 문서를 찾는다.

10. $exists (field existence)

  • 설명: 필드가 존재하는지 여부를 기준으로 문서를 찾는다.
  • 예시: { age: { $exists: true } }는 age 필드가 존재하는 문서를 찾는다.

11. $type (type)

  • 설명: 필드의 데이터 타입을 기준으로 문서를 찾는다.
  • 예시: { age: { $type: "int" } }는 age 필드가 정수형인 문서를 찾는다.

 

논리 연산자?

MongoDB에서는 다양한 논리 연산자를 제공하여 쿼리를 구성하고 데이터를 필터링할 수 있다.

 

예시를 통해 알아보자.

 

예외적으로 $or , $and , $nor 세 개의 연산자는 가장 바깥에 쓰인다.

 

db.myCollection.insertMany([
  { name: "Alice", age: 25, city: "New York" },
  { name: "Bob", age: 30, city: "San Francisco" },
  { name: "Charlie", age: 35, city: "Los Angeles" },
  { name: "David", age: 40, city: "Chicago" },
  { name: "Eve", age: 28, city: "New York" }
]);

 

1. $or

$or 연산자는 주어진 조건 중 하나라도 true 일 때 true 이다.

db.myCollection.find({
  $or: [
    { age: { $gte: 30 } },
    { city: "New York" }
  ]
});

 

$or 쿼리는 "Bob", "Charlie", "David", "Alice", "Eve" 문서를 찾는다. ( age 나 city 조건 중, 하나라도 만족하는 값)

 

2. $and

$and 연산자는 주어진 모든 조건이 true 일 때 true 이다. ( 쓸 일이 많지 않음. )

db.myCollection.find({
  $and: [
    { age: { $gte: 30 } },
    { city: "New York" }
  ]
});

 

$and 쿼리는 조건에 맞는 문서가 없으므로 빈 결과를 반환한다. ( age 와 city 조건 중, 모두 만족하는 값)

 

3. $nor

$nor 연산자는 주어진 조건 중 하나라도 false 일 때 true 이다.

db.myCollection.find({
  $nor: [
    { age: { $gte: 30 } },
    { city: "New York" }
  ]
});

 

$nor 쿼리는 "Charlie"와 "David" 문서를 찾는다. ( age 와 city 조건 중, 하나라도 만족하지 않는 값)

 

4. 복합쿼리연산자

db.myCollection.find({
  $and: [
    { $or: [{ age: { $gte: 30 } }, { city: "New York" }] },
    { $nor: [{ name: "Alice" }, { name: "Bob" }] }
  ]
});

 

복합 쿼리는 "Eve" 문서를 찾는다. ( age와 city 조건 중 하나라도 만족 하면서 name 조건중 Alice 또는 Bob이 아닌 값)

 

5. $not

$not 연산자는 주어진 조건이 false 일 때 true 이다. 주로 단일 조건과 함께 사용된다.

db.collection.find({
  age: {
    $not: { $gt: 30 }
  }
});

 

$not 쿼리는 "Charlie", "David" 문서를 찾는다.

 

문자열 연산자? ( 보통 잘 안 쓰인다. )

MongoDB에서는 문자열 연산자를 사용하여 문자열 데이터를 검색, 필터링, 및 변환할 수 있다.

 

이들 연산자는 다양한 문자열 기반 조건을 처리할 수 있도록 도와준다.

 

예시를 통해 한번 알아보자.

 

예시로 삽입한 데이터

db.collection.insertMany([
  { _id: 1, name: "Alice Smith", age: 25, description: "Alice is a software developer" },
  { _id: 2, name: "Bob Johnson", age: 30, description: "Bob is a database administrator" },
  { _id: 3, name: "Charlie Brown", age: 35, description: "Charlie is a web developer" },
  { _id: 4, name: "David Wilson", age: 40, description: "David is a network engineer" },
  { _id: 5, name: "Eva Davis", age: 45, description: "Eva is a project manager" }
]);

 

1. $mod

$mod 연산자는 숫자 필드가 특정 값으로 나누어질 때 나머지가 지정된 값과 일치하는 문서를 선택한다.

{ field: { $mod: [divisor, remainder] } }
// 'age' 필드가 5로 나누었을 때 나머지가 0인 문서 찾기
db.collection.find({ age: { $mod: [5, 0] } });

 

결과

[
  { _id: 1, name: "Alice Smith", age: 25, description: "Alice is a software developer" },
  { _id: 2, name: "Bob Johnson", age: 30, description: "Bob is a database administrator" },
  { _id: 3, name: "Charlie Brown", age: 35, description: "Charlie is a web developer" },
  { _id: 5, name: "Eva Davis", age: 45, description: "Eva is a project manager" }
]

 

2. $regex

$regex 연산자는 정규 표현식을 사용하여 문자열 필드에서 패턴을 검색한다.

{ field: { $regex: /pattern/, $options: 'options' } }

 

options 값으로는 총 네 가지가 있다.

 

1) i : 대소문자 무시

2) m : 정규식에서 anchor(^) 를 사용할 때 값에 \n 이 있다면 무력화

3) x : 정규식 안에 있는 whitespace(띄어쓰기)를 모두 무시

4) s : dot (.) 사용 할 때 \n 을 포함해서 매치

// 'name' 필드가 'Smith'로 끝나는 문서 찾기 (대소문자 구분 없이)
db.collection.find({ name: { $regex: /Smith$/, $options: 'i' } });

 

결과

[
  { _id: 1, name: "Alice Smith", age: 25, description: "Alice is a software developer" }
]

 

3. $text ( 전문검색 연산자 = 검색엔진 )

$text 연산자는 텍스트 인덱스를 사용하여 텍스트 검색을 수행한다.

 

텍스트 인덱스는 특정 문자열 필드에서 텍스트 검색을 가능하게 한다.

( 주로 검색엔진에서 검색 내용을 입력했을때 긴 문자열에서 내가 입력한 검색 내용과 일치하는 값을 찾음 )

{ $text: { "$search": <string>, 
	"$language": <string>, "$caseSensitive": <boolean>, "$diacriticSensitive": <boolean> } 
    }

 

$search는 기본 값이고 , 이 외에 option 값으로는 $language , $caseSensitive, $diacriticSensitive 가 있다.

 

1) $search : 검색할 내용

2) $language : option. 검색하는 언어를 지정

3) $caseSensitive : option. False일 경우 대소문자 무시. False가 기본값

4) $diacriticSensitive : option. ğ와 g 같이 diacritical mark를 구분할지 선택. False가 기본 값.

 

문자열 인덱스는 컬렉션당 하나만 만들 수 있다.

( text 인덱스를 사용하기 위해서는 문자열 인덱스를 미리 설정 해 놓아야한다. )

 

문자열 인덱스 값은 아래와 같이 언어를 설정할 수 있는데 단, 한국어는 문자열 인덱스로 지원하지 않는다.(mongodb 한정)

 

사전에 텍스트 인덱스를 설정해준다.

db.collection.createIndex(
  { description: "text" },  //이 부분은 description 필드에 텍스트 인덱스를 설정.
  { default_language: "english" }
);

 

텍스트 인덱스를 설정해준 description field에서 coffee를 포함하는 document를 찾는다.

// 'description' 필드에서 'developer'를 포함하는 문서 찾기
db.collection.find({ $text: { $search: "developer" } });

 

결과

[
  { _id: 1, name: "Alice Smith", age: 25, description: "Alice is a software developer" },
  { _id: 3, name: "Charlie Brown", age: 35, description: "Charlie is a web developer" }
]

 

여러개 단어도 띄어쓰기를 통해 가능하다.

// 'description' 필드에서 'manage' 또는 'developer'를 포함하는 문서 찾기
db.collection.find({ $text: { $search: "software developer" } });

 

결과

[
  { _id: 1, name: "Alice Smith", age: 25, description: "Alice is a software developer" },
  { _id: 3, name: "Charlie Brown", age: 35, description: "Charlie is a web developer" },
  { _id: 5, name: "Eva Davis", age: 45, description: "Eva is a project manager" }
]

 

두 개 이상의 단어가 모두 포함된 document를 찾을 수도 있다.

// 'description' 필드에서 'software'와 'developer' 를 포함하는 문서 찾기
db.collection.find({ $text: { $search: "\"software developer\"" } });

 

 

결과

[
  { _id: 1, name: "Alice Smith", age: 25, description: "Alice is a software developer" }
]

 

4. $where

$where 연산자는 JavaScript 표현식을 사용하여 복잡한 조건을 지정할 수 있다.

 

$where 연산자는 성능에 영향을 미칠 수 있으므로 주의해서 사용해야 한다.

{ $where: "this.field > value" }
// 'age' 필드가 30보다 큰 문서 찾기
db.collection.find({ $where: "this.age > 30" });

 

결과

[
  { _id: 3, name: "Charlie Brown", age: 35, description: "Charlie is a web developer" },
  { _id: 4, name: "David Wilson", age: 40, description: "David is a network engineer" },
  { _id: 5, name: "Eva Davis", age: 45, description: "Eva is a project manager" }
]

 

5. 복합쿼리연산자

다양한 문자열 연산자를 사용하는 복합 쿼리 예시이다.

 

텍스트 인덱스를먼저 설정해준다.

db.collection.createIndex({ description: "text" });
db.collection.find({
  $and: [
    { age: { $mod: [5, 0] } },  // 'age' 필드가 5의 배수인 문서
    { name: { $regex: /^C/, $options: 'i' } },  // 'name' 필드가 'C'로 시작하는 문서 (대소문자 구분 없이)
    { $text: { $search: "developer" } },  // 텍스트 인덱스를 사용하여 'developer'를 포함하는 문서
    { $where: "this.age > 30" }  // 'age' 필드가 30보다 큰 문서
  ]
});

 

결과

[
  { _id: 3, name: "Charlie Brown", age: 35, description: "Charlie is a web developer" }
]

 

$mod는 주로 숫자 필드의 특정 패턴을 찾을 때 사용되고, $regex와 $text는 문자열 검색에서 자주 사용되며,

$where는 매우 복잡한 조건을 지정할 때 사용된다.

 

배열 연산자?

MongoDB에서 배열 연산자는 배열 필드에서 특정 조건을 만족하는 문서를 검색하거나 배열 내부의 요소를 조작하는 데 사용된다.

( MongoDB에서는 배열을 그저 값이 여러 개 인 것으로 인식한다. 단, 순서는 상관있다.

그냥 arr = [ "가", "나", "다", "라" ] 가 아니라 arr = "가" , arr = "나", arr = "다", arr = "라" 로 인식한다는 뜻)

 

1. $all

$all 연산자는 배열 필드가 지정된 모든 값을 포함하는 문서를 검색한다.

{ field: { $all: [value1, value2, ...] } }
// tags 필드가 'mongodb'와 'database' 모두를 포함하는 문서 찾기
db.collection.find({ tags: { $all: ["mongodb", "database"] } });

 

$all 을 안 쓰면 정확하게 mongodb와 database 오로지 두 요소만 있고 순서도 같은 값을 찾는다.

 

2. $elemMatch

$elemMatch 연산자는 배열 필드의 요소 중 하나가 지정된 조건을 모두 만족하는 문서를 검색한다.

 

즉, document 안의 document 들도 검색 할 수 있도록 해준다.

{ field: { $elemMatch: { condition1, condition2, ... } } }
// grades 배열의 요소 중 score가 80 이상이고 subject가 'math'인 문서 찾기
db.collection.find({ grades: { $elemMatch: { score: { $gte: 80 }, subject: "math" } } });

 

3. $size

$size 연산자는 배열 필드의 길이가 지정된 크기와 일치하는 문서를 검색한다.

{ field: { $size: size } }
// tags 배열의 크기가 3인 문서 찾기
db.collection.find({ tags: { $size: 3 } });