[Mongo] ๋ชฝ๊ณ ์—์„œ Criteria ๋นผ๊ณ  Qclass ์‚ฌ์šฉํ•˜๊ธฐ

2025. 2. 2. 17:44ยทDB/Mongo

๐Ÿชด 0. ๋“ค์–ด๊ฐ€๊ธฐ ์ „

 

MongoDB๋Š” ์Šคํ‚ค๋งˆ๊ฐ€ ์—†๋Š” ๋น„๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ, ORM์ฒ˜๋Ÿผ ๊ด€๊ณ„๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ SQL์ด ์•„๋‹Œ JSON ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๋ฅผ ๊ฐ์ฒด๋กœ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด Criteria๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ Criteria๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ, ํ•„๋“œ๋ช…์„ ์‹ค์ˆ˜๋กœ ์ž˜๋ชป ์ž‘์„ฑํ•˜๋”๋ผ๋„ ์ปดํŒŒ์ผ ์‹œ ์—๋Ÿฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” MongoDB์—์„œ Criteria๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , Qclass ์™€ QueryDSL์„ ์ ์šฉํ•œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿชด 1. ๊ธฐ์กด์˜ Criteria ์ฝ”๋“œ

 

Criteria ๋Š” JSON ๊ธฐ๋ฐ˜์˜ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ์ฒด๋กœ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. 

๋น„๊ต๋ฅผ ์œ„ํ•ด ๋จผ์ € Criteria๋กœ ์ž‘์„ฑ๋œ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ๋“œ๋ฆฌ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@Slf4j
@Primary
@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
    private final ReactiveMongoOperations mongoOperations;

    @Override
    public Mono<Boolean> updateMemberPassword(String email, String newPassword, ServerWebExchange exchange) {
        Query query = new Query(Criteria.where("email").is(email));
        Update update = new Update()
                .set("password", newPassword)
                .set("updatedAt", LocalDateTime.now());

        return mongoOperations.updateFirst(query, update, Member.class)
                .map(updateResult -> updateResult.getModifiedCount() > 0)
                .defaultIfEmpty(false);
    }
}

 

์œ„์˜ ์ฝ”๋“œ๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

์ด ์ฝ”๋“œ์—์„œ "email" ์„ ๋ฌธ์ž์—ด๋กœ ์ž‘์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์‹ค์ œ ํ•„๋“œ๋ช…๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ž‘์„ฑํ•˜๋”๋ผ๋„

์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ๋Š” ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์น˜๋ช…์ ์ธ ๋ฌธ์ œ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿชด 2. Criteria ๋นผ๊ณ  Qclass + QueryDSL ์ ์šฉํ•˜๊ธฐ

 

ํ˜„์žฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

JDK 21, Spring Boot 3.2.2, MongoDB driver 4.11.2

ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์— ๋งž๋Š” QueryDSL๋ฒ„์ „์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. 

์•„๋ž˜์˜ ์„ค์ •ํŒŒ์ผ์„ ์ฐธ๊ณ ํ•˜์—ฌ ์ž์‹ ์˜ ๊ฐœ๋ฐœํ™˜๊ฒฝ์— ๋งž๋„๋ก ์—ฌ๋Ÿฌ ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.2.2'
	id 'io.spring.dependency-management' version '1.1.4'
}

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(21)
	}
}

ext {
	queryDslVersion = "5.0.0"
}

dependencies {
	// QueryDSL
	implementation "com.querydsl:querydsl-mongodb:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
	annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}"
    
	// MongoDB
	implementation 'org.mongodb:mongodb-driver-reactivestreams:4.11.2'
	implementation 'org.mongodb:mongodb-driver-core:4.11.2'
	configurations.all {
		exclude group: "org.mongodb", module: "mongo-java-driver" // ๊ธฐ์กด MongoDB Java ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์ œ๊ฑฐ(์ถฉ๋Œ ๋ฐฉ์ง€)
	}
}

// QueryDSL์ด ์ƒ์„ฑํ•œ ์ฝ”๋“œ์˜ ์ถœ๋ ฅ ๋””๋ ‰ํ„ฐ๋ฆฌ ์„ค์ •(Qclass ์ƒ์„ฑ ๊ฒฝ๋กœ)
def querydslDir = "${buildDir}/generated/querydsl" 

