Skip to content

Commit

Permalink
Including new features; free text search support and bulk delete in m…
Browse files Browse the repository at this point in the history
…ongo repository.

Also creating text indexes on application start if it doesn't exist
already. And some aesthetic changes in the web project.

Roadmap for the coming days - I'll overhaul the ElasticSearch repository
as there are many new features and breaking changes in the version 1.0.
  • Loading branch information
pro-dev-amit committed Apr 12, 2014
1 parent 05d40cd commit 8e8a762
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 51 deletions.
23 changes: 22 additions & 1 deletion Matrix.Core/FrameworkCore/IRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,31 @@ public interface IRepository

long BulkUpdate<T>(IMongoQuery query, IMongoUpdate update, bool bMaintainHistory = false) where T : IMXEntity;

/// <summary>
/// Delete by Id
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id">Document Id</param>
/// <returns></returns>
bool Delete<T>(string id) where T : IMXEntity;

/// <summary>
/// Delete by Ids for a smaller batch size; 100 or so.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ids"></param>
/// <returns></returns>
bool Delete<T>(IList<string> ids) where T : IMXEntity;

/// <summary>
/// Bulk delete
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query">MongoQuery: an example could be something like this; Query<T>.In<string>(e => e.Id, ids).
/// To delete all documents, set Query as Query.Null</param>
/// <returns></returns>
long BulkDelete<T>(IMongoQuery query) where T : IMXEntity;

//other important ones
string GetNameById<T>(string Id) where T : IMXEntity;

Expand All @@ -74,6 +95,6 @@ public interface IRepository
/// <param name="take"></param>
/// <param name="skip"></param>
/// <returns></returns>
IList<T> GetManyByTextSearch<T>(string term, int take = 128, int skip = 0) where T : IMXEntity;
IList<T> GetManyByTextSearch<T>(string term, int skip = 0, int take = 30) where T : IMXEntity;
}
}
51 changes: 48 additions & 3 deletions Matrix.Core/MongoCore/MXMongoRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public MXMongoRepository(){ }

#region "Interface implementaions; generic CRUD repository"

#region "Insert"

public virtual string Insert<T>(T entity, bool isActive = true) where T : IMXEntity
{
entity.IsActive = true;
Expand Down Expand Up @@ -86,6 +88,10 @@ public virtual IList<string> BulkInsert<T>(IList<T> entities, bool isActive = tr
return entities.Select(c => c.Id).ToList();
}

#endregion

#region "Get"

/// <summary>
/// Find one by Id
/// </summary>
Expand Down Expand Up @@ -119,6 +125,9 @@ public virtual IList<T> GetMany<T>(Expression<Func<T, bool>> predicate = null, b
}
}

#endregion

#region "Update"
/// <summary>
/// Update while giving option for maintaining history
/// </summary>
Expand Down Expand Up @@ -158,7 +167,7 @@ public virtual long BulkUpdate<T>(IMongoQuery query, IMongoUpdate update, bool b
var historyDocs = collection.FindAs<T>(query).ToList();

Task.Run(() =>
InsertMultipleDocumentsIntoHistory<T>(historyDocs)
InsertManyDocumentsIntoHistory<T>(historyDocs)
);
}

Expand All @@ -167,6 +176,16 @@ public virtual long BulkUpdate<T>(IMongoQuery query, IMongoUpdate update, bool b
return bulk.Execute(WriteConcern.Acknowledged).ModifiedCount;
}

#endregion

#region "Delete"

/// <summary>
/// Delete by Id
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id">Document Id</param>
/// <returns></returns>
public virtual bool Delete<T>(string id) where T : IMXEntity
{
var collection = dbContext.GetCollection<T>(typeof(T).Name);
Expand All @@ -177,6 +196,12 @@ public virtual bool Delete<T>(string id) where T : IMXEntity
return result.Ok;
}

