How to efficiently store records as Ember query parameters - ember.js

Background: The user can filter a list based on tags, every tag is an Ember Data model. The selected filtering tags should be stored in the URL via query parameters. I also want to display the selected tags in the interface.
What's the best way to go about this?
I'm pretty sure I only want to store the IDs, but if I do this I have to maintain a separate variable / computed property where I store the actual record of the ID which comes from the query parameters. This kind of duplication seems wrong to me.
Apart from this issue I don't know if I should use an array query parameter or build an comma separated string of the IDs. If I do the former I end up with ugly URLs like ?tags=%5B"3"%5D. But doing the later means doing even more work.
So what's your approach to this kind of problem? I hope I'm missing something obvious that doesn't have so many downsides :)

Easy!
Find out which non-alphanumeric characters are not getting encoded in URLs. Using this tool, I found these characters: ~!*()_-.
Pick one character that is not used in your tag names. Let's say it's *. Use it as a delimiter.
Use tag names for tag ids. Or at least enforce unique tag names.
Then you've got a nice readable query:
?tags=foo*bar*baz&search=quux
To implement custom query param serialization/deserialization, do this:
Ember.Route.reopen({
serializeQueryParam: function(value, urlKey, defaultValueType) {
if (defaultValueType === 'array') {
return `${value.join('*')}`;
}
return this._super(...arguments);
},
deserializeQueryParam: function(value, urlKey, defaultValueType) {
if (defaultValueType === 'array') {
return value.split('*');
}
return this._super(...arguments);
}
});
Demo: app, code.
If you must use numeric tag ids in query params (for example, your tag names aren't unique), then you need some more customization: app, code.

Related

How to run a combination of query and filter in elasticsearch?

I am experimenting using elasticsearch in a dummy project in django. I am attempting to make a search page using django-elasticsearch-dsl. The user may provide a title, summary and a score to search for. The search should match all the information given by the user, but if the user does not provide any info about something, this should be skipped.
I am running the following code to search for all the values.
client = Elasticsearch()
s = Search().using(client).query("match", title=title_value)\
.query("match", summary=summary_value)\
.filter('range', score={'gt': scorefrom_value, 'lte': scoreto_value})
When I have a value for all the fields then the search works correctly, but if for example I do not provide a value for the summary_value, although I am expecting the search to continue searching for the rest of the values, the result is that it comes up with nothing as a result.
Is there some value that the fields should have by default in case the user does not provide a value? Or how should I approach this?
UPDATE 1
I tried using the following, but it returns every time no matter the input i am giving the same results.
s = Search(using=client)
if title:
s.query("match", title=title)
if summary:
s.query("match", summary=summary)
response = s.execute()
UPDATE 2
I can print using the to_dict().
if it is like the following then s is empty
s = Search(using=client)
s.query("match", title=title)
if it is like this
s = Search(using=client).query("match", title=title)
then it works properly but still if i add s.query("match", summary=summary) it does nothing.
You need to assign back into s:
if title:
s = s.query("match", title=title)
if summary:
s = s.query("match", summary=summary)
I can see in the Search example that django-elasticsearch-dsl lets you apply aggregations after a search so...
How about "staging" your search? I can think if the following:
#first, declare the Search object
s = Search(using=client, index="my-index")
#if parameter1 exists
if parameter1:
s.filter("term", field1= parameter1)
#if parameter2 exists
if parameter2:
s.query("match", field=parameter2)
Do the same for all your parameters (with the needed method for each) so only the ones that exist will appear in your query. At the end just run
response = s.execute()
and everything should work as you want :D
I would recommend you to use the Python ES Client. It lets you manage multiple things related to your cluster: set mappings, health checks, do queries, etc.
In its method .search(), the body parameter is where you send your query as you normally would run it ({"query"...}). Check the Usage example.
Now, for your particular case, you can have a template of your query stored in a variable. You first start with, let's say, an "empty query" only with filter, just like:
query = {
"query":{
"bool":{
"filter":[
]
}
}
}
From here, you now can build your query from the parameters you have.
This is:
#This would look a little messy, but it's useful ;)
#if parameter1 is not None or emtpy
#(change the if statement for your particular case)
if parameter1:
query["query"]["bool"]["filter"].append({"term": {"field1": parameter1}})
Do the same for all your parameters (for strings, use "term", for ranges use "range" as usual) and send the query in the .search()'s body parameter and it should work as you want.
Hope this is helpful! :D

How to match strings in MongoDb and ignore any whitespace

Is it possible to ignore all whitespace using regex in MongoDB queries?
My Node.js program uses Cheerio to pull data from a number of websites, parses and then stores the data in MongoDB. My database has a People collection that keys on the string field Name.
Problem occurs where one website (site-A) shows the name HTML text as John&npsp;Smith, whereas another website (site-B) shows name as John Smith. My program has two scripts, one that scrapes site-A and another to scrape site-B; both of which use the following to scrape the Name data -
var $ = cheerio.load(htmlrow);
var personobj = { name: $('td.person a').text().trim() }
Each script then uses the following MongoDb command (using the native driver) to upsert the scraped data, keying on the Name field. However, this results in two records in the People collection -
db.collection('people').update(
{ Name: personobj.name },
{ $set: { LastScan: new Date() }},
{ upsert: true },
function(){} );
Now, I tried using the regex "extended" 'x' option to query in MongoDb, but it's not working. In fact, I tried testing the 'x' option via the find operator in Robomongo, and it returns zero records. I also note that when find testing in Robomongo, and I simply type Name: "John Smith", it only returns the site-B record, the one without the $nbsp; whitespace; even though when I view the detail of both records, the name strings appear identical. (I suppose difference is caused somewhere by all the encoding/decoding going on here to scrape, parse, store, retrieve... but I'm not sure where or why).
Is it possible to ignore all whitespace when querying MongoDb using regex?
Or, is it easier to handle this in my javascript parse line, to somehow replace and 'standardize' all possible whitespace characters? (Any recommended library to do so?)

