Skip to main content

query

질의를 위해서는 먼저 BaseModel.query를 이용해 질의 객체를 만드세요. 그리고 메소드 연쇄를 통해 질의를 만들어 나간 후, Query#execQuery#count, Query#update, Query#delete를 사용해 질의를 실행합니다.

단순한 질의를 쉽게 실행하기 위해서 BaseModel 클래스는 Query에서 일부 메소드를 빌려와 가지고 있습니다.

const users = await User.query().where(\{ age: 27 }).exec();

// 또는

const users = await User.where(\{ age: 27 }).exec();

필터

Query#whereQuery#find를 사용해 레코드를 선택할 수 있습니다. where의 조건문은 MongoDB의 문법과 비슷합니다. where를 두개 이상 사용할 경우 논리곱(모두 참)을 의미합니다.

설명CORMOSQLMongoDB
같음User.where({ age: 27 })SELECT * FROM users WHERE age=27db.users.find({ age: 27 })
논리곱(모두 참){ name: 'John Doe', age: 27 }name='John Doe' AND age=27{ name: 'John Doe', age: 27 }
.where({name: 'John Doe'}).where({age: 27})
{ $and: [ { name: 'John Doe' }, { age: 27 } ] }
[ { name: 'John Doe' }, { age: 27 } ]
논리합(하나 이상 참){ $or: [ { name: 'John Doe' }, { age: 27 } ] }name='John Doe' OR age=27{ $or: [ { name: 'John Doe' }, { age: 27 } ] }
비교 ($lt, $gt, $lte, $gte)[ { age: { $gt: 30 } }, { age: { $lte: 45 } } ]age>30 AND age<=45{ $and: [ { age: { $gt: 30 } }, { age: { $lte: 45 } } ] }
대소문자 구분 없이 텍스트를 포함{ name: { $contains: 'smi' } }name LIKE '%smi%'{ name: /smi/i }
{ name: { $contains: ['smi', 'doe'] } }name LIKE '%smi%' OR name LIKE '%doe%'{ name: { $in: [/smi/i, /doe/i] } }
대소문자 구분 없이 텍스트로 시작{ name: { $startswith: 'smi' } }name LIKE 'smi%'{ name: /^smi/i }
대소문자 구분 없이 텍스트로 끝남{ name: { $endswith: 'smi' } }name LIKE '%smi'{ name: /smi$/i }
정규표현식{ name: /smi/ }name REGEXP 'smi'{ name: /smi/i }
{ name: /smi|doe/ }name REGEXP 'smi|doe'{ name: /smi|doe/i }
배열의 값 중 하나라도 일치{ age: { $in: [ 10, 20, 30 ] } }age IN (10,20,30){ age: { $in: [ 10, 20, 30 ] } }
{ age: [ 10, 20, 30 ] }
부정{ age: { $not: 27 } }NOT (age=27) OR age IS NULL{ age: { $ne: 27 } }
{ age: { $not: { $lt: 27 } } }NOT (age<27) OR age IS NULL{ age: { $not: { $lt: 27 } } }
{ name: { $not: { $contains: 'smi' } } }NOT (name LIKE '%smi%') OR name IS NULL{ name: { $not: /smi/i } }
{ name: { $not: { $contains: ['smi', 'doe'] } } }NOT (name LIKE '%smi%' OR name LIKE '%doe%') OR name IS NULL{ name: { $nin: [/smi/i, /doe/i] } }
{ age: { $not: { $in: [ 10, 20, 30 ] } } }NOT (age IN (10,20,30)) OR age IS NULL{ age: { $nin: [10,20,30] } }
{ age: { $not: [ 10, 20, 30 ] } }
{ name: { $not: null } }NOT name IS NULL{ age: { $ne: null } }

식별자에 기반해 레코드를 찾으려면 하나의 ID나 ID의 배열을 인자로 하는 Query#find를 사용합니다. 논리적으로는 .where(\{ id: <주어진 ID나 ID의 배열> })과 동일하지만, 해당 레코드가 없을 경우 find는 예외를 발생시키는데 반해, where는 빈 결과를 반환합니다.

조건부 활성화

하나의 질의 연쇄에서 다른 조건을 적용하고 싶은 경우, Query#ifQuery#endif를 사용할 수 있습니다. 이를 이용해 질의 문장을 단순화할 수 있습니다.

async function getOldUsers(options: \{ limit?: number; columns?: string[] }) \{
const query = User.query();
query.where(\{ age: \{ $gt: 30 } });
if (options.limit) \{
query.limit(options.limit);
}
if (options.columns) \{
query.select(options.columns as any);
}
return await query.exec();
}

// 위 코드를 다음과 같이 작성할 수 있습니다.

async function getOldUsers(options: \{ limit?: number; columns?: string[] }) \{
return await User.query()
.where(\{ age: \{ $gt: 30 } })
.if(options.limit != null)
.limit(options.limit)
.endif()
.if(options.columns != null)
.select(options.columns as any)
.endif()
.exec();
}

레코드 가져오기

