How to make a rethinkdb atomic update if document exists, insert otherwise? - rethinkdb

How to make a rethinkdb atomic update if document exists, insert otherwise?
I want to do something like:
var tab = r.db('agflow').table('test');
r.expr([{id: 1, n: 0, x: 11}, {id: 2, n: 0, x: 12}]).forEach(function(row){
var _id = row('id');
return r.branch(
tab.get(_id).eq(null), // 1
tab.insert(row), // 2
tab.get(_id).update(function(row2){return {n: row2('n').add(row('n'))}}) // 3
)})
However this is not fully atomic, because between the time when we check if document exists (1) and inserting it (2) some other thread may insert it.
How to make this query atomic?

I think the solution is passing
conflict="update"
to the insert method.
Als see RethinkDB documentation on insert

To make the inner part atomic, you can use replace:
tab.get(_id).replace(function(row2){
return r.expr({id: _id, n: row2('n').add(row('n'))})
.default(row)
})
Using replace is the only way at the moment to perform fully atomic upserts with non-trivial update operations.

This is a standard database operation called an "upsert".
Does RethinkDB support upserts?
Another question from Sergio
Tulentsev. The first public release didn't include support for
upserts, but now it can be done by passing an extra flag to insert:
r.table('marvel').insert({
superhero: 'Iron Man',
superpower: 'Arc Reactor'
}, {upsert: true}).run()
When set to true, the new document
from insert will overwrite the existing one.
cite: Answers to common questions about RethinkDB

OK, I figured out how to do it.
The solution is to firstly try insert, and if it fail we make update:
var tab = r.db('agflow').table('test');
tab.delete();
r.expr([{id: 1, n: 0, x: 11}, {id: 2, n: 0, x: 12}]).forEach(function(row){
var _id = row('id');
var res = tab.insert(row);
return r.branch(
res('inserted').eq(1),
res,
tab.get(_id).update(function(row2){return {n: row2('n').add(1)}})
)})

Related

Google Sheets: Sort Two Columns

In a sheet I have two rows that I'd like to sort on:
ColA: Archived - True/False checkbox
ColB: SortOrder - number, a way I have at the moment to group things
Cols C-G: various details
I have a function that does this from a macro, as I'll add a button to the sheet later to run this:
function SortServices() {
var ss = SpreadsheetApp.getActive();
ss.getRange('A1:B').activate();
ss.getActiveRange().offset(1, 0, spreadsheet.getActiveRange().getNumRows() - 1).sort([{column: 1, ascending: true}, {column: 2, ascending: true}]);
};
I'm having a problem, as there are 1000 rows but only ~300 rows currently have data. Of these, about 200 are unchecked and 100 checked (as Archived). So this sorts the entire colA, then colB, which doesn't correspond to the data cols.
Struggling to explain this, imgs might be better. Here's an example, originally:
After applying the Sort:
The issue must be the rows without data, but ColA has checkboxes, which by default are unchecked. Is there a simple way to get around this? (I don't know much about Sheets)
[Edit] Sorry, should have added what I would like... the rows with no data at the end, same as the first img. When a row is checked as Archived, using Sort would then move it down into the lower section together with other Archived items:
Solution
Divide the data in two sets and sort in the desired order those that meet the requirements (have data in column B).
Code
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var lr = ss.getLastRow()
// original values
var range = ss.getRange(1, 1, lr, 3).getValues()
// cells without data in colB
var filtered = range.filter(function (value, index, arr) {
return value[1] == "";
});
// cells with data in colB
var original = range.filter(x => !filtered.includes(x));
// write
ss.getRange(1, 1, original.length, 3).setValues(original).sort([{ column: 1, ascending: true }, { column: 2, ascending: true }]);
ss.getRange(1 + original.length, 1, filtered.length, 3).setValues(filtered)
}
Thought there would be an easier answer, but this works OK:
Inserted a new colA with formula to create a single sortable column:
=if( isblank(D2), 20000, if(B2=true, 10000+C2, C2 ) )
Then used this script:
function SortServices() {
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActive().getActiveSheet();
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).activate();
ss.getActiveRange().offset(1, 0, ss.getActiveRange().getNumRows() - 1).sort({column: 1, ascending: true});
};
Probably add this to a custom menu.

Sort two dimensional table after value

