HACK: Creating triggers for MongoDB

14 05 2012

I visited the MongoDB conference in Berlin. At one talk about tips, tricks and hacks for MongoDB the speaker mentioned that there is a little hack which you can use to create a trigger for MongoDB. I wanted to try this out because he only mentioned how to do this theoretically very shortly.

When you have configured MongoDB to work as a replicaset you maybe have noticed that on the local database a new collection called “oplog.rs” is created. Inside this collection MongoDB stores all insert / update and delete operations which are executed against this replicaset (it’s comparable to the transaction log on a SQL Server). The oplog collection is used to distribute all the operations from the primary node to all secondary’s. With the help of this collection and a little javascript file we are able to create something which behaves like a trigger.

Let’s start with the oplog collection. If you look at an entry from this collection you can see something which can look similar to the following extract.

{
    "ts" : {
        "$timestamp" : NumberLong("5724119038133534721")
    },
    "h" : NumberLong("-7041921609633449468"),
    "op" : "i",
    "ns" : "TestApplication.BlogPost",
    "o" : {
        "_id" : ObjectId("4f7027f0df6e252390d2332a"),
        "Author" : "Test Author",
        "CreationDate" : new Date("Mon, 12 Mar 2012 00:00:00 GMT +01:00"),
        "Comment" : "My Comment"
    }
}

ts: is the timestamp. We need the timestamp to avoid that an element can be triggered twice.

op: is the operation. The interesting operations are “i” for insert / “u” for update and “d” for delete.

ns: is the namespace (database and collection) were the operation was executed.

o: is the object which is created or updated.

If you need more information about the oplog have a look at the following page about the oplog on the website from MongoDB:

http://www.mongodb.org/display/DOCS/Replica+Sets+-+Oplog

Now we create the javascript file. This script has a while loop without any option to exit this loop. We want to watch for all changes on the oplog and want to react on these changes. As long the script is running we have a behavior similar to a trigger.

Two features of MongoDB are used to allow the execution of this script (have a look at the links if you want to have further information):

Now have a look at the script and modify and reuse it if you like.

var coll = db.oplog.rs;
var lastTimeStamp = coll.find().sort({ '$natural' : -1 })[0].ts;

while(1){
    cursor = coll.find({ ts: { $gt: lastTimeStamp } });
    // tailable
    cursor.addOption( 2 );
    // await data
    cursor.addOption( 32 );

    while( cursor.hasNext() ){
        var doc = cursor.next();
        lastTimeStamp = doc.ts;
        printjson( doc );
    }
}

What the current script does is checking for operations inside the oplog and print out the oplog entry. Just change the line with the printjson command to the operation you want to perform as the result of the trigger. On the line where you initialize the cursor you can enhance the query if you maybe only want to react on update operations.

I developed on a project with MongoDB nearly 1.5 years now and I didn’t came across a problem were I really need a trigger. I saw a couple of people asking for triggers at different pages and hope I can help some of them with this little hack. This is not tested on a high traffic environments.





Persisting and fetching DateTime values with MongoDB

28 03 2012

The C# driver for MongoDB serializes data by default from C# objects to a bson representation which is stored inside MongoDB. The DateTime type is a bit special which I want to demonstrate with the following test.


public abstract class RepositorySubjectwhere T : Repository
{
    public static T Subject { get; set; }

    public RepositorySubject()
    {
        var mongoDb = new MongoDB();
        Subject = (T)Activator.CreateInstance(typeof(T), mongoDb);
    }
}


public static class BlogRepositorySpecs
{
    [Subject(typeof(BlogRepository))]
    public class When_refetching_persisted_data : RepositorySubject
    {
        private static BlogPost blogEntry;

        private static BlogPost result;

        Establish context = () =>
        {
            blogEntry = new BlogPost()
            {
                Author = "Test Author",
                Comment = "My Comment",
                CreationDate = new DateTime(2012, 4, 12),
                Id = ObjectId.GenerateNewId()
            };
        };

        Because of = () =>
        {
            Subject.Save(blogEntry);
            result = Subject.FindById(blogEntry.Id.ToString());
        };

        Cleanup after = () => Subject.Drop();

        It should_have_the_correct_creationdate = () => {
           result.CreationDate.ShouldEqual(blogEntry.CreationDate);
        }

        It should_have_the_correct_author = () => {
            result.Author.ShouldEqual(blogEntry.Author);
        }

