<데이터베이스> 관계형 vs. NoSQL 언제 무엇을 써야할까?

|
매번 아랑고DB에 관한 글만 다루다가, 오늘은 회사에서 간단하게 RDB vs. NoSQL에 대해 세미나를 진행한 내용이 있어 공유하려고 한다. 데이터베이스에 대해 공부하게 되면 정말 많이 찾아보게 되는 글인데, 사실 이론적인 부분보다는 내가 직접 쓰면서 느낀 경험적 측면에서 써보려고 한다.
여기서 읽는 내용들은 "참고"만 하자. 이론적으로 정교하게 서술한 글이 아니기 때문에 아 이런 성질이 있나 보구나 하고 가벼운 마음으로 읽기를 강력 추천함

1. RDB (Relational Database)

관계형 데이터베이스로 풀이되는 RDB는 말 그대로 관계형 모델을 기반으로 하는 데이터베이스이다. 이를 유지하고 관리하기 위한 시스템을 RDBMS (- Management System) 이라고 부른다.

그리고 이러한 RDBMS는 주로 SQL(Structured Query Lang)을 이용해 데이터를 조회하고, 관리하게 된다. 이 글에 DML, DDL, DCL 등에 대한 설명이 간결하게 잘 되어있는 것 같다.

관계형 데이터베이스의 특징은 아래와 같다.

  1. 2차원 데이터로 표현된다 (행/열)
  2. 상호관련성을 가진 테이블의 집합으로 구성된다
  3. 테이블 사이의 관계를 외래키로 나타낸다
  4. 스키마 변경이 어렵다
  5. Vertical Scalable 하지만, Horizontal scale은 어렵다
  6. 메인테넌스 코스트 / 사용 요금이 비싸다
  7. SQL을 사용해 데이터를 질의한다
  8. ACID 성질을 갖는다

여기서 몇가지만 자세히 다루고 넘어가자.

4 스키마 변경이 어렵다

RDB는 매우 정교한 초기 설계로 만들어진다. 테이블 사이에 서로 의존성이 있고, 쳇바퀴처럼 맞물려 돌기 때문에 데이터 타입을 바꾼다든지 새로운 열을 추가한다든지 하는 작업은 실제 프로덕션 환경에서 사실상 불가능하다.

보통 기존 테이블을 복제해서 거기에 수정을 가한 뒤, 기존 테이블과 교체하는 방식을 택한다.

5 스케일링

일반적으로 Vertical Scaling은 하드웨어 스펙의 확장을 의미하고, Horizontal Scaling은 양적 확장을 의미한다.

RDB가 수직 확장이 더 용이하고 수평 확장이 어려운 이유는, 데이터가 여러 테이블에 의존해있기 때문이다.

데이터가 서버에 분산될 경우 이를 중간에서 잘 중재해주는 역할이 중요해지는데, 그럴 바에는 그냥 좋은 서버를 하나 사서 분산 처리에 대한 신경을 쓰지 않아도 되기 때문이다.

8 ACID

ACID(원자성 Atomicity, 일관성 Consistency, 고립성 Isolation, 지속성 Durability)는 데이터베이스 트랜잭션의 성질을 나타낸다.

자세한 내용은 여기 읽어보자. 나중에 기회되면 공부해서 제대로 다루겠음

2. NoSQL Database

이러한 RDB에 대응되는 녀석이 NoSQL 데이터베이스다. Non-SQL 이라고도 하고, Not only SQL 의 약자라고도 한다.

아무튼 이들은 관계형이 아닌 데이터 모델을 총칭하고, 도큐먼트 모델 / 키-값 모델 / 그래프 모델 / 와이드 컬럼 모델 등 다양한 데이터 모델이 있다.

NoSQL 데이터베이스의 특징은 아래와 같다.

  1. 다양한 방식으로 데이터를 표현한다
  2. 테이블(혹은 컬렉션 혹은 또 다른 명칭) 사이에 딱히 명시된 제약이나 규칙이 없다
  3. 스키마가 고정적이지 않고, 매우 유연하다
  4. Horizontal Scale이 쉽다
  5. 코스트 저렴 / 오픈소스도 많다
  6. 연산이 빠르고 빅데이터 & 실시간 연산에 적합하다

1 다양한 방식으로 데이터를 표현한다

NoSQL 방식의 데이터 모델의 예시를 살펴보면, 아래 그림과 같이 표현할 수 있다. 출처 요기

NoSQL Data Models

  • 도큐먼트 모델은 레코드 하나를 오브젝트(도큐먼트) 형식으로 표현한다. 자유로운 스키마 구조를 가지며 구조가 확정되지 않은 데이터를 밀어넣고, 자유롭게 작업하기 좋다. 몽고DB나 아랑고DB가 대표적인 예시이다.
  • 그래프 모델은 데이터를 버텍스와 엣지로 그래프에 표현하는 방식이다. 데이터 사이의 유기적인 관계를 표현하기에 적합하다. 대표적인 예로 Neo4j와 ArangoDB, Gremlin 등이 있다. 아랑고DB에 대해서는 현재 블로그에서 다루고 있으니 궁금하면 여기
  • 키/값 모델은 하나의 키에 값을 맵핑하는 해시 구조의 데이터 모델이다. 빠르게 데이터에 접근할 수 있는 장점이 있다. 대표적인 예로 redis가 있음
  • 와이드 컬럼 모델은 테이블 형태를 취하지만 행마다 갖는 컬럼의 형태가 고정되어 있지 않은 데이터 모델이다. 언뜻 와닿지 않는 내용인데, 이 글을 참고하길 바란다.

3. RDB vs. NoSQL

그럼 이제 둘을 비교해보자.

  • RDB는 관계형으로 데이터를 저장하지만, NoSQL은 그렇지 않다.
  • RDB는 스키마가 정적이지만, NoSQL은 유연한 스키마 구조를 갖는다.
  • RDB는 수직 확장이 용이하고, NoSQL은 수평 확장이 용이하다. (즉, RDB는 서버 용량을 늘리는 게 쉽고, NoSQL은 서버를 여러 대 늘리는 게 쉽다)
  • 위와 관련해서, RDB는 확장 시 다운타임이 있을 수 있지만, NoSQL은 거의 없다.
  • RDB는 복잡한 쿼리와 Join 연산이 가능하다. NoSQL은 구조화된 쿼리 언어가 없는 경우도 많고, 일반적으로 Join이 없다.
  • RDB는 OLTP에 적합하고, NoSQL은 OLAP에 적합하다. (즉, RDB는 트랜잭션 처리에 용이하고, NoSQL은 분석 처리에 용이하다)