I'm trying to make a function to sort a table after a value inside it. Is there no functions for this already in lua? I can't seem to find one.
local table2 = {};
for i, v in pairs(table) do
if( table[i].field > table[i+1].field ) then
this is how far I got before I thought that it wouldn't work.
Can someone help me?
The question is not quite clear, but if you mean to sort values in a table that may have some complex value, you can do this by using a "custom" search function:
local t = {
{field = 2},
{field = 1},
}
table.sort(t, function(t1, t2)
return t1.field < t2.field
end)
print(t[1].field, t[2].field) -- prints 1, 2
See sorting table by value for related details.

Sort Google Spreadsheet With Multiple Criteria Using Script

I have a spreadsheet that I update on a regular basis. I also have to re-sort the spreadsheet when finished because of the changes made. I need to sort with multiple criteria like the below settings. I have searched for examples but my Google search skills have failed me.
Sort range from A1:E59
[x] Data has header rows
sort by "Priority" A > Z
then by "Open" Z > A
then by "Project" A > Z
Mogsdad's answer works fine if none of your cells have values automatically calculated via a formula. If you do use formulas, though, then that solution will erase all of them and replace them with static values. And even so, it is more complicated than it needs to be, as there's now a built-in method for sorting based on multiple columns. Try this instead:
function onEdit(e) {
var priorityCol = 1;
var openCol = 2;
var projectCol = 3;
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
dataRange.sort([
{column: priorityCol, ascending: true},
{column: openCol, ascending: false},
{column: projectCol, ascending: true}
]);
}
Instead of making a separate function, you can use the built-in onEdit() function, and your data will automatically sort itself when you change any of the values. The sort() function accepts an array of criteria, which it applies one after the other, in order.
Note that with this solution, the first column in your spreadsheet is column 1, whereas if you're doing direct array accesses like in Mogsdad's answer, the first column is column 0. So your numbers will be different.
That is a nice specification, a great place to start!
Remember that Google Apps Script is, to a large extent, JavaScript. If you extend your searching into JavaScript solutions, you'll find plenty of examples of array sorts here on SO.
As it happens, much of what you need is in Script to copy and sort form submission data. You don't need the trigger part, but the approach to sorting can be easily adapted to handle multiple columns.
The workhorse here is the comparison function-parameter, which is used by the JavaScript Array.sort() method. It works through the three columns you've indicated, with ascending or descending comparisons. The comparisons used here are OK for Strings, Numbers and Dates. It could be improved with some cleaning up, or even generalized, but it should be pretty fast as-is.
function sortMySheet() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sourceSheet.getDataRange();
var data = dataRange.getValues();
var headers = data.splice(0,1)[0]; // remove headers from data
data.sort(compare); // Sort 2d array
data.splice(0,0,headers); // replace headers
// Replace with sorted values
dataRange.setValues(data);
};
// Comparison function for sorting two rows
// Returns -1 if 'a' comes before 'b',
// +1 if 'b' before 'a',
// 0 if they match.
function compare(a,b) {
var priorityCol = 0; // Column containing "Priority", 0 is A
var openCol = 1;
var projectCol = 2;
// First, compare "Priority" A > Z
var result = (a[priorityCol] > b[priorityCol] ) ?
(a[priorityCol] < b[priorityCol] ? -1 : 0) : 1;
if (result == 0) {
// "Priority" matched. Then compare "Open" Z > A
result = (b[openCol] > a[openCol] ) ?
(b[openCol] < a[openCol] ? -1 : 0) : 1;
}
if (result == 0) {
// "Open" matched. Finally, compare "Project" A > Z
result = (a[projectCol] > b[projectCol] ) ?
(a[projectCol] < b[projectCol] ? -1 : 0) : 1;
}
return result;
}
Try this using the Apps Script sort instead of the native JavaScript. I had the same issue with sorting the header row(s) and this solved the issue.
So I think something like this should work:
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("Form Responses 1").sort(2);
}
Regarding sorting by multiple columns, you can chain that sort() method, with the final sort() having the highest priority, and the first sort() the lowest. So something like this should sort by Start date, then by End date:
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("Form Responses 1").sort(3).sort(2);
}
Reference link:-
https://support.google.com/docs/thread/16556745/google-spreadsheet-script-how-to-sort-a-range-of-data?hl=en
Not sure if this is still relevant, but you can use the sort() function to define another tab as a sorted version of the original data.
Say your original data is in a tab named Sheet1; I'm also going to act as though your Priority, Open, and Project columns are A, B, and C, respectively.
Create a new tab, and in cell A1 type:
=sort(Sheet1!A1:E59, 1, TRUE, 2, FALSE, 3, TRUE)
The first argument specifies the sheet and range to be sorted, followed by three pairs: the first of each pair specifies the column (A=1, B=2, etc.), and the second specifies ascending (TRUE) or descending (FALSE).

