Я ищу способ предотвратить запись более (определенного) предела документов в (под) коллекцию в заданном периоде.
Например: Messenger A не разрешено писать более 1000 сообщений в сутки.
Это должно быть сделано в контексте конечной точки API-функции Firebase, поскольку она вызывается третьими сторонами.
Конечная точка
app.post('/message', async function(req:any, res:any) {
// get the messenger's API key
const key = req.query.key
// if no key was provided, return error
if(!key) {
res.status(400).send('Please provide a valid key')
return
}
// get the messenger by the provided key
const getMessengerResult = await admin.firestore().collection('messengers')
.where('key', '==', key).limit(1).get()
// if there is no result the messenger is not valid, return error
if (getMessengerResult.empty){
res.status(400).send('Please provide a valid key')
return
}
// get the messenger from the result
const messenger = getMessengerResult.docs[0]
// TODO: check if messenger hasn't reached limit of 1000 messages per 24 hours
// get message info from the body
const title:String = req.body.title
const body: String = req.body.body
// add message
await messenger.ref.collection('messages').add({
'title':title,
'body':body,
'timestamp': Timestamp.now()
})
// send response
res.status(201).send('The notification has been created');
})
Одна вещь, которую я попробовал, была следующая часть кода вместо TODO:
:
// get the limit message and validate its timestamp
const limitMessageResult = await messenger.ref.collection('messages')
.orderBy('timestamp',"desc").limit(1).offset(1000).get()
if(!limitMessageResult.empty) {
const limitMessage = limitMessageResult.docs[0]
const timestamp: Timestamp = limitMessage.data()['timestamp']
// create a date object for 24 hours ago
const 24HoursAgo = new Date()
24HoursAgo.setDate(24HoursAgo.getDate()-1)
if(24HoursAgo < timestamp.toDate()) {
res.status(405).send('You\'ve exceeded your messages limit, please try again later!')
return
}
}
Этот код работает, но есть большое НО. Смещение действительно пропускает 1000 результатов, но Firebase все равно будет платить за это! Поэтому каждый раз, когда мессенджер пытается добавить 1 сообщение, 1000+ читаются ... и это дорого.
Поэтому мне нужен лучший (более дешевый) способ сделать это.
Одна вещь, которую я Придумал, но еще не пытался добавить поле индекса / счетчика к сообщению, которое увеличивается на 1 каждое сообщение. Тогда вместо того, чтобы делать:
const limitMessageResult = await messenger.ref.collection('messages')
.orderBy('timestamp',"desc").limit(1).offset(1000).get()
Я мог бы сделать что-то вроде:
const limitMessageResult = await messenger.ref.collection('messages')
.where('index','==', currentIndex-1000).limit(1).get()
Но мне было интересно, будет ли это безопасным способом. Например, что произойдет, если есть несколько запросов одновременно. Сначала мне нужно получить текущий индекс из последнего сообщения и добавить новое сообщение с индексом + 1. Но могут ли два запроса прочитать и, таким образом, записать один и тот же индекс? Или это может быть обработано транзакциями?
Или есть совершенно другой способ решить мою проблему?