Formation MongoDB M101N: semaine 2 – Driver .NET

Inclure le package .NuGet “MongoDB.Driver” dans son projet.
Plusieurs packages sont installés:
MongoDB.Drive, MongoDB.BSON et MongoDB.Driver.Core.
L’objet principal pour ouvrir une connection est MongoClient.
Pour entrer certains paramètres de connexion, il faut utiliser une connectionString.

var connectionString = "mongodb://localhost:27017";
var client = new MongoClient(connectionString);
var db = client.GetDatabase("test");
var col = db.GetCollection("person");

Représentation des documents

Pour représenter des documents en .NET, on utilise l’objet BsonDocument;

var doc = new BsonDocument
{
    { "name", "Jones" }
};

Pour ajouter une valeur:

doc.Add("age", 30);

Pour affecter une valeur:

doc["profression"] = "hacker";

Pour définir un tableau:

var nestedArray = new BsonArray();
nestedArray.Add(new BsonDocument("color", "red));
doc.Add("array", nestedArray);

Représentation POCO

Permet de mapper du POCO vers du Bson.
On peut utiliser directement des structures et préciser des attributs pour préciser des éléments sur des membres:
Par exemple:

class Person
{
    public ObjectId Id {get; set;}

    [BsonElement("name")]
    public string Name {get; set;}

    [BsonRepresentation(BsonType.String)]
    public int Age {get; set;}
}

Il est possible de préciser des données par code:

Par exemple:

BsonClassMap.RegisterClassMap<Person>(cm => *
{
    cm.AutoMap();
    cm.MapMember(x => x.Name).SetElementName("name");
});

Pour ajouter une convention qui permet d’indiquer que "name" doit être mappé vers le membre
Person.Name (avec une majuscule):

var conventionPack = new ConventionPack();
conventionPack.Add(new CamelCaseElementNameConvention());
ConventionRegistry.Register("camelcase", conventionPack, t => true);

insertOne

Pour insérer une valeur dans une collection:

var client = new MongoClient();
var db = client.GetDatabase("test");
var col = db.GetCollection<BsonDocument>("people");
var doc = new BsonDocument
{
    { "Name": "Smith" },
    { "Age": 30 },
};

Pour insérer un seul document:

await col.InsertOneAsync(doc);

Pour insérer plusieurs documents.

await col.InsertManyAsync();

Avec un classe mappée:

var person = class Person
{
    public ObjectId Id {get; set;}
    public string Name {get; set;}
    public int Age {get; set;}
};
var doc = new Person{ };
await col.InsertOneAsync(doc);

ATTENTION: on peut pas insérer 2 fois le même objet à cause de "_id" qui est valué.

Il faut que "_id" n’est pas de valeur.

find

find() permet de retourner plusieurs lignes comme le Shell:
Il faut passer par l’intermédiaire d’un curseur, on entoure l’utilisation du curseur avec un try...finally pour exécuter le close même en cas d’exception.

var col = db.GetCollection<BsonDocument>("people");
using (var cursor = qawait col.Find(new BsonDocument()).ToCursorAsync())
{
    while (await cursor.MoveNextAsync())
    {
        foreach (var doc in cursor.Current)
        {
            Console.WriteLine(doc);
        }
    }
}

Pour traiter une liste directement:

var list = await col.Find(new BsonDocument()).ToListAsync();

Avec un ForEach:

var list = await col.Find(new BsonDocument()).ForEachAsync(doc => ConsoleWriteLine(doc));

Avec des critères de sélection:

var filter = new BsonDocument("Name", "Smith");
var list = await col.Find(filter).ToListAsync();

Il est possible de passer du code Bson directement:

var list = await col.Find({ "Name" : "Smith" }).ToListAsync();

Pour entrer plus de conditions:

var filter = new BsonDocument("$and", new BsonArray
{
    new BsonDocument("Age", new BsonDocument("$lt", 30)), 
    new BsonDocument("Name", "Smith"),
});

var filter = builder.And(builder.Lt("Age", 30) & builder.Eq("Name", "Smith"));

Il est possible d’utiliser directement des POCO:

var col = db.GetCollection<Person>("people");

En utilisant des lambda expressions:

var list = await col.Find(x => x.Age < 30 && x.Name != "Smith").ToListAsync();

Skip

Permet de sauter des valeurs:

var list = await col.Find(new BsonDocument())
    .Limit(1)
    .Skip(1)
    .ToListAsync();

Sort

Pour trier des éléments:

var list = await col.Find(new BsonDocument())
    .Sort(new BsonDocument("{ Age : 1 }")
    .ToListAsync();

ou

var list = await col.Find(new BsonDocument())
    .Sort(new BsonDocument("Age", 1)
    .ToListAsync();

ou

var col = db.GetCollection<BsonDocument>("people");
var list = await col.Find(new BsonDocument())
    .Sort(Builders<BsonDocument>.Sort.Ascending("Age"))
    .ToListAsync();

En utilisant POCO;

var col = db.GetCollection<Person>("people");
var list = await col.Find(new BsonDocument())
    .Sort(Builders<Person>.Sort.Ascending("Age").Descending("Name"))
    .ToListAsync();

ou

var list = await col.Find(new BsonDocument())
    .SortBy(x => x.Age)
    .ToListAsync();

ou

var list = await col.Find(new BsonDocument())
    .Sort(Builders<Person>.Sort.Ascending(x => x.Age))
    .ToListAsync();

Projections

var list = await col.Find(new BsonDocument())
    .Project("{ Name : 1, _Id: 0}")
    .ToListAsync();

ou

var col = db.GetCollection<Person>("people");
var list = await col.Find(new BsonDocument())
    .Project<Person>(Builders<Person>.Projection.Include("Name").Exclude("_Id"))
    .ToListAsync();

ou

var col = db.GetCollection<Person>("people");
var list = await col.Find(new BsonDocument())
    .Project(x => x.Name)
    .ToListAsync();

Replace

var result = await col.ReplaceOneAsync(
    new BsonDocument("_Id", 5)
    new BsonDocument("_Id", 5).Add("x", 30)
);

Si on utilise les "_Id", il faut répéter le séquence.

var result = await col.ReplaceOneAsync(
    new BsonDocument("x", 5)
    new BsonDocument("x", 30)
);

Pour savoir si l’update a fait quelque chose, il faut regarder le résultat dans "result".
En ajoutant une option:

var result = await col.ReplaceOneAsync(
    new BsonDocument("x", 5)
    new BsonDocument("x", 30)
    new UpdateOptions { IsUpsert = true }
);

Update

Même type de syntaxe:

var result = await col.UpdateOneAsync(
    Builders<BsonDocument>.Filter.Eq("x", 5),
    new BsonDocument("$inc", new BsonDocument("x", 10))
);

ou

var result = await col.UpdateOneAsync(
    Builders<BsonDocument>.Filter.Eq("x", 5),
    Builders<BsonDocument>.Update.Inc("x", 10)
);

ou

var result = await col.UpdateOneAsync(
    x => x.X > 5,
    Builders<BsonDocument>.Update.Inc("x", 10)
);

UpdateMany permet de modifier plusieurs lignes.

Delete

Pour supprimer seulement 1 élément:

var result = await col.DeleteOneAsync(x => x.X > 5);

Ou pour supprimer plusieurs documents:

var result = await col.DeleteManyAsync(x => x.X > 5);

FindOneAndUpdate

Permet de faire une mise à jour si on trouve l’élément.

var result = await col.FindOneAndUpdateOneAsync(
    x => x.X > 5,
    Builders<BsonDocument>.Update.Inc("x", 10)
);

Le résultat contient le document qui a été modifié.
On peut rajouter des options:

var result = await col.FindOneAndUpdateOneAsync(
    x => x.X > 5,
    Builders<BsonDocument>.Update.Inc("x", 10),
    new FindOneAndUpdateOptions<Widget, Widget>
    {
         ReturnDocument = ReturnDocument.After
    }
);

Par défaut, on renvoie le document avant modification. L’option "ReturnDocument" permet de renvoyer le document après la modification.

Sort

Pour trier les éléments avant de les modifier:

var result = await col.FindOneAndUpdateOneAsync(
    x => x.X > 5,
    Builders<BsonDocument>.Update.Inc("x", 10),
    new FindOneAndUpdateOptions<Widget, Widget>
    {
        ReturnDocument = ReturnDocument.After,
        Sort = Builders<Widget>.Sort.Descending(x => x.X),
    }
);

Leave a Reply