Click here to Skip to main content
15,867,568 members
Articles / Database Development / MongoDB

MongoDB Version 2 Some Operations

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
3 Mar 2016CPOL4 min read 12.2K   4   3
CRUD with filtering for MongoDB version 2 driver
In this article, I will share some more information about working with version 2 of MongoDB driver. We will cover reading, sorting, inserting, replacing, updating, upserting and deleting. We will also take a look at Projections.

Introduction

There are plenty of manuals over the internet of how to work with MongoDB driver version 1, but not so much with version 2. I want to add a little bit more information about working with version 2.

So, Let's Start With Reading

In MongoDB, reading can be considered as following options:

  1. Finding all documents
  2. Filtering
  3. Sorting
  4. Definitions and builders

Creating documents in MongoDB is simple. You can do it just with Insert (letter C).

And here, you have plenty of options:

  1. Replace
  2. Update
  3. Upsert

I'll also mention deleting, or letter D.

And also, I want to describe how to use projections as a way to limit what you take from MongoDB.

So, let's start with synchronous finding of some information in MongoDB.

Suppose I have the following classes declarations:

public abstract class MongoEntityBase
    {
        // ReSharper disable once InconsistentNaming
        public ObjectId _id { get; set; }
    }
 
    public class SampleClarification : MongoEntityBase
    {
        public ObjectId SomeId { get; set; }
        public int RectificationNumber { get; set; }
        public string RectificationReason { get; set; }
        public string RectificationText { get; set; }
    }

This class will give me the option of working with SampleClarification collection in my MongoDB database.

Also, please look at Default construction of database context for MongoDB:

C#
public class SampleDataContext
    {
        public IMongoDatabase Database;
 
        public SampleDataContext()
        {
            var client = new MongoClient("http://localhost:27017/sample");
            Database = client.GetDatabase("sample");
        }
    }

In order to get this collection synchronously, I will need to add interface collection to datacontext. Data context will be transformed to this:

C#
public class SampleDataContext
    {
        public IMongoDatabase Database;
        public SampleDataContext()
        {
            var client = new MongoClient("http://localhost:27017/sample");
            Database = client.GetDatabase("sample");
        }
        public IMongoCollection<SampleClarification> 
        SampleClarifications => Database.GetCollection<SampleClarification>("sample");
    }

The most important part here is SampleClarifications.

And then, you can search for all SampleClarifications in the following way:

C#
SampleDataContext sc = new SampleDataContext();
var allDocs = sc.SampleClarifications.Find(new BsonDocument()).ToList();

Then, allDocs will be listed in memory of all documents.

So, that was a synchronous call.

Now I want to demonstrate an asynchronous call (that will be as easy as cake):

C#
SampleDataContext sc = new SampleDataContext();
var allDocs = await sc.SampleClarifications.Find(new BsonDocument()).ToListAsync();

But let's say you want to iterate through returned documents, and do something with them. Then very handy can be function ForEachAsync. And I recommend to use it with cursor.

The next is going filtering. One of the ways of filtering can be the following:

C#
SampleDataContext sc = new SampleDataContext();
            var allDocs = await sc.SampleClarifications.Find(new BsonDocument()
                    {
                        { "RectificationNumber" , 4}
                }
                ).ToListAsync();

Do you have an impression, that pointing string is not a great way to make filtering? If yes, you are not alone. And MongoDB driver has some new features for filtering:

C#
SampleDataContext sc = new SampleDataContext();
           
var allDocs = await sc.SampleClarifications.
              Find(Builders<SampleClarification>.Filter.Gte
              (a => a.RectificationNumber, 7)).ToListAsync();

One of the ways to read filters creation can be the following: build me the filter on a SampleClarification type which returns SampleClarification instances where RectificationNumber is greater or equal to 7.

Other possibilities can be Lte - less equal, Eq - equal to, etc.

Another useful feature is using Where. For example, like this:

C#
SampleDataContext sc = new SampleDataContext();
            
var allDocs = await sc.SampleClarifications.
              Find(Builders<SampleClarification>.Filter.Where
              (a => a.RectificationNumber == 7)).ToListAsync();

IMHO where is intended for cases if you don't want to remember Lte, Eq, Gte, Ne, etc. But Where has one important feature. You can pass nullable value there.

Another interesting feature of MongoDB is combining filtering features. See the following code:

C#
SampleDataContext sc = new SampleDataContext();
 
var filter = Builders<SampleClarification>.Filter.Empty;
 
if (true /*some condition*/)
{
     filter = filter & Builders<SampleClarification>.Filter.Where
              (a => a.RectificationText.Contains("aaa"));
}
 
var allDocs = await sc.SampleClarifications.Find(filter).ToListAsync();

Pretty interesting, huh??? I was surprised when I saw & instead of &&.

But that's not all. Let me introduce you to another shortcut: &=. Like this:

C#
if (true /* another condition */)
{
      filter &= Builders<SampleClarification>.Filter.Gte(a => a.RectificationNumber, 20);
}

Sorting

For sorting, you can work again with Builder. It can be achieved like this:

C#
SampleDataContext sc = new SampleDataContext();
 
var filter = Builders<SampleClarification>.Filter.Empty;
var sorting = Builders<SampleClarification>.Sort.Ascending(t => t.RectificationNumber);
var allDocs = await sc.SampleClarifications.Find(filter).Sort(sorting).ToListAsync();

