Docs Menu
Docs Home
/ /
Servicios de aplicaciones

Consulta MongoDB - SDK .NET

Puede consultar datos almacenados en MongoDB Atlas directamente desde el código de su aplicación .NET utilizando el SDK de Realm .NET MongoClient con la API de consulta. Atlas App Services proporciona reglas de acceso a datos en colecciones para recuperar resultados de forma segura según el usuario conectado o el contenido de cada documento.

Las siguientes acciones permiten el acceso a un clúster MongoDB Atlas vinculado desde una aplicación .NET mediante el SDK Realm .NET.

Nota

Cada operación descrita en esta página utiliza una consulta para buscar coincidencias en determinados documentos de la colección en la que se ejecuta la operación. Cuando un filtro busca coincidencias en varios documentos de una colección, estos se devuelven en un orden indeterminado a menos que se especifique un parámetro de ordenación. Esto significa que si no se especifica una ordenación para los... findOne(), o, updateOne() deleteOne() su operación podría coincidir con cualquier documento que coincida con la consulta. Para más información sobre la ordenación, consulte cursor.sort().

Existen variedad de razones por las que podría querer query una fuente de datos de MongoDB. Trabajar con datos en tu cliente a través de Atlas Device Sync no siempre es práctico o posible. Podrías querer query MongoDB cuando:

  • El conjunto de datos es grande o el dispositivo cliente tiene restricciones para cargar todo el conjunto de datos

  • Está creando o actualizando datos de usuario personalizados

  • Estás recuperando documentos que no están modelados en Realm

  • Su aplicación necesita acceder a colecciones que no tienen esquemas estrictos

  • Un servicio que no es de Realm genera colecciones a las que desea acceder

Si bien no son exhaustivos, estos son algunos casos de uso comunes para consultar MongoDB directamente.

Antes de poder consultar MongoDB desde su aplicación .NET, debe configurar el acceso a datos de MongoDB en su aplicación de App Services. Para saber cómo configurar su aplicación backend para que el SDK de Realm pueda consultar Atlas, consulte "Configurar el acceso a datos de MongoDB" en la documentación de App Services.

Para trabajar directamente con los datos de su clúster de MongoDB Atlas, primero instancia un objeto MongoClient, pasando el nombre del servicio de atlas en su aplicación Realm. A continuación, instancia un objeto MongoClient.Database y un objeto MongoClient.Collection para cada colección con la que desee trabajar. El siguiente código usa el nombre predeterminado del servicio Atlas, "mongodb-atlas", y crea un MongoClient.Collection para la colección "plantas" en la base de datos "inventario":

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

Los ejemplos de esta página utilizan la siguiente colección MongoDB que describe varias plantas a la venta en una cadena de tiendas de plantas:

{ _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" }

Al trabajar con objetos en MongoDB, debe crear clases .NET (POCOs) que correspondan a los objetos BSON. Esto le permite serializar y deserializar los objetos directamente, en lugar de trabajar con objetos BsonDocument genéricos. En todos los ejemplos de esta página, estamos utilizando la siguiente clase de mapeo Plant para este propósito:

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
}

Nota

Si elige proporcionar constructores personalizados, debe declarar un constructor público sin argumentos.

Para obtener más información sobre el uso de clases de mapeo, consulte Clases de mapeo en la documentación del controlador MongoDB .NET.

Para crear un documento en el almacén de datos de MongoDB, se instancia la clase de mapeo y se pasa el nuevo objeto a InsertOneAsync(). También se pueden crear varios documentos e insertarlos en una sola llamada mediante InsertManyAsync().

Puede insertar un solo documento utilizando InsertOneAsync().

El siguiente fragmento inserta un único documento que describe una planta "Venus atrapamoscas" en nuestra colección de "plantas":

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;

Puede insertar varios documentos al mismo tiempo utilizando InsertManyAsync().

El siguiente fragmento inserta cuatro objetos Plant en la colección "plantas" instanciando los objetos, agregándolos a un List<Plant> y pasando esa lista a InsertManyAsync():

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;

Para recuperar documentos del almacén de datos, cree un BsonDocument filtro que defina las propiedades que desea buscar y, a continuación, páselo a FindOneAsync() o FindAsync(). También puede obtener el recuento de todos los documentos que coinciden con el filtro llamando a CountAsync().

El siguiente ejemplo muestra cómo encontrar una planta donde la propiedad "name" sea "petunia":

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

El siguiente ejemplo muestra cómo encontrar todas las plantas donde la propiedad "tipo" es "perenne":

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

Importante

Usamos el tercer parámetro de FindAsync(), que especifica el orden de clasificación. Si consulta más de un documento, debe incluir el orden de clasificación para garantizar resultados consistentes.

El siguiente ejemplo devuelve un recuento de todas las plantas de la colección:

var allPlants = await plantsCollection.CountAsync();