// ์–ด๋…ธํ…Œ์ด์…˜ ํ”„๋กœ์„ธ์„œ ์„ค์ •(์ถ”๊ฐ€ ์„ค๋ช… ์˜ˆ์ •)
tasks.withType(JavaCompile).configureEach {
	options.annotationProcessorPath = configurations.annotationProcessor
}

// QueryDSL ์ฝ”๋“œ ์ƒ์„ฑ์„ ์œ„ํ•œ JavaCompile Task
task generateQueryDSL(type: JavaCompile, group: 'build') {
	source = sourceSets.main.java
	classpath = configurations.compileClasspath
	destinationDirectory = file(querydslDir)
	options.annotationProcessorPath = configurations.annotationProcessor
	options.compilerArgs = [
			"-proc:only"
	]
}

compileJava {
	dependsOn clean
}

clean {
	delete file(querydslDir)
}

 

์„ค์ •์„ ๋งˆ์นœ ํ›„์—, Document ๋ฅผ ์ •์˜ํ•œ ๊ณณ์— ์•„๋ž˜์ฒ˜๋Ÿผ @QueryEntity ๋ฅผ ์ถ”๊ฐ€๋กœ ์„ ์–ธํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์„ค์ •์—์„œ ์–ด๋…ธํ…Œ์ด์…˜ ํ”„๋กœ์„ธ์„œ(annotation processor)๋ฅผ ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด @QueryEntity๋ฅผ ์ž‘์„ฑํ•ด๋„ Qclass๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 

import com.querydsl.core.annotations.QueryEntity;

@QueryEntity //์ถ”๊ฐ€ํ•ด์•ผ ํ•  ์–ด๋…ธํ…Œ์ด์…˜
@Document
public record Member(

){}

 

๊ทธ๋ฆฌ๊ณ  ๋นŒ๋“œ๋ฅผ ํ•˜๊ฒŒ๋˜๋ฉด ์œ„์—์„œ ์„ค์ •ํ–ˆ๋˜ ๊ฒฝ๋กœ์— Qclass๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


๐Ÿชด 3.  ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ๊นŒ?

 

๋จผ์ €, QueryPathResolver ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

import com.querydsl.core.types.Path;
import org.springframework.stereotype.Component;

@Component
public class QueryPathResolver {
    public static String get(Path<?> path) {
        return path.getMetadata().getName();
    }
}

 

 

๊ทธ๋ฆฌ๊ณ , 1๋ฒˆ์˜ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

"email" -> QueryPathResolver.get(MEMBER.email)
@Slf4j
@Primary
@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
    private final ReactiveMongoOperations mongoOperations;
    private final QMember MEMBER = QMember.member; //์ถ”๊ฐ€


    @Override
    public Mono<Boolean> updateMemberPassword(String email, String newPassword, ServerWebExchange exchange) {
        Query query = new Query(Criteria.where(QueryPathResolver.get(MEMBER.email)).is(email));
        Update update = new Update()
                .set(QueryPathResolver.get(MEMBER.password), newPassword)
                .set(QueryPathResolver.get(MEMBER.updatedAt), LocalDateTime.now());

        return mongoOperations.updateFirst(query, update, Member.class)
                .map(updateResult -> updateResult.getModifiedCount() > 0)
                .defaultIfEmpty(false);
    }
}

 

 

๊ตณ์ด QueryPathResolver ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”

QueryDSL์—์„œ QMember.email ๊ฐ™์€ ํ•„๋“œ๋Š” ์ง์ ‘์ ์œผ๋กœ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ, Path ๊ฐ์ฒด๋กœ ํ‘œํ˜„๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

์•„๋ž˜์˜ Qclass ๋ฅผ ์‹ค์ œ๋กœ ํ™•์ธํ•ด๋ณด๋ฉด String ํƒ€์ž…์ด ์•„๋‹Œ Path ๊ฐ์ฒด๋กœ ํ‘œํ˜„ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public class QMember extends EntityPathBase<Member> {
    public static final QMember member = new QMember("member");
    public final StringPath email = createString("email");
    public final StringPath password = createString("password");
}

 