        It should_have_the_correct_comment = () => {
            result.Comment.ShouldEqual(blogEntry.Comment);
        }
    }
}

This simple test is written with mspec. What the tests does is create a BlogPost-object with a DateTime value and 2 string values. This object is persisted inside MongoDB. Afterwards the object is retrieved and the expected data is compared to the retrieved data.
The abstract RepositorySubject is a helper which can be used for different mspec tests which are written to test different repository functionality.
The Repository class by itself is an abstract class holding the most important CRUD-operations for the usage with MongoDB. BlogRepository is inherited from Repository. Additional implementations can be added here. Inside the MongoDB class the connection to the MongoDB database is established and the commands are executed.

Running the Test

When we run the test on a machine where the current time is set to something else than UTC time the test will fail. Why will the test fail? DateTime values are stored as UTC time inside the database. When we retrieve the data from the database the DateTime value is fetched as a UTC DateTime value. Therefore we compare a local DateTime with a UTC DateTime value.

Set Serialization Options for DateTimes

What can we do to fix this problem? We can register a serialization option for the DateTime value. With this option we can specify that the value will be converted to the local DateTime when we retrieve the object from the database. The following code snippet shows how to transfer the CreationDate from UTC to the local DateTime value.


public class RegisterSerializer
{
    public void Setup()
    {
        BsonClassMap.RegisterClassMap(cm => {
            cm.AutoMap();
            cm.GetMemberMap(c => c.CreationDate).SetSerializationOptions(
                    new DateTimeSerializationOptions(DateTimeKind.Local));
        });
     }
 }

After adding this class we only need to call the method which can be done inside the RepositorySubject by adding the following 2 lines of code.


var registerSerializer = new RegisterSerializer();
registerSerializer.Setup();

Now we can run the tests again. The result should be as expected – green.





Thoughts about Replica Set configuration with MongoDB

2 03 2012

In my last post I provided you with a setup script which can be used to get a simple replica set configuration up and running. Now I want to talk about some details of the script and why I have created the script like it is.

Why should I use the option notablescan?

In my opinion this is a flag which should be set on every development environment. When you write new functionality inside your data access it can happen that you forget to update the indices on the database. This will result in bad performance on queries. Especially on applications with a lot of traffic, this will result in big performance issues.

To avoid this problem enable the notablescan option on your development environment. Every time when a query has to run over the complete table to fetch data (because of a missing index) you will receive an exception similar to the following:

image

When you set this option on your development environment the risk to deploy code to your live systems, without a correct index, is reduced to a minimum.

Priority for Replica Set nodes

While setting up a replica set, you can provide every node with a priority thru the configuration. The priority is used to rate a single node as the primary. A higher priority will result in a higher chance to be rated as primary. The priority of 0 excludes a node from becoming a primary. This is useful to exclude nodes with bad performance to be rated as primary. With version 2.0.2 of MongoDB (Windows) you can specify a priority from 0.0 to 100.0; inside the script I want to achieve that the node with the smallest port number will be the primary. The configuration for the first node starts with the priority of 100. Every node receives a priority which is decreased by 1. Therefore we make sure that the node with the smallest port number has the highest priority and will be rated as primary. For the reason the first node fail to start, the node with the second highest priority will take over.

Reinstallation of Replica Sets; but what happened to my data?

As I mentioned in my last post about the setup script we remove the old service (if some exists with the same name) and install everything new. For the reason we want to keep the data inside the database we need to do some things to achieve this.

If we used the script to install the replica set and created a database called “MyTestDb”, we should have a folder structure on the file system which should look like in the following picture.

image

Now we want to reinstall the instance with another configuration and keep all the existing data. On every node, expect the node with the smallest port number; we make sure that none of the data folders hold any data or folders. In this case the “replSet2” and the “arbiter” folder are emptied completely. We need to do this because when installing a replica set it’s not allowed to have data inside any node except form the node where you initiate the configuration.

Inside the “replSet1” folder we only need to delete the content of the local folder. The content of the “MyTestDb” folder isn’t touched. Why do we need to do this? The configuration of the replica set is stored inside the local database. If we don’t delete content of the local folder, we can’t run the initiate method; we can only use the reconfigure options. To avoid a differentiation between a new installation and a reinstall, I decided to implement the script to use a remove with a completely new initiation process.