4. 언제 어떤 데이터베이스를 사용할까?

3번과 비슷한 이야기지만, 실제 내가 사용하고 있는 환경에 빗대어 내 경험을 토대로 이야기해보겠다.

RDB - MySQL

RDB 중 하나인 MySQL은 보통 관계형으로 잘 정리될 수 있는 고객 데이터나 비즈니스 데이터, 결제 데이터 등을 다룰 때 사용한다.

  • 테이블마다 연관되는 키가 잘 드러나기 때문에 관계형으로 표현하는게 매우 효율적이다 (JOIN 연산!)
  • 트랜잭션을 통해 OLTP의 역할을 해야할 때
  • 트랜잭션의 ACID가 보장되어야 할 때 (Dirty read..)

NoSQL - MongoDB

몽고DB는 아주 유용한 녀석이다. 도큐먼트 모델이기 때문에 넣는 데이터의 스키마에 구애받을 필요가 없다.

  • 중간 분석 데이터를 편하게 밀어넣어 두고, 꺼내쓰기가 편리함
  • 단, SQL에서는 간단한 쿼리문이 몽고DB의 언어로 바뀌면 수행하기가 어렵기 때문에 애초에 데이터를 잘 가공해서 넣어둠
  • 최종적으로 사용할 데이터를 넣어두는 용도로도 많이 씀
  • 한마디로 막쓰기 정말 좋음, 심지어 안정적이다

NoSQL - redis

redis는 인메모리 키-값 모델이다. 말그대로 인-메모리이기 때문에 데이터 접근 & 대기시간이 매우 매우 짧다. 따라서 주로 데이터 캐시, 메시지 브로커 & 대기열로 쓰임

  • 동시에 대량의 트래픽을 처리하는 웹서비스에서 데이터를 캐시하는 중간 DB 역할로 많이 씀 (1만명이 MySQL 칠 트래픽을 redis가 값을 가져와서 막아준다고 생각하면 됨)
  • celery, airflow 등의 분산 처리 프레임워크에서 메시지 브로커로 많이 쓴다. (‘분산’ 처리이기 때문에 워커나 태스크 사이의 데이터를 주고받을 때 중개자가 필요함. 그 역할을 수행한다)

NoSQL - ArangoDB

아랑고DB는 멀티 모델 데이터베이스이다. 즉, 도큐먼트 모델도 지원하지만 그래프 모델도 지원한다.

  • 그래프 모델은 데이터 분석의 깊이가 깊어질수록 그 진가를 발휘한다고 생각한다.
  • ‘내 친구의 친구가 좋아하는 영화의 감독이 만든 다른 영화들의 주연들의 목록’을 기존 데이터베이스로 뽑는다고 생각해보자. 아찔하다.
  • 그래프DB는 간단한 횡단(traversal) 쿼리로 이를 구현할 수 있다.
  • 물론, 초기 그래프 구조 설계가 효율에 많은 영향을 미치며, 쿼리 튜닝도 중요함

5. 마치며

이렇게 간단하게 RDB와 NoSQL 데이터베이스를 비교하는 시간을 가졌다. 각각을 심층적으로 모두 다루긴 어렵겠지만, 각 DB를 사용하며 겪었던 여러 이슈들이나 알면 좋은 개념들은 지속적으로 업데이트 할 생각이다!

<아랑고DB> 6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE

|
데이터를 조작하는 AQL에 대해 공부하는 마지막 시간이다. REPLACE, UPSERT, REMOVE 등의 연산을 소개하고, 이때까지 AQL1~3 시리즈에서 배운 연산들을 정리하는 시간을 가지려고 한다.

1. REPLACE, UPSERT, REMOVE

REPLACE

UPDATE_key값이 일치하는 도큐먼트의 일부분을 바꾸었다면 REPLACE는 도큐먼트 자체를 바꾸는 연산을 한다.

UPDATE와 마찬가지로 시스템 필드인 `_id`, `_key`, `_rev`는 업데이트가 불가능하고, 엣지 컬렉션의 `_from`과 `_to`는 업데이트가 가능하다.

문법도 UPDATE와 동일하다. _key값이 포함된 도큐먼트를 전달해 한 번에 바꾸거나, _key값을 먼저 지정해주고, 이후에 도큐먼트를 전달하는 방식이다.

  1. REPLACE document IN collection
  2. REPLACE keyExpression WITH document IN collection

나머지 방식이나 Options 같은 경우도 UPDATE와 동일하기 때문에 건너뛴다. UPDATE에 관한 이전 글은 여기를 보면 됨

REMOVE

UPSERT 전에 쉬운 REMOVE 먼저 잠깐 살펴본다. 이름 그대로 도큐먼트를 제거하는 연산이며, keyExpression 을 사용한다. 즉, _key값을 기준으로 제거할 도큐먼트를 찾는다.

아래 문법처럼 사용하며, 간단하니까 얘도 생략한다.

  • REMOVE keyExpression IN collection

UPSERT

마지막으로 볼 연산자는 UPSERT라는 재미있는 연산이다. UPSERTUPDATEINSERT의 합성어로써 아래 두 가지 상황에 맞는 동작을 한다.

  • 데이터가 없으면 INSERT를 한다.
  • 데이터가 이미 존재하면 UPDATEREPLACE를 한다.

문법은 아래 두 가지 형태를 취한다.

  1. UPSERT searchExpression INSERT insertExpression UPDATE updateExpression IN collection
  2. UPSERT searchExpression INSERT insertExpression REPLACE updateExpression IN collection

여기서 주목해야할 점은 keyExpression 을 통해 _key를 기준으로하는 UPDATE 연산과 달리, UPSERTsearchExpression 을 기준으로 삼는다는 점이다. 이는 아래 세 가지 포인트를 갖는다.

  • _key값에 국한되지 않고 여러 필드로 조건을 걸 수 있다!
  • 동시에, _key는 고유했지만 필드는 고유하지 않을 수 있기에 여러 도큐먼트가 UPSERT의 대상이 될 수 있다
  • 그리고 그들 중 하나가 임의로 대상 지정된다
