Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

MongoDB 쿼리 - .NET SDK

이 페이지의 내용

  • 사용 사례
  • 전제 조건
  • 설정
  • 데이터 예시
  • 클래스 매핑
  • 문서 만들기
  • 단일 문서 삽입
  • 여러 문서를 삽입합니다.
  • 문서 읽기
  • 단일 문서 찾기
  • 여러 문서 찾기
  • collection의 문서 수 계산
  • 문서 업데이트
  • 단일 문서 업데이트
  • 여러 문서 업데이트하기
  • 문서 업서트
  • 문서 삭제
  • 단일 문서 삭제
  • 여러 문서 삭제
  • 문서 애그리게이션
  • 컬렉션의 문서 그룹화
  • 문서 필터링
  • 프로젝트 데이터

쿼리 API 가 MongoDB Atlas .NET Realm .NET 포함된 SDK의MongoClient 를 사용하여 애플리케이션 코드에서 직접 에 저장된 데이터를 쿼리 할 수 있습니다. Atlas App Services 는 로그인한 사용자 또는 각 문서 의 콘텐츠를 기반으로 결과를 안전하게 조회 할 수 있도록 컬렉션에 대한 데이터 액세스 규칙 을 제공합니다.

다음 작업을 수행하면 Realm .NET SDK를 사용하여 .NET 애플리케이션에서 연결된 MongoDB Atlas 클러스터에 액세스할 수 있습니다.

참고

이 페이지에 설명된 각 작업은 쿼리 를 사용하여 작업이 실행되는 컬렉션의 특정 문서를 일치시킵니다. 필터가 컬렉션의 여러 문서와 일치하면 정렬 매개 변수를 지정하지 않는 한 확정되지 않은 순서 로 반환됩니다. 즉, findOne(), updateOne() 또는 deleteOne() 함수에 대해 정렬을 지정하지 않으면 쿼리와 일치하는 모든 문서와 작업이 일치할 수 있습니다. 정렬에 대한 자세한 내용은 cursor.sort()를 참조하세요.

MongoDB 데이터 소스를 쿼리해야 하는 이유는 여러 가지가 있습니다. Atlas Device Sync를 통해 클라이언트의 데이터로 작업하는 것이 항상 실용적이거나 가능한 것은 아닙니다. 다음과 같은 경우에는 MongoDB를 쿼리해야 할 수 있습니다.

  • 데이터 세트의 용량이 크거나, 클라이언트 디바이스로 데이터 세트 전체를 로드하는 데 제약이 있을 경우

  • 사용자 지정 사용자 데이터 생성 또는 업데이트를 실행하려는 경우

  • Realm에서 모델링되지 않은 문서를 검색하려는 경우

  • 앱으로 엄격한 스키마가 없는 컬렉션에 액세스해야 하는 경우

  • 비Realm 서비스를 통해 액세스하고자 하는 컬렉션을 생성할 경우

다음 내용은 MongoDB를 직접 쿼리할 수 있는 일반적인 사용 사례입니다. 단, 해당 사례들이 전부는 아닙니다.

애플리케이션에서 를 쿼리하려면 MongoDB .NET MongoDB 먼저 에서 데이터 액세스를 설정해야 App Services App 합니다. Realm SDK가 Atlas 를 쿼리할 수 있도록 백엔드 앱을 설정하는 방법을 알아보려면 Atlas 앱 서비스 문서에서 MongoDB 데이터 액세스 설정 을 참조하세요.

MongoDB Atlas cluster의 데이터로 직접 작업하려면 먼저 MongoClient 객체를 인스턴스화하고 Realm 앱에 Atlas 서비스 이름을 전달합니다. 그런 다음 작업하려는 각 컬렉션에 대해 MongoClient.DatabaseMongoClient.Collection 을 인스턴스화합니다. 다음 코드는 기본 'mongodb-atlas' Atlas 서비스 이름을 사용하고 'inventory' 데이터베이스의 'plants' 컬렉션에 대해 MongoClient.Collection 를 생성합니다.

mongoClient = user.GetMongoClient("mongodb-atlas");
dbPlantInventory = mongoClient.GetDatabase("inventory");
plantsCollection = dbPlantInventory.GetCollection<Plant>("plants");

이 페이지의 예시에서는 식물 매장 체인에서 판매되는 다양한 식물을 설명하는 다음 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" }

MongoDB에서 객체로 작업할 때는 BSON 객체에 대응하는 .NET 클래스(POCO)를 생성해야 합니다. 이를 통해 일반 BsonDocument 객체로 작업하는 대신 객체를 직접 직렬화 및 역직렬화할 수 있습니다. 이 페이지의 모든 예에서는 이러한 목적으로 다음 Plant 매핑 클래스를 사용하고 있습니다.