After the new installation the replica set should come up with the new configuration. On the startup the replica set will start to sync all data from the “replSet1” folder to all other nodes. All data from the “MyTestDb” folder are synced. When the replication process is finished, you have a completely new configured replica set with the complete content from the old configuration.

I hope this information help some of you. If you have any questions about this or the setup script just let me know.

Cheers,

Daniel





Setup MongoDB as a service with Powershell

27 02 2012

I have written a small Powershell script to setup a MongoDB instance as a single node or in a replicaset configuration. I want to share the script here and hope this is useful for some of you (feedback is welcome). To run the script you need admin rights; otherwise the service can’t be created. The main purpose of the script is to get MongoDB up and running on a Windows PC for local development.

In this post I want to talk about how the script works. In a further post I will provide some information regarding the setup and configuration.

I have separated the script into 3 files. MongoDbSetup.ps1, WebClient.ps1 and Zip.ps1. The MongoDbSetup-file is the main script and responsible for the installation. WebClient and Zip are only small helpers. WebClient.ps1 is used to download a file and display a progress bar (while downloading). The file Zip.ps1 is used to unzip a zip-file to a specified destination folder (used to unpack MongoDB after download).

What the MongoDB setup script do

The following picture shows a simplified process what the script does.

image

I want to provide you with a bit more details about the script execution. The first thing we do is to setup the folder structure we expect inside the script. We have a download folder where the downloaded binaries from MongoDB are stored (zip-files). Every installed instance has his own folder in this case “MongoDB ReplicaSet”. Inside the “MongoDB ReplicaSet” directory we have 3 folders. “Bin” for storing the unzipped MongoDB binaries, “data” for the database files and “log” for all log messages.

image

The location and name where the folders get stored can be defined as a parameter while calling the script. Before we start to download the zip-file holding the MongoDB binaries we want to make sure there is no service running with the same name like the service we want to create. Therefore the script shuts down existing services to allow replacing the service thru the script. This can be handy for the reason you want to update an existing instance (for example you want to update the MongoDB version). Then the download of the zip-file with the binaries starts. The download will fetch the Windows 64-bit version of the binaries for the specified MongoDB version (tested with version 2.0.2 and 1.8.5). If the format of the filename on the MongoDB server will change you need to update the script. If you install a second node the download won’t fetch the file from the server as long you have the zip file inside the download folder (which is created thru the installation process).

The next step is to unzip and copy the executables to the bin folder for the new instance. The fact that we have a bin folder for every instance, made it possible to run different MongoDB versions on the different instances.

Now all preparation is done. We can start with the installation of the single node or the replicaset. I will describe the process of the replicaset installation because it’s much more interesting. The single node installation is a sub-part of the replicaset configuration.

For the reason we want to make changes on an existing replicaset with the script, we need to remove the existing instances with the same name. Afterwards we can setup the number of nodes. The amount of nodes is provided thru a parameter when calling the script. After the setup of the nodes another node is installed as arbiter, if you didn’t change the default configuration. Now we have all nodes installed and need to start the services.

The last step is to configure of the replicaset. We create a file which holds the configuration for all nodes. After creating the file we can run mongo.exe and provide the file as parameter to run and initiate the replicaset configuration. The replicaset needs a bit of time till it is up and running. Connect to your newly created instance and check the replicaset status by calling rs.status(). Then you are done.

As I mentioned above there are a couple of parameters you can set by calling the script to override the default values. In the following table you can find a list with these parameters.

Parameter Default Usage
version 2.0.2 Specify the version of the MongoDB binaries we want to use for the new instance.
Mode ReplicaSet Options are ReplicaSet and SingleMode. Depends on the instance you want to install.
portNumber 30000 Start the port number at the given port. On nodes for a replicaset the port is increased for every node.
numberNodes 2 Number of nodes (without arbiter)
useArbiter True Create and use an arbiter
destinationPath c:\mongodb\ Path where the installation stores the data
serviceName MongoDB ReplicaSet Name of the service which is created. When creating a replicaset a number is attached to the name.

I have uploaded the scripts on GitHub; use it on your own risk :-)
The repository is located at: https://github.com/danielweberonline/MongoDB-Setup

Cheers,

Daniel





Creating Slugs with Action Filters

16 02 2012

Slugs are the possibility to create SEO-friendly URLs (speaking URLs). Slugs are a great way to optimize you page URL for search engines.

http://www.<domain>.de/Post/145732 – URL with a meaningless Id
http://www.<domain>.de/Post/Creating-slugs-with-Action-filters – speaking URL with a slug