따라서 UPSERT의 lookup 과정에서 성능을 높이기 위해서는 반드시 lookup 대상의 필드들에 인덱스를 걸어주어야 한다. 그렇지 않으면 UPSERT의 성능은 현저하게 떨어진다.

이제 실제 연산을 실행해보자. 컬렉션에 관한 설정은 여기에서 CREATE 부분의 노란 박스를 보면 됨.

titles 컬렉션의 인덱스 설정은 그대로 둔 채, 데이터만 truncate 해주자.

//  컬렉션에 해리포터 시리즈를 7 넣어준다
FOR i in 1..7
  INSERT {
      'title': CONCAT('Harry Potter ', i), 
      'series': 'Harry Potter'
  } INTO titles
// 이제 해리포터 시리즈에 UPSERT 연산을 해보자
// 임의의 해리포터 도큐먼트( 7)  하나에 `series_num`이라는 필드가 추가되었다
UPSERT {'series': 'Harry Potter'}
  INSERT {'meaning': 'less'}
  UPDATE {'series_num': 1}
INTO titles
// 이번에는 없는 도큐먼트에 대해 UPSERT 해보자
UPSERT {'series': 'Avengers'}
  INSERT {'meaning': 'less'}
  UPDATE {'series_num': 1}
INTO titles

위 연산은 대상 도큐먼트가 없기 때문에 INSERT 연산을 수행하게 되어 새로운 도큐먼트를 만든다.

그럼 위 연산을 한 번 더 실행하면 어떻게 될까? 지금 생각으로는 또다른 {‘meaning’: ‘less’} 도큐먼트를 삽입할 것 같다.

직접 해보자

// 원모어타임
UPSERT {'series': 'Avengers'}
  INSERT {'meaning': 'less'}
  UPDATE {'series_num': 1}
INTO titles

title 필드에 고유 인덱스 설정을 잘 주었다면, 위 AQL은 오류를 일으킨다. title은 반드시 unique해야 하는데, {‘meaning’: ‘less’} 도큐먼트는 ‘title’을 null값으로 가지고 있는 도큐먼트이기 때문이다.

따라서 해당 도큐먼트를 2개 넣으면 null이 두 개가 되어 고유값 에러를 일으킨다. 재미있는 발견이다.

UPSERT 연산에서 lookup 파트와 insert/update/replace 파트는 아토믹하지 않게 실행이 된다. 즉, 동시에 여러 UPSERT 쿼리를 쳤을 경우 lookup 과정에서 도큐먼트가 존재하지 않다고 인식하고 모든 쿼리가 INSERT 연산을 수행할 수 있다는 것이다. 따라서 찾으려는 lookup 키 (searchExpression)에는 unique constraint을 주는 것이 낫다. 이는 몽고DB의 UPSERT에서도 동일하게 발생하는 문제이다. 잘 알아두자.
UPSERT를 대량으로 하게되면 intermediate commit을 하게 되어 전체 연산이 끝나기 전에 중간 연산을 write하게 된다!

UPSERT는 매우 유용한 기능이지만, 위와 같이 사용에 주의해야할 점들이 존재한다. 또한, UPSERT는 아랑고DB에서 HTTP API를 제공해주지 않는 연산 중 하나이다. 나머지 연산들은 모두 API가 열려있지만, UPSERT만은 AQL을 통해서만 수행이 가능하다.

이는 많은 아랑고 유저들이 개선을 원하는 부분 중 하나인데 아직까지 해결되고 있지는 않다. 깃헙 이슈 참고.

2. CRUD Best Practice

AQL 기초 1~3편을 통해 기초 연산들을 배워보았다. 그럼 언제 어느 연산을 사용해야 할까?

데이터를 넣고, 업데이트하는 몇가지 상황을 생각해보자.

정말 많은 데이터를 관리해야 한다면, HTTP API를 통해 직접 ArangoDB에 데이터를 보내는 게 가장 빠른 방법이다. 다른 언어의 라이브러리를 통해서 하면 편리하긴 하지만, 효율이 최우선이라면 HTTP API를 살펴보자.

데이터를 넣을건데, (영화명, 영화시리즈번호)의 쌍이 고유했으면 좋겠다.

이 경우는 이때까지 예제로 살펴봤던 것과 약간 다르게, 여러 개의 필드쌍이 하나의 _key를 구성해야 하는 경우이다.

여러 방법이 있는데, 1) index에 컴마로 분리하여 두 개 필드를 넣어 unique 제한을 주거나 2) 애초에 _key값을 영화명_영화시리즈번호로 만들어 넣는 것이다.

나는 후자의 방법이 가장 빠른 시스템 인덱스인 _key를 사용하고, 별도의 추가 인덱스를 생성하지 않기 때문에 선호하는 편이다.

이렇게 인덱스를 설정한 후, INSERTignoreErrors:true, overWrite:ignore 를 줘서 빠르게 밀어넣는다.

시간별 통계 데이터를 넣을건데, 10분마다 업데이트되는 값을 반영하고싶다.

예를 들어, 시간별 블로그 이용자 통계를 만들고 싶다고 가정해보자. 이 통계의 업데이트 주기가 10분이라면 15시 데이터에 대해, 15시 10분에 측정한 값과 15시 20분에 측정한 값은 다를 것이다. (10분동안 사람들이 더 들어왔을거니까)

그럼 나는 {시간 : ‘2021-11-14-15’} 인 도큐먼트가 없으면 넣어주고, 있으면 업데이트를 하고 싶다.

없으면 넣어주고 있으면 업데이트하는 편리한 연산을 우리는 방금 배웠다. 이런 경우에 UPSERT - REPLACE를 쓰면 된다. 1번과 마찬가지로 시간값을 _key로 만들어주는게 쿼리 튜닝에 좋다.

UPSERT - UPDATE가 아니고 REPLACE를 썼을까? 단순히 통계값이 방문자수 하나이면 UPDATE가 간편하지만, 통계값이 무수히 많다면 REPLACE 하나로 전체 도큐먼트를 통째로 교체하는게 낫다.

