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.
The following actions enable access to a linked MongoDB Atlas cluster from a .NET application using the Realm .NET SDK.
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().
Casos de uso
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:
The data set is large or the client device has constraints against loading the entire data set
Estás recuperando documentos que no están modelados en Realm
Your app needs to access collections that don't have strict schemas
A non-Realm service generates collections that you want to access
While not exhaustive, these are some common use cases for querying MongoDB directly.
Requisitos previos
Antes de que puedas consultar MongoDB desde tu aplicación .NET, debes configurar el acceso a datos de MongoDB en tu App Services App. Para aprender a configurar tu aplicación backend para permitir que el SDK de Realm consulte Atlas, consulta Configurar el acceso a los datos de MongoDB en la documentación de App Services.
Configuración
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");
Datos de ejemplo
Los ejemplos en esta página usan 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" }
Clases de mapeo
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 { [] public ObjectId Id { get; set; } = ObjectId.GenerateNewId(); [] public string? Name { get; set; } [] [] public string? Sunlight { get; set; } [] [] public string? Color { get; set; } [] [] public string? Type { get; set; } [] public string? Partition { get; set; } } public enum Sunlight { Full, Partial } public enum PlantColor { White, Green, Yellow, Purple } public enum PlantType { Perennial, Annual }
Nota
If you choose to provide custom constructors, you must declare a public constructor with no arguments.
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.
Crear documentos
Para crear un documento en el almacén de datos de MongoDB, debes instanciar la clase de mapeo y pasar el nuevo objeto a InsertOneAsync(). También puedes crear varios documentos e insertarlos en una única llamada utilizando InsertManyAsync().
Inserta un solo documento
Puedes insertar un único documento usando InsertOneAsync().
El siguiente snippet inserta un solo documento que describe una planta "Venus Atrapamoscas" en nuestra colección "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;
Inserta varios documentos
You can insert multiple documents at the same time by using 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;
Lea los documentos
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().
Find a Single Document
El siguiente ejemplo muestra cómo encontrar una planta donde la propiedad "name" sea "petunia":
var petunia = await plantsCollection.FindOneAsync( new { name = "Petunia" }, null);
Encuentra varios documentos
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
We are using the third parameter of FindAsync(), which specifies the sort order. If you are querying for more than one document, you should include the sort order to ensure consistent results.
Contar documentos en la colección
El siguiente ejemplo devuelve un recuento de todas las plantas de la colección:
var allPlants = await plantsCollection.CountAsync();
Update Documents
Para actualizar un documento existente en el almacén de datos de MongoDB, crea un filtro BsonDocument que defina las propiedades que quieres buscar y luego crea un segundo filtro BsonDocument que defina las propiedades que quieres cambiar. Si solo se actualiza un documento, se pasan ambos objetos a UpdateOneAsync(). Si quieres realizar una actualización masiva de varios documentos, llama a UpdateManyAsync().
Actualiza un solo documento
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())) );
Actualiza varios documentos
The following code finds all plants with a "_partition" value of "store 47" and changes them all to "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);
Realizar inserción de documentos
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" } */
Delete Documents
El proceso para borrar documentos es muy similar al de crear (o actualizar) documentos: se crea un BsonDocument que define las propiedades que se desea hacer coincidir, y luego se llama a DeleteOneAsync(). o DeleteManyAsync().
Borrar un único documento
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);
Borra varios documentos
The following example deletes all documents that have a "type" property value of "annual":
var filter = new BsonDocument("type", PlantType.Annual); var deleteResult = await plantsCollection.DeleteManyAsync(filter);
Documentos agregados
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.
Aggregation operations accept an array of aggregation stages as input, and return a Task that resolves to a collection of documents processed by the pipeline.
Nota
Compass provides a utility for building aggregation pipelines and exporting them to C# and other languages. For more information, see Aggregation Pipeline Builder.
Agrupa documentos en una colección
The .NET SDK supports aggregation on a collection with the AggregateAsync() method and its generic overload.
The following example groups all documents in the plants collection by their type value, aggregates a count of the number of each type, and then sorts them in ascending order:
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}"); }
Filtrar Documentos
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}"); }
Project Data
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:
Incluya de forma explícita campos con un valor de 1. Esto tiene el efecto secundario de excluir, de forma implícita, todos los campos no especificados.
Implicitly exclude fields with a value of 0. This has the side-effect of implicitly including all unspecified fields.
Estos dos métodos de proyección son mutuamente excluyentes: si incluyes explícitamente campos, no puedes excluir explícitamente campos y viceversa.
Nota
The _id field is a special case: it is always included in every query unless explicitly specified otherwise. For this reason, you can exclude the _id field with a 0 value while simultaneously including other fields, like _partition, with a 1. Only the special case of exclusion of the _id field allows both exclusion and inclusion in one $project stage.
El siguiente ejemplo muestra cómo usar el proyecto al usar la agregación. En este ejemplo:
Excluding the "Id" property,
Including the "Partition", "Type", and "Name" properties,
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 ] } }");