Even for humans speaking URLs are much better instead of meaningless URLs with Ids. You can already see what will occur when opening a link.

Basic slug implementation

We start with the creation of a new Route. This can be done by adding the following route to the Global.asax:

routes.MapRoute(
    null,
    "Post/{slug}",
    new { controller = "Post", action = "Show", slug = string.Empty });

With this route we are able to create URLs like shown in the sample above. As you can see inside the route, we need a post controller with an action called show. The following code shows a sample implementation of this controller (I assume you have a working DI-Configuration and the BlogPostRepository is injected)

private readonly IBlogPostRepository blogPostRepository;

public PostController(IBlogPostRepository blogPostRepository)
{
    this.blogPostRepository = blogPostRepository;
}

public ActionResult Show(string slug)
{
    if (slug.Equals(string.Empty))
    {
        return this.HttpNotFound();
    }

    var blogPost = blogPostRepository.FindPost(slug);
    if (blogPost == null) {
        return this.HttpNotFound();
    }

    return View(blogPost);
}

Inside the action show, we check that a slug value is provided thru the URL. If no slug value is present we return HttpNotFound (404) as result. Having a slug value inside the URL we can call the repository which is responsible for fetching data from the data store. If the URL is valid, a BlogEntry is fetched from the repository. The result should be given to the view to display the data. For the reason the repository returns no result we return another 404.
The problem with this implementation is that the size of the controller can increase very fast, especially when you have more parameters.

Slugs with Action Filters

Now I want to show you the same implementation using action filters. In my opinion this is quiet handy and better then the basic implementation.
We start with the implementation of the new action filter.

public class BlogPostFilterAttribute : ActionFilterAttribute {

    [Dependency]
    public IBlogPostRepository BlogPostRepository { get; set; }

    public override void OnActionExecuting(ActionExecutingContext 
        filterContext) {
        var slug = filterContext.RouteData.Values["slug"] as string;

        if (slug.Equals(string.Empty)) {
            filterContext.Result = new HttpNotFoundResult();
            return;
        }

        var blogPost = BlogPostRepository.FindPost(slug.ToString());

        if (blogPost == null) {
            filterContext.Result = new HttpNotFoundResult();
            return;
        }

        filterContext.ActionParameters["BlogPost"] = blogPost;
    }
}

As you can see, the code looks similar to the basic implementation. What changed is the fact that we extract the slug value from the RouteData of the filterContext. For the cases we want to display a 404 we provide the filterContext result with a new instance of HttpNotFoundResult. On the happy path when we found a post with the help of the repository, the blogPost entry is stored as action parameter on the filterContext. Now we need to update the show action. First we need to provide the new attribute on the action. Next we need to change the method parameters from string to blogPost. The blogPost parameter inside the action will now be filled with the blogPost data which was fetched inside the action filter. Last but not least we can remove all the unnecessary code from the action. The show action should look similar to the following code:

[BlogPostFilter]
public ActionResult Show(BlogPost blogPost) {
    return View(blogPost);
}

Add support for Property Injection on Action Filters

The special thing about action filters is that we need to write some additional code to support injecting data into action filters. In the code above you can already see that I provided the Dependency attribute on the BlogPostRepository property. Without the customizing the property injection didn’t work. What we need to do, I found inside a blog post from Brad Wilson (http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html).
We need write a filter attribute provider, which is provided with your dependency injection container. The following code shows a sample implementation for unity.