If you feel bored to do a lot of typing in order to Sort something, you can see to SortBy function:

C#
SampleDataContext sc = new SampleDataContext();
var filter = Builders<SampleClarification>.Filter.Empty;
var allDocs = await sc.SampleClarifications.Find(filter).SortBy
              (s => s.RectificationNumber).ToListAsync();

Or you can use even more complicated schema:

C#
SampleDataContext sc = new SampleDataContext();
var filter = Builders<SampleClarification>.Filter.Empty;
var allDocs = await sc.SampleClarifications.Find(filter).
              SortBy(s => s.RectificationNumber)
              .ThenByDescending(a => a.TenderId)
              .ThenBy(a => a.RectificationReason).ToListAsync();

Inserting or C from CRUD

You can insert either one element, or more. Here is an example of how to create one:

C#
SampleDataContext sc = new SampleDataContext();
var filter = Builders<SampleClarification>.Filter.Empty;
var clar = new SampleClarification();
clar.RectificationNumber = 10;
clar.RectificationReason = "some reason";
clar.RectificationText = "fasdfdas fdsfas";
await sc.SampleClarifications.InsertOneAsync(clar);

Replacing or Almost U from CRUD

First of all, what is replacing. Replace is when you find document, delete it, and instead of it put a new one, with modified values.

First of all, you will need to find element, then update its value, and then save it. Here is an example:

C#
SampleDataContext sc = new SampleDataContext();
//var filter = Builders<SampleClarification>.Filter.Where
//(r => r.TenderId == ObjectId.Parse("56d55f1d4ee6bc45a0d7b539"));
//var clar = sc.SampleClarifications.Find(filter).FirstOrDefault();
 
//or another way:
var clar =  sc.SampleClarifications.Find(a => a.TenderId == ObjectId.Parse
            ("56d55f1d4ee6bc45a0d7b539")).FirstOrDefault();
 
if (clar != null)
{
    sc.SampleClarifications.ReplaceOne(r => r._id == clar._id, clar);
}

Replace one, will take as parameter search criteria, and will replace passed element.

U from CRUD or Update

Well, for making update, you'll need Builder with update policy. See the example of code:

C#
SampleDataContext sc = new SampleDataContext();
 
var text = "fasfds afasfas";
var clar =  sc.SampleClarifications.Find
            (a => a.TenderId == ObjectId.Parse("56d55f1d4ee6bc45a0d7b539")).FirstOrDefault();
var modificationsUpdate = Builders<SampleClarification>.Update
    .Set(a => a.RectificationReason, text)
    .Set(v => v.RectificationNumber, 35);
 
if (clar != null)
{
    sc.SampleClarifications.UpdateOne(c => c._id == clar._id, modificationsUpdate);
}

Also, you can make it async if you wish.

Another U from CRUD or Upsert

Upsert means the following. If upsert option is set to true, then if not matching document exists, then it will be inserted. If document exists, then it will be replaced.

Code which can be helpful:

C#
SampleDataContext sc = new SampleDataContext();
 
var text = "fasfds afasfas";
var clar =  sc.SampleClarifications.Find
            (a => a.TenderId == ObjectId.Parse("56d55f1d4ee6bc45a0d7b539")).FirstOrDefault();
UpdateOptions options = new UpdateOptions
{
    IsUpsert = true
};
 
if (clar != null)
{
    sc.SampleClarifications.ReplaceOne(c => c._id == clar._id, clar, options);
}

Finally Delete or D

Finally, you can delete any document. It's relatively easy:

C#
SampleDataContext sc = new SampleDataContext();
sc.SampleClarifications.DeleteOne(a => a.RectificationNumber == 10);

Projections

Let's say that you want to return not full list of SampleClarification fields, but subset of them. For this purpose, you can use projections.

Imagine that you don't want to extract all fields from SampleClarification, and for this purpose, you created the following view class:

C#
public class SampleClarificationView : MongoEntityBase
    {
        public ObjectId TenderId { get; set; }
        public int RectificationNumber { get; set; }
    }

Then you can use projections:

C#
SampleDataContext sc = new SampleDataContext();
var filter = Builders<SampleClarification>.Filter.Empty;
var middle = sc.SampleClarifications.Find(filter).Project(r => new SampleClarificationView()
{
    _id =  r._id,
    TenderId = r.TenderId,
    RectificationNumber = r.RectificationNumber
});
var result = await middle.ToListAsync();

Result will contain not all fields.

Points of Interest

In this article, I wrote my observation of CRUD operations for MongoDB along with filtering. While writing this article, I was most surprised with Projects of MongoDB which take only some fields, and not all of them.

History

  • 3rd March, 2021: Initial post
This article was originally posted at http://blog.zaletskyy.com/crud-with-mongodb-version-2

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Kensium
Ukraine Ukraine
Hi,
I'm Acumatica ERP Solutions architect at Kensium. Besides ERP programming my area of interests includes Neural Networks, Machine Learning, Statistics and of course performance optimization.
Here is my blog: http://blog.zaletskyy.com

Comments and Discussions

 
QuestionI got an error Pin
handschuh7-Mar-16 4:19
handschuh7-Mar-16 4:19 
AnswerRe: I got an error Pin
witnes8-Mar-16 22:35
witnes8-Mar-16 22:35 
QuestionThanks. Pin
237413-Mar-16 10:32
237413-Mar-16 10:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.