#javascript #firebase #firebase-realtime-database
#javascript #firebase #firebase-база данных в реальном времени
Вопрос:
Я хотел бы изменить местоположение элемента в базе данных. Я попытался сначала удалить элемент из одного местоположения, затем переместить его в другое. Вот метод:
firebase.database().ref('completed').on('value', (snapshot) => {
snapshot.forEach((snapchild) => {
if(snapchild.val().title === item.title amp;amp; snapchild.val().id === item.id) {
firebase.database().ref('todos').push(snapchild.val()).then(() => {
firebase.database().ref(`anotherlocation/${snapchild.key}`).remove()
}
}
})
})
К сожалению, это не работает, элемент удаляется, но он не добавляется в другое место.
Правильный ли это способ сделать это?
Комментарии:
1. Можете ли вы добавить данные вашей базы данных и объяснить, где вы пытаетесь изменить путь?? Из вашего вопроса я вижу, что вы также хотите удалить его из одного места.
2. У меня просто есть список
todo
элементов и списокcompleted
элементов, я хочу удалить элемент изcompleted
и вернуть его обратно вtodo
.3. Да, вставьте эти дочерние элементы
todo
иcompleted
items в виде кода, чтобы мы могли понять структуру вашей базы данных и помочь вам с этим.4. Когда я пытаюсь запустить созданный мной метод, оба
completed
иtodos
удаляются.
Ответ №1:
Есть несколько проблем с кодом:
- Вы вызываете
push
в новом расположении, что означает, что элемент добавлен с новым ключом. Вероятно, вы захотите, чтобы в новом местоположении элемент имел тот же ключ, что и в старом местоположении. - Вы выполняете две операции с базой данных, что означает, что первая может быть успешной, в то время как другая завершается неудачей. Используя одно обновление с несколькими местоположениями, вы можете гарантировать, что либо обе записи завершатся успешно, либо ни одна из них не произойдет.
- Вы читаете больше элементов, чем необходимо. Поскольку вы знаете
id
элементы, которые хотите переместить, вы можете ограничить операцию чтения этим.
В коде:
var query = firebase.database().ref('completed').orderByChild('id').equalTo(item.id);
query.on('value', (snapshot) => {
snapshot.forEach((snapchild) => {
if(snapchild.val().title === item.title) {
var updates = {};
updates['/todos/' snapchild.key] = snapchild.val();
updates['/completed/' snapchild.key] = null;
firebase.database().ref().update(updates);
}
})
})
Это перемещает завершенный элемент с item.id
обратно в todos
. Я не уверен, что это именно тот ход, который вы хотите выполнить, поскольку это не было ясно из вашего вопроса. Если нет, вам придется обновить пути в updates
.
Комментарии:
1. Предоставленный код, безусловно, является правильным способом решения моего вопроса, однако, когда я его запускаю, он
completed
становитсяnull
, как и предполагалось,todo
обновляется и немедленно также удаляется.2. Это, скорее всего, потому, что у вас нет разрешения на запись в
completed
. Проверьте свои правила безопасности.3. Вы имеете в виду это:
"rules": { ".read": true, ".write": true }
?
Ответ №2:
Однажды я написал метод, который сначала создает копию, а затем удаляет исходный узел. это всего лишь нужно было бы перенести с Java
на JavaScript
, что должно быть довольно простой задачей. доказано, что порядок операций, по крайней мере, рабочий. как правило, вы должны заменить .on('value')
на .once('value')
, потому что дальнейших событий не будет — и удаление должно быть перехвачено ChildEventListener
на родительском узле (или как бы это ни вызывалось в JavaScript
). если вы хотите написать этот реальный сценарий должным образом, инкапсуляция в транзакцию имела бы смысл для данного сценария.
/** relocates a record from one to another path (v2). */
protected void move(final DatabaseReference source, final DatabaseReference target) {
source.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
target.setValue(snapshot.getValue(), new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError databaseError, @NonNull DatabaseReference databaseReference) {
/* if not the operation has failed */
if (databaseError != null) {
if(mDebug) {Log.w(LOG_TAG, databaseError.getMessage());}
} else {
/* remove the source path */
source.removeValue(new DatabaseReference.CompletionListener(){
@Override
public void onComplete(DatabaseError databaseError, @NonNull DatabaseReference databaseReference) {
if(mDebug) {Log.d(LOG_TAG, "moved " source.toString() " to " target.toString());}
}
});
}
}
});
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
if(mDebug) {Log.w(LOG_TAG, databaseError.getMessage());}
}
});
}