Realm 1.0を公開しました。 詳しくはリリースのお知らせをご覧ください。
Realmは、SQLiteやCoreDataから置き換わるモバイルデータベースです。

13949回のcommitと6148個のissueを経てRealmがバージョン1.0になりました

2014年7月に“世界初のモバイルファーストなデータベース”としてRealmを公開して以来13949回のcommitと6148個のissueを経て、本日Realm 1.0をリリースいたします。これはRealm社およびRealmプロダクトとしてだけでなく、Realmを利用していただいているiOSやAndroid開発者にとっても大きな節目であると言えます。

リリース当初はiOSとMacの開発者向けにObjective-C版を提供するのみでしたが、その後Swift版とAndroid版が加わり、つい先日React Native版とXamarin版をリリースいたしました。その結果、現在ではすべてのメジャーなモバイルプラットフォーム上の主要言語においてRealmを使用することができます。今回のRealm 1.0リリースは2年以上におよぶ開発の集大成であり、Realmをご利用いただいている皆様のご支援なしには成し得ないものでした。改めてお礼を申し上げます。

バージョン1.0に到達する以前から、Realmはモバイルアプリ開発者の方々に広く使われています。RealmはGitHubプロジェクトへの1万2千を超えるスターをいただくとともに、10万を超える開発者の方々による数万のアプリケーションにおいて実際に利用されています。これらのアプリにはStarbucks、Twitter、Anheuser-Busch、NBCUniversal、Alibaba、eBayをはじめとする大きなユーザー数をもつ企業からリリースされているアプリが含まれています。

Realmをつかうことでアプリをより良いものにすることができる、言い換えるとこれらのアプリを開発している開発者がよりよいユーザー体験をより簡単に、より短時間で開発することができるということがこれほど多くご利用いただいている理由です。また本日のバージョン1.0のリリースによって、iOS版およびAndroid版のRealmをご利用いただいている開発者の方々は成熟と安定を手にすることができます。

これまでにどのような変更が行われてきたかについては、Java版およびObjective-CとSwift版のchangelogをご参照ください。

Realmについて

RealmはSQLite上に構築されたいわゆるORMではありません。我々はモバイルアプリケーション開発者のために1からデータベースを開発しています。そのため単なるキーバリューストアではなく、データベースエンジンが保持するデータに動的に対応付けられたネイティブなオブジェクトを提供します。このことにより、Realmは簡潔なAPIとパフォーマンスの両立を達成しています。Realmを用いることで、複雑なデータのモデリング、オブジェクト間のリンク、高度なクエリのすべてが可能となります。

// Define you model class by extending RealmObject
public class Dog extends RealmObject {
    private String name;
    private int age;

    // ... Generated getters and setters ...
}

public class Person extends RealmObject {
    @PrimaryKey
    private long id;
    private String name;
    private RealmList<Dog> dogs; // Declare one-to-many relationships

    public Person(long id, String name) {
        this.id = id;
        this.name = name;
    }

    // ... Generated getters and setters ...
}

// Use them like regular java objects
Dog dog = new Dog();
dog.setName("Rex");
dog.setAge(1);

// Create a RealmConfiguration that saves the Realm file in the app's "files" directory.
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);

// Get a Realm instance for this thread
Realm realm = Realm.getDefaultInstance();

// Query Realm for all dogs younger than 2 years old
final RealmResults<Dog> puppies = realm.where(Dog.class).lessThan("age", 2).findAll();
puppies.size(); // => 0 because no dogs have been added to the Realm yet

// Persist your data in a transaction
realm.beginTransaction();
final Dog managedDog = realm.copyToRealm(dog); // Persist unmanaged objects
Person person = realm.createObject(Person.class); // Create managed objects directly
person.getDogs().add(managedDog);
realm.commitTransaction();

// Listeners will be notified when data changes
puppies.addChangeListener(new RealmChangeListener<RealmResults<Dog>>() {
    @Override
    public void onChange(RealmResults<Dog> results) {
        // Query results are updated in real time
        puppies.size(); // => 1
    }
});

// Asynchronously update objects on a background thread
realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm bgRealm) {
        Dog dog = bgRealm.where(Dog.class).equals("age", 1).findFirst();
        dog.setAge(3);
    }
}, new Realm.Transaction.OnSuccess() {
    @Override
    public void onSuccess() {
      // Original queries and Realm objects are automatically updated.
      puppies.size(); // => 0 because there are no more puppies younger than 2 years old
      managedDog.getAge();   // => 3 the dogs age is updated
    }
});
// Define your models like regular Objective‑C classes
@interface Dog : RLMObject
@property NSString *name;
@property NSData   *picture;
@property NSInteger age;
@end
@implementation Dog
@end
RLM_ARRAY_TYPE(Dog)
@interface Person : RLMObject
@property NSString             *name;
@property RLMArray<Dog *><Dog> *dogs;
@end
@implementation Person
@end