아니면, 앞서 배운 INSERT의 OPTIONS가 기억나는가? 얘를 써도 좋다.

두 연산이 완전히 동일한 것인지에 대한 의문이 드는데, 이 부분은 Arango Community에 질문 후 답변이 오면 여기에 수정해두도록 하겠다.

===

2021년 11월 24일 추가) 까먹고 있다가 오늘 질문을 해서 관련 답변을 받았다. 결론은 여기에 매우 자세하게 나와있다.

핵심만 말하면, 아래의 경우일 때, INSERTUPSERT는 거의 동일한 연산이라고 볼 수 있다.

  • _key를 사용하여 탐색할 경우
  • 그리고 RETURN OLD와 같이 기존 데이터를 참조하는 표현을 쓰지 않는 경우

그럼에도, INSERT가 훨씬 효율이 좋다. 그리고 REST API를 사용하면 효율이 더더욱 좋다.

===

3. 어디까지 왔나

이제 기초적인 CRUD에 관한 AQL은 다 다룬 것 같다. 나중에 기회가되면 부록처럼 각 연산의 원리와 성능에 대해 추가적으로 적어보려고 한다.

다음 시간부터는 AQL의 꽃인 그래프 관련 연산을 살펴본다. 그래프 횡단부터 시작하여, 각 횡단 단계에서 실행할 수 있는 여러가지 연산들을 배워보자.

아~주 재미있는 시간이 될 것이다. 기대해도 좋다 :)

  1. 아랑고DB란? 왜 쓰는가?
  2. 아랑고DB 세팅하기 on Ubuntu
  3. 아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. AQL(Arango Query Lang) 배워보기 1
  5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. (지금 보고있는 글) AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)

<아랑고DB> 5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE

|
저번 시간에 이어서 아랑고DB의 AQL을 활용해 데이터를 다루는 방법을 배워보자. RETURN, UPDATE 등의 문법을 살펴볼 것임

1. RETURN, UPDATE

RETURN

지난 시간에는 데이터를 삽입하는 INSERT 연산을 배워보았다. 이제 데이터를 넣었으니 꺼내보자. AQL에서 데이터를 꺼내는 방법은 RETURN 연산을 통해서이다.

아래 AQL 예시에서, RETURN 에서 하나의 AQL이 끝나기 때문에 한 줄씩 실행해야 한다!!
// 무언가를 Return 하려면 아래처럼 쓴다
RETURN _expression_

// 예를들어, 문자열 hello world 리턴한다
RETURN 'hello world'

위 문자열을 리턴했는데 이상한 점이 있다. 단순히 ‘hello world’가 아니라 [‘hello world’]로 배열이 리턴되었기 때문이다. 이는 AQL이 쿼리의 결과값을 항상 배열로 리턴하기 때문이다. 궁금하면 여기 읽어보셈

이제 컬렉션의 도큐먼트에 접근해보자. 컬렉션은 도큐먼트의 배열로 취급되기 때문에, FOR 반복문을 통해 접근한다.

// 도큐먼트의 _id 값을 조회하여 직접 불러온다. 가장 빠르게 데이터에 접근하는 방법이다.
RETURN DOCUMENT('titles/178829')

// 컬렉션의 데이터를 조회하기
// 프로그래밍 언어의 반복문처럼 앞의 title 사용자가 지정하는 임의의 변수다
FOR title in titles
    RETURN title

//  AQL 똑같음
FOR abcabc in titles
    RETURN abcabc

이번에는 전체 도큐먼트가 아닌, 영화의 제목만을 리턴해보자 RETURN DISTINCT의 쓰임도 알아두자

// 영화의 제목이 title이라는 이름을 가지고 있어서, 혼동을 줄이기 위해 반복 변수 이름을 movie 했음
// 이래서 네이밍이 중요하다
FOR movie in titles
    RETURN movie.title
  
// 지금은 titles 컬렉션의 title 필드에 unique constraint 있기 때문에 중복되는 타이틀이 없다
// 만약 제약 조건이 없는데 중복을 거르고 리턴하고 싶다면?
FOR movie in titles
    RETURN DISTINCT movie.title

이번에는 연산자(Operator)를 사용해보자.

조건을 걸 때는 FILTER와 함께 사용한다.

// 어벤져스의 50번째 이상 시리즈만 보고싶다면?
FOR movie in titles
    FILTER movie.title >= 'Avengers 50'
    RETURN movie
 
// 어벤져스 100번째 시리즈를 리턴하고 싶다면?
FOR movie in titles
    FILTER movie.title == 'Avengers 100'
    RETURN movie

위 예시에서 >= ‘Avengers 50’ 와 같은 표현은 사실 위험하다. 앞의 ‘Avengers’가 무조건 똑같이 위치한다고 가정하고, 숫자로만 크기를 비교하는 것이기 때문 ‘The Avengers 1’ 처럼 The가 붙으면 당연히 얘가 ‘Avengers 50’보다 더 커진다. 예시를 위해 대충 한거니까 실제 사용할 때는 주의하자.

마지막으로 한 가지 재미있는 예시 하나만 보고가자. 각각의 도큐먼트는 서로 다른 필드를 가지고 있다. 만약 도큐먼트에 없는 필드로 조건을 걸면 어떻게 될까?

// 시청 연령이 19 이하인 영화만 리턴하고 싶다
// 그런데 age 라는 필드는 만든 적도 없다
FOR movie in titles
    FILTER movie.age <= 19
    RETURN movie

위 쿼리를 날리면 놀랍게도 컬렉션의 모든 도큐먼트가 리턴된다. 이는 존재하지 않는 데이터를 참조하게 되면, 해당 필드는 null로 취급되는데, null은 데이터 타입 사이에서 순서상 가장 작기 때문이다. 따라서 존재하지 않는 movie.agenull이고, 이는 19보다 작으므로 True가 되어 모든 데이터가 리턴된다.

원래 의도에 맞게 다시 AQL을 구성해보면, 아래처럼 하면 된다.

// HAS 연산은 해당 오브젝트에 age라는 필드가 있는지 확인한다
FOR movie in titles
    FILTER HAS(movie, 'age')
    FILTER movie.age <= 19
    RETURN movie    

UPDATE

UPDATE는 컬렉션의 도큐먼트를 부분적으로 업데이트하는 연산이다.