Query#exec는 레코드를 가져옵니다.

보통은 Model 인스턴스의 배열을 반환합니다. 하지만 하나의 ID를 가지고 Query#find를 호출한 경우에는 하나의 Model 인스턴스를 반환합니다.

const user = await User.find(1).exec();
const users = await User.find([1, 2, 3]).exec();

Query는 내부적으로 exec를 호출하는 then 메소드를 가지고 있습니다(즉 thenable). 따라서 exec 호출을 생략하고 단순히 await만 붙여줘도 됩니다.

const users = await User.where(\{ age: 30 });

찾지 못하는 ID가 있는 경우 Query#find는 에러를 던집니다. find는 주어진 순서를 보정하지 않습니다. 순서를 보장하고 싶은 경우 대신 Query#findPreserve를 사용하십시오.

const users = await User.findPreserve([2, 1, 2, 3]).exec();
// users[0].id는 2, users[1].id는 1, users[2].id는 2, users[3].id는 3입니다.

가져오기시 몇가지 옵션을 줄 수 있습니다.

설명CORMOSQLMongoDB
컬럼 선택User.select(['id', 'name', 'age'])SELECT id,name,age FROM usersdb.users.find({}, { name: 1, age: 1 })
정렬User.order('age -name')SELECT * FROM users ORDER BY age ASC, name DESCdb.users.find().sort({ age: 1, name: -1 })
제한User.query().limit(3)SELECT * FROM users LIMIT 3db.users.find().limit(3)
건너뛰기User.query().skip(3)SELECT * FROM users LIMIT 2147483647 OFFSET 3db.users.find().skip(3)

하나의 레코드만 요청하기

하나의 결과만 있는 것을 알고 있다면 (예를 들어 유니크 컬럼으로 질의), Query#one가 유용할 겁니다. 인스턴스 배열을 반환하는 대신 하나의 인스턴스 (또는 null)을 반환하도록 만듭니다.

const user = await User.where(\{ age: 27 }).one();

하나의 컬럼만 선택하기

하나의 컬럼에만 관심이 있다면 Query#selectSingle를 사용할 수 있습니다. 그러면 질의 객체는 Model 인스턴스 대신 하나의 값이나 값의 배열을 반환합니다.

const user_ids = await User.where(\{ age: 27 }).selectSingle('id');
const user_name = await User.find(1).selectSingle('name');

결과를 스트림 시키기

결과가 아주 많은 레코드를 가지고 있는 경우, 메모리 사용량을 줄이기 위해 Node.js의 stream API를 사용할 수 있습니다.

let count = 0;
await new Promise((resolve, reject) => \{
const stream = User.where(\{ age: 27 }).stream();
stream.on('data', function (user) \{
count++;
});
stream.on('end', function () \{
resolve();
});
});

레코드 수 새기

Query#count는 레코드의 수를 반환합니다.

CORMOSQLMongoDB
User.count()SELECT COUNT(*) FROM usersdb.users.count()
User.count({age: 27})SELECT COUNT(*) FROM users WHERE age=27db.users.find({age: 27}).count()
User.where({age: 27}).count()

레코드 갱신하기

레코드를 갱신하기 위해 BaseModel#saveQuery#update를 제공하고 있습니다.

BaseModel#save는 가져온 하나의 레코드를 갱신하기 위해 사용합니다.

const user = await User.find(1);
user.age = 30;
await user.save();

한편, Query#update는 필터된 레코드를 갱신합니다.

CORMOSQLMongoDB
User.update({ age: 10 }, { age: 27 })UPDATE users SET age=10 WHERE age=27db.users.update({age: 27}, {$set: {age: 10}}, {multi: true})
User.where({ age: 27 }).update({ age:10 })
User.find(1).update({ age: 10 })UPDATE users SET age=10 WHERE id=1db.users.update({_id: 1}, {$set: {age: 10}}, {multi: true})
User.find(2).update({ age: { $inc: 3 } })UPDATE users SET age=age+3 WHERE id=2db.users.update({_id: 2}, {$inc: {age: 3}}, {multi: true})

Query#update는 갱신 명량만 데이터베이스 시스템에 전송하기 때문에 보통 더 빠릅니다. 대신 수정된 객체를 얻을 수 없고, 갱신 콜백도 호출되지 않습니다.

필요에 따라서 적절한 것을 사용하세요.

In CORMO, Active Record 패턴(즉 BaseModel#save)은 운영환경에서 잘 검증되지 않았습니다. 그러므로 주의해서 사용해주세요.

레코드 삭제하기

Query#deleteBaseModel#destroy는 레코드를 삭제합니다.

BaseModel#destroyBaseModel#save와 비슷하게 ID를 통해 하나의 레코드를 삭제합니다. 그리고 Query#deleteQuery#update와 비슷하게 필터된 레코드를 삭제합니다.

CORMOSQLMongoDB
User.delete({age: 27})DELETE FROM users WHERE age=27db.users.remove({age: 27})
User.where({age: 27}).delete()
User.delete()DELETE FROM usersdb.users.remove()