public partial class Plant : IRealmObject
{
[BsonElement("_id")]
public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
[BsonElement("name")]
public string? Name { get; set; }
[BsonElement("sunlight")]
[BsonRepresentation(BsonType.String)]
public string? Sunlight { get; set; }
[BsonElement("color")]
[BsonRepresentation(BsonType.String)]
public string? Color { get; set; }
[BsonElement("type")]
[BsonRepresentation(BsonType.String)]
public string? Type { get; set; }
[BsonElement("_partition")]
public string? Partition { get; set; }
}
public enum Sunlight
{
Full,
Partial
}
public enum PlantColor
{
White,
Green,
Yellow,
Purple
}
public enum PlantType
{
Perennial,
Annual
}

참고

사용자 지정 생성자를 제공하기로 선택한 경우 인수 없이 공용 생성자를 선언해야 합니다.

매핑 클래스 사용에 대한 자세한 내용은 매핑 클래스 를 참조하세요. MongoDB .NET 드라이버 설명서에서 확인 가능합니다.

MongoDB 데이터 저장소에서 문서를 만들려면 매핑 클래스를 인스턴스화하고 새 객체를 InsertOneAsync() 에 전달합니다. InsertManyAsync()를 사용하여 여러 문서를 만들고 단일 호출에 삽입할 수도 있습니다.

InsertOneAsync()를 사용하여 단일 문서를 삽입할 수 있습니다.

다음 스니펫은 'Venus Flytrap' 식물을 설명하는 단일 문서를 'plants' 컬렉션에 삽입합니다.

var plant = new Plant
{
Name = "Venus Flytrap",
Sunlight = Sunlight.Full.ToString(),
Color = PlantColor.White.ToString(),
Type = PlantType.Perennial.ToString(),
Partition = "Store 42"
};
var insertResult = await plantsCollection.InsertOneAsync(plant);
var newId = insertResult.InsertedId;

InsertManyAsync()를 사용하여 여러 문서를 동시에 삽입할 수 있습니다.

다음 스니펫은 객체를 인스턴스화하고 이를 List<Plant>에 추가한 다음 해당 목록을 InsertManyAsync()에 전달하여 4개의 Plant 객체를 'plants' 컬렉션에 삽입합니다.

var sweetBasil = new Plant
{
Name = "Sweet Basil",
Sunlight = Sunlight.Partial.ToString(),
Color = PlantColor.Green.ToString(),
Type = PlantType.Annual.ToString(),
Partition = "Store 42"
};
var thaiBasil = new Plant
{
Name = "Thai Basil",
Sunlight = Sunlight.Partial.ToString(),
Color = PlantColor.Green.ToString(),
Type = PlantType.Perennial.ToString(),
Partition = "Store 42"
};
var helianthus = new Plant
{
Name = "Helianthus",
Sunlight = Sunlight.Full.ToString(),
Color = PlantColor.Yellow.ToString(),
Type = PlantType.Annual.ToString(),
Partition = "Store 42"
};
var petunia = new Plant
{
Name = "Petunia",
Sunlight = Sunlight.Full.ToString(),
Color = PlantColor.Purple.ToString(),
Type = PlantType.Annual.ToString(),
Partition = "Store 47"
};
var listofPlants = new List<Plant>
{
sweetBasil,
thaiBasil,
helianthus,
petunia
};
var insertResult = await plantsCollection.InsertManyAsync(listofPlants);
var newIds = insertResult.InsertedIds;

데이터 저장소에서 문서를 검색하려면 Atlas Search에 사용할 속성을 정의하는 BsonDocument 필터를 만든 다음 해당 필터를 FindOneAsync() 또는 FindAsync() 에 전달합니다. CountAsync()를 호출하여 필터와 일치하는 모든 문서의 개수를 가져올 수도 있습니다.

다음 예시에서는 'name' 속성이 'petunia'인 식물을 찾는 방법을 보여 줍니다.

var petunia = await plantsCollection.FindOneAsync(
new { name = "Petunia" },
null);

다음 예시에서는 'type' 속성이 'perennial'인 모든 식물을 찾는 방법을 보여 줍니다.

var allPerennials = await plantsCollection.FindAsync(
new { type = PlantType.Perennial.ToString() },
new { name = 1 });

중요

정렬 순서를 지정하는 세 번째 매개 변수 FindAsync()를 사용하고 있습니다. 둘 이상의 문서를 쿼리하는 경우 일관된 결과를 보장하기 위해 정렬 순서를 포함해야 합니다.

다음 예시에서는 컬렉션에 있는 모든 식물의 수를 반환합니다.

var allPlants = await plantsCollection.CountAsync();

