MongoDB에서 필드 이름에 점(.)이 포함된 경우, 일반적인 도트 표기법(dot notation)으로는 해당 필드에 접근하기 어렵습니다. 이럴 때 $addFields 연산자를 활용하면 됩니다. 내부적으로 $objectToArray를 사용해 데이터를 키(key)와 값(value) 형태의 배열로 변환한 뒤, $filter와 $indexOfBytes를 조합하여 키 안에 점이 포함되어 있는지 확인할 수 있습니다.
1. 샘플 컬렉션 생성하기
먼저 점이 포함된 키를 가진 문서들로 컬렉션을 생성해 보겠습니다.
> db.demo364.insertOne(
... {
... "details" : {
... "details1.otherdetails.Name" : {"FirstName":"Chris" }
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e57d485d0ada61456dc936d")
}
> db.demo364.insertOne(
... {
... "details" : {
... "details1.otherdetails.Name" : {"FirstName":"David" }
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e57d486d0ada61456dc936e")
}2. 저장된 문서 확인하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 조회할 수 있습니다.
> db.demo364.find();
위 쿼리는 다음과 같은 결과를 출력합니다.
{ "_id" : ObjectId("5e57d485d0ada61456dc936d"), "details" : { "details1.otherdetails.Name" : { "FirstName" : "Chris" } } }
{ "_id" : ObjectId("5e57d486d0ada61456dc936e"), "details" : { "details1.otherdetails.Name" : { "FirstName" : "David" } } }3. 점이 포함된 키를 찾는 집계 쿼리
다음은 키에 점이 포함된 레코드를 검색하는 집계(aggregation) 쿼리입니다.
> db.demo364.aggregate([
... {
... $addFields: {
... result: {
... $filter: {
... input: { $objectToArray: "$details" },
... cond: {
... $ne: [ { $indexOfBytes: [ "$$this.k", "." ] } , -1 ]
... }
... }
... }
... }
... },
... {
... $match: {
... $expr: {
... $ne: [ { $size: "$result" }, 0 ]
... }
... }
... },
... {
... $project: {
... result: 0
... }
... }
... ])쿼리 동작 원리
이 쿼리가 어떻게 동작하는지 단계별로 살펴보겠습니다.
첫 번째 단계($addFields): $objectToArray가 details 객체를 { k: 키, v: 값 } 형태의 배열로 변환합니다. 이후 $filter가 각 요소를 순회하며 $indexOfBytes로 키($$this.k) 안에서 점(.)의 위치를 찾습니다. 점이 존재하면 -1이 아닌 값이 반환되므로, 해당 요소는 필터링 결과에 포함됩니다.
두 번째 단계($match): 임시로 만든 result 배열의 크기가 0이 아닌 문서, 즉 점이 포함된 키를 하나 이상 가진 문서만 남깁니다.
세 번째 단계($project): 불필요해진 result 필드를 결과에서 제거하여 원본 문서 형태 그대로 출력합니다.
실행 결과
위 쿼리를 실행하면 다음과 같이 키에 점이 포함된 두 개의 문서가 모두 조회됩니다.
{ "_id" : ObjectId("5e57d485d0ada61456dc936d"), "details" : { "details1.otherdetails.Name" : { "FirstName" : "Chris" } } }
{ "_id" : ObjectId("5e57d486d0ada61456dc936e"), "details" : { "details1.otherdetails.Name" : { "FirstName" : "David" } } }참고 사항
MongoDB에서는 필드 이름에 점을 사용하는 것이 권장되지 않습니다. 점은 중첩 필드 경로를 나타내는 예약 문자이기 때문에, 점이 포함된 키는 일반적인 쿼리나 업데이트 작업에서 예상치 못한 동작을 유발할 수 있습니다. 따라서 이런 쿼리로 점이 포함된 키를 찾아낸 후에는, 데이터 마이그레이션을 통해 키 이름을 언더스코어(_) 같은 안전한 문자로 변경하는 것이 좋습니다.