Использование существующих свойств выполняется с помощью root или parent и довольно просто.
{
"rules": {
"things": {
// assuming value is being stored as an integer
".validate": "newData.val() <= root.child('max')"
}
}
}
Однако определение количества записей и их принудительное выполнение несколько сложнее, чем просто написать правило безопасности:
.length
on объект, нам нужно сохранить, сколько записей существует Наивный подход
. Один подход бедных людей, предполагая, что предел является чем-то небольшим (например, 5 записей), состоял бы в простом перечислении их в правилах безопасности:
{
"rules": {
"things": {
".write": "newData.hasChildren()", // is an object
"thing1": { ".validate": true },
"thing2": { ".validate": true },
"thing3": { ".validate": true },
"thing4": { ".validate": true },
"thing5": { ".validate": true },
"$other": { ".validate": false
}
}
}
Реальный пример
Такая структура данных, как это работает:
/max/
/things_counter/
/things/$record_id/{...data...}
Таким образом, каждый раз, когда добавляется запись , счетчик должен быть увеличен.
var fb = new Firebase(URL);
fb.child('thing_counter').transaction(function(curr) {
// security rules will fail this if it exceeds max
// we could also compare to max here and return undefined to cancel the trxn
return (curr||0)+1;
}, function(err, success, snap) {
// if the counter updates successfully, then write the record
if( err ) { throw err; }
else if( success ) {
var ref = fb.child('things').push({hello: 'world'}, function(err) {
if( err ) { throw err; }
console.log('created '+ref.name());
});
}
});
И каждый раз, когда запись удаляется, счетчик должен быть уменьшен.
var recordId = 'thing123';
var fb = new Firebase(URL);
fb.child('thing_counter').transaction(function(curr) {
if( curr === 0 ) { return undefined; } // cancel if no records exist
return (curr||0)-1;
}, function(err, success, snap) {
// if the counter updates successfully, then write the record
if( err ) { throw err; }
else if( success ) {
var ref = fb.child('things/'+recordId).remove(function(err) {
if( err ) { throw err; }
console.log('removed '+recordId);
});
}
});
Теперь о правилах безопасности:
{
"rules": {
"max": { ".write": false },
"thing_counter": {
".write": "newData.exists()", // no deletes
".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= root.child('max').val()"
},
"things": {
".write": "root.child('thing_counter').val() < root.child('max').val()"
}
}
}
Обратите внимание, что это не заставляет пользователя писать в thing_counter перед обновлением записи, поэтому, хотя это подходит для ограничения количества записей, оно не подходит для обеспечения правил игры или предотвращения читов.
Другие ресурсы и Мысли
Если вы хотите защитить уровень игры, проверьте эту скрипту , в которой подробно описано, как создавать записи с инкрементными идентификаторами, включая правила безопасности, необходимые для обеспечения соответствия счетчику. Вы можете комбинировать это с приведенными выше правилами, чтобы обеспечить максимальное значение для инкрементных идентификаторов и обеспечить, чтобы счетчик обновлялся до записи записи.
Кроме того, убедитесь, что вы не слишком задумываетесь об этом, и есть законный прецедент для ограничения количества записей, а не просто для удовлетворения здоровой дозы беспокойства. Это сложная задача, чтобы просто обеспечить квоту бедного человека в ваших структурах данных.
Используйте кумулятивные суммы:
select t.*,
sum(cases - closed) over (order by year) as state
from t;
Я считаю state
любопытным названием для кумулятивной суммы.
Вы хотите функцию окна:
select t.*,
sum(cases - closed) over (order by year) as state
from table t;
РЕДАКТИРОВАТЬ: Для более старой версии вы можете использовать apply
:
select t.*, t1.state
from table t cross apply
(select sum(t1.cases - t1.closed) as state
from table t1
where t1.yr <= t.yr
) t1;