/// <summary>
/// Delete by Ids for a smaller batch size; 100 or so.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ids"></param>
/// <returns></returns>
public virtual bool Delete<T>(IList<string> ids) where T : IMXEntity
{
var collection = dbContext.GetCollection<T>(typeof(T).Name);
Expand All @@ -187,6 +212,26 @@ public virtual bool Delete<T>(IList<string> ids) where T : IMXEntity
return result.Ok;
}

/// <summary>
/// Bulk delete
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query">MongoQuery: an example could be something like this; Query<T>.In<string>(e => e.Id, ids).
/// To delete all documents, set Query as Query.Null</param>
/// <returns></returns>
public virtual long BulkDelete<T>(IMongoQuery query) where T : IMXEntity
{
var collection = dbContext.GetCollection<T>(typeof(T).Name);

var bulk = collection.InitializeOrderedBulkOperation();

bulk.Find(query).Remove();

return bulk.Execute(WriteConcern.Acknowledged).ModifiedCount;
}

#endregion

#endregion

#region "Full text search"
Expand All @@ -200,7 +245,7 @@ public virtual bool Delete<T>(IList<string> ids) where T : IMXEntity
/// <param name="take"></param>
/// <param name="skip"></param>
/// <returns></returns>
public virtual IList<T> GetManyByTextSearch<T>(string term, int take = 128, int skip = 0) where T : IMXEntity
public virtual IList<T> GetManyByTextSearch<T>(string term, int skip = 0, int take = 30) where T : IMXEntity
{
var collection = dbContext.GetCollection<T>(typeof(T).Name);

Expand Down Expand Up @@ -318,7 +363,7 @@ protected void InsertDocumentIntoHistory<T>(string id) where T : IMXEntity
collectionX.Insert(tX);
}

protected void InsertMultipleDocumentsIntoHistory<T>(IList<T> entities) where T : IMXEntity
protected void InsertManyDocumentsIntoHistory<T>(IList<T> entities) where T : IMXEntity
{
List<MXMongoEntityX<T>> xDocs = new List<MXMongoEntityX<T>>();

Expand Down
7 changes: 6 additions & 1 deletion Matrix.Core/SearchCore/MXSearchRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

namespace Matrix.Core.SearchCore
{
/// <summary>
/// An abstraction over the NEST ElasticSearch client. I'll evolve this in the coming days as there are going to be breaking changes in version 1.0
/// Diving deep into ElasticSearch engine is also one of my primary goals.
/// </summary>
public class MXSearchRepository : ISearchRepository
{
Lazy<MXSearchClient> _searchClient = new Lazy<MXSearchClient>(() => new MXSearchClient());
Expand Down Expand Up @@ -143,6 +147,7 @@ public virtual bool Update<T>(T document, string index = "") where T : MXSearchD
Client.Update<T>(c => c.Object(document).Document(document).Index(index));

return true;
}
}

}//End of repository
}
1 change: 1 addition & 0 deletions Matrix.DAL/Matrix.DAL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MongoIndexSettings\MXMongoIndexes.cs" />
<Compile Include="Repositories\ClientRepository.cs" />
<Compile Include="Repositories\BookRepository.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
28 changes: 28 additions & 0 deletions Matrix.DAL/MongoIndexSettings/MXMongoIndexes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Matrix.Core.FrameworkCore;
using Matrix.Entities.MongoEntities;
using MongoDB.Driver.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Matrix.DAL.MongoIndexSettings
{
/// <summary>
/// call this setting of indexes only once during the lifetime of the app. Though better approach is to create indexes directly in mongo shell.
/// </summary>
public class MXMongoIndexes : MXMongoRepository
{
public void SetTextIndexOnBookCollection()
{
var collection = dbContext.GetCollection<Book>("Book");

if (!collection.IndexExistsByName("book_text"))
{
collection.CreateIndex(IndexKeys.Text("nm", "au.nm", "ct.nm"), IndexOptions.SetName("book_text").SetWeight("nm", 4).SetWeight("au.nm", 3));
}
}

}//End of class
}
71 changes: 58 additions & 13 deletions Matrix.Web/Areas/Sales/Controllers/BookController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Matrix.Core.FrameworkCore;
using Matrix.Core.QueueCore;
using Matrix.Core.SearchCore;
using Matrix.DAL.Repositories;
using Matrix.DAL.SearchRepositories;
using Matrix.Entities.MongoEntities;
Expand All @@ -25,29 +26,65 @@ public BookController(IBookRepository mongoRepository, IBookSearchRepository boo
this._bookSearchRepository = bookSearchRepository;
}

