meerkat 2.0.0
dotnet add package meerkat --version 2.0.0
NuGet\Install-Package meerkat -Version 2.0.0
<PackageReference Include="meerkat" Version="2.0.0" />
paket add meerkat --version 2.0.0
#r "nuget: meerkat, 2.0.0"
// Install meerkat as a Cake Addin #addin nuget:?package=meerkat&version=2.0.0 // Install meerkat as a Cake Tool #tool nuget:?package=meerkat&version=2.0.0
πΎ Meerkat
Meerkat is an ODM (Object Document Mapper) library designed to replicate the functionality of NodeJS's Mongoose in the .NET ecosystem. π For those unfamiliar, Mongoose is a JavaScript ODM wrapper library that simplifies data access when working with MongoDB. Similarly, Meerkat wraps around the official MongoDB client library for .NET, simplifying common data access patterns.
The name Meerkat is a playful homage to Mongoose, as a meerkat is a type of mongoose. π If you find this library cool or useful, don't forget to give it a βοΈ star!
π¨ Breaking Changes
With the release of version 2.0.0, the underlying MongoDB driver was upgraded to 3.2.0. The library also transitions the base Schema
class to using strongly typed Ids
π€ Contributing
Thereβs still a lot to be done! Feel free to:
- Open new issues to suggest features or report bugs π
- Submit PRs with updates or improvements π οΈ
π¦ Installation
Manual Installation (for the hardcore devs πͺ)
Add the following to your .csproj
file:
<PackageReference Include="meerkat" Version="2.0.0"/>
Visual Studio Package Manager Console
Run the following command:
Install-Package meerkat
.NET CLI
Run the following in your terminal:
dotnet add package meerkat
π οΈ Setup
Before using any of Meerkat's functions, you need to initialize it. This only needs to be done once. π
using meerkat;
...
Meerkat.Connect("<any valid full MongoDB connection string>"); // e.g., mongodb://user:password@server-address:port/database-name?other-options
π Usage
Ensure youβve declared the necessary namespace at the top of your class file:
using meerkat;
Note: All async methods support CancellationToken
for canceling operations. β³
𧩠Modelling
All models must inherit from the abstract Schema
class. The Schema
class has a an Id
property whose type is determined by the TKey
generic argument. In the example below, the Id
property is of type ObjectId
.
class Student : Schema<ObjectId>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Student()
{
// Example: Generate an ObjectID (you'd likely use a methode better suited to your Id type)
Id = ObjectId.GenerateNewId();
}
}
To specify a custom collection name or enable timestamp tracking:
[Collection(Name = "Persons", TrackTimestamps = true)]
public class Student : Schema
{
...
}
πΎ Persistence
Meerkat simplifies CRUD operations by combining create and update into a single API. If an entity doesnβt exist, itβs inserted; if it does, itβs updated. π
var student = new Student
{
FirstName = "Olubakinde",
LastName = "Chukumerije"
};
await student.SaveAsync(); // or student.Save(); for synchronous calls
Itβs that simple! π
π Querying
Find by ID
var student = await Meerkat.FindByIdAsync<Student>(1234); // or Meerkat.FindById<Student>(1234); for sync calls
Find by Predicate
var student = await Meerkat.FindOneAsync<Student>(x => x.FirstName == "John"); // or Meerkat.FindOne(x => x.LastName == "Jane");
Complex Queries
For complex queries, you can access the underlying IQueryable
:
var queryable = Meerkat.Query<Student>();
var students = await queryable
.Where(x => x.FirstName == "Olubakinde")
.ToListAsync();
ποΈ Removal
Remove by ID
await Meerkat.RemoveByIdAsync<Student>(1234); // or Meerkat.RemoveById<Student>(1234); for sync calls
Remove by Predicate
await Meerkat.RemoveOneAsync<Student>(x => x.FirstName == "John"); // or Meerkat.RemoveOne(x => x.LastName == "Jane");
Remove All Matching Entities
await Meerkat.RemoveAsync<Student>(x => x.FirstName == "John"); // or Meerkat.Remove(x => x.LastName == "Jane");
β Existence Checks
Check if Any Entities Exist
var exists = await Meerkat.ExistsAsync<Student>(); // or Meerkat.Exists<Student>(); for sync calls
Check if Entities Match a Predicate
var exists = await Meerkat.ExistsAsync<Student>(x => x.FirstName.StartsWith("Ja")); // or Meerkat.Exists<Student>(x => x.FirstName.StartsWith("Ja"));
π’ Counting
Count All Entities
var count = await Meerkat.CountAsync<Student>(); // or Meerkat.Count<Student>(); for sync calls
Count Entities Matching a Predicate
var count = await Meerkat.CountAsync<Student>(x => x.FirstName.StartsWith("Ja")); // or Meerkat.Count<Student>(x => x.FirstName.StartsWith("Ja"));
π Collections
Meerkat allows for bulk upsert operations on collections of entities, both synchronously and asynchronously. π¦
var peter = new Student();
var paul = new Student();
var students = new [] { peter, paul };
await students.SaveAllAsync(); // or students.SaveAll(); for sync calls
π Index Attributes
This section provides an overview of the custom attributes used to define MongoDB indexes in your model classes. These attributes are applied to fields or properties and are used to generate appropriate indexes in MongoDB. All model classes must inherit from the abstract class Schema<TKey>
.
ποΈ Index Attributes Overview
π― SingleFieldIndexAttribute
- Purpose: Defines a single-field index on a specific field or property.
- Usage: Apply this attribute to a field or property to create an index on that single field.
- Optional Properties:
Name
: Specifies the name of the index. If not provided, MongoDB generates a default name.Sparse
: A boolean value indicating whether the index should be sparse. Default isfalse
.IndexOrder
: Specifies the order of the index. Options areAscending
,Descending
, orHashed
.
Example:
public class User : Schema<Guid>
{
[SingleFieldIndex(Name = "username_index", Sparse = true, IndexOrder = IndexOrder.Ascending)]
public string Username { get; set; }
}
- Explanation: This creates a single-field index on the
Username
property with an ascending order. The index is sparse, meaning it will only include documents where theUsername
field exists.
What is a Sparse Index? π€
A sparse index only includes documents that have the indexed field. If a document does not contain the indexed field, it is excluded from the index. This can save space and improve performance for fields that are not present in all documents.
What is a Hashed Index? π
A hashed index in MongoDB uses a hash function to compute the value of the indexed field. This is particularly useful for sharding and equality queries but does not support range queries.
π UniqueIndexAttribute
- Purpose: Defines a unique index on a specific field or property.
- Usage: Apply this attribute to enforce uniqueness on a field or property.
- Optional Properties:
Name
: Specifies the name of the index. If not provided, MongoDB generates a default name.Sparse
: A boolean value indicating whether the index should be sparse. Default isfalse
.
Example:
public class User : Schema<Guid>
{
[UniqueIndex(Name = "email_unique_index", Sparse = true)]
public string Email { get; set; }
}
- Explanation: This creates a unique index on the
Email
property. The index is sparse, meaning it will only include documents where theEmail
field exists.
𧩠CompoundIndexAttribute
- Purpose: Defines a compound index on multiple fields or properties.
- Usage: Apply this attribute to multiple fields or properties to create a compound index.
- Optional Properties:
Name
: Specifies the name of the index. If two or more fields have the sameName
, they are grouped into a single compound index. Unnamed indexes are grouped into one compound index.IndexOrder
: Specifies the order of the index. Options areAscending
,Descending
, orHashed
.
Example:
public class Order : Schema<Guid>
{
[CompoundIndex(Name = "order_index", IndexOrder = IndexOrder.Ascending)]
public DateTime OrderDate { get; set; }
[CompoundIndex(Name = "order_index", IndexOrder = IndexOrder.Descending)]
public decimal TotalAmount { get; set; }
}
- Explanation: This creates a compound index on the
OrderDate
andTotalAmount
properties. TheOrderDate
is indexed in ascending order, while theTotalAmount
is indexed in descending order.
Note on Compound Indexes π
If multiple fields have the same Name
in the CompoundIndexAttribute
, they are grouped into a single compound index. Unnamed indexes are grouped into one compound index automatically.
π GeospatialIndexAttribute
- Purpose: Defines a geospatial index on a field or property.
- Usage: Apply this attribute to fields or properties that store geospatial data (e.g., coordinates).
- Optional Properties:
Name
: Specifies the name of the index. If not provided, MongoDB generates a default name.IndexType
: Specifies the type of geospatial index. Options areTwoD
(default) orTwoDSphere
.
Example:
public class Location : Schema<Guid>
{
[GeospatialIndex(Name = "location_geo_index", IndexType = IndexType.TwoDSphere)]
public double[] Coordinates { get; set; }
}
Explanation: This creates a geospatial index on the
Coordinates
property, using theTwoDSphere
index type, which is useful for querying geospatial data on a spherical surface. What is the Difference Between TwoD and TwoDSphere? πTwoD
: This index type is used for flat, 2D geospatial data. It is suitable for simple 2D coordinate systems.TwoDSphere
: This index type is used for geospatial data on a spherical surface (e.g., Earth). It supports more complex queries involving distances, intersections, and other spherical calculations.
Summary of Index Types π
Attribute | Purpose | Optional Properties |
---|---|---|
SingleFieldIndex |
Single-field index | Name , Sparse , IndexOrder |
UniqueIndex |
Unique index | Name , Sparse |
CompoundIndex |
Compound index on multiple fields | Name , IndexOrder |
GeospatialIndex |
Geospatial index | Name , IndexType |
Example Model Class π§βπ»
Hereβs an example of a model class using all the attributes:
public class Product : Schema<Guid>
{
[SingleFieldIndex(Name = "name_index", IndexOrder = IndexOrder.Ascending)]
public string Name { get; set; }
[UniqueIndex(Name = "sku_unique_index", Sparse = true)]
public string SKU { get; set; }
[CompoundIndex(Name = "price_category_index", IndexOrder = IndexOrder.Descending)]
public decimal Price { get; set; }
[CompoundIndex(Name = "price_category_index", IndexOrder = IndexOrder.Ascending)]
public string Category { get; set; }
[GeospatialIndex(Name = "location_geo_index")]
public double[] Location { get; set; }
}
- Explanation: This example demonstrates the use of multiple index types within a single model class. It includes a single-field index, a unique index, a compound index, and a geospatial index.
Enjoy using Meerkat! π If you have any questions or feedback, feel free to reach out or contribute to the project. π
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- MongoDB.Driver (>= 3.2.0)
- mongo-url-parser (>= 1.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.0.0 | 92 | 2/26/2025 |
1.1.0 | 111 | 2/2/2025 |
1.0.19 | 96 | 2/2/2025 |
1.0.18 | 154 | 8/17/2024 |
1.0.17 | 276 | 11/5/2023 |
1.0.16 | 138 | 11/5/2023 |
1.0.13 | 5,080 | 6/8/2022 |
1.0.12 | 547 | 2/4/2022 |
1.0.11 | 460 | 2/4/2022 |
1.0.10 | 281 | 1/3/2022 |
1.0.9 | 377 | 10/27/2021 |
1.0.8 | 333 | 10/27/2021 |
1.0.7 | 338 | 10/26/2021 |
1.0.6 | 339 | 10/25/2021 |
1.0.5 | 322 | 10/23/2021 |
1.0.4 | 321 | 10/11/2021 |
1.0.3 | 347 | 10/8/2021 |
1.0.2 | 350 | 10/8/2021 |
1.0.1 | 333 | 10/7/2021 |
1.0.0 | 340 | 10/6/2021 |
1.0.0-beta.2 | 199 | 10/6/2021 |
1.0.0-beta.1 | 150 | 10/6/2021 |
1.0.0-alpha.2 | 187 | 10/6/2021 |
1.0.0-alpha.1 | 196 | 10/5/2021 |
- Add generic typed key support