A NoSql database provides a different way of storing and handling data then the classical sql. While in a relational environment you have to split your models into logical components and store them in different tables using relations to define how will they be grouped together, in NoSql you work with json-like formats and this allows you to store entire documents.
Designing a NoSQL database is simpler and using it provide several advantages like easier horizontal scaling to clusters of machines and finer control over availability. Data structures used by NoSQL databases are more flexible than relational database tables but if it is actually suitable for your needs…well that depends on your project.
In this article I will present several ways of using filters for retrieving data from mongo using the MongoDB C# driver. While there is some documentation available on the official site, I found that it’s easier to dive in to the actual driver’s implementation and check out how are the components that I need defined.
You can download the Mongo Driver source code from the following github page. And I strongly recomend you to do so when learning because it offers a greater insight over the internal processes.
I will continue this article by simply showing you how to use the mongo client to connect to the database, how to get the mongo collection for our book and then several ways you can define filters for the GET method.
To find out how to install and configure mongo, there is a great article provided by which offers a clear and detailed description of the process. Just follow this link
We will start by defining our model. For this example I will create a simple Book class with several properties.
Our book will have 4 properties. Notice that above each property I added some attributes that will guide the mongo driver.
BsonElement – You can opt out of using this attribute and the driver will pick up the name from the property name. However I prefer using these attributes for database consistency. If somewhere in the process I decide that a property should have a different name I will want to be able to reference the existing document properties so I prefer to keep naming them manually.
BsonId – Each document in mongo must have an Id. If you do not provide a field for it mongo will automatically create one for you. However we want to be able to access the Id. This attribute will link the Id from the database to the class property.
BsonRepresentation – In our example this attribute is not relevant, but it’s important to have this option in mind. The default Id type in mongo is an objectId. However it’s possible that for your project you consider that you want to use another type, like a string. To do so you must set the ObjectType to string. BsonRepresentation let’s you change how the document property is represented in the class.
[BsonId]
[BsonRepresentation(BsonType.String)]
public string SId { get; set; }
public class Book
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public ObjectId Id { get; set; }
[BsonElement("Name")]
public string Name { get; set; }
[BsonElement("Author")]
public string Author { get; set; }
[BsonElement("InStock")]
public bool InStock { get; set; }
}
To connect to the database and get our book collection there are several steps to meet:
Define the server address (the default values are 127.0.0.1 with port 27017)
Get the database (if the database doesn’t exist mongo will create it for us)
Get the collection (if the collection doesn’t exist mongo will create it for us)
For this example I create a list of books that will be pushed into our collection.
public static List GetBooks()
{
return new List
{
new Book { Author = "Justine Picardie", Name = "Inge Morath: On Style" , InStock = true },
new Book { Author = "Justine Picardie", Name = "If the Spirit Moves You" , InStock = false },
new Book { Author = "Justine Picardie", Name = "Wish I May", InStock = false },
new Book { Author = "Tembi Locke", Name = "From Scratch", InStock = true }
};
}
MongoServerAddress server = new MongoServerAddress("127.0.0.1", 27017);
MongoClientSettings settings = new MongoClientSettings { Server = server };
MongoClient client = new MongoClient(settings);
IMongoDatabase database = client.GetDatabase("FreeBooksLibrary");
IMongoCollection bookCollection = database.GetCollection("Books");
bookCollection.InsertMany(DbSeed.GetBooks());
You can use the amazing free tool Robo3T to see your database. Our collection has now 4 entries and you can see it’s structure:
1. Using Linq Expressions syntax
You can use linq expression to filter data. Mongo driver will convert these expressions into valid mongo syntax and pass it along through the pipeline.
2. Using the Builders to create a filter definition
FilterDefinitions are a fast and intuitive way to create filters. They require less processing then using expressions and offer a lot of methods for you to use.
Here I created 2 filters (one for each property) and I combined them using the And filter:
3. Using ExpressionFieldDefinitions and combining filters with bitwise &
ExpressionFieldDefintion – this defines a way of letting mongo know what property is it targeting by using a lambda expression
Bitwise Add – If you take a peek in the filter definition you can see that the driver has overriden bitwise operators. This means that we can easily combine filters using the & operator instead of calling the Builders<T>.Filters.And method.
Peek:
var nameFieldDefinition = new ExpressionFieldDefinition<Book, string>(x => x.Author);
var inStockFieldDefinition = new ExpressionFieldDefinition<Book, bool>(x => x.InStock);
FilterDefinition nameFilter = Builders.Filter.Eq(nameFieldDefinition, authorName);
FilterDefinition inStockFilter = Builders.Filter.Eq(inStockFieldDefinition, true);
var books = _bookCollection.Find(nameFilter & inStockFilter).ToList();
4. Using StringFieldDefinitions
FilterDefinitions require a way of knowing what property is it targeting. StringDefintion allows you to state the name of the property you are targeting
var nameFieldDefinition = new StringFieldDefinition<Book, string>("Author");
var inStockFieldDefinition = new StringFieldDefinition<Book, bool>("InStock");
FilterDefinition nameFilter = Builders.Filter.Eq(nameFieldDefinition, authorName);
FilterDefinition inStockFilter = Builders.Filter.Eq(inStockFieldDefinition, true);
var books = _bookCollection.Find(nameFilter & inStockFilter).ToList();
5. The IN operator in Mongo
You have a lot of features to chose from when defining filters. One example is using the IN operator which, similar to SQL, let’s you match a value in a list of values.
//creating a filter using the builder
FilterDefinition nameFilter2 = Builders.Filter.In(x => x.Author, authorNames);
var books = _bookCollection.Find(nameFilter2).ToList();
Intro In the realm of extensive datasets — and for this discussion, I’ve zeroed in on MongoDB — it’s imperative to understand the database’s response patterns to the queries our applications launch against it. NotRead more
Why locking in the first place? Because in many scenarios we need to guarantee the consistency of the data, this means that we will not allow for one user changing data that another user hasRead more
Click to download the source file Yet another article about MONGO! This article is about retrieving data in mongo and tweaking the retrieval method to accommodate some project requirements. I am not an expert inRead more
With mongo some operations will return a dynamic object, usually wrapped in an expando object. To deserialize the expando object in the target class is quite simple, I actually looked in the source code toRead more
The mongo driver offers a rich and complete infrastructure to create rich domain entities out of the box. The bson serializer integrated with the mongo driver can tackle all types of entities, it can deserializeRead more
We use cookies to optimize our website and our service.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.