is there a way to delete data from a firebase real time database (using flutter) after 1 day? - flutter

I want to add data that stays in the database for 1 day by default and then get deleted. Unless I set a different time (more than one day).

You can create something like below method and you need to upload that on Firebase Cloud Function
const CUT_OFF_TIME = 24 * 60 * 60 * 1000; // 2 Hours in milliseconds.
exports.deleteOldMessages = functions.database.ref('[path]').onWrite(async (change) => {
const ref = change.after.ref.parent; // reference to the parent
const now = Date.now();
const cutoff = (now - CUT_OFF_TIME) / 1000; // convert to seconds
const oldItemsQuery = ref.orderByChild('seconds').endAt(cutoff);
const snapshot = await oldItemsQuery.once('value');
// create a map with all children that need to be removed
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
// execute all updates in one go and return the result to end the function
return ref.update(updates);
});
You can checkout below link for reference as well.
souce

Related

I need to append a single row of data that has 'Quantity Sold' cell populated

Data Input Page
Appended Data
Data from rows 5 and 6 have been appended into sheet, but I just want from the row where data is shown (B7)
function appendSoldData() {
const ss =SpreadsheetApp.getActiveSpreadsheet();
// Collect the data.
const sourceRange = ss.getRangeByName("PlantData");
const inputRange = ss.getRangeByName("QtySold")
const sourceVals = sourceRange.getValues().flat();
// Check for row that has quantity sold - this is what i want to append to 'Form responses 1'
const anyPopulatedCell = sourceVals.findIndex(cell => cell =="");
if(anyPopulatedCell !== 1){
}
// Gather current date time
const date = new Date();
const data = [date,...sourceVals];
//Append the data.
const destinationSheet = ss.getSheetByName("Form responses 1");
destinationSheet.appendRow(data);
// Clear the source sheet rows.
inputRange.clearContent();
ss.toast("Sale Added to 'Form responses 1'!");
};

Comparing Dates in Google Scripts with Sheets Input

I am trying to create a pop up to warn a user they must update a part in inventory if the part date is more than 90 days old. The date on the sheet (Cell Q5) is autofilled from another sheet, but that shouldn't matter. The value for the cell on the spreadsheet is 9/2/2021. I've tried many things, but currently I am getting the value for Q5 showing up as NaN .
function CheckInvDate() {
var ss = SpreadsheetApp.getActive().getId();
var partsrange = Sheets.Spreadsheets.Values.get(ss, "BOM!A5:Q5");
var currentDate = new Date();
var parthist = new Date();
parthist.setDate(currentDate.getDate() -90);
for (var i = 0; i < partsrange.values.length; i++){
var name = partsrange.values [i][1]
var partdate = partsrange.values [i][16]
var parthisttime = new Date(parthist).getTime();
var partdatetime = new Date(partdate).getTime();
Logger.log("History " + parthisttime)
Logger.log("Current " + partdatetime)
SpreadsheetApp.flush()
// if (parthist > partdate == "TRUE") {
// SpreadsheetApp.getUi().alert('The price on '+ name + ' is out of date. Please update price and try again.')
// }
}
}
My last log was
[22-07-06 11:50:55:851 EDT] History 1649346655850
[22-07-06 11:50:55:853 EDT] Current NaN
I've seen a number of responses on Stack Overflow, but I can't understand them. They seem to refer to variables that I don't see in code, or commands I haven't seen before and I'm not sure if they are in date.
Try this:
function CheckInvDate() {
const ss = SpreadsheetApp.getActive();
const vs = Sheets.Spreadsheets.Values.get(ss.getId(), "BOM!A5:Q5").values;
let d = new Date();
d.setDate(d.getDate() - 90)
const dv = d.valueOf();
const oldthan5 = vs.map(r => {
if (new Date(r[16]).valueOf() < dv) {
return r;
}
}).filter(e => e);
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(`<textarea rows="12" cols="100">${JSON.stringify(oldthan5)}</textarea>`).setWidth(1000), "Older Than 90 Days");
}
This outputs a dialog with the rows older than 90 days
I went to try this on my script again after lunch, and for whatever reason I am no longer getting the NaN value. I made one change on the if statement to fix the logic, and now it is working correctly. Not sure what I did, but apparently the coding gods were unhappy with me before.
The only part I changed was
if (parthisttime > partdatetime) {
SpreadsheetApp.getUi().alert('The price on '+ name + ' is out of date. Please update price and try again.')
}

Add future date in Google script and Goggle Sheet