public class UnityFilterAttributeFilterProvider : 
    FilterAttributeFilterProvider {
    private readonly IUnityContainer container;

    public UnityFilterAttributeFilterProvider(IUnityContainer container) {
        this.container = container;
    }

    protected override IEnumerableGetControllerAttributes(
        ControllerContext controllerContext,
        ActionDescriptor actionDescriptor) {

        var attributes = base.GetControllerAttributes(controllerContext, 
            actionDescriptor);

        foreach (var attribute in attributes) {
            this.container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerableGetActionAttributes(
        ControllerContext controllerContext,
        ActionDescriptor actionDescriptor) {

        var attributes = base.GetControllerAttributes(controllerContext, 
            actionDescriptor);

        foreach (var attribute in attributes) {
            this.container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}

Inside the Global.asax you need to add the following code inside the Application_Start. This removes the default filter and adds the filter with the DI container to the FilterProviders.

var filterAttributProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(filterAttributProvider);

var provider = new UnityFilterAttributeFilterProvider(container);
FilterProviders.Providers.Add(provider);

After this last step you should be able to use the injected repository.

Conclusion

With the help of action filters, it’s easier to reduce the controller size and make the code reusable thru an attribute which can be provided on different controllers and actions.





CSV export from MongoDB using PowerShell

7 02 2012

The tools to import and export data on a MongoDB instance are very powerful. I really like the tools because they are very easy to use. Some features would be nice to have, but you can reach a lot with the current set of tools and options.  Detailed information about the import and export tools can be found at the following address: http://www.mongodb.org/display/DOCS/Import+Export+Tools

Mongoexport offers an ability to export data to csv which you can easily read with Excel. This allows “normal” users to display, sort & filter data in their familiar environment. Especially for flat documents the csv export is a great option.

To export data from a collection you can use a command which is similar to this one:

mongoexport -d <databaseName> -c <collectionName> -f “<field1,field2>” --csv -o <outputFile>

But wait there is one thing which I don’t like about this. We must define the fields we want to export. When you use the “csv”-option for mongoexport, the field-options becomes required. But what can I do to avoid a hard coded list of fields? Especially on an environment where many changes will happen, you need a solution which works without a manual edited field list.

What we can do is a map/reduce to get all field names from every document inside a collection. With this result you are able to call mongoexport with a field list which is generated on the fly. Details about map/reduce for MongoDB can be found at the following address: http://www.mongodb.org/display/DOCS/MapReduce

The map/reduce can look like the following example:

function GetAllFields() {
    map = function(){
        for (var key in this) { emit(1, {"keys" : [ key ]}); }
    };

    reduce = function(key, values) {
        var resultArray = [],
            removeDuplicates = function (elements) {
                var result=[],
                    listOfElemets={};
                for (var i = 0, elemCount = elements.length;
                                                        i < elemCount; i++) {
                    for (var j = 0, keyCount = elements[i].keys.length;
                                                         j < keyCount; j++) {
                       listOfElemets[elements[i].keys[j]] = true;
                    }
                }
                for (var element in listOfElemets) {
                    result.push(element);
                }
            return result;
        }

        return { "keys" : removeDuplicates(values) };
    };

    retVal = db.<collectionName>.mapReduce(map, reduce, {out : {inline : 1}})
    print(retVal.results[0].value.keys);
}
GetAllFields();

This function can be stored inside a js-file. Now we need to execute the function. This can be done, for example with PowerShell and the help of mongo.exe. The result of the script execution is a comma separated field list with all field-names on the 1st -level from one collection. This is exactly the format we need for the csv export using mongoexport. Therefore we are ready to go and can call the export to a csv-file.

The following code shows a PowerShell script which retrieves the field-list and runs the export afterwards.

$fieldNames = (mongo.exe <server>/<database> <scriptFile> --quiet)
(mongoexport.exe -d <databaseName> -c <collectionName> -f $fieldNames --csv   -o <outputFile>)

Hope this will be useful for someone!





Problem using $rename on indexed fields using MongoDB

1 02 2012

Today we found a problem which occurs on MongoDB when you rename an indexed field. This problem occurs on version 2.0.2. I didn’t test the problem on another version.

If you have simple documents having the following structure:

{
    PreName : “Daniel”,
    Name: “Weber”
}

You maybe want to rename all “Name” elements to “LastName”. To do this you can use the rename functionality from MongoDB
http://www.mongodb.org/display/DOCS/Updating#Updating-%24rename

The command for a rename should be something like this:

db.MyCollection.update( { } , { $rename : { "Name " : "LastName" } } )

When you look at the documents after running the rename query everything is fine, the field name is renamed correctly.

For the reason you run the rename command again, nothing happen (as expected) because a field with “Name” doesn’t exist anymore.

The problem occurs only when you have an index on the field you want to rename. Therefore we create the same simple document and insert an index on the “Name” property with the following command:

db.MyCollection.ensureIndex( { "Name" : 1 } )

Information about index creation can be found on
http://www.mongodb.org/display/DOCS/Indexes#Indexes-Basics

Now we run the same update command. When we have a look into the database the field name changed as expected. Then we run the rename command again. A strange thing happened. The renamed field is deleted and the “LastName” value is lost.

Therefore be careful with renames of indexed elements where a script runs the rename more than once.





Query and update data on MongoDB using PowerShell

30 01 2012

I’m working on client side at the moment where we use MongoDB as data storage. We reached the point where we need to read some data from MongoDB with PowerShell. I thought this might be interesting to some people. Therefore I decided to share my experience about this.

What do we need to connect to MongoDB with PowerShell

The only thing we need is a MongoDB driver. I used the official C# driver which is supported by 10gen. 10gen is the company which develops MongoDB and offers support, training and consulting for MongoDB. The latest driver binaries can be downloaded at github from https://github.com/mongodb/mongo-csharp-driver/downloads

How to connect to the MongoDB server

First you need to add references to the dll’s which are provided by the MongoDB driver. Then you can establish the connection to the database. The next step is to connect to a collection. On the collection you can perform different CRUD operations.

$mongoDbDriverPath = "C:\driver\mongoDB\"
$dbName = "MyDatabase"
$collectionName = "MyCollection"
Add-Type -Path "$($mongoDbDriverPath)\MongoDB.Bson.dll"
Add-Type -Path "$($mongoDbDriverPath)\MongoDB.Driver.dll"
$db = [MongoDB.Driver.MongoDatabase]::Create("mongodb://localhost/$($dbName)")
$collection = $db[$collectionName]

Create a new document

First you need to create a BsonDocument. On the document you can add new key-value pairs by calling the add-method. As soon you finalized the new document you can store the document inside a collection with the save-method.

$document = new-object MongoDB.Bson.BsonDocument
$document.Add("PreName",[MongoDB.Bson.BsonValue]::Create("Daniel"))
$document.Add("LastName",[MongoDB.Bson.BsonValue]::Create("Weber"))
$collection.save($document)

When you use the add-method like on the sample above, MongoDB automatically creates a string value for you. If you want to create an entry with an e.g. an ObjectId, you can use the following statement.

$document.Add("UserId",[MongoDB.Bson.BsonObjectId]::Create("4f2193e0df6e251d040a6df6"))

For other object types please have a look at the MongoDB driver documentation.

Read data from collection

If you want to fetch all data from a single collection and display all objects you can use the following command.

$results = $collection.findall()
foreach ($result in $results) {
    write-host $result
}

For the reason you are only interested in a single column you can access a single columns with the following notation.

foreach ($result in $results) {
    write-host $result[“LastName”]
}

If you want to select a specific document you need to start writing a query. If you want to select all documents which have a specific LastName use the following query.

$query = [MongoDB.Driver.Builders.Query]::EQ("LastName","Weber")

For more complex scenarios you can combine different conditions to a single query. If you want to select all documents having the specified LastName and PreName use this command.


$query = [MongoDB.Driver.Builders.Query]::AND(
            [MongoDB.Driver.Builders.Query]::EQ("PreName","Daniel"),
            [MongoDB.Driver.Builders.Query]::EQ("LastName","Weber"))

The driver offer many different options to combine conditions to a single query. Not only an AND exists. After building the query, you need to find the results. This can be done by calling a find with the query as parameter.

$results = $collection.find($query)

Update data inside a collection

To update an existing document you can start with querying for an existing document. The following command search for a document with the provided ObjectId. The Id on the document is unique. Therefore we can use findOne to get this document from the collection (because we expect only a single result). To update the fetched document we use the set-method. When everything is changed don’t forget to call save. The fact that we have a document with an existing ObjectId forces MongoDB to update the document and not to create a new one.

$query = [MongoDB.Driver.Builders.Query]::EQ("_id",
            [MongoDB.Bson.BsonObjectId]::Create("4f2198f8df6e251d040a6e17"))
$result = $collection.findOne($query)
$result.Set("LastName",[MongoDB.Bson.BsonValue]::Create(“W.”))
$collection.save($result)

Delete documents from a collection

Deleting existing documents from a collection is easy. If you want to delete every document you can do this by calling removeAll. This will remove every document from the specified collection. Most of the time, you only want so delete a single document. To remove only specific data call the remove-method on the collection with a query. Every document which is returned by the query will be then be deleted.


$query = [MongoDB.Driver.Builders.Query]::EQ("PreName",
            [MongoDB.Bson.BsonValue]::Create("Daniel"))
$collection.remove($query);

Conclusion

With the C# driver it is easy to perform CRUD-Operations with MongoDB. Just have a look at the documentation of the driver if you need to perform some advanced queries. I really like how easy it is to connect to MongoDB via PowerShell.








Follow

Get every new post delivered to your Inbox.