주어진 키로 도큐먼트를 찾아내어, 특정 필드를 업데이트한다.

시스템 필드인 `_id`, `_key`, `_rev`는 업데이트가 불가능하고, 엣지 컬렉션의 `_from`과 `_to`는 업데이트가 가능하다는 점을 알아두자.

업데이트는 아래의 두 가지 문법 중 아무거나 사용해도 된다.

  1. UPDATE document IN collection
  2. UPDATE keyExpression WITH document IN collection
// 첫번째 방식. 오브젝트 내에 _key값을 주면, 컬렉션 내의 해당 _key값을 매칭하여 나머지 값들을 업데이트한다.
// 아래 예시에서 _key 178833 도큐먼트를 찾아서, title Avengers 2001 업데이트한다.
UPDATE {"_key": "178833", "title" : "Avengers 2001"} IN titles

// 두번째 방식. 위와 같은 결과를 만든다
UPDATE {"_key" : "178833"} WITH {"title" : "Avengers 2020"} IN titles
UPDATE는 keyExpression을 통해 특정 _key를 기준으로 업데이트하기 때문에 다중 도큐먼트에 대한 업데이트를 신경 쓸 필요가 없다. 즉, _key는 항상 unique하기 때문에 UPDATE 연산도 고유하다.

두 방식은 언제 어떻게 사용하는게 편할까? 아래와 같은 상황에서는 두번째 방식이 더 편할 것이다.

상황 : Avengers 2020 이라는 제목을 가진 영화를 Avengers 3030으로 업데이트하고싶다.

// 첫번째 방식
// new_doc 이라는 오브젝트를 새로 만들어주고, UPDATE 구문을 친다
FOR movie in titles
    FILTER movie.title == 'Avengers 2020'
    LET new_doc = {'_key' : movie._key, 'title' : 'Avengers 3030'}
    UPDATE new_doc IN titles
  
// 두번째 방식
// 바로 UPDATE 구문을 친다
FOR movie in titles
    FILTER movie.title == 'Avengers 2020'
    UPDATE movie WITH {'title' : 'Avengers 3030'} IN titles

필요할 때 상황에 맞게 쓰면 될 듯

또한 UPDATE 구문은 업데이트 하기 전 도큐먼트와 하고 난 이후의 도큐먼트를 반환할 수 있다.

UPDATE document IN collection options RETURN OLD
UPDATE document IN collection options RETURN NEW
UPDATE keyExpression WITH document IN collection options RETURN OLD
UPDATE keyExpression WITH document IN collection options RETURN NEW

UPDATEINSERT와 마찬가지로 여러가지 옵션을 줄 수 있다.

  • ignoreErrors : 업데이트에서 발생하는 에러 (unique key constraint violation이나 non-existing document) 무시
  • keepNull : null로 필드 업데이트 할 수 있게 해줌. 디폴트로는 null이 저장이 안 된다. (필드가 안생김)
  • mergeObjects : 오브젝트 필드의 경우, 업데이트 오브젝트에 명시되지 않은 필드들을 merge해서 그대로 둘 지, 아니면 없앨지를 결정한다.

마지막 옵션만 조금 더 설명하자면, {‘target’ : {‘a’ : 1, ‘b’: 2}}인 도큐먼트에서 {‘target’ : {‘a’: 3}}으로 업데이트 하는 상황을 가정하면,

  • mergeObjects가 True인 디폴트의 경우, {‘target’ : {‘a’:3, ‘b’: 2}}가 된다
  • False로 지정하면, 업데이트 대상이 아닌 필드는 날아간다. {‘target’ : {‘a’:3}}이 된다.

2. 어디까지 왔나

2편까지 기초 연산을 끝내려고 했는데, 생각보다 길어지고 있다. 빠르게 대충 치고 넘어가려다가 아랑고DB에 관한 손쉬운 한글 튜토리얼을 만들겠다는 다짐을 되살렸다. 조금 내용이 많아지더라도 각 부분에서 다룰 수 있는 부분은 다 다루려고 한다.
3편에서 기초가 끝날지 모르겠지만, 다음 글에서는 REPLACE / UPSERT / REMOVE 내용을 다룬다!

  1. 아랑고DB란? 왜 쓰는가?
  2. 아랑고DB 세팅하기 on Ubuntu
  3. 아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. AQL(Arango Query Lang) 배워보기 1
  5. (지금 보고있는 글) AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)

<아랑고DB> 4. AQL(Arango Query Lang) 배워보기 1 - WebUI / INSERT

|
이번 글에서는 아랑고DB의 아주 간편한 웹 인터페이스로 시작한다. 웹 UI를 간단히 보고, 아랑고DB의 데이터 타입과 데이터를 삽입하는 방법, 그리고 다양한 설정값에 대해 알아본다.

1. 들어가기에 앞서

여기서는 아랑고DB에서 제공하는 교육 자료를 사용할 예정이기 때문에 영어를 읽는데 무리가 없다면 해당 자료만 보고 이 글은 패스해도 된다. 자료는 아랑고DB의 공식 튜토리얼 자료 중 하나를 발췌했고, 여기를 눌러 다운받을 수 있다. 더 많은 자료는 여기에서 확인하자.

2. Web UI 사용해보기

AQL을 사용하고 데이터를 쉽게 조회할 수 있는 가장 간단한 방법은 아랑고DB를 설치하면 자동으로 설치되는 Web UI에 접속하는 것이다. 아무 브라우저나 열어서 아랑고DB가 설치된 서버 주소의 8529 포트로 접속할 수 있으며, 잘 안 되면 세팅에 대해 적었던 글에서 Web UI 관련 부분을 읽어보자.

나는 AWS EC2를 사용중이기 때문에, http://ec2-xxx-xxx-xxx-xxx.ap-northeast-2.compute.amazonaws.com:8529 주소로 접속했다. 성공적으로 접속했다면 귀여운 아보카도 그림과 함께 로그인 화면이 뜬다. 따로 사용자를 생성해주지 않았다면 계정은 root, 비밀번호는 초기 설정한 비밀번호를 입력하자.