I use Google sheet and Cryptofinance.ai to retreive cryptocurrency prices. I have one script that works well : it appends data periodically from one row in tab A to save them in a tab B so I can make graphs and charts.
Now I'd like to add date + 1 year in the next row. Idealy, each time the script is triggered, it make two new rows : The one with the data as it is now and the one with the date + 1 year.
If you curious and want to know why I want to do that is is to make projection price using this
formula in another tab : =TREND(filter(B2:B,B2:B<>""),filter(A2:A,B2:B<>""),filter(A2:A,(N(B2:B)=0)*(A2:A>0)))
Here is my script now:
// [START modifiable parameters]
var rangeToLog = 'Portefeuille!A28:L28';
var sheetToLogTo = 'Archive BTC/USD KRAKEN';
// [END modifiable parameters]
////////////////////////////////
/**
* Appends a range of values to the end of an archive sheet.
* A timestamp is inserted in column A of each row on the archive sheet.
* All values in rangeToLog go to one row on the archive sheet.
*
* #OnlyCurrentDoc
*/
function appendValuesToArchiveBTCUSDKRAKENSheet() {
// version 1.4, written by --Hyde, 30 January 2020
// - use Array.prototype.some() to skip empty rows when concating
// - see https://support.google.com/docs/thread/27095918?msgid=27148911
// version 1.3, written by --Hyde, 26 January 2020
// - see https://support.google.com/docs/thread/26760916
var ss = SpreadsheetApp.getActive();
var valuesToLog = ss.getRange(rangeToLog).getValues();
var logSheet = ss.getSheetByName(sheetToLogTo);
if (!logSheet) {
logSheet = ss.insertSheet(sheetToLogTo);
logSheet.appendRow(['Date time', 'Data']);
}
var rowToAppend = [new Date()].concat(
valuesToLog.reduce(function concatArrays_(left, right) {
var arrayContainsData = right.some(function isNonBlanky_(element, index, array) {
return element !== null && element !== undefined && element !== '';
});
return arrayContainsData ? left.concat(right) : left;
})
);
logSheet.appendRow(rowToAppend);
}
NOW :
What I want to do:
The easy fix is to simply add another appendRow() call at the end of your function with the one year from now value.
function appendValuesToArchiveBTCUSDKRAKENSheet() {
// ...
logSheet.appendRow(rowToAppend);
logSheet.appendRow([new Date(new Date().setFullYear(new Date().getFullYear() + 1))]);
}
A more complex solution, but with better execution time, would have you print both rows in a single setValues() call. This follows the best practice of using batch operations, but I suspect that the easier solution above is adequate for your purpose. I do encourage you, however, to try implementing the batch operation if you want to improve your apps script skills.
Finally, after some research I came to this :
function expCalc(){
delLastNRows();
appendValuesToArchiveBTCUSDKRAKENSheet();
}
function delLastNRows(n){
var n=n || 1;//allows you to delete last three rows without passing function a parameter.
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Archive BTC/USD KRAKEN');
var lr=sh.getLastRow();
if(lr>=n){
for(var i=0;i<n;i++){
sh.deleteRow(sh.getLastRow());
}
}
}
// [START modifiable parameters]
var rangeToLog = 'Portefeuille!A28:L28';
var sheetToLogTo = 'Archive BTC/USD KRAKEN';
// [END modifiable parameters]
////////////////////////////////
/**
* Appends a range of values to the end of an archive sheet.
* A timestamp is inserted in column A of each row on the archive sheet.
* All values in rangeToLog go to one row on the archive sheet.
*
* #OnlyCurrentDoc
*/
function appendValuesToArchiveBTCUSDKRAKENSheet() {
// version 1.4, written by --Hyde, 30 January 2020
// - use Array.prototype.some() to skip empty rows when concating
// - see https://support.google.com/docs/thread/27095918?msgid=27148911
// version 1.3, written by --Hyde, 26 January 2020
// - see https://support.google.com/docs/thread/26760916
var ss = SpreadsheetApp.getActive();
var valuesToLog = ss.getRange(rangeToLog).getValues();
var logSheet = ss.getSheetByName(sheetToLogTo);
var sheet = ss.getSheets()[0]
if (!logSheet) {
logSheet = ss.insertSheet(sheetToLogTo);
logSheet.appendRow(['Date time', 'Data']);
}
var rowToAppend = [new Date()].concat(
valuesToLog.reduce(function concatArrays_(left, right) {
var arrayContainsData = right.some(function isNonBlanky_(element, index, array) {
return element !== null && element !== undefined && element !== '';
});
return arrayContainsData ? left.concat(right) : left;
})
);
logSheet.appendRow(rowToAppend);
logSheet.appendRow([new Date(new Date().setFullYear(new Date().getFullYear() + 1))]);
}
Works like a charm !