// Use them like regular Objective‑C objects
Dog *mydog = [[Dog alloc] init];
mydog.name = @"Rex";
mydog.age = 1;
mydog.picture = nil; // properties are nullable
NSLog(@"Name of dog: %@", mydog.name);

// Query Realm for all dogs less than 2 years old
RLMResults<Dog *> *puppies = [Dog objectsWhere:@"age < 2"];
puppies.count; // => 0 because no dogs have been added to the Realm yet

// Persist your data easily
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
  [realm addObject:mydog];
}];

// Queries are updated in real-time
puppies.count; // => 1

// Query and update the result in another thread
dispatch_async(dispatch_queue_create("background", 0), ^{
  Dog *theDog = [[Dog objectsWhere:@"age == 1"] firstObject];
  RLMRealm *realm = [RLMRealm defaultRealm];
  [realm beginWriteTransaction];
  theDog.age = 3;
  [realm commitWriteTransaction];
});
// Define your models like regular Swift classes
class Dog: Object {
  dynamic var name = ""
  dynamic var age = 0
}
class Person: Object {
  dynamic var name = ""
  dynamic var picture: NSData? = nil // optionals supported
  let dogs = List<Dog>()
}

// Use them like regular Swift objects
let myDog = Dog()
myDog.name = "Rex"
myDog.age = 1
print("name of dog: \(myDog.name)")

// Get the default Realm
let realm = try! Realm()

// Query Realm for all dogs less than 2 years old
let puppies = realm.objects(Dog).filter("age < 2")
puppies.count // => 0 because no dogs have been added to the Realm yet

// Persist your data easily
try! realm.write {
  realm.add(myDog)
}

// Queries are updated in real-time
puppies.count // => 1

// Query and update from any thread
dispatch_async(dispatch_queue_create("background", nil)) {
  let realm = try! Realm()
  let theDog = realm.objects(Dog).filter("age == 1").first
  try! realm.write {
    theDog!.age = 3
  }
}
// Define your models and their properties
class Car {}
Car.schema = {
  name: 'Car',
  properties: {
    make:  'string',
    model: 'string',
    miles: 'int',
  }
};
class Person {}
Person.schema = {
  name: 'Person',
  properties: {
    name:    {type: 'string'},
    cars:    {type: 'list', objectType: 'Car'},
    picture: {type: 'data', optional: true}, // optional property
  }
};

// Get the default Realm with support for our objects
let realm = new Realm({schema: [Car, Person]});

// Create Realm objects and write to local storage
realm.write(() => {
  let myCar = realm.create('Car', {
    make: 'Honda',
    model: 'Civic',
    miles: 1000,
  });
  myCar.miles += 20; // Update a property value
});

// Query Realm for all cars with a high mileage
let cars = realm.objects('Car').filtered('miles > 1000');

// Will return a Results object with our 1 car
cars.length // => 1

// Add another car
realm.write(() => {
  let myCar = realm.create('Car', {
    make: 'Ford',
    model: 'Focus',
    miles: 2000,
  });

// Query results are updated in real-time
cars.length // => 2
// Define your models like regular C# classes
public class Dog : RealmObject
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person Owner { get; set; }
}

public class Person : RealmObject
{
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; }
}

var realm = Realm.GetInstance();

// Use LINQ to query
var puppies = realm.All<Dog>().Where(d => d.Age < 2);

puppies.Count(); // => 0 because no dogs have been added yet

// Update and persist objects with a thread-safe transaction
realm.Write(() =>
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Rex";
    mydog.Age = 1;
});

// Queries are updated in real-time
puppies.Count(); // => 1

// LINQ query syntax works as well
var oldDogs = from d in realm.All<Dog>() where d.Age > 8 select d;

// Query and update from any thread
new Thread(() =>
{
    var realm2 = Realm.GetInstance();

    var theDog = realm2.All<Dog>().Where(d => d.Age == 1).First();
    realm2.Write(() => theDog.Age = 3);
}).Start();

Realmを使うべき理由

使い方が簡単

Realmは使いやすさを最も重視しています。規模の大きなアプリでも数時間でRealmに対応させることができ、実装、最適化、デバッグのための時間を数週間節約できたということも珍しくありません。