입력하면 데이터베이스를 선택하는 드롭다운이 생기는데, 일단은 그대로 _system 데이터베이스로 접속한다. 관리자 데이터베이스이기 때문에 서버 상태에 대한 대시보드와 함께 데이터베이스 목록(Databases), 레플리케이션, 서버 Log, 유저 권한을 설정할 수 있는 메뉴 등이 나타난다.

당장 여기서는 볼 게 없기 때문에, 우측 상단의 DB:_SYSTEM 옆의 새로고침 버튼 같은 걸 눌러서 데이터베이스 선택 화면으로 다시 나간 뒤, 저번에 만들었던 movies 데이터베이스에 접속해보자. 아까와는 메뉴 구성이 다른 것을 볼 수 있다.

Collections 메뉴로 들어가면 지난번에 만들었던 titles 컬렉션이 있는데, 눌러보면 도큐먼트들의 목록이 쭉 나오는 것을 알 수 있다. 탑바에 있는 Indexes, Info, Settings 들은 컬렉션 수준의 설정을 의미한다. 나중에 인덱스가 정상적으로 만들어졌는지 확인하기 위해 종종 사용한다.

그리고 대망의 Queries 메뉴로 들어가보자. 여기는 AQL을 입력하고 바로 실행시킬 수 있는 환경을 제공해준다. 비록 에디터의 기능이 거의 없다시피해서 수정이 편리하지는 않지만, 쿼리의 실행 관련 Execution Plan과 실행 결과를 곧바로 볼 수 있어 편리하다.

저번 글에서 잠깐 맛만 봤던 AQL을 테스트해보자. titles 컬렉션의 모든 도큐먼트를 반환하는 쿼리다.

FOR title IN titles
    RETURN title

3. AQL(Arangu Query Language) 파헤쳐보기

이제 본격적으로 AQL에 대해 배워보려고 한다. AQL의 문서에 따르면, AQL은 선언형 언어로써 어떤 결과를 조회 할지를 표현하는 언어이다. 목적성에 있어서 SQL과 유사하지만, 큰 차이점이 있다면 AQL은 DML(Data Manipulation Lang)이지, DDL(Data Definition Lang)이나 DCL(Data Control Lang)이 아니라는 점이다. 즉, 데이터를 읽고 수정은 하지만, 데이터베이스를 생성하거나 인덱스를 생성하거나 하는 연산은 지원하지 않는다. (아랑고DB를 의미하는 게 아닌, AQL에서 지원하지 않는다는 것!) 즉 SQL에서는 CREATE DATABASE ..., CREATE TABLE ...과 같은 DDL 구문이 있지만 AQL에는 없다는 것임!

기본 연산을 배우기 전에, 아랑고DB의 데이터 타입을 잠깐 짚고 넘어가자.

데이터 타입

아랑고DB는 데이터 타입을 primitivecompound로 분류한다. 전자는 하나의 값을 가지는 데이터 형태이고, null, boolean, number, string 형태가 있다. 후자는 0개~ 여러 값을 포함하는 데이터 타입으로, array/listobject/document가 있다.

오브젝트는 중괄호 {}로 감싸진 데이터 타입이고, 이름-값 쌍으로 구성되어 있으며, 각 쌍은 컴마,로 분리된다.

즉, 아래의 형태이다. 이름에 해당하는 name, age, blog는 따옴표나 쌍따옴표로 감싸도 되고, 감싸지 않아도 된다.

{
  'name' : 'Scott',
  'age' : 29,
  'blog' : 'ud803.github.io' 
}

글에서 계속해서 나오는 도큐먼트는 컬렉션에서 최상위 데이터 레벨을 의미한다. 즉, 오브젝트나 도큐먼트나 같은 형태이지만 컬렉션에 들어가는 레코드로써의 의미를 위해 도큐먼트라는 표현을 쓴다. 하나의 도큐먼트 내에 또다른 도큐먼트 형태가 있다면 (즉, nested object) 보통 오브젝트라고 분리하여 부르는 것 같다.

CREATE

아래 예시를 따라하기 전에, Collections에서 titles를 선택하고, 탑바의 Settings를 눌러 데이터를 Truncate 해주자. 그리고 탑바의 Indexes에서 +를 누르고, Persistent Type을 선택, Fields와 Name에는 title을 입력하고, Unique를 체크하고 Create을 눌러주자. 이는 컬렉션에서 title 필드에 인덱스를 추가하고, 값이 고유하도록 constraint을 주는 작업이다!
컬렉션 설정에서 Delete는 컬렉션을 아예 통째로 없애는 것이고, Truncate은 나머지 설정값은 그대로 둔 채 도큐먼트들만 지운다.

INSERT는 말그대로 특정 컬렉션에 도큐먼트를 삽입하는 연산이며, 아래와 같이 쓰인다.

// 기본 형태
INSERT _document_ INTO _collection_
// 아래 명령은  줄씩 입력해야한다
INSERT { title: "Avengers 1" } INTO titles
INSERT { "title" : "Avengers 2" } INTO titles

위 AQL에서 왜 명령을 한 줄씩 입력해야할까? AQL은 컬렉션 하나당 한 번의 Insert 연산만을 허용하기 때문이다. 요기 맨 첫 부분에 나와있음

// 1..100이라는 표현은 1부터 100까지 반복하는 For 문법의  예시이다
// CONCAT 타입에 관계없이  값을 문자열 형태로 합친다
// 위에서 Avengers 1, 2 생성했다면 아래 AQL 실패하는  정상이다
FOR i IN 1..100
  INSERT { "title" : CONCAT("Avengers ", i) }  INTO titles

앞서 title에 unique constraint을 주었기 때문에, Avengers 1을 생성하려는 시도는 실패했다. 하지만 때로는 중복인 도큐먼트는 무시하고 알아서 잘 센스있게 나머지 도큐먼트만 넣어주었으면 하는 바람이 든다. 이때 사용할 수 있는 것이 AQL의 Options 개념이다. 여기에서 Insert와 관련된 추가 설정들을 잘 보여주고 있는데, 중복을 무시하기 위해서는 ignoreErrors 옵션을 사용하면 된다.

FOR i IN 1..100
  INSERT { "title" : CONCAT("Avengers ", i) }  INTO titles
OPTIONS {ignoreErrors: True}