Finding Closest Users Without Looping Through Many Records

When users log in to my app, I want them to be able to see the number of users within a selected radius. I was planning to start storing coordinates in my database and looping through each record (~50,000), running userCoordinates.distance(from: databaseCoordinateValue). However, during testing, I've found that this process takes a long time and is not a scalable solution. Do you have any advice on how to quickly query database items within a defined radius?
I am using:
Swift 4
Firebase (Firestore beta)
Xcode 10
Example of database structure and how data gets stored
database.collection("users").document((Auth.auth().currentUser?.uid)!).setData([
"available_tags" : ["milk", "honey"]]) { err in
if let err = err {
print("Error adding document: \(err)")
}
}
Take a look at s2 geometry - http://s2geometry.io/. The basic concept is you encode each location on earth as a 64 bit # with locations close to each other being close #'s. Then, you can look up locations within x distance by finding anything that is +/- a certain # from the location. Now, the actual implementation is a bit more complicated, so you end up needing to creating multiple 'cells' ie. a min and max # on the range. Then, you do lookups for each cell. (More info at http://s2geometry.io/devguide/examples/coverings.)
Here's an example of doing this in node.js / javascript. I use this in the backend and have the frontend just pass in the region/area.
const S2 = require("node-s2");
static async getUsersInRegion(region) {
// create a region
const s2RegionRect = new S2.S2LatLngRect(
new S2.S2LatLng(region.NECorner.latitude, region.NECorner.longitude),
new S2.S2LatLng(region.SWCorner.latitude, region.SWCorner.longitude),
);
// find the cell that will cover the requested region
const coveringCells = S2.getCoverSync(s2RegionRect, { max_cells: 4 });
// query all the users in each covering region/range simultaneously/in parallel
const coveringCellQueriesPromies = coveringCells.map(coveringCell => {
const cellMaxID = coveringCell
.id()
.rangeMax()
.id();
const cellMinID = coveringCell
.id()
.rangeMin()
.id();
return firestore
.collection("User")
.where("geoHash", "<=", cellMaxID)
.where("geoHash", ">=", cellMinID).
get();
});
// wait for all the queries to return
const userQueriesResult = await Promise.all(coveringCellQueriesPromies);
// create a set of users in the region
const users = [];
// iterate through each cell and each user in it to find those in the range
userQueriesResult.forEach(userInCoveringCellQueryResult => {
userInCoveringCellQueryResult.forEach(userResult => {
// create a cell id from the has
const user = userResult.data();
const s2CellId = new S2.S2CellId(user.geoHash.toString());
// validate that the user is in the view region
// since cells will have areas outside of the input region
if (s2RegionRect.contains(s2CellId.toLatLng())) {
user.id = userResult.id;
users.push(user);
}
});
});
return users;
}
S2 geometry has a lot of ways to find the covering cells (i.e. what area you want to look up values for), so it's definitely worth looking at the API and finding the right match for your use case.

Ember 2.5 ember-cmi-mirage trying to get a subset of collection

Using ember 2.5 and ember-cli-mirage 0.2)
In my mirage/config.js , I am trying to get a subset ofa collection, for pagination purpose) using the slice() function
var books = schema.book.all().slice(startItem, endItem );
but I get an error:
schema.book.all(...).slice is not a function
I tried also , same error
var books = schema.book.all();
var items = books.slice(startItem, endItem );
Here is my mirage/config.js
export default function() {
....
this.get('/books', function(schema, request) {
const pageNumber = request.queryParams['page[number]'];
const pageSize = request.queryParams['page[size]'];
const startItem= (pageNumber - 1) * pageSize;
const endItem = (pageNumber * pageSize) - 1;
var books = schema.book.all().slice(startItem, endItem );
....
return books;
});
}
It seems that slice() is a function of ArrayProxy.. however this may not help as with a JSONAPISerializer
I'm a little bit lost as all exampels I can google relate to Ember 1.13 and not Ember 2.5...
This is because Collection is array-like, but not a true array. Precisely for this reason, in the next beta release we'll expose a .models property which has the underlying array.
For now, try calling .toArray() on your schema.book.all() collection, and then calling slice on it.
To take advantage of the Serializer layer, make sure to return a new Collection from your handler:
import Collection from 'ember-cli-mirage/orm/collection';
this.get('/books', (schema, request) => {
let books = schema.book.all().toArray().slice(...);
return new Collection('book', books);
});