public ActionResult Index()
public ActionResult Index(bool isUsingElasticSearch = true)
{
IList<Book> model;
if (isUsingElasticSearch) ViewBag.IsUsingElasticSearch = true;
else ViewBag.IsUsingElasticSearch = false;

//This is being used for checking if sample data is there. No need to do this in real scenarios.
model = _mongoRepository.GetMany<Book>(take: 1);
if (model.Count < 1)
var count = _mongoRepository.GetCount<Book>();

if (count < 1)
{
ViewBag.ShowDummyButton = true;
}

return View();
}

public ActionResult IndexSub(string term = "")

/// <summary>
/// the results here are coming from ElasticSearch server
/// </summary>
/// <param name="term"></param>
/// <returns></returns>
public ActionResult IndexSub(string term = "", bool isUsingElasticSearch = true)
{
MXTiming timing = new MXTiming();

var results = _bookSearchRepository.Search(term);
if (isUsingElasticSearch) ViewBag.IsUsingElasticSearch = true;
else ViewBag.IsUsingElasticSearch = false;

ViewBag.QueryTime = timing.Finish();
IList<BookSearchDocument> results;

if (isUsingElasticSearch)
{
MXTiming timing = new MXTiming();

results = _bookSearchRepository.Search(term);

ViewBag.QueryTime = timing.Finish();
}
else
{
MXTiming timing = new MXTiming();

var books = _mongoRepository.GetManyByTextSearch<Book>(term);

results = new List<BookSearchDocument>();

foreach (var book in books)
{
results.Add(new BookSearchDocument
{
Id = book.Id,
Title = book.Name,
Author = new MXSearchDenormalizedRefrence { DenormalizedId = book.Author.DenormalizedId, DenormalizedName = book.Author.DenormalizedName },
Category = new MXSearchDenormalizedRefrence { DenormalizedId = book.Category.DenormalizedId, DenormalizedName = book.Category.DenormalizedName },
AvaliableCopies = book.AvaliableCopies,
});
}

ViewBag.QueryTime = timing.Finish();
}

return View(results);
}

Expand Down Expand Up @@ -102,10 +139,10 @@ public ActionResult AddSampleData()
var authors = _mongoRepository.GetOptionSet<Author>(); ;
var categories = _mongoRepository.GetOptionSet<BookCategory>();

//now let's add some 10K more documents
//now let's add some 20K more documents
var randomValue = new Random();

for (int count = 0; count < 10000; count++)
for (int count = 0; count < 20000; count++)
{
var book = new Book
{
Expand Down Expand Up @@ -211,6 +248,14 @@ List<Book> getSampleBooks()
AvaliableCopies = 110,
Author = authors.FirstOrDefault(c => c.DenormalizedName == "Max Payne"),
Category = bookCategories.FirstOrDefault(c => c.DenormalizedName == "Ruby On Rails"),
},
new Book
{
Name = "Rails Tutorial",
Description = "",
AvaliableCopies = 110,
Author = authors.FirstOrDefault(c => c.DenormalizedName == "Michael Hartl"),
Category = bookCategories.FirstOrDefault(c => c.DenormalizedName == "Ruby On Rails"),
}

};
Expand Down
4 changes: 4 additions & 0 deletions Matrix.Web/Areas/Sales/Controllers/ClientContactController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ public ClientContactController(IRepository repository)

public ActionResult Index(string id) //id - clientID
{
MXTiming timing = new MXTiming();

var model = _repository.GetOne<Client>(id);

ViewBag.QueryTime = timing.Finish();

return View(model);
}

Expand Down
Loading

0 comments on commit 8e8a762

Please sign in to comment.