여기서 더 나아가, overwriteMode 옵션을 설정하면, 중복 도큐먼트를 마주했을 때의 규칙을 설정할 수도 있다.

  • ignore : 그냥 무시한다
  • replace : 덮어쓴다
  • update : 지정한 도큐먼트의 일부 부분만 업데이트한다
  • conflict : 에러를 일으킨다. 이는 따로 설정값이 없을 때의 기본 규칙임

그 외에 컬렉션 수준의 락을 거는 exclusive 옵션과 같은 유용한 설정이 있으니 시간이 되면 살펴보자. 나중에 아랑고DB에 수많은 도큐먼트를 벌크로 넣을 때, 이런 세세한 옵션들의 존재 유무를 알아두는 것이 큰 도움이 된다.

물론 시작부터 문서를 보면서 모든 설정을 달달달 외우는 것은 아무 필요가 없다. 어떤 설정이 있는지만 슥 훑어보고 정말 필요할 때 가져다 쓰면 되는 것임

4. 어디까지 왔나

생각보다 쓸 내용이 많아져서 AQL 기초 관련 내용을 1편과 2편으로 나누려고 한다. 2편은 도큐먼트를 삽입하는 또다른 방법인 UPSERT를 알아보고, 나머지 Read, Update, Delete 를 간단히 짚고 넘어가려고 한다. 그리고 그래프 횡단은 내용이 방대하기에 따로 분리할 예정이다.

  1. 아랑고DB란? 왜 쓰는가?
  2. 아랑고DB 세팅하기 on Ubuntu
  3. 아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. (지금 보고있는 글) AQL(Arango Query Lang) 배워보기 1
  5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)

<아랑고DB> 3. 아랑고DB 사용해보기

|
이번 글에서는 아랑고DB의 쉘을 사용해 아랑고DB의 기초 사용법을 배워보려고 한다. 사실 실제 작업은 Python 커넥터를 통해서 하는 경우가 대부분이지만, 실체를 알기 위해서는 직접 쉘로 붙어보는 것이 가장 효과적이라고 생각하기 때문이다.

들어가기에 앞서

  • 아랑고DB가 이미 설치되어있다고 가정한다. 만약 아직 설치되지 않았다면 여기를 보고 따라 설치해보자.
  • 또한 아랑고쉘은 JavaScript Shell 환경을 사용한다고 한다. 따라서 JS문법을 그대로 이용할 수 있다.

1. 데이터베이스 수준 명령어

초기 실행은 arangosh 명령어를 통해 한다. 그리고 초기에 입력했던 root 계정의 비밀번호를 입력해주면 된다. 쉘에 접속 후 tutorial 명령어를 입력하면 간단한 튜토리얼도 따라할 수 있으니 참고하자.

쉘에 접속했을 때 기본 데이터베이스는 _system 이다. 이제 movies라는 데이터베이스를 만들고, titles라는 도큐먼트 컬렉션을 만들어 볼 것이다. 데이터베이스 이름을 짓는 Naming Convention도 읽어보자.

// 현재 아랑고DB에 있는 데이터베이스들의 목록을 조회한다 
127.0.0.1:8529@_system> db._databases()
[ 
  "_system" 
]

// movies라는 데이터베이스를 만든다
127.0.0.1:8529@_system> db._createDatabase('movies')
true

// 생성된 것을 확인할 수 있다
127.0.0.1:8529@_system> db._databases()
[ 
  "_system", 
  "movies" 
]

// 데이터베이스를 변경해준다
127.0.0.1:8529@_system> db._useDatabase('movies')
true

// 컬렉션을 생성해준다. 탭을 눌러 자동완성 기능을 애용하자
// 컬렉션은 Edge Collection과 Document Collection으로 나뉘는데, 여기서는 단순히 도큐먼트의 집합을 생성할 예정이다.
127.0.0.1:8529@movies> db._createDocumentCollection('titles')
[ArangoCollection 139708, "titles" (type document, status loaded)]

127.0.0.1:8529@movies> db._collections()
[ 
  [ArangoCollection 139603, "_analyzers" (type document, status loaded)], 
  [ArangoCollection 139618, "_appbundles" (type document, status loaded)], 
  [ArangoCollection 139615, "_apps" (type document, status loaded)], 
  [ArangoCollection 139606, "_aqlfunctions" (type document, status loaded)], 
  [ArangoCollection 139621, "_frontend" (type document, status loaded)], 
  [ArangoCollection 139600, "_graphs" (type document, status loaded)], 
  [ArangoCollection 139612, "_jobs" (type document, status loaded)], 
  [ArangoCollection 139609, "_queues" (type document, status loaded)], 
  [ArangoCollection 139708, "titles" (type document, status loaded)] 
]

도큐먼트 컬렉션과 엣지 컬렉션은 데이터 모델의 성격에 따라 구분되는 컬렉션이다. 도큐먼트 컬렉션은 그래프DB에서 노드(버텍스)의 개념이고, 엣지 컬렉션은 이 노드들 사이의 관계를 나타내는 컬렉션이다.

2. 컬렉션 수준 명령어

이제 생성된 컬렉션 안에 도큐먼트를 추가해보자. 사실 쉘에서 데이터를 다루는 방식은 불편하기 때문에 이런 방법도 있다 정도로만 끝내려고 한다. 컬렉션 수준에서 사용하는 명령어들은 db.컬렉션명의 형태에 CRUD 관련 명령어들이 붙는 형태이다. 예를 들어 다음과 같은 식이다.

  • Create : db.titles.save({name : “Harry”})
  • Read : db.titles.toArray()
  • Update : db.titles.update(‘140292’, {name : “Sally”})
  • Delete : db.title.remove(‘140292’)

CREATE

save 명령어는 도큐먼트를 저장하기 위해 쓰이는데, 모든 데이터의 검색에서 쓰이는 _key 값을 직접 설정할 수 있다.

  • _key는 컬렉션 레벨에서 고유한 값이다.
  • _id는 데이터베이스 레벨에서 고유한 값이며, ‘{컬렉션명}/{_key 값}’ 의 형태이다.
  • 자세한 내용은 여기를 읽어보기

_key값을 어떻게 설정하느냐에 따라 쿼리의 효율이 하늘과 땅 차이이기 때문에 설계를 잘 해보자. 키 이름의 네이밍 컨벤션도 확인해보자.

