Bu belge, Firebase Gerçek Zamanlı Veritabanınıza veri yazmanın dört yöntemini kapsar: ayarlama, güncelleme, gönderme ve işlem desteği.
Verileri Kaydetmenin Yolları
ayarlamak | Verileri, messages/users/<username> gibi tanımlı bir yola yazın veya değiştirin |
güncelleme | Tüm verileri değiştirmeden tanımlanmış bir yol için bazı anahtarları güncelleyin |
itmek | Veritabanındaki bir veri listesine ekleyin . Bir listeye her yeni düğüm gönderdiğinizde, veritabanınız, messages/users/<unique-user-id>/<username> gibi benzersiz bir anahtar oluşturur. |
işlem | Eşzamanlı güncellemeler tarafından bozulabilecek karmaşık verilerle çalışırken işlemleri kullanın |
Verileri Kaydetme
Temel veritabanı yazma işlemi, yeni verileri belirtilen veritabanı referansına kaydeden ve bu yoldaki mevcut verileri değiştiren bir kümedir. Kümeyi anlamak için basit bir blog uygulaması oluşturacağız. Uygulamanızın verileri şu veritabanı referansında depolanır:
java
final FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("server/saving-data/fireblog");
Node.js
// Import Admin SDK const { getDatabase } = require('firebase-admin/database'); // Get a database reference to our blog const db = getDatabase(); const ref = db.ref('server/saving-data/fireblog');
Piton
# Import database module. from firebase_admin import db # Get a database reference to our blog. ref = db.reference('server/saving-data/fireblog')
Gitmek
// Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln("Error initializing database client:", err) } // Get a database reference to our blog. ref := client.NewRef("server/saving-data/fireblog")
Bazı kullanıcı verilerini kaydederek başlayalım. Her kullanıcıyı benzersiz bir kullanıcı adı ile saklayacağız ve ayrıca tam adlarını ve doğum tarihlerini de saklayacağız. Her kullanıcının benzersiz bir kullanıcı adı olacağından, zaten anahtara sahip olduğunuzdan ve bir anahtar oluşturmanıza gerek olmadığından burada push yöntemi yerine set yöntemini kullanmak mantıklıdır.
İlk olarak, kullanıcı verilerinize bir veritabanı referansı oluşturun. Ardından, bir kullanıcı nesnesini kullanıcının kullanıcı adı, tam adı ve doğum günüyle birlikte veritabanına kaydetmek için set()
/ setValue()
öğesini kullanın. Set a string, number, boolean, null
, array veya herhangi bir JSON nesnesini iletebilirsiniz. null
iletmek, belirtilen konumdaki verileri kaldıracaktır. Bu durumda, ona bir nesne ileteceksiniz:
java
public static class User { public String date_of_birth; public String full_name; public String nickname; public User(String dateOfBirth, String fullName) { // ... } public User(String dateOfBirth, String fullName, String nickname) { // ... } } DatabaseReference usersRef = ref.child("users"); Map<String, User> users = new HashMap<>(); users.put("alanisawesome", new User("June 23, 1912", "Alan Turing")); users.put("gracehop", new User("December 9, 1906", "Grace Hopper")); usersRef.setValueAsync(users);
Node.js
const usersRef = ref.child('users'); usersRef.set({ alanisawesome: { date_of_birth: 'June 23, 1912', full_name: 'Alan Turing' }, gracehop: { date_of_birth: 'December 9, 1906', full_name: 'Grace Hopper' } });
Piton
users_ref = ref.child('users') users_ref.set({ 'alanisawesome': { 'date_of_birth': 'June 23, 1912', 'full_name': 'Alan Turing' }, 'gracehop': { 'date_of_birth': 'December 9, 1906', 'full_name': 'Grace Hopper' } })
Gitmek
// User is a json-serializable type. type User struct { DateOfBirth string `json:"date_of_birth,omitempty"` FullName string `json:"full_name,omitempty"` Nickname string `json:"nickname,omitempty"` } usersRef := ref.Child("users") err := usersRef.Set(ctx, map[string]*User{ "alanisawesome": { DateOfBirth: "June 23, 1912", FullName: "Alan Turing", }, "gracehop": { DateOfBirth: "December 9, 1906", FullName: "Grace Hopper", }, }) if err != nil { log.Fatalln("Error setting value:", err) }
Bir JSON nesnesi veritabanına kaydedildiğinde, nesne özellikleri otomatik olarak iç içe bir şekilde veritabanı alt konumlarına eşlenir. Şimdi https://docs-examples.firebaseio.com/server/saving-data/fireblog/users/alanisawesome/full_name URL'sine giderseniz, "Alan Turing" değerini göreceğiz. Verileri doğrudan bir alt konuma da kaydedebilirsiniz:
java
usersRef.child("alanisawesome").setValueAsync(new User("June 23, 1912", "Alan Turing")); usersRef.child("gracehop").setValueAsync(new User("December 9, 1906", "Grace Hopper"));
Node.js
const usersRef = ref.child('users'); usersRef.child('alanisawesome').set({ date_of_birth: 'June 23, 1912', full_name: 'Alan Turing' }); usersRef.child('gracehop').set({ date_of_birth: 'December 9, 1906', full_name: 'Grace Hopper' });
Piton
users_ref.child('alanisawesome').set({ 'date_of_birth': 'June 23, 1912', 'full_name': 'Alan Turing' }) users_ref.child('gracehop').set({ 'date_of_birth': 'December 9, 1906', 'full_name': 'Grace Hopper' })
Gitmek
if err := usersRef.Child("alanisawesome").Set(ctx, &User{ DateOfBirth: "June 23, 1912", FullName: "Alan Turing", }); err != nil { log.Fatalln("Error setting value:", err) } if err := usersRef.Child("gracehop").Set(ctx, &User{ DateOfBirth: "December 9, 1906", FullName: "Grace Hopper", }); err != nil { log.Fatalln("Error setting value:", err) }
Yukarıdaki iki örnek - her iki değeri aynı anda bir nesne olarak yazmak ve bunları alt konumlara ayrı ayrı yazmak - aynı verilerin veritabanınıza kaydedilmesine neden olur:
{ "users": { "alanisawesome": { "date_of_birth": "June 23, 1912", "full_name": "Alan Turing" }, "gracehop": { "date_of_birth": "December 9, 1906", "full_name": "Grace Hopper" } } }
İlk örnek, verileri izleyen istemcilerde yalnızca bir olayı tetiklerken, ikinci örnek iki olayı tetikleyecektir. Veriler usersRef
zaten mevcutsa, ilk yaklaşımın bunun üzerine yazacağını, ancak ikinci yöntemin usersRef
diğer çocuklarını değiştirmeden bırakırken yalnızca her bir ayrı alt düğümün değerini değiştireceğini not etmek önemlidir.
Kayıtlı Verileri Güncelleme
Diğer alt düğümlerin üzerine yazmadan aynı anda bir veritabanı konumunun birden çok alt öğesine yazmak istiyorsanız, aşağıda gösterilen update yöntemini kullanabilirsiniz:
java
DatabaseReference hopperRef = usersRef.child("gracehop"); Map<String, Object> hopperUpdates = new HashMap<>(); hopperUpdates.put("nickname", "Amazing Grace"); hopperRef.updateChildrenAsync(hopperUpdates);
Node.js
const usersRef = ref.child('users'); const hopperRef = usersRef.child('gracehop'); hopperRef.update({ 'nickname': 'Amazing Grace' });
Piton
hopper_ref = users_ref.child('gracehop') hopper_ref.update({ 'nickname': 'Amazing Grace' })
Gitmek
hopperRef := usersRef.Child("gracehop") if err := hopperRef.Update(ctx, map[string]interface{}{ "nickname": "Amazing Grace", }); err != nil { log.Fatalln("Error updating child:", err) }
Bu, takma adını içerecek şekilde Grace'in verilerini güncelleyecektir. Burada güncelleme yerine set kullanmış olsaydınız, hem full_name
hem de date_of_birth
hopperRef
silinirdi.
Firebase Gerçek Zamanlı Veritabanı, çok yollu güncellemeleri de destekler. Bu, güncellemenin artık veritabanınızdaki birden çok konumdaki değerleri aynı anda güncelleyebileceği anlamına gelir; bu, verilerinizi normalleştirmenize yardımcı olan güçlü bir özelliktir. Çok yollu güncellemeleri kullanarak hem Grace'e hem de Alan'a aynı anda takma adlar ekleyebilirsiniz:
java
Map<String, Object> userUpdates = new HashMap<>(); userUpdates.put("alanisawesome/nickname", "Alan The Machine"); userUpdates.put("gracehop/nickname", "Amazing Grace"); usersRef.updateChildrenAsync(userUpdates);
Node.js
const usersRef = ref.child('users'); usersRef.update({ 'alanisawesome/nickname': 'Alan The Machine', 'gracehop/nickname': 'Amazing Grace' });
Piton
users_ref.update({ 'alanisawesome/nickname': 'Alan The Machine', 'gracehop/nickname': 'Amazing Grace' })
Gitmek
if err := usersRef.Update(ctx, map[string]interface{}{ "alanisawesome/nickname": "Alan The Machine", "gracehop/nickname": "Amazing Grace", }); err != nil { log.Fatalln("Error updating children:", err) }
Bu güncellemeden sonra hem Alan hem de Grace'in takma adları eklendi:
{ "users": { "alanisawesome": { "date_of_birth": "June 23, 1912", "full_name": "Alan Turing", "nickname": "Alan The Machine" }, "gracehop": { "date_of_birth": "December 9, 1906", "full_name": "Grace Hopper", "nickname": "Amazing Grace" } } }
Dahil edilen yollarla nesneleri yazarak nesneleri güncellemeye çalışmanın farklı davranışlarla sonuçlanacağını unutmayın. Bunun yerine Grace ve Alan'ı şu şekilde güncellemeye çalışırsanız ne olacağına bir göz atalım:
java
Map<String, Object> userNicknameUpdates = new HashMap<>(); userNicknameUpdates.put("alanisawesome", new User(null, null, "Alan The Machine")); userNicknameUpdates.put("gracehop", new User(null, null, "Amazing Grace")); usersRef.updateChildrenAsync(userNicknameUpdates);
Node.js
const usersRef = ref.child('users'); usersRef.update({ 'alanisawesome': { 'nickname': 'Alan The Machine' }, 'gracehop': { 'nickname': 'Amazing Grace' } });
Piton
users_ref.update({ 'alanisawesome': { 'nickname': 'Alan The Machine' }, 'gracehop': { 'nickname': 'Amazing Grace' } })
Gitmek
if err := usersRef.Update(ctx, map[string]interface{}{ "alanisawesome": &User{Nickname: "Alan The Machine"}, "gracehop": &User{Nickname: "Amazing Grace"}, }); err != nil { log.Fatalln("Error updating children:", err) }
Bu, farklı davranışlarla sonuçlanır, yani tüm /users
düğümünün üzerine yazılır:
{ "users": { "alanisawesome": { "nickname": "Alan The Machine" }, "gracehop": { "nickname": "Amazing Grace" } } }
Bir Tamamlama Geri Araması Ekleme
Node.js ve Java Admin SDK'larında, verilerinizin ne zaman işlendiğini öğrenmek isterseniz bir tamamlama geri araması ekleyebilirsiniz. Bu SDK'lardaki hem ayarlama hem de güncelleme yöntemleri, yazma işlemi veritabanına işlendiğinde çağrılan isteğe bağlı bir tamamlama geri araması alır. Arama herhangi bir nedenle başarısız olursa, geri arama, hatanın neden oluştuğunu gösteren bir hata nesnesi iletilir. Python ve Go Admin SDK'larında tüm yazma yöntemleri engelleniyor. Diğer bir deyişle, yazma yöntemleri, yazma işlemleri veritabanına işlenene kadar geri dönmez.
java
DatabaseReference dataRef = ref.child("data"); dataRef.setValue("I'm writing data", new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) { if (databaseError != null) { System.out.println("Data could not be saved " + databaseError.getMessage()); } else { System.out.println("Data saved successfully."); } } });
Node.js
dataRef.set('I\'m writing data', (error) => { if (error) { console.log('Data could not be saved.' + error); } else { console.log('Data saved successfully.'); } });
Veri Listelerini Kaydetme
Veri listeleri oluştururken, çoğu uygulamanın çok kullanıcılı yapısını akılda tutmak ve liste yapınızı buna göre ayarlamak önemlidir. Yukarıdaki örneği genişleterek, uygulamanıza blog gönderileri ekleyelim. İlk içgüdünüz, aşağıdaki gibi otomatik artan tamsayı dizinlerine sahip çocukları depolamak için set kullanmak olabilir:
// NOT RECOMMENDED - use push() instead! { "posts": { "0": { "author": "gracehop", "title": "Announcing COBOL, a New Programming Language" }, "1": { "author": "alanisawesome", "title": "The Turing Machine" } } }
Bir kullanıcı yeni bir gönderi eklerse, /posts/2
olarak saklanır. Bu, yalnızca tek bir yazar gönderi eklediğinde işe yarardı, ancak işbirlikçi blog uygulamanızda birçok kullanıcı aynı anda gönderi ekleyebilir. İki yazar aynı anda /posts/2
yazarsa, gönderilerden biri diğeri tarafından silinir.
Bunu çözmek için Firebase istemcileri, her yeni çocuk için benzersiz bir anahtar oluşturan bir push()
işlevi sağlar . Benzersiz alt anahtarlar kullanarak, birkaç istemci, yazma çakışmaları konusunda endişe duymadan aynı yere aynı anda alt anahtarlar ekleyebilir.
java
public static class Post { public String author; public String title; public Post(String author, String title) { // ... } } DatabaseReference postsRef = ref.child("posts"); DatabaseReference newPostRef = postsRef.push(); newPostRef.setValueAsync(new Post("gracehop", "Announcing COBOL, a New Programming Language")); // We can also chain the two calls together postsRef.push().setValueAsync(new Post("alanisawesome", "The Turing Machine"));
Node.js
const newPostRef = postsRef.push(); newPostRef.set({ author: 'gracehop', title: 'Announcing COBOL, a New Programming Language' }); // we can also chain the two calls together postsRef.push().set({ author: 'alanisawesome', title: 'The Turing Machine' });
Piton
posts_ref = ref.child('posts') new_post_ref = posts_ref.push() new_post_ref.set({ 'author': 'gracehop', 'title': 'Announcing COBOL, a New Programming Language' }) # We can also chain the two calls together posts_ref.push().set({ 'author': 'alanisawesome', 'title': 'The Turing Machine' })
Gitmek
// Post is a json-serializable type. type Post struct { Author string `json:"author,omitempty"` Title string `json:"title,omitempty"` } postsRef := ref.Child("posts") newPostRef, err := postsRef.Push(ctx, nil) if err != nil { log.Fatalln("Error pushing child node:", err) } if err := newPostRef.Set(ctx, &Post{ Author: "gracehop", Title: "Announcing COBOL, a New Programming Language", }); err != nil { log.Fatalln("Error setting value:", err) } // We can also chain the two calls together if _, err := postsRef.Push(ctx, &Post{ Author: "alanisawesome", Title: "The Turing Machine", }); err != nil { log.Fatalln("Error pushing child node:", err) }
Eşsiz anahtar, bir zaman damgasını temel alır, bu nedenle liste öğeleri otomatik olarak kronolojik olarak sıralanır. Firebase her blog gönderisi için benzersiz bir anahtar oluşturduğundan, birden fazla kullanıcı aynı anda bir gönderi eklerse yazma çakışması olmaz. Veritabanı verileriniz artık şöyle görünür:
{ "posts": { "-JRHTHaIs-jNPLXOQivY": { "author": "gracehop", "title": "Announcing COBOL, a New Programming Language" }, "-JRHTHaKuITFIhnj02kE": { "author": "alanisawesome", "title": "The Turing Machine" } } }
JavaScript, Python ve Go'da push()
ve ardından hemen set()
çağırma modeli o kadar yaygındır ki Firebase SDK, ayarlanacak verileri aşağıdaki gibi doğrudan push()
'a ileterek bunları birleştirmenize izin verir:
java
// No Java equivalent
Node.js
// This is equivalent to the calls to push().set(...) above postsRef.push({ author: 'gracehop', title: 'Announcing COBOL, a New Programming Language' });;
Piton
# This is equivalent to the calls to push().set(...) above posts_ref.push({ 'author': 'gracehop', 'title': 'Announcing COBOL, a New Programming Language' })
Gitmek
if _, err := postsRef.Push(ctx, &Post{ Author: "gracehop", Title: "Announcing COBOL, a New Programming Language", }); err != nil { log.Fatalln("Error pushing child node:", err) }
Push() tarafından oluşturulan benzersiz anahtarı alma
push()
çağrısı, anahtarı almak veya ona veri ayarlamak için kullanabileceğiniz yeni veri yoluna bir referans döndürür. Aşağıdaki kod, yukarıdaki örnekle aynı verilerle sonuçlanacak, ancak artık oluşturulan benzersiz anahtara erişimimiz olacak:
java
// Generate a reference to a new location and add some data using push() DatabaseReference pushedPostRef = postsRef.push(); // Get the unique ID generated by a push() String postId = pushedPostRef.getKey();
Node.js
// Generate a reference to a new location and add some data using push() const newPostRef = postsRef.push(); // Get the unique key generated by push() const postId = newPostRef.key;
Piton
# Generate a reference to a new location and add some data using push() new_post_ref = posts_ref.push() # Get the unique key generated by push() post_id = new_post_ref.key
Gitmek
// Generate a reference to a new location and add some data using Push() newPostRef, err := postsRef.Push(ctx, nil) if err != nil { log.Fatalln("Error pushing child node:", err) } // Get the unique key generated by Push() postID := newPostRef.Key
Gördüğünüz gibi benzersiz anahtarın değerini push()
referansınızdan alabilirsiniz.
Verileri Alma ile ilgili bir sonraki bölümde, bu verileri bir Firebase veritabanından nasıl okuyacağımızı öğreneceğiz.
İşlem Verilerini Kaydetme
Artımlı sayaçlar gibi eşzamanlı değişikliklerle bozulabilen karmaşık verilerle çalışırken, SDK bir işlem işlemi sağlar.
Java ve Node.js'de işlem işlemine iki geri arama verirsiniz: bir güncelleme işlevi ve isteğe bağlı bir tamamlama geri araması. Python ve Go'da işlem işlemi engelliyor ve bu nedenle yalnızca güncelleme işlevini kabul ediyor.
Güncelleme işlevi, verilerin mevcut durumunu bir argüman olarak alır ve yazmak istediğiniz yeni istenen durumu döndürmelidir. Örneğin, belirli bir blog gönderisindeki olumlu oyların sayısını artırmak isterseniz, aşağıdaki gibi bir işlem yazarsınız:
java
DatabaseReference upvotesRef = ref.child("server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes"); upvotesRef.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { Integer currentValue = mutableData.getValue(Integer.class); if (currentValue == null) { mutableData.setValue(1); } else { mutableData.setValue(currentValue + 1); } return Transaction.success(mutableData); } @Override public void onComplete( DatabaseError databaseError, boolean committed, DataSnapshot dataSnapshot) { System.out.println("Transaction completed"); } });
Node.js
const upvotesRef = db.ref('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes'); upvotesRef.transaction((current_value) => { return (current_value || 0) + 1; });
Piton
def increment_votes(current_value): return current_value + 1 if current_value else 1 upvotes_ref = db.reference('server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes') try: new_vote_count = upvotes_ref.transaction(increment_votes) print('Transaction completed') except db.TransactionAbortedError: print('Transaction failed to commit')
Gitmek
fn := func(t db.TransactionNode) (interface{}, error) { var currentValue int if err := t.Unmarshal(¤tValue); err != nil { return nil, err } return currentValue + 1, nil } ref := client.NewRef("server/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes") if err := ref.Transaction(ctx, fn); err != nil { log.Fatalln("Transaction failed to commit:", err) }
Yukarıdaki örnek, sayacın null
olup olmadığını veya henüz artırılmadığını kontrol eder, çünkü herhangi bir varsayılan değer yazılmamışsa işlemler null
ile çağrılabilir.
Yukarıdaki kod bir işlem işlevi olmadan çalıştırılmışsa ve iki müşteri bunu aynı anda artırmaya çalışırsa, her ikisi de yeni değer olarak 1
yazar ve iki yerine bir artışla sonuçlanır.
Ağ Bağlantısı ve Çevrimdışı Yazmalar
Firebase Node.js ve Java istemcileri, tüm etkin verilerin kendi dahili sürümlerini korur. Veri yazıldığında, önce bu yerel sürüme yazılır. İstemci daha sonra bu verileri veritabanıyla ve diğer istemcilerle 'en iyi çaba' esasına göre eşitler.
Sonuç olarak, veritabanına yapılan tüm yazmalar, herhangi bir veri veritabanına yazılmadan hemen önce yerel olayları tetikleyecektir. Bu, Firebase kullanarak bir uygulama yazdığınızda, ağ gecikmesinden veya İnternet bağlantısından bağımsız olarak uygulamanızın yanıt vermeye devam edeceği anlamına gelir.
Bağlantı yeniden sağlandığında, istemcinin herhangi bir özel kod yazmak zorunda kalmadan mevcut sunucu durumuna "yetişmesi" için uygun olay dizisini alacağız.
Verilerinizi Koruma
Firebase Gerçek Zamanlı Veritabanı, verilerinizin farklı düğümlerinde hangi kullanıcıların okuma ve yazma erişimi olduğunu tanımlamanıza izin veren bir güvenlik diline sahiptir. Bununla ilgili daha fazla bilgiyi Verilerinizi Koruyun bölümünde okuyabilirsiniz.