MongoDB 데이터 저장소의 기존 문서를 업데이트하려면 Atlas Search의 대상 속성을 정의하는 BsonDocument 필터를 만든 다음 변경하려는 속성을 정의하는 두 번째 BsonDocument 를 만듭니다. 하나의 문서만 업데이트하는 경우 두 객체를 모두 UpdateOneAsync() 에 전달합니다. 여러 문서를 일괄 업데이트하려면 UpdateManyAsync()를 호출합니다.

다음 코드는 'name' 속성이 'petunia'인 식물을 찾아 'sunlight' 속성을 'partial'로 변경합니다:

var updateResult = await plantsCollection.UpdateOneAsync(
new { name = "Petunia" },
new BsonDocument("$set", new BsonDocument("sunlight", Sunlight.Partial.ToString()))
);

다음 코드는 '_partition' 값이 'store 47'인 모든 식물을 찾아 모두 'area 51'로 변경합니다:

var filter = new { _partition = "Store 47" };
var updateDoc = new BsonDocument("$set",
new BsonDocument("_partition", "Area 51"));
var updateResult = await plantsCollection.UpdateManyAsync(
filter, updateDoc);

UpdateOneAsync()UpdateManyAsync() 에는 모두 업데이트가 업서트여야 하는지(즉, 문서가 존재하지 않는 경우 생성해야 하는지) 여부를 지정하는 선택적 부울 속성이 있습니다. 기본적으로 업서트는 수행되지 않습니다.

다음 예에서는 name 속성이 'Pothos', type 속성이 'perennial', sunlight 속성이 'full'인 식물을 찾습니다. 이러한 기준과 일치하는 식물이 있는 경우 메서드는 식물의 _partition 값을 'Store 42'로 업데이트합니다. 컬렉션에 해당 이름의 식물이 없는 경우 메서드는 업데이트를 포함한 정의된 모든 속성을 사용하여 새 식물을 만듭니다.

var filter = new BsonDocument()
.Add("name", "Pothos")
.Add("type", PlantType.Perennial.ToString())
.Add("sunlight", Sunlight.Full.ToString());
var updateResult = await plantsCollection.UpdateOneAsync(
filter,
new BsonDocument("$set", new BsonDocument("_partition", "Store 42")),
upsert: true);
/* The upsert will create the following object:
{
"name": "pothos",
"sunlight": "full",
"type": "perennial",
"_partition": "Store 42"
}
*/

문서를 삭제하는 프로세스는 문서를 만들거나 업데이트하는 것과 거의 동일합니다. 즉, 일치시키려는 속성을 정의하는 BsonDocument 를 만든 다음 DeleteOneAsync() 를 호출합니다. 또는 DeleteManyAsync().

다음 예에서는 'name' 속성 값이 'Thai Basil'인 첫 번째 문서를 삭제합니다.

var filter = new BsonDocument("name", "Thai Basil");
var deleteResult = await plantsCollection.DeleteOneAsync(filter);

다음 예에서는 'type' 속성 값이 'annual'인 모든 문서를 삭제합니다.

var filter = new BsonDocument("type", PlantType.Annual);
var deleteResult = await plantsCollection.DeleteManyAsync(filter);

집계 작업은 집계 파이프라인이라고 하는 일련의 데이터 집계 단계를 통해 컬렉션의 모든 문서를 실행합니다. 집계를 통해 문서 필터링 및 변환, 관련 문서 그룹에 대한 요약 데이터 수집 등의 복잡한 데이터 작업을 수행할 수 있습니다.

애그리게이션 작업은 애그리게이션 단계의 배열을 입력으로 받아들이고 작업 을 반환합니다. 파이프라인에서 처리한 문서 컬렉션으로 확인됩니다.

참고

Compass는 집계 파이프라인을 빌드하고 이를 C# 및 기타 언어로 내보낼 수 있는 유틸리티를 제공합니다. 자세한 내용은 집계 파이프라인 빌더 를 참조하세요.

.NET SDK는 AggregateAsync() 메서드 및 일반 오버로드를 사용하여 컬렉션에 대한 집계를 지원합니다.

다음 예에서는 식물 컬렉션의 모든 문서를 type 값으로 그룹화하고 각 유형의 수를 집계한 다음 오름차순으로 정렬합니다.

var groupStage =
new BsonDocument("$group",
new BsonDocument
{
{ "_id", "$type" },
{ "count", new BsonDocument("$sum", 1) }
});
var sortStage = new BsonDocument("$sort",
new BsonDocument("_id", 1));
var aggResult = await plantsCollection.AggregateAsync(groupStage, sortStage);
foreach (var item in aggResult)
{
var id = item["_id"];
var count = item["count"];
Console.WriteLine($"Plant type: {id}; count: {count}");
}