Linq To Entities Get 2nd Last entry In List

I have the following code which returns a list of Objects.
var listOfLogins = _logService.GetLogEventsByItemID(137).ToList();
I would like to get the 2nd last object in this list.
Does anyone know how to do this using Linq to Entities?
Thanks.
var secondlast = _logService.GetLogEventsByItemID(137)
.Reverse()
.Skip(1)
.Take(1)
.FirstOrDefault();
Update
#Dherik makes a good point in his comment that .Reverse is not actually supported in LINQ to Entities and will result in the query being evaluated at the point of calling reverse, rather than at the point of calling .FirstOrDefault. See here for all (not) supported methods.
The alternative (LINQ to Entities friendly) solution requires that you have a suitable field to order by (which must be the case anyway otherwise "second last" has no relevance):
var secondlast = _logService.GetLogEventsByItemID(137)
.OrderByDescending(e => e.EventDate /* could be any db field */)
.Skip(1)
.Take(1)
.FirstOrDefault();
int[] items = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int item = items.Skip(items.Count() - 2).Take(1).Single();
//will return 9
like this?

Using Linq to create crosstab results [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is it possible to Pivot data using LINQ?
I'm wondering if its at all possible to create crosstab style results with Linq.
I have some data that looks like the following:
var list = new[]
{
new {GroupId = 1, Country = "UK", Value = 10},
new {GroupId = 1, Country = "FR", Value = 12},
new {GroupId = 1, Country = "US", Value = 18},
new {GroupId = 2, Country = "UK", Value = 54},
new {GroupId = 2, Country = "FR", Value = 55},
new {GroupId = 2, Country = "UK", Value = 56}
};
and I'm trying to output to a repeater control something like the following:
GroupId.....UK.....FR.....US
1...........10.....12.....18
2...........54.....55.....56
Its the dynamic columns that are causing my problems. Any solutions to this?
You need a runtimy class to hold these runtimy results. How about xml?
XElement result = new XElement("result",
list.GroupBy(i => i.GroupId)
.Select(g =>
new XElement("Group", new XAttribute("GroupID", g.Key),
g.Select(i => new XAttribute(i.Country, i.Value))
)
)
);
Are you expecting multiple records per result cell? If so there would need to be some Summing (and more grouping) in there.
(this answer is proof of concept, not final result. There's several issues to address, such as: ordering of columns, missing cells, and so on).
After doing a quick search you might want to look at the ModuleBuilder, TypeBuilder, and FieldBuilder classes in System.Reflection.Emit. They allow you to create a class dynamically at runtime. Outside of that you would need to do grouping on your objects and then do something with the hierarchical results you get from LINQ. I am not sure of a way to dynamically create anonymous type fields at runtime, and that sounds like what would need to happen.
You could try using the dynamic linq library provided by MS. They have a number of overloads to extensions methods that take strings as arguments. They also have an expression parser that takes a string an emits a lambda expression. You should be able to create a dynamic select using them.
A word of warning though, you end up with a non-generic IQueryable rather than a generic IQueryable so you are a little bit limited on what you can do with the result, and you give up a bit of type safety, but that may be OK in your application...
The link for the dynamic linq stuff is
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
There is a link where you can download the source code the the dynamic library, plus some nice illustrations of how you can use it.
var labResults = from lab in CoreLabResults
where lab.Patient == 8
group lab by new { lab.Patient, lab.TestNo, lab.CollectedDate }
into labtests
select new
{
labtests.Key.Patient,
labtests.Key.TestNo,
labtests.Key.CollectedDate,
MCHC = labtests.Where(lab => lab.TestVar == "MCHC").FirstOrDefault().Result,
LYABS = labtests.Where(lab => lab.TestVar == "LYABS").FirstOrDefault().Result,
TotalTests = labtests.Count()
}

Resources