How to handle search queries that contain "/" in Ember.js apps?

I created a small app that takes a search query and returns mock content. You can see the app here: http://embersherpa.com/wip/search-example/app/#/search
It work correctly when entering the query via the search but not via the url.
How do I correctly handle search queries with "/" when entered via url?
You should probably not put your keyword directly into the URL. Instead escape it first with encodeURIComponent and unescape it with decodeURIComponent in your model hook. The rough code look like this:
serialize : function(model){
// model is the keyword in your case
return {keyword: encodeURIComponent(model)};
},
model : function(params){
var keyword = decodeURIComponent(params.keyword);
// do what you need to do with the keyword
}

.Net MVC route for undetermined number of folders (nested category structure)

I'm exploring the possibility of using MVC for my next e-commerce site. One thing I can't seem to figure out is whether or not I can use the same URL convention I normally use. Currently, the URL for any product could be one of the following:
Category/SubCategory/Product1.html
Category/SubCategory/SubSubCategory/Product2.html
Category/SubCategory/SubSubCategory/Product3.html
Category/SubCategory/SubSubCategory/SubSubSubCategory/Product4.html
etc.
The issue I'm having is with the nested category structure. So far the only thing I've come up with is as follows:
routes.MapRoute(
"Products",
"{categories}/{productname}",
new { controller = "Product", action = "Details", productname = UrlParameter.Optional },
new { categories = #"\w+/\w+" }
);
I was hoping that {categories} could be matched with any one of the following which I could process to identify the right category that the product belongs to:
Sport/Tennis/Rackets/ProductA
Sport/Badminton/Rackets/ProductB
But the route shown above doesn't work correctly.
Does anyone know how this can be achieved, or if it can't be done?
The routing system allows you to define catchall parameters, which ignore slashes and capture
everything up to the end of a URL. Designate a parameter as being catchall by prefixing it with an
asterisk (*).
routes.MapRoute(null, "Articles/{*articlePath}",
new { controller = "Articles", action = "Show" }
);
You can only have one catchall parameter in a URL pattern, and it must be the last (i.e.,
rightmost) thing in the URL, since it captures the entire URL path from that point onward.
One Caveat though, it doesn’t capture anything from the query string as route objects only look at the
path portion of a URL.
Catchall parameters are useful if you’re letting visitors navigate through some kind of arbitrary
depth hierarchy, such as in a content management system (CMS).
You can use the RouteData object to extract information about the route. For your needs, you would probably create a custom route handler that parses the route data and calls the correct controller methods.
You need access to the individual segments of the URL so you need to divide the category segment into two segments. That would make it much easier.
Let's say we call Tennis and Badminton categories and Rackets within those categories as a product class
You need a way to access the category, productClass and productName parameters. Supposing that "Sport" is fixed in this case, I will do it like this:
routes.MapRoute(
"Products",
"sport/{category}/{productClass}/{productName}",
new { controller = "Product", action = "Details", productClass = UrlParameter.Optional, productName = UrlParameter.Optional }
);
Your action method will be something like this
public ActionResult Details(string category, string productClass, string productName){
//Do whatever you need to do in order to get the specified product
}
You could use Areas in MVC2
So it would read:
Area/Controller/View/id
So in your case it would end up being:
Sport being the area,
Tennis The controller,
Rackets the view,
ProductA being an ID or querystring,
http://www.asp.net/mvc/videos/aspnet-mvc-2-areas
Hope this makes sense.

Search value in body tag in Sitecore

I want to implement search functionality, So my requirement is I want to search some keyword in body tag in all content page. I do not know how I can search keyword in body tag in Sitecore. Please guide me?
As Anton outlined, the concept of searching the Body tag is wrong for Sitecore. You want to think in terms of Content in fields of Items. Sitecore's ContentSearch is how you can achieve this.
Sitecore comes with default indexes out-of-the-box that you should use for the search. You should rebuild these via the Index Manager in the Content Editor and then base your search on the basic example I've outlined for you below.
public IEnumerable<Item> Search(string searchterm)
{
string indexName = "sitecore_web_index";
using (var index = ContentSearchManager.GetIndex(indexName).CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
IQueryable<SearchResultItem> query = index.GetQueryable<SearchResultItem>().Where(i => i.Content.Contains(searchterm)).Filter(predicate);
var searchResults = query.GetResults();
foreach (var hit in searchResults.Hits)
{
yield return hit.Document.GetItem();
}
}
}
jRobbins's answer is sensible (he get's my upvote). However, it is technically possible to index the content of the body tag. I would be cautious with this. I've seen it working well, but I've also seen it completely destroy the performance of a site.
The approach involves the creating a computed field in your index. You populate the computed field by making a web request to your newly published page and scraping the response body tag.
Here's are a couple of module that more or less does that:
https://github.com/efocus-nl/sitecorewebsearch
https://github.com/hermanussen/sitecore-html-crawler
If you can accept something a little less accurate, then you could loop through each of the components on your page and extract content from their datasources. That approach is discussed in this video:
http://www.techphoria414.com/Blog/2012/May/Sitecore_Page_Editor_Unleashed