위 예제에서는 일련의 중첩된 BsonDocuments를 사용하여 파이프라인을 빌드하는데, 이 경우 작성 및 디버깅이 복잡해질 수 있습니다. Query API 에 이미 익숙하다면 쿼리를 로 전달할 수 string 있습니다.BsonDocument_Parse() 메서드. 다음 예제에서는 이전 예제와 동일한 애그리게이션을 수행합니다.

var groupStep = BsonDocument.Parse(@"
{
$group: {
_id: '$type',
count: {
$sum: 1
}
}
}
");
var sortStep = BsonDocument.Parse("{$sort: { _id: 1}}");
aggResult = await plantsCollection.AggregateAsync(groupStep, sortStep);
foreach (var item in aggResult)
{
var id = item["_id"];
var count = item["count"];
Console.WriteLine($"Id: {id}, Count: {count}");
}

$match 단계를 사용하여 표준 MongoDB 쿼리 구문을 사용하여 문서를 필터링할 수 있습니다.

다음 예에서는 집계를 사용할 때 문서를 필터링하는 방법을 보여줍니다. 이 집계 파이프라인이 Plant 객체의 컬렉션을 반환한다는 것을 알고 있으므로 AggregateAsync() 메서드의 일반적인 재정의를 사용합니다.

var matchStage = new BsonDocument("$match",
new BsonDocument("type",
new BsonDocument("$eq",
PlantType.Perennial)));
// Alternate approach using BsonDocument.Parse(...)
matchStage = BsonDocument.Parse(@"{
$match: {
type: { $eq: '" + PlantType.Perennial + @"' }
}}");
var sortStage = BsonDocument.Parse("{$sort: { _id: 1}}");
var aggResult = await plantsCollection.AggregateAsync<Plant>(matchStage, sortStage);
foreach (var plant in aggResult)
{
Console.WriteLine($"Plant Name: {plant.Name}, Color: {plant.Color}");
}

$project 단계를 사용하여 문서의 특정 필드를 포함 또는 생략하거나 애그리게이션 연산자 를 사용하여 새 필드를 계산할 수 있습니다. 프로젝션은 두 가지 방식으로 작동합니다.

  • 값이 '1'인 필드를 명시적으로 포함합니다. 이 방법에는 지정되지 않은 모든 필드를 암시적으로 제외하는 부작용이 있습니다.

  • 값이 '0'인 필드를 암시적으로 제외합니다. 이 방법에는 지정되지 않은 모든 필드를 암시적으로 포함하는 부작용이 있습니다.

이 두 가지 프로젝션 방법은 상호 배타적입니다. 필드를 명시적으로 포함하는 경우 필드를 명시적으로 제외할 수 없으며 그 반대의 경우도 마찬가지입니다.

참고

_id 필드는 특별한 경우에 해당하며 명시적으로 지정하지 않는 한 항상 모든 쿼리에 포함됩니다. 따라서 0 값이 있는 _id 필드를 제외하는 동시에 1을 사용해 _partition 등의 다른 필드를 포함하는 것이 가능합니다. _id 필드를 제외하는 특수한 경우에만 하나의 $project 단계에서 제외와 포함을 동시에 적용할 수 있습니다.

다음 예에서는 집계를 사용할 때 프로젝트를 사용하는 방법을 보여줍니다. 이 예에서는 다음을 참고합니다:

  1. 'Id' 속성 제외,

  2. 'Partition', 'Type', 'Name' 속성 포함,

  3. 'storeNumber'라는 새 속성 생성. 이 속성은 _partition 값을 공백으로 분할하고 두 번째 부분만 반환하여 작성됩니다.

var projectStage = new BsonDocument("$project",
new BsonDocument
{
{ "_id", 0 },
{ "_partition", 1 },
{ "type", 1 },
{ "name", 1 },
{ "storeNumber",
new BsonDocument("$arrayElemAt",
new BsonArray {
new BsonDocument("$split",
new BsonArray
{
"$_partition",
" "
}), 1 }) }
});
var sortStage = BsonDocument.Parse("{$sort: { storeNumber: 1}}");
var aggResult = await plantsCollection.AggregateAsync(projectStage, sortStage);
foreach (var item in aggResult)
{
Console.WriteLine($"{item["name"]} is in store #{item["storeNumber"]}.");
}

다음은 BsonDocument.Parse() 메서드를 사용하여 projectStage를 빌드하는 방법도 보여줍니다:

projectStage = BsonDocument.Parse(@"
{
_id:0,
_partition: 1,
type: 1,
name: 1,
storeNumber: {
$arrayElemAt: [
{ $split:[
'$_partition', ' '
]
}, 1 ]
}
}");

돌아가기

함수 호출