I am seeing a very strange behaviour from the Sitecore 7.1 Search when ordering by a string field. The code is something like this:
var indexableItem = new SitecoreIndexableItem(Sitecore.Context.Item);
var searchIndex = ContentSearchManager.GetIndex(indexableItem);
var context = searchIndex.CreateSearchContext();
var results = new List<Item>();
var count = 0;
var totalSearchResults = 0;
var contactColleagues = context.GetQueryable<SearchResultItem>()
.FirstOrDefault(x => x.ItemId == Sitecore.Context.Item.ID);
if (contactColleagues != null)
{
var items = contactColleagues.GetDescendants<ColleagueSearchResultItem>(context)
.Where(x => x.TemplateId == Templates.Colleague);
items = items.OrderBy(x => x.Surname);
var resultItems = items.Page(this.PageNumber, PageSize).GetResults();
}
This all works as expected and returns my dataset ordered by surname as expected. That is until a certainly individual comes along who's surname is "Or". Now Sitecore returns this persons name at the start of the list, no matter what we do.
After some testing I found the same issue happened if I decided to call someone "Andy And", this would appear at the being of the list before "Jeff Aardvark".
I'm assuming this is a bug in the way the data is being presented to the Lucene index.
Has anyone come across this, or have any thoughts about how this could be worked around?
Thanks in advance.
I think you have a problem with stop words. The default analyzer removes them when the item is crawled. You can however prevent this behaviour.
This post explains how to to turn off the stop words filter:
http://blog.horizontalintegration.com/2015/01/08/sitecore-standard-analyzer-turn-off-the-stop-words-filter/
If you look at the surname field in the index using Luke (https://code.google.com/p/luke/) is the value blank? It sounds like potentially dangerous query values are being stripped out either at the index level or as they are being loaded from the index.
Related
I want to Remove an item from a list once chosen in the dropdown and then the next dropdown won't have that item anymore. I've already made something manually but it takes super long and is not really ideal because you would need to go down in order otherwise it gets all mixed up.
https://docs.google.com/spreadsheets/d/1o3J1ZXzxQL11pdN1FDOQZ7YXbSib6A8KwkxBzO5bSM0/edit?usp=sharing
I've made 3 tabs one where I explain what I want and the other were I made it manually so you have an idea on how it works. But remember the manually one you need to go down in order. I want for it to look at a range so it doesn't matter which dropdown I choose for it to get removed from the list.
If it isn't possible to do it by range then like the same way as manually but then in script form would be a great help as well.
Here is what I tried but I'm really new with scripting so I might not even be close:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Dropdown');
//get's the value in range A1 ( the firstdropdown value )
var firstDrop = ss.getRange("A1").getValue();
//get's the value in range A3 ( the seconddropdown value )
var secondDrop = ss.getRange("A3").getValue();
//get the list ( I don't want to put the list in here sincec I'll be
//working with entries from google forms. so the list will be changing)
var list = ss.getRange("H1:H5").getValues();
if(firstDrop == list){
var newlist = (list-firstDrop);
}
}
This may work for you - I think it gives you the result you want, but its appearance isn't ideal. I've placed it into your sheet, in the last tab. I believe that this is the same approach as Mateo's earlier answer, but down with a formula instead of code.
=SORT(FILTER(B2:B;NOT(COUNTIF(A2:A;B2:B))))
where A is the column where you are entering data, and B has your list of valid names/words.
I use this formula to filter the list of words/names that show in each dropdown list. It starts with the original list, and excludes any that have already been selected. The data validation for your cells points to the filtered list, not the original list.
The drawback is that once you select a word/name, it is no longer eligible for the dropdown cells, so even the cell where it has already been applied shows it as an invalid entry, with a little red triangle. The benefit of a working solution may outweigh this though.
I believe it should look like this:
function availableSlots(){
var form = FormApp.openByUrl('URL_OF_YOUR_FORM'); // TODO add your form url
// need to read what slots are available
var slots = SpreadsheetApp
.getActiveSpreadsheet()
.getRange("slots!A2:C10")
.getValues(); // TODO make sure getRange matches your quota range
var choice = [];
// loop through our available slots
for (s in slots){
// test if slot still available
if (slots[s][0] != "" && slots[s][2] > 0){
choice.push(slots[s][0]); // if so we add to temp array
}
}
var formItems = form.getItems(FormApp.ItemType.LIST); // our form list items
// TODO assumption that first select list is the one you want to change
// change formItems[n] if you have more than one select list
// and we just rewrite all the options to ones that are free
formItems[0].asListItem().setChoiceValues(choice);
}
As I was not sure which dropdown menus you wanted to use I have created a sample sheet with your requirements (photo attached below). In order to reduce the list of items in function of the output of the rest of the dropdowns I have used on onEdit() trigger to check for any changes in these dropdowns and in function of these cell values remove the required items from the list.
The following piece of code has self explanatory comments that address how I have implemented this:
function onEdit(e) {
// Get sheet
var sheet = SpreadsheetApp.getActive().getSheetByName('Share your Ideas here :)');
// Get list from range. Flat will make the 2D array returned by getVaues() into a 1D array
var list = sheet.getRange("E1:E5").getValues().flat();
// Get values from the dropdowns
var a = sheet.getRange("A1");
var b = sheet.getRange("B1");
var c = sheet.getRange("C1");
// Check if any of the values in the dropdowns match the list and if so remove them from
// the list
var index = list.indexOf(a.getValue()); if(index != -1){list.splice(index,1);}
index = list.indexOf(b.getValue()); if(index != -1){list.splice(index,1);}
index = list.indexOf(c.getValue()); if(index != -1){list.splice(index,1);}
// Create the data validation rule with the filtered list
var rule = SpreadsheetApp.newDataValidation().requireValueInList(list).setAllowInvalid(false).build();
// Create/update the dropdowns with the right filtered list
a.setDataValidation(rule);
b.setDataValidation(rule);
c.setDataValidation(rule);
}
References
Data Validation
requireValueInList
I have an interactive grid with a bunch of records, and I want to set up a button on the page that changes one column in all records currently selected.
Running APEX 18.2, the IG has a whole bunch of columns and I want to change just one of them, but on a whole bunch of rows, so I do need a button.
The IG has ROWID as PK because the actual PK is assembled from 4 different columns.
I have spent some time googling this issue and have found a couple people with solutions:
http://thejavaessentials.blogspot.com/2017/03/getting-selected-rows-in-oracle-apex.html
This is the first, and simplest solution. But it doesn't return any rowid or anything like that, it returns the value in the first column.
Then I also found
http://apex-de.blogspot.com/2018/09/update-several-rows-in-tabular-form-grid.html
and
https://ruepprich.wordpress.com/2017/03/23/bulk-updating-interactive-grid-records/
Which are pretty similair and seem to be the best for me, but I get a Javascript error in the console: http://prntscr.com/n5wvqj
And I dont really know much Javascript, so I dont know what went wrong or how to best fix it.
I set up a Dynamic action on button click that executes Javascript and I have the selected element being the region named CUR_STAT.
var record;
//Identify the particular interactive grid
var ig$ = apex.region("CUR_STAT").widget();
//Fetch the model for the interactive grid
var grid = ig$.interactiveGrid("getViews","grid");
//Fetch the model for the interactive grid
var model = ig$.interactiveGrid("getViews","grid").model;
//Fetch selected records
var selectedRecords = apex.region("CUR_STAT").widget().interactiveGrid("getViews","grid").view$.grid("getSelectedRecords");
//Loop through selected records and update value of the AVT_OBR column
for (idx=0; idx < selectedRecords.length; idx++)
{
//Get the record
record = model.getRecord(selectedRecords[idx][0]);
// set Value for column AVT_OBR on "D"
model.setValue(record,"AVT_OBR", 'D');
}
The column named AVT_OBR is a select list with display values(DA, NE) and return values(D, N). But I tried having it be a text field and it didnt help.
I want to be able to select multiple columns and change the data in those entries.
If possible I would also like to be able to change data in such a way in a hidden column. Or if I could get all the ROWIDs for selected records and execute a PLSQL block with them.
Ended up with noone responding so I spent a lot of time and finally came up with a solution.
var g = apex.region('myIG').widget().interactiveGrid('getViews','grid');
var r = g.getSelectedRecords();
for(i = 0; i < r.length; i++) {
g.model.setValue(r[i], 'myColumn', 'Value');
}
For some reason none of the solutions I found had worked. But I learned from those solutions and made this simple piece of code that does what I need.
Also, I was wanting to set up so I could do this set value on a hidden column, I achieved this by just having the column visible and editable, but then when running the page I clicked on the column and hid it, and set the current view as the default report.
If anyone stumbles upon this question, I hope it helps.
I'm new to Google script and hoping someone here could answer this.
I have 7 columns and each one has a drop down box so we can select a status "Ready", "Approved", "Waiting" etc.
There will soon be over 500 rows of statuses so ideally I would like to have a function on each column to automatically set the status of the column after it.
Example Cells:
Ready|Waiting|Waiting|Waiting|Waiting|Waiting|Waiting
When the first task is Approved, the cells should look like this:
Approved|Ready|Waiting|Waiting|Waiting|Waiting|Waiting
In the above example, the first cell should be clicked "Approved" by the user from the drop down list. Then the script should read the cell edit, and switch the next cell from "Waiting" to "Ready"
I am looking at the script route as I need to have the drop down cells clickable. If I put a function onto the cell itself, I lose the drop down options.
Any help with this would be really awesome!
Thanks in advance!
You may want to check this YouTube video and this transcribed code can be tweaked to suit your needs:
function setDataValid_(range, sourceRange) {
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(sourceRange, true).build();
range.setDataValidation(rule);
}
function onEdit() {
var aSheet = SpreadsheetApp.getActiveSheet();
var aCell = aSheet.getActiveCell();
var aColumn = aCell.getColumn();
if (aColumn == 1 && aSheet.getName() == 'Worksheet') {
var range = aSheet.getRange(aCell.getRow(), aColumn + 1);
var sourceRange = SpreadsheetApp.getActiveSpreadsheet().getRangeByName(aCell.getValue());
setDataValid_(range, sourceRange)
}
}
And for additional insights, you may want to also see this thread.
I have a table in Dynamo with a hash & range index plus a secondary global index with just a hash. If I try to Query or Save an object I get the following error:
Number of hash keys on table TableName does not match number of hash keys on type ObjectModelType
(Replacing TableName and ObjectModelType with the actual table and model type)
I have the hash properties (both the primary and secondary) decorated with DynamoDBHashKey
Googling the error turns up exactly zero results
Update: Ok, so not exactly zero, obviously it now returns this question!
Update the second: I've tried using the helper API & it works just fine, so I am assuming at this point that the Object Persistence Model doesn't support Global Secondary Indexes
I encountered the same problem and found FromQuery worked, although QueryFilter is actually from the DocumentModel namespace:
var queryFilter = new QueryFilter(SecondaryIndexHashKeyColumn, QueryOperator.Equal, "xxxx");
queryFilter.AddCondition(SecondaryIndexRangeKeyColumn, QueryOperator.LessThan, DateTime.Today);
var items = context.FromQuery<MyItem>(new QueryOperationConfig { IndexName = SecondaryIndexName, Filter = queryFilter }).ToList();
Thank you Brendon for that tip! I was able to adapt it to get deserialization of a multiple result set.
var queryFilter = new QueryFilter(indexedColumnName, QueryOperator.Equal, targetValue);
Table table = Table.LoadTable(client, Configuration.Instance.DynamoTable);
var search = table.Query(new QueryOperationConfig { IndexName = indexName, Filter = queryFilter });
List<MyObject> objects = new List<MyObject>();
List<Document> documentSet = new List<Document>();
do
{
documentSet = search.GetNextSetAsync().Result;
foreach (var document in documentSet)
{
var record = JsonConvert.DeserializeObject<MyObject>(document.ToJson());
objects .Add(record);
}
} while (!search.IsDone);
Thanks x1000!! :)
I have an item structure that doens't correspond to "documents" in the standard Sitecore sense. It corresponds to data items.
One of the relationships that my items have is the following:
Person -> State -> Country
Where a Person has a link field to a State and state's have link fields to a Country.
My question is: How would one write a query to retrieve all of the People who have an eventual link to a Country of a certain abbreviation?
I'm stumped as to how to do it in Sitecore Query. My current solution is using LINQ and several queries.
Assuming that the links between these items where created using a Reference field, such as a Droplink, Treelist, Droptree, etc., you can traverse the references/referrers using the Sitecore Links database.
Here is an example (untested) that starts with a country item and fetches any referring states. The same query is performed on the states to fetch any referring people. The results are added to a generic List<Item> collection.
List<Item> peopleList = new List<Item>();
var countryReferences = Globals.LinkDatabase.GetReferences(countryItem);
var referringStates = countryReferences.Select(c => c.GetTargetItem()).Where(c => c.Template.Key == "state");
foreach (var state in referringStates)
{
var stateReferences = Globals.LinkDatabase.GetReferences(state);
var referringPeople = stateReferences.Select(s => s.GetTargetItem()).Where(s => s.Template.Key == "person");
foreach (var person in referringPeople)
{
peopleList.Add(person);
}
}