速い!

Realmの使いやすさはパフォーマンスを犠牲にしません。メモリマッピング、遅延ローディング、独自のストレージエンジンなどにより、RealmはリッチなオブジェクトベースのAPIを提供しているにもかかわらず、通常SQLiteよりも高速に動作します。それぞれのユースケースでの確認を行うことをおすすめしていますが、多くの場合既存のコードをRealmに対応させることで大幅な高速化を達成できます。

クロスプラットフォーム

RealmはJavaObjective-CReact NativeSwiftXamarinをサポートしています。これらのプラットフォーム間でRealmファイルは互換性があります。また、これらすべてのプラットフォームで同じようなロジックを用いてアプリを実装することができます。デバッグの際は、.realmファイルの中身をRealm Browserを用いて確認することができます。

先進的

Realmオブジェクトはつねに最新の状態に維持され、そのことがリアクティブパターンや一方向データフローを当たり前のものにします。リンクの機能はグラフ構造のRealmオブジェクトの扱いを可能にし、先進的なクエリ言語を用いることができます。また、AES256による暗号化機構を持ち、アドオンクラスを用いることでRealm上のデータを簡単にUIに表示することができます。

信頼性

大規模なアプリや多数のユーザーがいる場合でも安心です。Realmはすでに銀行のアプリケーション、ヘルスケア分野、複雑なエンタープライズアプリ、AppleのAppストアやGoogle Playストアでナンバーワンになるようなアプリでも採用されています。

コミュニティドリブン

RealmはGitHub上でオープンに開発されています。機能はユーザーの要求によって優先順位付けされるだけでなく、コードのコントリビューションも歓迎しています。Realmのプロジェクトは1万2千を超えるスターをGitHub上で獲得し、たくさんのアプリ、プラグイン、コンポーネントが作られています。

サポート

Realmはサポートとバグフィックスを他のすべてのタスクよりも優先します。そのため、データベースに関する質問には直接その開発やメンテナンスを行っている開>発者から回答を得ることができます。 質問はSlack(日本語)Twitter(日本語)StackOverflow(日本語)GitHub(英語)で受け付けています。

Realmの利用者について

Realmはさまざまなアプリに組み込まれ、10億人を超えるユーザーに利用されています。

Twitter

Appストアで大成功を収めたアプリがRealmを使用しています。Twitter社の動画アプリで2億人のMAUを抱えるVineが2016年からRealmを使い始めました。

Starbucks

フォーチュン500の小売り企業も主力アプリにRealmを使用しています。来店前にスマートフォンから注文し、カウンターですぐに受け取ることができます。

Alibaba

NYSEに上場している中国の巨大企業もRealmを使用しています。マーケット上での売り買いのためのアプリで使用され、昨年はおよそ30億ドルの売上を達成しています。

Budweiser

フォーチュン・グローバル500の巨大企業はTapWiserという革新的なアプリでRealmを使っています。バーや小売店がパソコン無しに素早くビールの樽や瓶を注文できるモバイルアプリです。

SAP

もしすでにConcurというアプリを使ったことがあるなら、あなたはすでにRealmユーザーかも知れません。経費精算やトラベルプランのためのアプリで、2万社に3000万人のエンドユーザーがいます。

Rite Aid

フォーチュン500の巨大小売業者もEnvisionRxというアプリで安全にお客様のデータを扱うためRealmを使っています。

ここにあげた以外にもAmazon、eBay、Google、GoPro、Walmart、Adidas、Cisco、NBCUniversal、Nike、NFLなど数多くの企業で、また日本ではAWA株式会社、日本経済新聞社、Sansan株式会社、株式会社マネーフォワード、ヤフー株式会社、LINE株式会社、株式会社サイバーエージェントなど、皆さんご存知の企業のアプリでRealmをご利用いただいています。

What’s Next

ぜひ改善に関するフィードバックをお寄せください。困りの際はStack Overflow(日本語)Slack(日本語)Twitter(日本語)でご相談ください。

Realm Javaの公式ドキュメントおよびGitHubリポジトリ

Realm Objective-Cの公式ドキュメントおよびGitHubリポジトリ

Realm Swiftの公式ドキュメントおよびGitHubリポジトリ

Realm React Nativeの公式ドキュメントおよびGitHubリポジトリ

Realm Xamarinの公式ドキュメントおよびGitHubリポジトリ

Realmがどのようなプロダクトに使われることになるのか、我々はとても楽しみにしています。