MongoDB 쿼리 - React Native SDK
이 페이지의 내용
쿼리 API 가 포함된 Realm React Native SDK의 MongoDB 클라이언트 를 사용하여 클라이언트 애플리케이션 코드에서 직접 MongoDB Atlas 에 저장된 데이터를 쿼리 할 수 있습니다. Atlas App Services 는 로그인한 사용자 또는 각 문서 의 콘텐츠를 기반으로 결과를 안전하게 조회 할 수 있도록 컬렉션에 대한 데이터 액세스 규칙 을 제공합니다.
참고
예시 데이터 세트
이 페이지의 예제에서는 식물 매장 체인의 재고를 설명하는 MongoDB 컬렉션을 사용합니다. 컬렉션 스키마 및 문서 콘텐츠에 대한 자세한 내용은 예제 데이터를 참조하세요.
사용 사례
MongoDB 데이터 소스를 쿼리해야 하는 이유는 여러 가지가 있습니다. Atlas Device Sync를 통해 클라이언트의 데이터로 작업하는 것이 항상 실용적이거나 가능한 것은 아닙니다. 다음과 같은 경우에는 MongoDB를 쿼리해야 할 수 있습니다.
데이터 세트의 용량이 크거나, 클라이언트 디바이스로 데이터 세트 전체를 로드하는 데 제약이 있을 경우
사용자 지정 사용자 데이터 생성 또는 업데이트를 실행하려는 경우
Realm에서 모델링되지 않은 문서를 검색하려는 경우
앱으로 엄격한 스키마가 없는 컬렉션에 액세스해야 하는 경우
비Realm 서비스를 통해 액세스하고자 하는 컬렉션을 생성할 경우
다음 내용은 MongoDB를 직접 쿼리할 수 있는 일반적인 사용 사례입니다. 단, 해당 사례들이 전부는 아닙니다.
전제 조건
애플리케이션에서 를 쿼리하려면 MongoDB React Native MongoDB 먼저 에서 데이터 액세스를 설정해야 App Services App 합니다. Realm SDK가 Atlas 를 쿼리할 수 있도록 백엔드 앱을 설정하는 방법을 알아보려면 Atlas 앱 서비스 문서에서 MongoDB 데이터 액세스 설정 을 참조하세요.
예시
데이터 예시
이 페이지의 예시에서는 식물 매장 체인에서 판매되는 다양한 식물을 설명하는 다음 MongoDB 컬렉션을 사용합니다.
{ _id: ObjectId("5f87976b7b800b285345a8c4"), name: "venus flytrap", sunlight: "full", color: "white", type: "perennial", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c5"), name: "sweet basil", sunlight: "partial", color: "green", type: "annual", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c6"), name: "thai basil", sunlight: "partial", color: "green", type: "perennial", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c7"), name: "helianthus", sunlight: "full", color: "yellow", type: "annual", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c8"), name: "petunia", sunlight: "full", color: "purple", type: "annual", _partition: "Store 47" }
plants
컬렉션의 문서들은 다음 스키마를 사용합니다.
{ "title": "Plant", "bsonType": "object", "required": ["_id", "_partition", "name"], "properties": { "_id": { "bsonType": "objectId" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" }, "sunlight": { "bsonType": "string" }, "color": { "bsonType": "string" }, "type": { "bsonType": "string" } } }
type Plant = { _id: BSON.ObjectId; _partition: string; name: string; sunlight?: string; color?: string; type?: string; };
연결된 클러스터에 연결하기
클라이언트 애플리케이션에서 연결된 클러스터에 액세스하려면 사용자를 인증하고 클러스터 이름을 User.mongoClient()에 전달합니다. 이렇게 하면 클러스터의 데이터베이스 및 컬렉션에 액세스할 때 사용할 수 있는 MongoDB 서비스 인터페이스가 반환됩니다.
@realm/react
를 사용하는 경우 UserProvider
로 래핑된 구성 요소의 useUser()
후크를 사용하여 MongoDB 클라이언트에 액세스할 수 있습니다.
import React from 'react'; import {useUser} from '@realm/react'; function QueryPlants() { // Get currently logged in user const user = useUser(); const getPlantByName = async name => { // Access linked MongoDB collection const mongodb = user.mongoClient('mongodb-atlas'); const plants = mongodb.db('example').collection('plants'); // Query the collection const response = await plants.findOne({name}); return response; }; // ... }
import React from 'react'; import {useUser} from '@realm/react'; function QueryPlants() { // Get currently logged in user const user = useUser(); const getPlantByName = async (name: string) => { // Access linked MongoDB collection const mongodb = user.mongoClient('mongodb-atlas'); const plants = mongodb.db('example').collection<Plant>('plants'); // Query the collection const response = await plants.findOne({name}); return response; }; // ... }
읽기 작업
단일 문서 찾기
단일 문서를 찾으려면 해당 문서와 일치하는 쿼리를 collection.findOne() 에 전달합니다. 쿼리를 전달하지 않으면 findOne()
이(가) 컬렉션에서 찾은 첫 번째 문서와 일치합니다.
다음 스니펫 은 매장 그룹의 판매 대상 식물을 설명하는 문서 컬렉션에서 '파리지옥(venus flytrap)' 식물을 설명하는 문서를 찾습니다.
const venusFlytrap = await plants.findOne({ name: "venus flytrap" }); console.log("venusFlytrap", venusFlytrap);
{ _id: ObjectId("5f87976b7b800b285345a8c4"), name: "venus flytrap", sunlight: "full", color: "white", type: "perennial", _partition: "Store 42", }
여러 문서 찾기
여러 문서를 찾으려면 해당 문서와 일치하는 쿼리를 collection.find() 에 전달합니다. 쿼리를 전달하지 않으면 find()
이(가) 컬렉션의 모든 문서와 일치합니다.
다음 스니펫 은 매장 그룹의 판매 대상 식물을 설명하는 문서 컬렉션에서 다년생 식물을 설명하는 모든 문서를 찾습니다.
const perennials = await plants.find({ type: "perennial" }); console.log("perennials", perennials);
[ { _id: ObjectId("5f87976b7b800b285345a8c4"), name: 'venus flytrap', sunlight: 'full', color: 'white', type: 'perennial', _partition: 'Store 42' }, { _id: ObjectId("5f87976b7b800b285345a8c6"), name: 'thai basil', sunlight: 'partial', color: 'green', type: 'perennial', _partition: 'Store 42' }, { _id: ObjectId("5f879f83fc9013565c23360e"), name: 'lily of the valley', sunlight: 'full', color: 'white', type: 'perennial', _partition: 'Store 47' }, { _id: ObjectId("5f87a0defc9013565c233611"), name: 'rhubarb', sunlight: 'full', color: 'red', type: 'perennial', _partition: 'Store 47' }, { _id: ObjectId("5f87a0dffc9013565c233612"), name: 'wisteria lilac', sunlight: 'partial', color: 'purple', type: 'perennial', _partition: 'Store 42' }, { _id: ObjectId("5f87a0dffc9013565c233613"), name: 'daffodil', sunlight: 'full', color: 'yellow', type: 'perennial', _partition: 'Store 42' } ]
문서 수 계산
문서 수를 계산하려면 해당 문서들과 일치하는 쿼리를 collection.count()( 으)로 전달하세요. 쿼리를 전달하지 않으면 count()
이(가) 컬렉션의 모든 문서 수를 계산합니다.
다음 스니펫 은 매장 그룹에서 판매할 식물을 설명하는 문서 컬렉션의 문서 수를 계산합니다.
const numPlants = await plants.count(); console.log(`There are ${numPlants} plants in the collection`);
"There are 9 plants in the collection"
쓰기 작업
단일 문서 삽입
단일 문서를 삽입하려면 collection.insertOne()에 전달합니다.
다음 스니펫 은 매장 그룹의 판매 대상 식물을 설명하는 문서 모음에 '은방울꽃' 식물을 설명하는 단일 문서를 삽입합니다.
const result = await plants.insertOne({ name: "lily of the valley", sunlight: "full", color: "white", type: "perennial", _partition: "Store 47", }); console.log(result);
{ insertedId: "5f879f83fc9013565c23360e", }
여러 문서를 삽입합니다.
여러 문서를 동시에 삽입하려면 해당 문서를 배열로 collection.insertMany()에 전달합니다.
다음 스니펫 은 매장 그룹에서 판매할 식물을 설명하는 문서 모음에 식물을 설명하는 문서 3개를 삽입합니다.
const result = await plants.insertMany([ { name: "rhubarb", sunlight: "full", color: "red", type: "perennial", _partition: "Store 47", }, { name: "wisteria lilac", sunlight: "partial", color: "purple", type: "perennial", _partition: "Store 42", }, { name: "daffodil", sunlight: "full", color: "yellow", type: "perennial", _partition: "Store 42", }, ]); console.log(result);
{ insertedIds: [ "5f87a0defc9013565c233611", "5f87a0dffc9013565c233612", "5f87a0dffc9013565c233613", ], }
단일 문서 업데이트
단일 문서를 업데이트하려면 해당 문서 및 업데이트 문서와 일치하는 쿼리를 collection.updateOne()(으)로 전달하세요.
다음 스니펫 은 매장 그룹에서 판매할 식물을 설명하는 문서 컬렉션 에서 단일 문서를 업데이트합니다. 이 작업은 name
필드에 'petunia' 값이 포함된 문서를 쿼리하고 첫 번째 일치하는 문서의 sunlight
필드 값을 'partial'로 변경합니다.
const result = await plants.updateOne( { name: "petunia" }, { $set: { sunlight: "partial" } } ); console.log(result);
{ matchedCount: 1, modifiedCount: 1 }
여러 문서 업데이트하기
여러 문서를 동시에 업데이트하려면 해당 문서 및 업데이트 설명과 일치하는 쿼리를 collection.updateMany()(으)로 전달하세요.
다음 스니펫 은 매장 그룹에서 판매할 식물을 설명하는 문서 모음 에서 여러 문서를 업데이트합니다. 이 작업은 _partition
필드에 'Store 47' 값이 포함된 문서를 쿼리하고 일치하는 각 문서의 _partition
필드 값을 'Store 51'로 변경합니다.
const result = await plants.updateMany( { _partition: "Store 47" }, { $set: { _partition: "Store 51" } } ); console.log(result);
{ matchedCount: 3, modifiedCount: 3 }
문서 업서트
문서를 업서트하려면 업데이트 작업에서 upsert
옵션을 true
(으)로 설정하세요. 이 작업의 쿼리가 컬렉션의 어떤 문서와도 일치하지 않는 경우, 업서트는 새 문서 1개를 업데이트가 적용된 상태로 제공된 쿼리 문서와 일치하는 컬렉션에 자동으로 삽입합니다.
다음 스니펫은 매장 그룹의 판매 대상 식물을 설명하는 문서 컬렉션에서 업서트 작업으로 문서를 업데이트합니다. 이 쿼리가 기존 문서와 일치하지 않으므로, MongoDB는 새 문서를 자동으로 생성합니다.
const result = await plants.updateOne( { sunlight: "full", type: "perennial", color: "green", _partition: "Store 47", }, { $set: { name: "sweet basil" } }, { upsert: true } ); console.log(result);
{ matchedCount: 0, modifiedCount: 0, upsertedId: ObjectId("5f1f63055512f2cb67f460a3"), }
단일 문서 삭제
컬렉션에서 문서를 1개 삭제하려면 해당 문서와 일치하는 쿼리를 collection.deleteOne()(으)로 전달하세요. 쿼리를 전달하지 않았거나 쿼리가 여러 문서와 일치하면 해당 작업에서 최초로 발견된 문서가 삭제됩니다.
다음 스니펫 은 매장 그룹에서 판매할 식물을 설명하는 문서 모음에서 문서 하나를 삭제합니다. 이 작업은 color
필드 값이 '녹색'인 문서를 쿼리하고 일치하는 첫 번째 문서를 삭제합니다.
const result = await plants.deleteOne({ color: "green" }); console.log(result);
{ deletedCount: 1 }
여러 문서 삭제
컬렉션에서 여러 문서를 삭제하려면 해당 문서와 일치하는 쿼리를 collection.deleteMany()( 으)로 전달하세요. 쿼리를 전달하지 않으면 deleteMany()
가 컬렉션의 모든 문서를 삭제합니다.
다음 스니펫 은 매장 그룹의 판매 대상 식물을 설명하는 문서 컬렉션에서 'Store 51'에 있는 식물에 대한 모든 문서를 삭제합니다.
const result = await plants.deleteMany({ _partition: "Store 51", }); console.log(result);
{ deletedCount: 3 }
실시간 변경 알림
collection.watch() 를 호출하여 컬렉션의 문서가 추가, 수정 또는 삭제될 때마다 MongoDB가 보내는 실시간 변경 알림을 구독할 수 있습니다. 각 알림은 변경된 문서, 변경 방법, 이벤트를 일으킨 작업 이후의 전체 문서를 지정합니다.
collection.watch()
비동기 생성기 를 반환합니다. 이를 통해 작업이 발생할 때 작업에 대한 변경 이벤트 를 비동기적으로 가져올 수 있습니다.
collection.watch()
React Native 클라이언트 앱과 함께 작동하려면 몇 가지 설정이 필요합니다. 컬렉션의 변경 사항을 관찰하려면 먼저 react-native-polyfill-globals를 설치해야 합니다.및 @babel/plugin-proposal-async-generator-functions 패키지.
collection.watch()를 사용하려면:
종속 요소를 설치합니다.
npm install react-native-polyfill-globals text-encoding npm install --save-dev @babel/plugin-proposal-async-generator-functions 사용해야 하는 위치보다 더 높은 범위에서 폴리필을 가져옵니다. 예를 들어
index.js
이 있습니다.import { polyfill as polyfillReadableStream } from "react-native-polyfill-globals/src/readable-stream"; import { polyfill as polyfillEncoding } from "react-native-polyfill-globals/src/encoding"; import { polyfill as polyfillFetch } from "react-native-polyfill-globals/src/fetch"; polyfillReadableStream(); polyfillEncoding(); polyfillFetch();
중요
서버리스 제한 사항
데이터 원본이 Atlas 서버리스 인스턴스인 경우 변경 사항을 모니터링할 수 없습니다. MongoDB 서버리스는 현재 변경 스트림을 지원하지 않습니다. 변경 스트림은 감시되는 컬렉션에서 변경 사항을 수신하는 데 사용됩니다.
컬렉션의 모든 변경사항 보기
@realm/react
패키지를 사용하는 경우 앱에 대한 사용자 인증을 구성했는지 확인합니다.
컬렉션의 모든 변경 사항을 감시하려면 인수 없이 collection.watch() 를 호출합니다. 이 호출은 인증된 사용자와 함께 UserProvider
로 래핑해야 합니다.
import React, {useEffect} from 'react'; import Realm from 'realm'; import {useUser, useApp, AppProvider, UserProvider} from '@realm/react'; function AppWrapper() { return ( <AppProvider id={APP_ID}> <UserProvider fallback={<LogIn />}> <NotificationSetter /> </UserProvider> </AppProvider> ); } function NotificationSetter() { // Get currently logged in user const user = useUser(); const watchForAllChanges = async ( plants, ) => { // Watch for changes to the plants collection for await (const change of plants.watch()) { switch (change.operationType) { case 'insert': { const {documentKey, fullDocument} = change; // ... do something with the change information. break; } case 'update': { const {documentKey, fullDocument} = change; // ... do something with the change information. break; } case 'replace': { const {documentKey, fullDocument} = change; // ... do something with the change information. break; } case 'delete': { const {documentKey} = change; // ... do something with the change information. break; } } } }; useEffect(() => { const plants = user .mongoClient('mongodb-atlas') .db('example') .collection('plants'); // Set up notifications watchForAllChanges(plants); }, [user, watchForAllChanges]); // ... rest of component }
import React, {useEffect} from 'react'; import Realm from 'realm'; import {useUser, useApp, AppProvider, UserProvider} from '@realm/react'; function AppWrapper() { return ( <AppProvider id={APP_ID}> <UserProvider fallback={<LogIn />}> <NotificationSetter /> </UserProvider> </AppProvider> ); } function NotificationSetter() { // Get currently logged in user const user = useUser(); const watchForAllChanges = async ( plants: Realm.Services.MongoDB.MongoDBCollection<Plant>, ) => { // Watch for changes to the plants collection for await (const change of plants.watch()) { switch (change.operationType) { case 'insert': { const {documentKey, fullDocument} = change; // ... do something with the change information. break; } case 'update': { const {documentKey, fullDocument} = change; // ... do something with the change information. break; } case 'replace': { const {documentKey, fullDocument} = change; // ... do something with the change information. break; } case 'delete': { const {documentKey} = change; // ... do something with the change information. break; } } } }; useEffect(() => { const plants = user! .mongoClient('mongodb-atlas') .db('example') .collection<Plant>('plants'); // Set up notifications watchForAllChanges(plants); }, [user, watchForAllChanges]); // ... rest of component }
컬렉션의 특정 변경사항 보기
컬렉션의 특정 변경 사항을 감시하려면 변경 이벤트 필드와 일치하는 쿼리를 collection.watch()에 전달합니다.
for await (const change of plants.watch({ filter: { operationType: "insert", "fullDocument.type": "perennial", }, })) { // The change event will always represent a newly inserted perennial const { documentKey, fullDocument } = change; console.log(`new document: ${documentKey}`, fullDocument); }
집계 작업
집계 작업은 집계 파이프라인 이라는 일련의 단계를 통해 컬렉션의 모든 문서를 실행합니다. 애그리게이션을 사용하면 문서를 필터링 및 변환하고, 관련 문서 그룹에 대한 요약 데이터를 수집하는 등의 복잡한 데이터 작업을 수행할 수 있습니다.
집계 파이프라인실행
집계 파이프라인을 실행하려면 집계 단계 배열을 collection.aggregate()(으)로 전달하세요. 집계 작업에서는 이 파이프라인 내 마지막 단계의 결과 세트가 반환됩니다.
다음 스니펫은 type
값을 기준으로 plants
컬렉션의 모든 문서를 그룹화하고 각 유형의 개수를 집계합니다.
const result = await plants.aggregate([ { $group: { _id: "$type", total: { $sum: 1 }, }, }, { $sort: { _id: 1 } }, ]); console.log(result);
[ { _id: "annual", total: 1 }, { _id: "perennial", total: 5 }, ]
문서 필터링
$match 단계를 사용하여 표준 MongoDB 쿼리 구문에 따라 문서를 필터링할 수 있습니다.
{ "$match": { "<Field Name>": <Query Expression>, ... } }
예시
다음 $match
단계는 type
필드 값이 '다년생'인 문서만 포함하도록 필터링합니다.
const perennials = await plants.aggregate([ { $match: { type: { $eq: "perennial" } } }, ]); console.log(perennials);
[ { "_id": ObjectId("5f87976b7b800b285345a8c4"), "_partition": "Store 42", "color": "white", "name": "venus flytrap", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f87976b7b800b285345a8c6"), "_partition": "Store 42", "color": "green", "name": "thai basil", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87a0dffc9013565c233612"), "_partition": "Store 42", "color": "purple", "name": "wisteria lilac", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87a0dffc9013565c233613"), "_partition": "Store 42", "color": "yellow", "name": "daffodil", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f1f63055512f2cb67f460a3"), "_partition": "Store 47", "color": "green", "name": "sweet basil", "sunlight": "full", "type": "perennial" } ]
문서 그룹화
$group 단계를 사용하여 하나 이상의 문서에 대한 요약 데이터를 집계할 수 있습니다. MongoDB는 $group
단계의 _id
필드에 정의된 표현식을 기반으로 문서를 그룹화합니다. 필드 이름 앞에 $
를 붙여 특정 문서 필드를 참조할 수 있습니다.
{ "$group": { "_id": <Group By Expression>, "<Field Name>": <Aggregation Expression>, ... } }
예시
다음 $group
단계에서는 type
필드 값을 기준으로 문서를 정렬하고 각 고유 type
값이 나타나는 식물 문서 수를 계산합니다.
const result = await plants.aggregate([ { $group: { _id: "$type", numItems: { $sum: 1 }, }, }, { $sort: { _id: 1 } }, ]); console.log(result);
[ { _id: "annual", numItems: 1 }, { _id: "perennial", numItems: 5 }, ]
페이지 매김 문서
결과를 페이지로 나누려면 $match
, $sort
및 $limit
연산자와 함께 범위 집계 쿼리를 사용할 수 있습니다. 문서 페이지 매김에 대해 자세히 알아보려면 MongoDB Server 문서에서 범위 쿼리 사용하기를 참조하세요.
예시
다음 예시에서는 문서 컬렉션을 오름차순으로 페이지를 매깁니다.
// Paginates through list of plants // in ascending order by plant name (A -> Z) async function paginateCollectionAscending( collection, nPerPage, startValue ) { const pipeline = [{ $sort: { name: 1 } }, { $limit: nPerPage }]; // If not starting from the beginning of the collection, // only match documents greater than the previous greatest value. if (startValue !== undefined) { pipeline.unshift({ $match: { name: { $gt: startValue }, }, }); } const results = await collection.aggregate(pipeline); return results; } // Number of results to show on each page const resultsPerPage = 3; const pageOneResults = await paginateCollectionAscending( plants, resultsPerPage ); const pageTwoStartValue = pageOneResults[pageOneResults.length - 1].name; const pageTwoResults = await paginateCollectionAscending( plants, resultsPerPage, pageTwoStartValue ); // ... can keep paginating for as many plants as there are in the collection
문서 필드 프로젝트
$project 단계를 사용하여 문서의 특정 필드를 포함 또는 생략하거나 애그리게이션 연산자 를 사용하여 새 필드를 계산할 수 있습니다. 프로젝션은 두 가지 방식으로 작동합니다.
값이 '1'인 필드를 명시적으로 포함합니다. 이 방법에는 지정되지 않은 모든 필드를 암시적으로 제외하는 부작용이 있습니다.
값이 '0'인 필드를 암시적으로 제외합니다. 이 방법에는 지정되지 않은 모든 필드를 암시적으로 포함하는 부작용이 있습니다.
이 두 가지 프로젝션 방법은 상호 배타적입니다. 필드를 명시적으로 포함하는 경우 필드를 명시적으로 제외할 수 없으며 그 반대의 경우도 마찬가지입니다.
참고
_id
필드는 특별한 경우에 해당하며 명시적으로 지정하지 않는 한 항상 모든 쿼리에 포함됩니다. 따라서 0
값이 있는 _id
필드를 제외하는 동시에 1
을 사용해 _partition
등의 다른 필드를 포함하는 것이 가능합니다. _id
필드를 제외하는 특수한 경우에만 하나의 $project
단계에서 제외와 포함을 동시에 적용할 수 있습니다.
{ "$project": { "<Field Name>": <0 | 1 | Expression>, ... } }
예시
다음 $project
단계에서는 _id
필드를 생략하고 name
필드를 포함하며 storeNumber
라는 새 필드를 생성합니다. storeNumber
는 다음 집계 연산자 두 개를 사용하여 생성됩니다.
$split
값_partition
을 공백 문자를 둘러싼 두 개의 문자열 세그먼트로 분리합니다. 예를 들어 이처럼 '매장 42'로 분할된 값은 다음과 같이 '매장' 및 '42'의 두 개의 요소가 있는 배열을 반환합니다.$arrayElemAt
두 번째 인수를 기반으로 배열에서 특정 요소를 선택합니다. 이 경우 배열 인덱스는0
이므로 값1
은$split
연산자로 생성된 배열에서 두 번째 요소를 선택합니다. 예를 들어 이 연산에 전달된 값 ['매장', '42']는 값 '42'를 반환합니다.
const result = await plants.aggregate([ { $project: { _id: 0, name: 1, storeNumber: { $arrayElemAt: [{ $split: ["$_partition", " "] }, 1], }, }, }, ]); console.log(result);
[ { "name": "venus flytrap", "storeNumber": "42" }, { "name": "thai basil", "storeNumber": "42" }, { "name": "helianthus", "storeNumber": "42" }, { "name": "wisteria lilac", "storeNumber": "42" }, { "name": "daffodil", "storeNumber": "42" }, { "name": "sweet basil", "storeNumber": "47" } ]
문서에 필드 추가
$addFields 단계에서 애그리게이션 연산자를 사용하여 계산된 값이 있는 새 필드를 추가할 수 있습니다.
{ $addFields: { <newField>: <expression>, ... } }
참고
$addFields
는 $project와 유사하지만 필드를 포함하거나 생략할 수 없습니다.
예시
다음 $addFields
단계에서는 storeNumber
라는 새 필드를 만듭니다. 여기서 값은 _partition
필드의 값을 변환하는 두 집계 연산자의 출력입니다.
const result = await plants.aggregate([ { $addFields: { storeNumber: { $arrayElemAt: [{ $split: ["$_partition", " "] }, 1], }, }, }, ]); console.log(result);
[ { "_id": ObjectId("5f87976b7b800b285345a8c4"), "_partition": "Store 42", "color": "white", "name": "venus flytrap", "storeNumber": "42", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f87976b7b800b285345a8c6"), "_partition": "Store 42", "color": "green", "name": "thai basil", "storeNumber": "42", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87976b7b800b285345a8c7"), "_partition": "Store 42", "color": "yellow", "name": "helianthus", "storeNumber": "42", "sunlight": "full", "type": "annual" }, { "_id": ObjectId("5f87a0dffc9013565c233612"), "_partition": "Store 42", "color": "purple", "name": "wisteria lilac", "storeNumber": "42", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87a0dffc9013565c233613"), "_partition": "Store 42", "color": "yellow", "name": "daffodil", "storeNumber": "42", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f1f63055512f2cb67f460a3"), "_partition": "Store 47", "color": "green", "name": "sweet basil", "storeNumber": "47", "sunlight": "full", "type": "perennial" } ]
배열 값 풀기
$unwind 단계를 사용하여 배열이 포함된 단일 문서를 해당 배열의 개별 값이 포함된 여러 문서로 변환할 수 있습니다. 배열 필드를 풀면 MongoDB는 배열 필드의 각 요소에 대해 각 문서를 한 번씩 복사하지만 배열 값을 각 사본의 배열 요소로 바꿉니다.
{ $unwind: { path: <Array Field Path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
예시
다음 예시에서는 각 객체의 type
및 color
조합에 대해 $unwind
단계를 사용합니다. 집계 파이프라인은 다음과 같은 단계로 이루어져 있습니다.
$addToSet
를 포함해$group
단계를 사용하여 컬렉션에 있는 해당 꽃 유형의 모든 색상 배열을 포함하는 새 필드colors
를 사용하여 각type
별로 새 문서를 생성합니다.$unwind
단계를 사용하여 각 유형 및 색상 조합에 대해 별도의 문서를 생성합니다.$sort
단계를 사용하여 결과를 알파벳 순서로 정렬합니다.
const result = await plants.aggregate([ { $group: { _id: "$type", colors: { $addToSet: "$color" } } }, { $unwind: { path: "$colors" } }, { $sort: { _id: 1, colors: 1 } }, ]); console.log(result);
[ { "_id": "annual", "colors": "yellow" }, { "_id": "perennial", "colors": "green" }, { "_id": "perennial", "colors": "purple" }, { "_id": "perennial", "colors": "white" }, { "_id": "perennial", "colors": "yellow" }, ]