Para actualizar un documento existente en el almacén de datos de MongoDB, cree un BsonDocument filtro que defina las propiedades que desea buscar y, a continuación, cree un segundo filtro BsonDocument que defina las propiedades que desea modificar. Si solo actualiza un documento, pase ambos objetos a UpdateOneAsync(). Si desea actualizar varios documentos en bloque, llame a UpdateManyAsync().

El siguiente código busca la planta cuya propiedad "nombre" es "petunia" y cambia su propiedad "luz solar" a "parcial":

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

El siguiente código busca todas las plantas con un valor "_partition" de "store 47" y las cambia todas a "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);

Tanto UpdateOneAsync() como UpdateManyAsync() tienen una propiedad booleana opcional que especifica si la actualización debe ser una inserción (upsert) (es decir, si el documento no existe, debe crearse). De forma predeterminada, no se realiza ninguna inserción.

El siguiente ejemplo busca una planta cuya propiedad name sea "Pothos", la propiedad type sea "perenne" y la propiedad sunlight sea "completamente". Si una planta cumple con estos criterios, el método actualizará el valor _partition de la planta a "Tienda 42". Si no existe ninguna planta en la colección con ese nombre, el método creará una nueva planta con todas las propiedades definidas, incluida la actualización.

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"
}
*/

El proceso para eliminar documentos es muy similar al de crear (o actualizar) documentos: se crea un BsonDocument que define las propiedades que desea que coincidan y luego se llama a DeleteOneAsync() o a DeleteManyAsync().

El siguiente ejemplo elimina el primer documento que encuentra con un valor de propiedad "nombre" de "Albahaca tailandesa":

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

El siguiente ejemplo elimina todos los documentos que tienen un valor de propiedad "tipo" de "anual":

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

Las operaciones de agregación ejecutan todos los documentos de una colección a través de una serie de etapas de agregación de datos denominadas canalización de agregación. La agregación permite filtrar y transformar documentos, recopilar datos resumidos sobre grupos de documentos relacionados y realizar otras operaciones complejas de datos.

Las operaciones de agregación aceptan una matriz de etapas de agregación como entrada y devuelven una tarea que se resuelve en una colección de documentos procesados ​​por la canalización.

Nota

Compass ofrece una utilidad para crear pipelines de agregación y exportarlos a C# y otros lenguajes. Para más información, consulte Generador de pipelines de agregación.

El SDK .NET admite la agregación en una colección con el método AggregateAsync() y su sobrecarga genérica.

El siguiente ejemplo agrupa todos los documentos de la colección de plantas por su valor type, agrega un recuento de la cantidad de cada tipo y luego los ordena en orden ascendente:

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}");
}

El ejemplo anterior crea la canalización con una serie de BsonDocuments anidados, cuya escritura y depuración pueden resultar complejas. Si ya está familiarizado con la API de consultas, puede pasar consultas como una cadena al método BsonDocument_Parse(). El siguiente ejemplo realiza la misma agregación que el anterior:

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}");
}

Puede utilizar la etapa $match para filtrar documentos utilizando la sintaxis de consulta estándar de MongoDB.

El siguiente ejemplo muestra cómo filtrar documentos cuando se utiliza la agregación. Dado que sabemos que esta pipeline de agregación devuelve una colección de objetos Plant, utilizamos la sobrecarga genérica del método 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}");
}

Puede usar la etapa $project para incluir u omitir campos específicos de los documentos o para calcular nuevos campos mediante operadores de agregación. Las proyecciones funcionan de dos maneras:

  • Incluir explícitamente los campos con el valor 1. Esto tiene el efecto secundario de excluir implícitamente todos los campos no especificados.

  • Excluye implícitamente los campos con un valor de 0. Esto tiene el efecto secundario de incluir implícitamente todos los campos no especificados.

Estos dos métodos de proyección son mutuamente excluyentes: si incluye campos explícitamente, no puede excluirlos explícitamente, y viceversa.

Nota

El _id campo es un caso especial: siempre se incluye en todas las consultas, a menos que se especifique lo contrario. Por esta razón, se puede excluir el _id campo con un 0 valor e incluir simultáneamente otros campos,_partition como, con un 1 valor. Solo el caso especial de exclusión del _id campo permite tanto la exclusión como la inclusión en una sola $project etapa.

El siguiente ejemplo muestra cómo usar el proyecto al usar la agregación. En este ejemplo:

  1. Excluyendo la propiedad "Id",

  2. Incluidas las propiedades "Partición", "Tipo" y "Nombre",

  3. Creando una nueva propiedad llamada "storeNumber", que se construye dividiendo el valor _partition en el espacio en blanco y devolviendo solo la segunda parte.

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"]}.");
}

A continuación se muestra cómo también se puede construir el projectStage utilizando el método BsonDocument.Parse():

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

Volver

Llamar a una función