-
Notifications
You must be signed in to change notification settings - Fork 27
Querying for content
the QueryHelper<T>
class is in the puck.core.Helpers
namespace and is used to query for content stored in Lucene. Puck stores your content revisions in SQL Server using entity framework but that's for the backoffice. your web pages/templates retrieve content from Lucene, which is where the last published revision is stored and can be queried from.
the T parameter is the Type of ViewModel you're trying to retrieve. you'd think that this:
var qh = new QueryHelper<Page>();
would return all ViewModels of type Page
but actually it returns all ViewModels who have Page
in their inheritance chain. so basically all ViewModels which can be cast successfully to Page
. if you want to return only Page
content specifically, you can do the following:
var qh = new QueryHelper<Page>()
.ExplicitType();
if you wanted to limit the search to the current root (if you have a multi-site setup) and also get only content of the current language (taking into account localisation settings for the current url) you would do the following:
qh.CurrentRoot(Model)
.CurrentLanguage();
notice how you can chain methods. the Model
argument above is the Model property of your template.
you can also search fields in a strongly typed way:
qh.Must().Field(x => x.MainContent, "london")
you can also chain multiple fields with Or()
and the search will use the Lucene analyzers specified (per field) in the ViewModel being searched for.
there are also methods for range queries:
qh.GreaterThanEqualTo(x => x.Age, 18);
qh.Range(x => x.Updated, new DateTime(2019, 7, 12, 11, 28, 20), DateTime.Now, true, true);
the two boolean arguments for Range()
are inclusive start and inclusive end, respectively.
you can also search Lists.
public class Page:BaseModel
{
[Display(ShortName ="input",GroupName ="Content")]
[UIHint("ListEditor")]
public List<string> Names { get; set; }
}
given the model above has a Names
property which is a List<string>
, you can search for any names in the list by doing the following:
var qh = new QueryHelper<Page>();
qh.Must().Field(x=>x.Names,"Joe")
.GetAll()
the above query will search the list of names for "Joe".
you can execute your query by using the Get()
or GetAll()
methods on the QueryHelper
instance.
Puck also supports Geo queries. the first thing you need to do is include a GeoPosition
property in your ViewModel. GeoPosition
can be found in the puck.core.Models
namespace.
public class Page:BaseModel
{
[UIHint("PuckGoogleLongLat")]
public GeoPosition Location { get; set; }
}
you can see in the ViewModel above, the location property is of type GeoPosition
and it uses a google maps editor template to set the Longitude and Latitude values.
to search this field, you would do the following:
var geoQuery = new QueryHelper<Page>();
geoQuery.WithinMiles(x => x.Location.LatLong, 51.5073509, -0.1277582, 10);
var georesults = geoQuery.GetAll();
the query above searches for Page
ViewModels which are within 10 miles of Latitude 51.5073509, and Longitude -0.1277582. there is also a WithinKilometers
method if you prefer.
if you don't want to use the GeoPosition class, you can specify your own Property as being a spatial field:
[IndexSettings(Spatial=true)]
public string LatLong { get; set; }
use the IndexSettings
attribute to mark the property as a spatial field and the value for a spatial field must be a string in the format of "Latitude,Longitude". eg "51.50,-0.12" - notice the comma separating the Latitude from the Longitude and also notice it's Y,X or Latitude first.
your ViewModels will all have access to extensions methods to help you get Parent, Ancestors, Children, Descendants, Siblings and Variants.
here's an example of getting Descendants of the current ViewModel:
var descendants = Model.Descendants<Page>();
if you're using QueryHelper
rather than the extension methods, you also have access to Ancestors
, Siblings
, Children
and Descendants
methods.
for example:
var qh = new QueryHelper<Section>()
.Descendants(Model)
.ExplicitType()
.GetAll();
the query above will get the descendants of the current Model
which are of type Section
you can pass in an inner query to the Group()
, And()
, Or()
and Not()
methods for more advanced queries. here's an example:
var qh = new QueryHelper<Page>();
var innerQuery = qh.New();
qh.Must().Group(innerQuery.Field(x=>x.MainContent,"news").Field(x=>x.MainContent,"events"));
qh.GetAll();
in the above query, you use New()
to get a new inner query and then have a query where MainContent
must contain either "news" or "events".
if you've intercepted the current page and want to retrive its ViewModel from your controller action, you can do this:
var currentNode = QueryHelper<Page>.Current();