Veri Kaydetme

Bu belge, Firebase Gerçek Zamanlı Veritabanınıza veri yazmaya yönelik dört yöntemi kapsar: ayarlama, güncelleme, aktarma ve işlem desteği.

Veri Kaydetmenin Yolları

ayarlamak Verileri, messages/users/<username> gibi tanımlanmış 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 verilerin listesine ekleyin . Bir listeye her yeni düğüm eklediğinizde, veritabanınız messages/users/<unique-user-id>/<username> gibi benzersiz bir anahtar oluşturur.
işlem Eşzamanlı güncellemeler nedeniyle 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 o yoldaki mevcut verilerin yerini alan bir kümedir. Seti anlamak için basit bir blog uygulaması geliştireceğiz. Uygulamanızın verileri şu veritabanı referansında saklanı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ıyla saklayacağız ve ayrıca tam adını ve doğum tarihini de saklayacağız. Her kullanıcının benzersiz bir kullanıcı adı olacağından, anahtarınız zaten olduğundan ve bir anahtar oluşturmanıza gerek olmadığından, push yöntemi yerine burada set yöntemini kullanmak mantıklıdır.

Öncelikle kullanıcı verilerinize bir veritabanı referansı oluşturun. Daha sonra 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 değerini geçmek, 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 veritabanı alt konumlarına iç içe bir biçimde eşlenir. Şimdi https://docs-examples.firebaseio.com/server/tained-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 kaydedilmesiyle sonuçlanacaktır:

{
  "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. usersRef veriler zaten mevcutsa, ilk yaklaşımın bunun üzerine yazacağını, ancak ikinci yöntemin yalnızca her bir alt düğümün değerini değiştirip, usersRef diğer alt öğelerini değiştirmeden bırakacağını unutmamak önemlidir.

Kayıtlı Verileri Güncelleme

Bir veritabanı konumunun birden fazla alt öğesine, diğer alt düğümlerin üzerine yazmadan aynı anda yazmak istiyorsanız, aşağıda gösterilen güncelleme 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, Grace'in verilerini takma adını içerecek şekilde güncelleyecektir. Eğer update yerine set here kullanmış olsaydınız, hopperRef hem full_name hem de date_of_birth silinirdi.

Firebase Gerçek Zamanlı Veritabanı aynı zamanda çok yollu güncellemeleri de destekler. Bu, güncellemenin artık veritabanınızdaki birden fazla 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 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"
    }
  }
}

Nesneleri, yolları dahil ederek yazarak 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ışlara, yani tüm /users düğümünün üzerine yazılmasına neden olur:

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}

Tamamlama Geri Araması Ekleme

Node.js ve Java Yönetici SDK'larında verilerinizin ne zaman kaydedildiğini bilmek istiyorsanız bir tamamlama geri çağrısı ekleyebilirsiniz. Bu SDK'lardaki hem ayarlama hem de güncelleme yöntemleri, veritabanına yazma işlemi tamamlandığında çağrılan isteğe bağlı bir tamamlama geri çağrısını alır. Çağrı herhangi bir nedenden dolayı başarısız olursa, geri çağrıya hatanın neden oluştuğunu belirten bir hata nesnesi iletilir. Python ve Go Admin SDK'larında tüm yazma yöntemleri engelleniyor. Yani yazma yöntemleri, yazma işlemleri veritabanına aktarılana 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ı doğası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, çocukları aşağıdaki gibi otomatik artan tamsayı indeksleriyle 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, bu /posts/2 olarak depolanır. Bu, yalnızca tek bir yazarın gönderi eklemesi durumunda işe yarar, ancak ortak blog uygulamanızda birçok kullanıcı aynı anda gönderi ekleyebilir. Eğer iki yazar aynı anda /posts/2 yazarsa, gönderilerden biri diğeri tarafından silinecektir.

Bunu çözmek için Firebase istemcileri, her yeni alt öğe için benzersiz bir anahtar üreten bir push() işlevi sağlar . Benzersiz alt anahtarlar kullanarak, birkaç istemci, yazma çakışmaları konusunda endişelenmeden çocukları aynı anda aynı konuma 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)
}

Benzersiz anahtar bir zaman damgasını temel aldığından liste öğeleri otomatik olarak kronolojik olarak sıralanacaktır. Firebase her blog yazısı için benzersiz bir anahtar oluşturduğundan, birden fazla kullanıcının aynı anda bir yazı eklemesi durumunda herhangi bir yazma çakışması meydana gelmez. Veritabanı verileriniz artık şöyle görünüyor:

{
  "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() çağırma ve ardından hemen set() çağırma düzeni o kadar yaygındır ki Firebase SDK, ayarlanacak verileri doğrudan push() öğesine aşağıdaki gibi ileterek bunları birleştirmenize olanak tanır:

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() öğesini çağırmak, anahtarı almak veya ona veri ayarlamak için kullanabileceğiniz yeni veri yoluna bir referans döndürecektir. Aşağıdaki kod, yukarıdaki örnekle aynı verilerle sonuçlanacaktır, ancak artık oluşturulan benzersiz anahtara erişebileceğiz:

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.

Veri Alma ile ilgili bir sonraki bölümde, bu verileri Firebase veritabanından nasıl okuyacağımızı öğreneceğiz.

İşlem Verilerini Kaydetme

Artımlı sayaçlar gibi eşzamanlı değişikliklerle bozulabilecek 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 engelleniyor ve bu nedenle yalnızca güncelleme işlevini kabul ediyor.

Güncelleme işlevi verinin mevcut durumunu argüman olarak alır ve yazmak istediğiniz yeni durumu döndürmelidir. Örneğin, belirli bir blog yazısının olumlu oy sayısını artırmak istiyorsanız 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(&currentValue); 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ü varsayılan değer yazılmamışsa işlemler null ile çağrılabilir.

Yukarıdaki kod bir işlem fonksiyonu olmadan çalıştırılmış olsaydı ve iki istemci bunu aynı anda artırmaya çalışırsa, her ikisi de yeni değer olarak 1 yazar ve sonuçta iki yerine bir artış olur.

Ağ Bağlantısı ve Çevrimdışı Yazma

Firebase Node.js ve Java istemcileri, tüm etkin verilerin kendi dahili sürümlerini korur. Veriler yazıldığında öncelikle bu yerel versiyona yazılır. Müşteri daha sonra bu verileri veritabanıyla ve diğer istemcilerle 'en iyi çabayı' esas alarak senkronize eder.

Sonuç olarak, veritabanına yapılan tüm yazma işlemleri, veritabanına herhangi bir veri yazılmadan önce yerel olayları anında tetikleyecektir. Bu, Firebase kullanarak bir uygulama yazdığınızda uygulamanızın ağ gecikmesine veya İnternet bağlantısına bakılmaksızın yanıt vermeye devam edeceği anlamına gelir.

Bağlantı yeniden kurulduğunda, istemcinin herhangi bir özel kod yazmaya gerek kalmadan mevcut sunucu durumunu "yakalaması" için uygun olay dizisini alacağız.

Verilerinizin Güvenliğini Sağlama

Firebase Gerçek Zamanlı Veritabanı, hangi kullanıcıların verilerinizin farklı düğümlerine okuma ve yazma erişimine sahip olduğunu tanımlamanıza olanak tanıyan bir güvenlik diline sahiptir. Bu konuda daha fazla bilgiyi Verilerinizi Güvence Altına Alın bölümünde okuyabilirsiniz.