// Harry Potter 1이라는 도큐먼트를 생성한다. _key값을 지정해주지 않으면 자동으로 생성해준다.
127.0.0.1:8529@movies> db.titles.save({title: "Harry Potter 1"})
{ 
  "_id" : "titles/140292", 
  "_key" : "140292", 
  "_rev" : "_dNTU1bG---" 
}

// JS 문법을 활용해 반복문도 쓸 수 있다.
127.0.0.1:8529@movies> for (var i=0; i< 10; ++i) {
...> db.titles.save({name: "Harry Potter" + i});
...> }
{ 
  "_id" : "titles/141195", 
  "_key" : "141195", 
  "_rev" : "_dNT028W--A" 
}

READ

데이터를 조회하는 방법도 간단하다.

  • toArray()를 통해 해당 컬렉션의 전체 도큐먼트를 조회하거나
  • byExample({조건})의 형태로 조건에 해당하는 도큐먼트만 조회할 수 있다
// toArray() 함수를 통해 컬렉션의 모든 도큐먼트를 조회한다
127.0.0.1:8529@movies> db.titles.toArray()
[ 
  { 
    "_key" : "140292", 
    "_id" : "titles/140292", 
    "_rev" : "_dNTU1bG---", 
    "title" : "Harry Potter 1" 
  } 
]

// 위에서 _key값은 설정하지 않았지만, 직접 도큐먼트를 조회하기 위해서는 document 함수에서 _key값을 불러주면 된다.
// 이렇게 _key값으로 도큐먼트를 조회하는 방법이 도큐먼트를 조회하는 가장 빠른 방법임을 새겨두자
127.0.0.1:8529@movies> db.titles.document('140292')
{ 
  "_key" : "140292", 
  "_id" : "titles/140292", 
  "_rev" : "_dNTU1bG---", 
  "title" : "Harry Potter 1" 
}

// 컬렉션 이름을 문자화하여 호출할 수도 있다
127.0.0.1:8529@movies> db._document("titles/140292")
{ 
  "_key" : "140292", 
  "_id" : "titles/140292", 
  "_rev" : "_dNTU1bG---", 
  "title" : "Harry Potter 1" 
}
 
// 이름이 Harry Potter8인 도큐먼트 조회
127.0.0.1:8529@movies> db.titles.byExample({name : "Harry Potter8"}).toArray();
[ 
  { 
    "_key" : "141193", 
    "_id" : "titles/141193", 
    "_rev" : "_dNT028W--_", 
    "name" : "Harry Potter8" 
  } 
]

UPDATE

도큐먼트 업데이트는 update(업데이트 매치 조건, 업데이트 할 필드) 형태로 쓴다. 여기서 주목할 점은 리턴값으로 _rev, _oldRev를 제공한다는 점이다. rev는 revision의 약자로 일종의 도큐먼트의 버전과 같은 개념인데, 아랑고쉘의 tutorial에서는 이 revision 이 조건부 수정을 위한 용도로 쓰인다고 말한다. 즉, 도큐먼트를 동시에 업데이트 하는 동시성 문제가 발생했을 때 상황에 따라서 revision 개념을 사용하면 의도하지 않았던 결과를 막을 수 있다는 개념인 것 같다.

// revision 설명 전에 잠깐 보면, 업데이트를 하면 기존의 old revision과 새롭게 바뀐 revision을 리턴해준다
// 즉, 도큐먼트의 버전이 바뀌었다고 안내해준다
127.0.0.1:8529@movies> db.titles.update('140292', {series : 1})
{ 
  "_id" : "titles/140292", 
  "_key" : "140292", 
  "_rev" : "_dNTcxl6---", 
  "_oldRev" : "_dNTU1bG---" 
}
  
// 여기서부터는 아랑고쉘에서 쉽게 설명해주는 부분이다
// 우선 도큐먼트를 조회해 doc이라는 변수에 저장한다
 > doc = db._document("places/example1");
// 그리고 아래 업데이트를 수행하면, 이는 별 문제없이 성공한다. 이때, 업데이트가 성공했기 때문에 기존의 revision 값은 변경됐다 
> db._update("places/example1", { someValue: 23 });
// 아래 업데이트는 위에서 선언한 doc을 기준으로 한다. 하지만, doc의 revision은 이미 위 업데이트 이후 old revision이 되었기 때문에 업데이트는 실패하게 된다. 
> db._update(doc, { someValue: 42 });
JavaScript exception in file '/usr/share/arangodb3/js/client/modules/@arangodb/arangosh.js' at 99,7: ArangoError 1200: conflict, _rev values do not match
!      throw error;
!      ^
stacktrace: ArangoError: conflict, _rev values do not match

DELETE

도큐먼트를 삭제하는 것도 매우 간단하다. 마찬가지로 도큐먼트의 _id_key 값을 remove() 함수에 전달하면 된다.

// _id로 지우기
127.0.0.1:8529@movies> db._remove("titles/140292");
{ 
  "_id" : "titles/140292", 
  "_key" : "140292", 
  "_rev" : "_dNTpPd----" 
}
  
// _key로 지우기
127.0.0.1:8529@movies> db.titles.remove("140292");
  

3. AQL 실행하기

AQL은 Arango Query Lang의 약자로, SQL처럼 편리하게 아랑고DB를 조회하고, 횡단하기 위한 언어이다. 아랑고쉘에서도 AQL을 실행할 수 있으며, 어떻게 하는지만 언급하고 나중에 제대로 배워보기로 한다.

// 쿼리는 멀티라인이기 때문에 키보드 숫자 1 옆의 `(backtick이라고 부름) 로 쿼리를 감싸주도록 한다
// 아래 AQL은 titles 컬렉션에 있는 모든 도큐먼트를 리턴하는 쿼리다
// db.titles.toArray()와 동일하다
127.0.0.1:8529@movies> db._query(`
...> FOR title in titles
...> RETURN title`)

4. 어디까지 왔나

다음 글에서는 아랑고DB의 Web UI를 통해 우리가 넣은 데이터를 살펴보고, 다양한 기능들을 살펴보려고 한다.

  1. 아랑고DB란? 왜 쓰는가?
  2. 아랑고DB 세팅하기 on Ubuntu
  3. (지금 보고있는 글)아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. AQL(Arango Query Lang) 배워보기 1
  5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)