How can I fetch specific rows from a Parse class with indexes? (Parse.Promise.when bug?) - parse-platform

In Parse, let's say I have 1000 rows of Bar. Say I want to find the rows at specific 'positions' based on when the row was created.
What I've tried:
var _ = require('lodash');
var indexes = [1,2,3];
var query = new Parse.Query('Bar');
query.addAscending('createdAt'); // oldest first for predictable ordering
var promises = indexes.map((i) => {
var q = _.clone(query);
q.skip(i);
return q.first();
});
Parse.Promise.when(promises)
.done((results) => {
console.log(results); // returns ONE row only.
});
I was expecting an array of results, of all the first() promises' results. Alas, I cannot understand why Parse.Promise.when only returns one result.

Related

How to order items within the group of anonymous type?

I would like to get a result of Linq query as groups of anonymous objects. The items within the groups should be ordered by ID field. I can reach this partly by lambda syntax, but can't get an anonymous objects as result. So I need part of each example.
Executable code: https://dotnetfiddle.net/cPJUN9
var res_g = (from dg in list
group new { dg.ID, dg.IDOperation, dg.IDDiagnosis } by dg.IDOperation
into dg_group
select dg_group);
lambda syntax
var res_g = list
.GroupBy(x => x.IDOperation)
.Select(x => x.OrderBy(x => x.ID)); // order dg by ID asc within group
Alas, you didn't describe exactly your requirements where, only that you want some anonymous type and that they should be ordered by Id. Your query syntax makes different groups than your method syntax. So I can only give an example to create your sequence of anonymous objects
So you have a sequence of similar items, where every item has at least properties Id and IdOperation. You want to make groups of items where every item in each group has the same value for IdOperation. You want to order the elements in each group by ascending Id, and create some anonymous type.
You didn't specify what you want in your anonymous object (after all: your code doesn't do what you want, so I can't deduct it from your code)
Whenever I use GroupBy, and I want to specify the elements of each group, I use the overload of GroupBy that has a parameter resultSelector. With the resultSelector I can precisely define the elements of the group. (The link refers to IQueryable, there is also an IEnumerable version)
IEnumerable<Operations> operations = ... // = your list
// Make Groups of Operations that have the same value for IdOperation
var result = operations.GroupBy(operation => operation.IdOperation,
// parameter resultSelector: take the key (=idOperation) and all Operations that have
// this idOperation, to make one new.
(idOperation, operationsWithThisId) => new
{
// do you need the common idOperation?
IdOperation = idOperation,
// Order the elements in each group by Id:
Operations = operationsWithThisId.OrderBy(operation => operation.Id)
.Select(operation => new
{
// Select only the operation properties that you plan to use
Id = operation.Id,
Name = operation.Name,
StartDate = operation.StartDate,
...
})
.ToList(),
});
In words: from your sequence of Operations, make groups of Operations that have the same value for IdOperation. Then take this common IdOperation, and all Operations that are in this group, to make one anonymous object: this is the anonymous object that you were talking about. So per group, you make one anonymous object.
IdOperation is the value that all Operations in this group have in common
Operations is a list. All Operations in this group are ordered by ascending Id. Several properties are Selected and the result is put in a List.
If you want to group differently, like in you query syntax, simply change parameter keySelector:
var result = operations.GroupBy(operation => new
{
Id = operation.ID,
IdOperation = operation.IDOperation,
IdDiagnosis = operation.IDDiagnosis
},
Although this corresponds with what you did in your query syntax, you will have groups of Operations that have same value for Id / IdOperation / IDDiagnosis. It will be useless to sort the elements in the group by Id, because all Ids in this group will be equal.
Conclusion
With parameter resultSelector you can define the result exactly as you want: the result is not an IEnumerable<IGrouping<Tkey, TElement>>, but an IEnumerable<TResult>.
The TResult is one object created from all elements in one group and the common group value.
you can update GetDict function inner loop to use orderby on group elements
public static void GetDict(List<Operation> list)
{
var res_g = (from dg in list
group new { dg.ID, dg.IDOperation, dg.IDDiagnosis } by dg.IDOperation
into dg_group
select dg_group);
foreach (var x in res_g)
{
Console.WriteLine("Key: " + x.Key);
foreach (var y in x.OrderBy(o=>o.ID))
{
Console.WriteLine("{0} {1} {2}", y.ID, y.IDOperation, y.IDDiagnosis); ;
}
}
}
I hope this solve the issue.
Depending on your Requirements EDIT but I'm Tuning the result set
var res_g_2 = list.Select( p=> new { p.ID, p.IDOperation, p.IDDiagnosis }) .GroupBy(g => g.IDOperation)
.Select(g => new {
IDOperation = g.Key,
Records = g.OrderBy(group => group.ID)
});
Edit full version
public static void GetDict(List<Operation> list)
{
var res_g = (from dg in list
group new { dg.ID, dg.IDOperation, dg.IDDiagnosis } by dg.IDOperation
into dg_group
select new
{
Key = dg_group.Key,
Records = dg_group.OrderBy(g => g.ID)
}) ;
var res_g_2 = list.Select( p=> new { p.ID, p.IDOperation, p.IDDiagnosis }) .GroupBy(g => g.IDOperation)
.Select(g => new {
Key = g.Key,
Records = g.OrderBy(group => group.ID)
});
// you can use either res_g or res_g_2 both give the same results
foreach (var x in res_g)
{
Console.WriteLine("Key: " + x.Key);
foreach (var y in x.Records)
{
Console.WriteLine("{0} {1} {2}", y.ID, y.IDOperation, y.IDDiagnosis); ;
}
}
}

dc.js filtered table export using filesaver.js

I'm trying to export dc.js filtered table data using FileSaver.js.
I use the code below based on this which is fine except it export all fields (but filtered ok) whereas I would just need table specific fields which are are only a few of the fields plus 2 calculated.
d3.select('#download')
.on('click', function() {
var blob = new Blob([d3.csv.format(dateDim.top(Infinity))], {type: "text/csv;charset=utf-8"});
saveAs(blob, DateT + '.csv');
});
Is there a way I can point to the table rather that dimension?
Thanks.
EDIT: Working code below
d3.select('#download')
.on('click', function() {
var data = MYTABLEDIM.top(Infinity);
{
data = data.map(function(d) {
var row = {};
MYTABLENAME.columns().forEach(function(c) {
row[MYTABLENAME._doColumnHeaderFormat(c)] = MYTABLENAME._doColumnValueFormat(c, d);
});
return row;
});
}
var blob = new Blob([d3.csv.format(data)], {type: "text/csv;charset=utf-8"});
saveAs(blob, 'data.csv');
});
Good question.
It is actually possible to format the data according to the column definitions, by using some undocumented methods of the data table.
I've updated the example with a radio button to choose which data to download.
Here is the code that transforms and download the data as it is encoded in the table:
d3.select('#download')
.on('click', function() {
var data = nameDim.top(Infinity);
data = data.map(function(d) {
var row = {};
table.columns().forEach(function(c, i) {
// if you're using the "original method" for specifying columns,
// use i to index an array of names, instead of table._doColumnHeaderFormat(c)
row[table._doColumnHeaderFormat(c)] = table._doColumnValueFormat(c, d);
});
return row;
});
var blob = new Blob([d3.csv.format(data)], {type: "text/csv;charset=utf-8"});
saveAs(blob, 'data.csv');
});
Basically, when the table radio is selected, we'll transform the data row-by-row using the same functions that the table uses to format its data.
The rows will be in the order of the original data, not sorted like the table. (And strictly speaking, the columns may not be in the same order either). That would be a bigger endeavor, and might require new features in dc.js. But this works without any changes. Hope it helps!

Parse Query with array include not always returning every array object

I'm running into some strange behavior when using Parse.Query.find() and am hoping someone can show me my errors. My scenario is that I'm including an array field in my query and sometimes, at a random record, some of the included array elements are null. I've verified that the array elements are indeed NOT null. Additionally, if I use each() instead of find(), I don't see this problem. Also, if I reduce the # of records I read at a time (CHUNK_SIZE) from Parse's 1000 maximum to 500, things work, so I'm not sure what's going on.
Here's the code I'm using.
/**
Iterates over a query using find(), which is very fast, compared to each().
Works up to 10,000 records maximum.
#param query Parse.Query to iterate.
#param callback Called for each batch of records.
#return Promise, fulfilled when iteration is done.
*/
function findAll(query, callback) {
var queryCount = 0;
var startTime = new Date();
var CHUNK_SIZE=1000;
query.limit(CHUNK_SIZE);
var queryFind = function() {
query.skip(CHUNK_SIZE * queryCount);
queryCount++;
return query.find().then(function(rows) {
callback(rows);
if (rows.length == CHUNK_SIZE) {
return queryFind();
}
});
}
return queryFind();
}
// Example of how to use findAll.
function fetchTree() {
var records = 0;
var query = new Parse.Query('TreeNode');
query.include('scores');
return findAll(query, function(nodes) {
nodes.forEach(function(node) {
records++;
node.get('scores').forEach(function(score, scoreIndex) {
if (!score) {
throw "Null score at row " + node.id + "/" + records + " index " + scoreIndex;
}
});
});
}, true);
}
fetchTree();
Thanks in advance.
Parse limits rows returned per query to a default of 50 with a max of 1000.
This limit includes related records, so if you get 10 records that each have on average 50 pointers in their array and you include() them you are using 500/1000 max records for your query.

Selecting related pairs LINQ

I'm using LINQ to manipulate a datatable. I have 3 columns - I would like group by one and then select the remaining 2 columns together. At the moment I have something like this
var query = reportDataTable.AsEnumerable()
.GroupBy(c => c["Code"])
.Select(g =>
new {
Code = g.Key,
Rank = g.Select(f => new
{ f["rank"],
f["Name"]}).ToArray()
});
but I get issues due to anonymous types. I know this syntax would work if I could reference the the column headers directly (in say a list or w/e). How can I get around this with DataTables? Cheers.
Edit:
Well I'd like to be able to reference the fields later when I come to populate the data into a different datatable:
foreach (var q in query)
{
DataRow df = dp.NewRow();
df["Code"] = q.Code;
foreach (var rank in q.Rank)
{
df[rank.name] = rank.rank;
}
dp.Rows.Add(df);
}
define your Rank fields, Also if you have a class for it, call related class constructor,
you can see this in bellow code, before ToArray.
var query = reportDataTable.AsEnumerable()
.GroupBy(c => c["Code"])
.Select(g =>
new { Code = g.Key, Rank =
g.Select(f => new { rank = f["rank"], name = f["Name"]})
.ToArray() });

How to use JQUERY to filter table rows dynamically using multiple form inputs

I'm displaying a table with multiple rows and columns. I'm using a JQUERY plugin called uiTableFilter which uses a text field input and filters (shows/hides) the table rows based on the input you provide. All you do is specify a column you want to filter on, and it will display only rows that have the text field input in that column. Simple and works fine.
I want to add a SECOND text input field that will help me narrow the results down even further. So, for instance if I had a PETS table and one column was petType and one was petColor -- I could type in CAT into the first text field, to show ALL cats, and then in the 2nd text field, I could type black, and the resulting table would display only rows where BLACK CATS were found. Basically, a subset.
Here is the JQUERY I'm using:
$("#typeFilter").live('keyup', function() {
if ($(this).val().length > 2 || $(this).val().length == 0)
{
var newTable = $('#pets');
$.uiTableFilter( theTable, this.value, "petType" );
}
}) // end typefilter
$("#colorFilter").live('keyup', function() {
if ($(this).val().length > 2 || $(this).val().length == 0)
{
var newTable = $('#pets');
$.uiTableFilter( newTable, this.value, "petColor" );
}
}) // end colorfilter
Problem is, I can use one filter, and it will display the correct subset of table rows, but when I provide input for the other filter, it doesn't seem to recognize the visible table rows that are remaining from the previous column, but instead it appears that it does an entirely new filtering of the original table. If 10 rows are returned after applying one filter, the 2nd filter should only apply to THOSE 10 rows. I've tried LIVE and BIND, but not working.
Can anyone shed some light on where I'm going wrong? Thanks!
The uiTableFilter plugin doesn't support what you're trying to do. A quick look at the source reveals this:
elems.each(function(){
var elem = jQuery(this);
jQuery.uiTableFilter.has_words(getText(elem), words, false)
? matches(elem)
: noMatch(elem);
});
and that expands to (essentially) this:
elems.each(function(){
var elem = jQuery(this);
jQuery.uiTableFilter.has_words(getText(elem), words, false)
? elem.show()
: elem.hide();
});
So all it does is spin through all the rows, .show() those that match, and .hide() those that don't; uiTableSorter doesn't pay attention to the current shown/hidden state of the rows and there's no way to tell it to filter on multiple columns.
If you really need your desired functionality then you can modify the plugin's behavior (the code is pretty small and simple) or just write your own. Here's a stripped down and simplified version that supports multiple filters and is a more conventional jQuery plugin than uiTableFilter:
(function($) {
$.fn.multiFilter = function(filters) {
var $table = $(this);
return $table.find('tbody > tr').each(function() {
var tr = $(this);
// Make it an array to avoid special cases later.
if(!$.isArray(filters))
filters = [ filters ];
howMany = 0;
for(i = 0, f = filters[0]; i < filters.length; f = filters[++i]) {
var index = 0;
$table.find('thead > tr > th').each(function(i) {
if($(this).text() == f.column) {
index = i;
return false;
}
});
var text = tr.find('td:eq(' + index + ')').text();
if(text.toLowerCase().indexOf(f.word.toLowerCase()) != -1)
++howMany;
}
if(howMany == filters.length)
tr.show();
else
tr.hide();
});
};
})(jQuery);
I'll leave error handling and performance as an exercise for the reader, this is just an illustrative example and I wouldn't want to get in the way of your learning. You could wire it up something like this:
$('#type').keyup(function() {
$('#leeLooDallas').multiFilter({ column: 'petType', word: this.value });
});
$('#color').keyup(function() {
$('#leeLooDallas').multiFilter([
{ column: 'petType', word: $('#type').val() },
{ column: 'petColor', word: this.value }
]);
});
And here's a live example (which assumes that you're going to enter something in "type" before "color"): http://jsfiddle.net/ambiguous/hdFDt/1/

Resources