๐Ÿชด 4. ๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ํฌ์ŠคํŒ…์€ '์ปดํŒŒ์ผ ์—๋Ÿฌ ๋ฐฉ์ง€'์™€ '์ฝ”๋“œ ์ผ๊ด€์„ฑ'์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๊ธฐ๋Š” ํ•˜์ง€๋งŒ,

์†”์งํžˆ MongoDB์—์„œ queryDSL์„ ์ ์šฉํ•˜๋ฉด ์žฅ์ ์ด ๋งŽ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

 

MongoDB์—์„œ๋Š” ์ค‘์ฒฉ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•˜๋Š”๋ฐ queryDSL์€ ์ด๋Ÿฐ ๋ถ€๋ถ„์„ ์™„๋ฒฝํ•˜๊ฒŒ ์ง€์›ํ•ด์ฃผ์ง€ ์•Š์•„์„œ ์ง์ ‘ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

(์•„๋ž˜ ์˜ˆ์‹œ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ƒ์œ„๊ฒฝ๋กœ + "." + ํ•˜์œ„๊ฒฝ๋กœ ์˜ ํ˜•ํƒœ๋กœ ์ž‘์„ฑ์„ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.)

Member member = mongoOperations.findOne(
                query(where(QueryPathResolver.get(Member.groupMemberInfoList) + "." + QueryPathResolver.get(MEMBER_INFO.memberId)).is(memberId).and(QueryPathResolver.get(Member.id)).is(meberId)),
                Member.class
        );

 

๊ทธ๋ฆฌ๊ณ  queryDSL์€ SQL์— ์ตœ์ ํ™”๊ฐ€ ๋˜์–ด์žˆ์–ด์„œ MongoDB์ฒ˜๋Ÿผ Aggregation Framework๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š”

$lookup, $unwind, $group ์™€ ๊ฐ™์€ ๋ณต์žกํ•œ ๊ธฐ๋Šฅ๋“ค์€ ์ง€์› ๋ฐ›์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. 

 

๋”ฐ๋ผ์„œ Qclass + MongoDB ๋ฐฉ์‹์€ ํœด๋จผ ์—๋Ÿฌ๋กœ ์ธํ•œ ์ปดํŒŒ์ผ ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ  ์‹ถ์€ ๋ถ„๋“ค์—๊ฒŒ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

'DB > Mongo' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Mongo] ObjectId ์ค‘๋ณต๊ฐ€๋Šฅ์„ฑ  (2) 2024.12.06
[Mongo] MongoDB ์„ค์น˜ ๋ฐ ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ์ง„ํ–‰ (+์—๋Ÿฌํ•ด๊ฒฐ)  (0) 2024.04.09
'DB/Mongo' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [Mongo] ObjectId ์ค‘๋ณต๊ฐ€๋Šฅ์„ฑ
  • [Mongo] MongoDB ์„ค์น˜ ๋ฐ ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ์ง„ํ–‰ (+์—๋Ÿฌํ•ด๊ฒฐ)
ssddo
ssddo
๊ตฌ๊ฒฝํ•˜๊ณ  ๊ฐ€์„ธ์š”
  • ssddo
    ssddo-story
    ssddo
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (44)
      • SpringBoot (9)
      • webFlux (2)
      • DB (8)
        • MySQL (3)
        • Mongo (3)
        • Docker (1)
        • Postgres (1)
      • JAVA (1)
      • ORM & DSL (4)
        • JPA (3)
        • JOOQ (1)
      • React (12)
        • ์„ค์น˜ ๋ฐ ํ™˜๊ฒฝ ๊ตฌ์ถ• (1)
        • ๊ธฐ๋ณธ (4)
        • ํ™œ์šฉ (7)
      • CS (1)
      • ๊ณตํ†ต (6)
      • ํ”„๋กœ์ ํŠธ (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    postgre
    springboot
    react
    Java
    Redisson
    MySQL
    ๋ณตํ˜ธํ™”
    RSS
    ๋ธ”๋ก
    docker
    JPA
    mongo
    git
    ์•”ํ˜ธํ™”
    ํŒจ๋”ฉ
    jooq
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.1
ssddo
[Mongo] ๋ชฝ๊ณ ์—์„œ Criteria ๋นผ๊ณ  Qclass ์‚ฌ์šฉํ•˜๊ธฐ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”