How to use Project to query fields in child collection? - indexing

I was trying to achieve exactly what is described in Querying a child collection by multiple values in RavenDB, but when I try to implement it, I can't seem to the location of method Project and class Field as suggested in this snippet from that original question.
public class Products_ByCategoryIdAndSpecs_SortByTotalSold : AbstractIndexCreationTask<Product>
{
public Products_ByCategoryIdAndSpecs_SortByTotalSold()
{
this.Map = products => from product in products
select new
{
product.CategoryId,
_ = Project(product.Specs, spec => new Field("Spec_" + spec.Key, spec.Value, Field.Store.NO, Field.Index.ANALYZED)),
product.TotalSold
};
}
}
I am using unstable build 721 of RavenDB

ErikR,
You need to use the syntax outlined here:
http://ravendb.net/docs/client-api/advanced/dynamic-fields

Looks like you want to use the new .Intersect() feature that has been added by Matt Warren just a few days ago. Seems to be a perfect solution for the question you have linked. Take a look here: http://issues.hibernatingrhinos.com/issue/RavenDB-51

Related

HotChocolate: Dynamic schemas and how to update filters accordingly

NOTE: If you do know that the below is not possible, this information is just as valuable.
Im checking out HotChocolate and Ive looked into the dynamic schemas
I have taken the code in your Github-example This works ok. I have extended our Product-type like so:
//Same json as in your Github-sample, new properties are "color" and some more
foreach (var field in type.GetProperty("fields").EnumerateArray())
{
string name = field.GetString();
typeDefinition.Fields.Add(new ObjectFieldDefinition(field.GetString()!, type: TypeReference.Parse("String"), pureResolver: ctx =>
{
var product = ctx.Parent<Product>();
return product.SubTypeSpecific.ContainsKey(name) ? product.SubTypeSpecific[name] : null;
}));
}
now I have "moved out" dynamic properties from a Dictionary (That is a sub-object in my documentDb) to own properties. Works well.
BUT:
How can I extend my ProductFilter in the same fashion?
I would like to extend my current Product-filter so its possible to search on the new dynamic property "color"
getProducts(where : color : {eq :"blue" }}) {...}
I can create new FilterInputDefinition, but not extend existing filter (because there is no FilterInputTypeExtensions.CreateUnsafe()
If I manage to create the new filter, is there any way to update the IQueryable-generation so that the inputed color ("blue")
So the query to my CosmosDb will be created automatically?
Many thanks in advance.

Getting New Field using the CMS Service

Had some trouble getting the newly created fields using the "this.cmsservice.getcurrentpage()".
I've tried extending the PageNormalizer, but unsuccessful.
Any idea or workaround.
Resolved this by extending/overriding the 'CMS_PAGE_NORMALIZER'. Added the new field under the properties of the original structure.
See below code:
export class pageNormalizer implements Converter<Occ.CMSPage, CmsStructureModel> {
convert(source: any, target?: CmsStructureModel): CmsStructureModel {
target.page.properties = {
newfield: source.newfield,
};
return target;
}
}
Although I never worked with the spartacus-storefront, you problem seems similar to another one I´ve seen here before.
Try this:
https://pipedrive.readme.io/docs/adding-a-new-custom-field

Raven DB: How can I delete all documents of a given type

More specifically in Raven DB, I want to create a generic method with a signature like;
public void Clear<T>() {...
Then have Raven DB clear all documents of the given type.
I understand from other posts by Ayende to similar questions that you'd need an index in place to do this as a batch.
I think this would involve creating an index that maps each document type - this seems like a lot of work.
Does anyone know an efficient way of creating a method like the above that will do a set delete directly in the database?
I assume you want to do this from the .NET client. If so, use the standard DocumentsByEntityName index:
var indexQuery = new IndexQuery { Query = "Tag:" + collectionName };
session.Advanced.DocumentStore.DatabaseCommands.DeleteByIndex(
"Raven/DocumentsByEntityName",
indexQuery,
new BulkOperationOptions { AllowStale = true });
var hilo = session.Advanced.DocumentStore.DatabaseCommands.Get("Raven/H‌​ilo/", collectionName);
if (hilo != null) {
session.Advanced.DocumentStore.DatabaseCommands.Delete(hilo.‌​Key, hilo.Etag);
}
Where collectionName is the actual name of your collection.
The first operation deletes the items. The second deletes the HiLo file.
Also check out the official documentation - How to delete or update documents using index.
After much experimentation I found the answer to be quite simple, although far from obvious;
public void Clear<T>()
{
session.Advanced.DocumentStore.DatabaseCommands.PutIndex(indexName, new IndexDefinitionBuilder<T>
{
Map = documents => documents.Select(entity => new {})
});
session.Advanced.DatabaseCommands.DeleteByIndex(indexName, new IndexQuery());
}
Of course you almost certainly wouldn't define your index and do your delete in one go, I've put this as a single method for the sake of brevity.
My own implementation defines the indexes on application start as recommended by the documentation.
If you wanted to use this approach to actually index a property of T then you would need to constrain T. For example if I have an IEntity that all my document classes inherit from and this class specifies a property Id. Then a 'where T : IEntity' would allow you to use that property in the index.
It's been said in other places, but it's also worth noting that once you define a static index Raven will probably use it, this can cause your queries to seemingly not return data that you've inserted:
RavenDB Saving to disk query
I had this problem as well and this is the solution that worked for me. I'm only working in a test project, so this might be slow for a bigger db, but Ryan's answer didn't work for me.
public static void ClearDocuments<T>(this IDocumentSession session)
{
var objects = session.Query<T>().ToList();
while (objects.Any())
{
foreach (var obj in objects)
{
session.Delete(obj);
}
session.SaveChanges();
objects = session.Query<T>().ToList();
}
}
You can do that using:
http://blog.orangelightning.co.uk/?p=105

NHibernate: Creating a criteria which applies for all queries on a table

Using Castle ActiveRecord / NHibernate: Is there a way you can force an ICriterion on all queries on a table?
For example, a good amount of of my tables have a "UserId" column. I might want to ensure that I am always selecting rows for the logged in user. I can easily create an ICriterion object, but I am forced to supply it for different methods: FindAll(), FindFirst(), FindLast() etc.
Is there a way to force a WHERE clause on all queries to a Castle ActiveRecord?
I finally found a great solution (using filters). Since Castle AR does not have any native API for mapping to NHibernate filters, this part was pretty much undocumented. So here goes.
This example filter, will make sure you will never get news more than a year old, no matter what kind of query you use on the ActiveRecord. You can probably think of more practical applications for this.
First, create an ActiveRecord "News".
Use the following code before you initialize ActiveRecordStarter.
ActiveRecordStarter.MappingRegisteredInConfiguration += MappingRegisteredInConfiguration;
Castle.ActiveRecord.Framework.InterceptorFactory.Create = () => { return new EnableFiltersInterceptor(); };
Then, add the missing function and class:
void MappingRegisteredInConfiguration(Castle.ActiveRecord.Framework.ISessionFactoryHolder holder)
{
var cfg = holder.GetConfiguration(typeof (ActiveRecordBase));
var typeParameters = new Dictionary<string, IType>
{
{"AsOfDate", NHibernateUtil.DateTime}
};
cfg.AddFilterDefinition(new FilterDefinition("Latest", "", typeParameters));
var mappings = cfg.CreateMappings(Dialect.GetDialect(cfg.Properties));
var newsMapping = cfg.GetClassMapping(typeof (News));
newsMapping.AddFilter("Latest", ":AsOfDate <= Date");
}
public class EnableFiltersInterceptor : EmptyInterceptor
{
public override void SetSession(ISession session)
{
session.EnableFilter("Latest").SetParameter("AsOfDate", DateTime.Now.AddYears(-1));
}
}
And voila! Queries on News, e.g. FindAll(), DeleteAll(), FindOne(), Exists(), etc. will never touch entries more than a year old.
The closest thing would be using filters. See http://ayende.com/Blog/archive/2009/05/04/nhibernate-filters.aspx

Encapsulating common logic (domain driven design, best practices)

Updated: 09/02/2009 - Revised question, provided better examples, added bounty.
Hi,
I'm building a PHP application using the data mapper pattern between the database and the entities (domain objects). My question is:
What is the best way to encapsulate a commonly performed task?
For example, one common task is retrieving one or more site entities from the site mapper, and their associated (home) page entities from the page mapper. At present, I would do that like this:
$siteMapper = new Site_Mapper();
$site = $siteMapper->findByid(1);
$pageMapper = new Page_Mapper();
$site->addPage($pageMapper->findHome($site->getId()));
Now that's a fairly trivial example, but it gets more complicated in reality, as each site also has an associated locale, and the page actually has multiple revisions (although for the purposes of this task I'd only be interested in the most recent one).
I'm going to need to do this (get the site and associated home page, locale etc.) in multiple places within my application, and I cant think of the best way/place to encapsulate this task, so that I don't have to repeat it all over the place. Ideally I'd like to end up with something like this:
$someObject = new SomeClass();
$site = $someObject->someMethod(1); // or
$sites = $someObject->someOtherMethod();
Where the resulting site entities already have their associated entities created and ready for use.
The same problem occurs when saving these objects back. Say I have a site entity and associated home page entity, and they've both been modified, I have to do something like this:
$siteMapper->save($site);
$pageMapper->save($site->getHomePage());
Again, trivial, but this example is simplified. Duplication of code still applies.
In my mind it makes sense to have some sort of central object that could take care of:
Retrieving a site (or sites) and all nessessary associated entities
Creating new site entities with new associated entities
Taking a site (or sites) and saving it and all associated entities (if they've changed)
So back to my question, what should this object be?
The existing mapper object?
Something based on the repository pattern?*
Something based on the unit of work patten?*
Something else?
* I don't fully understand either of these, as you can probably guess.
Is there a standard way to approach this problem, and could someone provide a short description of how they'd implement it? I'm not looking for anyone to provide a fully working implementation, just the theory.
Thanks,
Jack
Using the repository/service pattern, your Repository classes would provide a simple CRUD interface for each of your entities, then the Service classes would be an additional layer that performs additional logic like attaching entity dependencies. The rest of your app then only utilizes the Services. Your example might look like this:
$site = $siteService->getSiteById(1); // or
$sites = $siteService->getAllSites();
Then inside the SiteService class you would have something like this:
function getSiteById($id) {
$site = $siteRepository->getSiteById($id);
foreach ($pageRepository->getPagesBySiteId($site->id) as $page)
{
$site->pages[] = $page;
}
return $site;
}
I don't know PHP that well so please excuse if there is something wrong syntactically.
[Edit: this entry attempts to address the fact that it is oftentimes easier to write custom code to directly deal with a situation than it is to try to fit the problem into a pattern.]
Patterns are nice in concept, but they don't always "map". After years of high end PHP development, we have settled on a very direct way of handling such matters. Consider this:
File: Site.php
class Site
{
public static function Select($ID)
{
//Ensure current user has access to ID
//Lookup and return data
}
public static function Insert($aData)
{
//Validate $aData
//In the event of errors, raise a ValidationError($ErrorList)
//Do whatever it is you are doing
//Return new ID
}
public static function Update($ID, $aData)
{
//Validate $aData
//In the event of errors, raise a ValidationError($ErrorList)
//Update necessary fields
}
Then, in order to call it (from anywhere), just run:
$aData = Site::Select(123);
Site::Update(123, array('FirstName' => 'New First Name'));
$ID = Site::Insert(array(...))
One thing to keep in mind about OO programming and PHP... PHP does not keep "state" between requests, so creating an object instance just to have it immediately destroyed does not often make sense.
I'd probably start by extracting the common task to a helper method somewhere, then waiting to see what the design calls for. It feels like it's too early to tell.
What would you name this method ? The name usually hints at where the method belongs.
class Page {
public $id, $title, $url;
public function __construct($id=false) {
$this->id = $id;
}
public function save() {
// ...
}
}
class Site {
public $id = '';
public $pages = array();
function __construct($id) {
$this->id = $id;
foreach ($this->getPages() as $page_id) {
$this->pages[] = new Page($page_id);
}
}
private function getPages() {
// ...
}
public function addPage($url) {
$page = ($this->pages[] = new Page());
$page->url = $url;
return $page;
}
public function save() {
foreach ($this->pages as $page) {
$page->save();
}
// ..
}
}
$site = new Site($id);
$page = $site->addPage('/');
$page->title = 'Home';
$site->save();
Make your Site object an Aggregate Root to encapsulate the complex association and ensure consistency.
Then create a SiteRepository that has the responsibility of retrieving the Site aggregate and populating its children (including all Pages).
You will not need a separate PageRepository (assuming that you don't make Page a separate Aggregate Root), and your SiteRepository should have the responsibility of retrieving the Page objects as well (in your case by using your existing Mappers).
So:
$siteRepository = new SiteRepository($myDbConfig);
$site = $siteRepository->findById(1); // will have Page children attached
And then the findById method would be responsible for also finding all Page children of the Site. This will have a similar structure to the answer CodeMonkey1 gave, however I believe you will benefit more by using the Aggregate and Repository patterns, rather than creating a specific Service for this task. Any other retrieval/querying/updating of the Site aggregate, including any of its child objects, would be done through the same SiteRepository.
Edit: Here's a short DDD Guide to help you with the terminology, although I'd really recommend reading Evans if you want the whole picture.