572 lines
23 KiB
HTML
572 lines
23 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="generator" content="Asciidoctor 1.5.8">
|
|
<title>Spring Data Reactive Repositories for Cloud Firestore</title>
|
|
<link rel="stylesheet" href="css/spring.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
|
|
<style>
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.switch {
|
|
border-width: 1px 1px 0 1px;
|
|
border-style: solid;
|
|
border-color: #7a2518;
|
|
display: inline-block;
|
|
}
|
|
|
|
.switch--item {
|
|
padding: 10px;
|
|
background-color: #ffffff;
|
|
color: #7a2518;
|
|
display: inline-block;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.switch--item:not(:first-child) {
|
|
border-width: 0 0 0 1px;
|
|
border-style: solid;
|
|
border-color: #7a2518;
|
|
}
|
|
|
|
.switch--item.selected {
|
|
background-color: #7a2519;
|
|
color: #ffffff;
|
|
}
|
|
</style>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
|
|
<script type="text/javascript">
|
|
function addBlockSwitches() {
|
|
$('.primary').each(function() {
|
|
primary = $(this);
|
|
createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected");
|
|
primary.children('.title').remove();
|
|
});
|
|
$('.secondary').each(function(idx, node) {
|
|
secondary = $(node);
|
|
primary = findPrimary(secondary);
|
|
switchItem = createSwitchItem(secondary, primary.children('.switch'));
|
|
switchItem.content.addClass('hidden');
|
|
findPrimary(secondary).append(switchItem.content);
|
|
secondary.remove();
|
|
});
|
|
}
|
|
|
|
function createBlockSwitch(primary) {
|
|
blockSwitch = $('<div class="switch"></div>');
|
|
primary.prepend(blockSwitch);
|
|
return blockSwitch;
|
|
}
|
|
|
|
function findPrimary(secondary) {
|
|
candidate = secondary.prev();
|
|
while (!candidate.is('.primary')) {
|
|
candidate = candidate.prev();
|
|
}
|
|
return candidate;
|
|
}
|
|
|
|
function createSwitchItem(block, blockSwitch) {
|
|
blockName = block.children('.title').text();
|
|
content = block.children('.content').first().append(block.next('.colist'));
|
|
item = $('<div class="switch--item">' + blockName + '</div>');
|
|
item.on('click', '', content, function(e) {
|
|
$(this).addClass('selected');
|
|
$(this).siblings().removeClass('selected');
|
|
e.data.siblings('.content').addClass('hidden');
|
|
e.data.removeClass('hidden');
|
|
});
|
|
blockSwitch.append(item);
|
|
return {'item': item, 'content': content};
|
|
}
|
|
|
|
$(addBlockSwitches);
|
|
</script>
|
|
|
|
</head>
|
|
<body class="book toc2 toc-left">
|
|
<div id="header">
|
|
<div id="toc" class="toc2">
|
|
<div id="toctitle">Table of Contents</div>
|
|
<ul class="sectlevel1">
|
|
<li><a href="#_spring_data_reactive_repositories_for_cloud_firestore">Spring Data Reactive Repositories for Cloud Firestore</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#_configuration">Configuration</a></li>
|
|
<li><a href="#_object_mapping">Object Mapping</a></li>
|
|
<li><a href="#_reactive_repositories">Reactive Repositories</a></li>
|
|
<li><a href="#_query_methods_by_convention">Query methods by convention</a></li>
|
|
<li><a href="#_transactions">Transactions</a></li>
|
|
<li><a href="#_reactive_repository_sample">Reactive Repository Sample</a></li>
|
|
<li><a href="#_cloud_firestore_spring_boot_starter">Cloud Firestore Spring Boot Starter</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div id="content">
|
|
<div class="sect1">
|
|
<h2 id="_spring_data_reactive_repositories_for_cloud_firestore"><a class="link" href="#_spring_data_reactive_repositories_for_cloud_firestore">Spring Data Reactive Repositories for Cloud Firestore</a></h2>
|
|
<div class="sectionbody">
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
Currently some features are not supported: transactions, sorting, query by example, projections, auditing.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><a href="https://projects.spring.io/spring-data/">Spring Data</a> is an abstraction for storing and retrieving POJOs in numerous storage technologies.
|
|
Spring Cloud GCP adds Spring Data support for <a href="https://cloud.google.com/firestore/">Google Cloud Firestore</a> in native mode, providing reactive template and repositories support.
|
|
To begin using this library, add the <code>spring-cloud-gcp-data-firestore</code> artifact to your project.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Maven coordinates for this module only, using <a href="getting-started.html#_bill_of_materials">Spring Cloud GCP BOM</a>:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-gcp-data-firestore</artifactId>
|
|
</dependency></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Gradle coordinates:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code>dependencies {
|
|
compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-data-firestore'
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>We provide a Spring Boot Starter for Spring Data Firestore, with which you can use our recommended auto-configuration setup. To use the starter, see the coordinates below.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-gcp-starter-data-firestore</artifactId>
|
|
</dependency></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Gradle coordinates:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code>dependencies {
|
|
compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-data-firestore'
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_configuration"><a class="link" href="#_configuration">Configuration</a></h3>
|
|
<div class="sect3">
|
|
<h4 id="_properties"><a class="link" href="#_properties">Properties</a></h4>
|
|
<div class="paragraph">
|
|
<p>The Spring Boot starter for Google Cloud Firestore provides the following configuration options:</p>
|
|
</div>
|
|
<table class="tableblock frame-all grid-all stretch">
|
|
<colgroup>
|
|
<col style="width: 25%;">
|
|
<col style="width: 25%;">
|
|
<col style="width: 25%;">
|
|
<col style="width: 25%;">
|
|
</colgroup>
|
|
<tbody>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Name</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Description</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Required</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Default value</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>spring.cloud.gcp.firestore.enabled</code></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Enables or disables Pub/Sub auto-configuration</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>spring.cloud.gcp.firestore.project-id</code></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">GCP project ID where the Google Cloud Firestore API is hosted, if different from the one in the <a href="#spring-cloud-gcp-core">Spring Cloud GCP Core Module</a></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>spring.cloud.gcp.firestore.credentials.location</code></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">OAuth2 credentials for authenticating with the Google Cloud Firestore API, if different from the ones in the <a href="#spring-cloud-gcp-core">Spring Cloud GCP Core Module</a></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>spring.cloud.gcp.firestore.credentials.encoded-key</code></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Base64-encoded OAuth2 credentials for authenticating with the Google Cloud Firestore API, if different from the ones in the <a href="#spring-cloud-gcp-core">Spring Cloud GCP Core Module</a></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>spring.cloud.gcp.firestore.credentials.scopes</code></p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://developers.google.com/identity/protocols/googlescopes">OAuth2 scope</a> for Spring Cloud GCP Cloud Firestore credentials</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://www.googleapis.com/auth/datastore" class="bare">https://www.googleapis.com/auth/datastore</a></p></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_reactive_repository_settings"><a class="link" href="#_reactive_repository_settings">Reactive Repository settings</a></h4>
|
|
<div class="paragraph">
|
|
<p>Spring Data Repositories can be configured via the <code>@EnableReactiveFirestoreRepositories</code> annotation on your main <code>@Configuration</code> class.
|
|
With our Spring Boot Starter for Spring Data Cloud Firestore, <code>@EnableReactiveFirestoreRepositories</code> is automatically added.
|
|
It is not required to add it to any other class, unless there is a need to override finer grain configuration parameters provided by <a href="https://github.com/spring-cloud/spring-cloud-gcp/blob/master/spring-cloud-gcp-data-firestore/src/main/java/org/springframework/cloud/gcp/data/firestore/repository/config/EnableReactiveFirestoreRepositories.java"><code>@EnableReactiveFirestoreRepositories</code></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_autoconfiguration"><a class="link" href="#_autoconfiguration">Autoconfiguration</a></h4>
|
|
<div class="paragraph">
|
|
<p>Our Spring Boot autoconfiguration creates the following beans available in the Spring application context:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>an instance of <code>FirestoreTemplate</code></p>
|
|
</li>
|
|
<li>
|
|
<p>instances of all user defined repositories extending <code>FirestoreReactiveRepository</code> (an extension of <code>ReactiveCrudRepository</code> with additional Cloud Firestore features) when repositories are enabled</p>
|
|
</li>
|
|
<li>
|
|
<p>an instance of <a href="https://developers.google.com/resources/api-libraries/documentation/firestore/v1/java/latest/"><code>Firestore</code></a> from the Google Cloud Java Client for Firestore, for convenience and lower level API access</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_object_mapping"><a class="link" href="#_object_mapping">Object Mapping</a></h3>
|
|
<div class="paragraph">
|
|
<p>Spring Data Cloud Firestore allows you to map domain POJOs to <a href="https://firebase.google.com/docs/firestore/data-model#collections">Cloud Firestore collections</a> and documents via annotations:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.data.annotation.Id;
|
|
import org.springframework.cloud.gcp.data.firestore.Document;
|
|
|
|
@Document(collectionName = "usersCollection")
|
|
public class User {
|
|
@DocumentId
|
|
private String name;
|
|
|
|
private Integer age;
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><code>@Document(collectionName = "usersCollection")</code> annotation configures the collection name for the documents of this type.
|
|
This annotation is optional, by default the collection name is derived from the class name.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><code>@DocumentId</code> annotation marks a field to be used as document id. This annotation is required.</p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
Internally we use Firestore client library object mapping. See <a href="https://developers.google.com/android/reference/com/google/firebase/firestore/package-summary">the documentation</a> for supported annotations.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_reactive_repositories"><a class="link" href="#_reactive_repositories">Reactive Repositories</a></h3>
|
|
<div class="paragraph">
|
|
<p><a href="https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/reactive/ReactiveCrudRepository.html">Spring Data Repositories</a> is an abstraction that can reduce boilerplate code.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>For example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public interface UserRepository extends FirestoreReactiveRepository<User> {
|
|
Flux<User> findByAge(Integer age);
|
|
|
|
Flux<User> findByAgeGreaterThanAndAgeLessThan(Integer age1, Integer age2);
|
|
|
|
Flux<User> findByAgeGreaterThan(Integer age);
|
|
|
|
Flux<User> findByAgeGreaterThan(Integer age, Pageable pageable);
|
|
|
|
Mono<Long> countByAgeIsGreaterThan(Integer age);
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Spring Data generates a working implementation of the specified interface, which can be autowired into an application.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The <code>User</code> type parameter to <code>FirestoreReactiveRepository</code> refers to the underlying domain type.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class MyApplication {
|
|
|
|
@Autowired
|
|
UserRepository userRepository;
|
|
|
|
public void writeReadDeleteTest() {
|
|
User alice = new User("Alice", 29);
|
|
User bob = new User("Bob", 60);
|
|
|
|
this.userRepository.save(alice).block();
|
|
this.userRepository.save(bob).block();
|
|
|
|
assertThat(this.userRepository.count().block()).isEqualTo(2);
|
|
assertThat(this.userRepository.findAll().map(User::getName).collectList().block())
|
|
.containsExactlyInAnyOrder("Alice", "Bob");
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Repositories allow you to define custom Query Methods (detailed in the following sections) for retrieving and counting based on filtering and paging parameters.</p>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
Custom queries with <code>@Query</code> annotation are not supported since there is no query language in Cloud Firestore
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_query_methods_by_convention"><a class="link" href="#_query_methods_by_convention">Query methods by convention</a></h3>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class MyApplication {
|
|
public void partTreeRepositoryMethodTest() {
|
|
User u1 = new User("Cloud", 22);
|
|
User u2 = new User("Squall", 17);
|
|
Flux<User> users = Flux.fromArray(new User[] { u1, u2 });
|
|
|
|
this.userRepository.saveAll(users).blockLast();
|
|
|
|
assertThat(this.userRepository.count().block()).isEqualTo(2);
|
|
assertThat(this.userRepository.findByAge(22).collectList().block()).containsExactly(u1);
|
|
assertThat(this.userRepository.findByAgeGreaterThanAndAgeLessThan(20, 30).collectList().block())
|
|
.containsExactly(u1);
|
|
assertThat(this.userRepository.findByAgeGreaterThan(10).collectList().block()).containsExactlyInAnyOrder(u1,
|
|
u2);
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>In the example above the query method implementations in <code>UserRepository</code> are generated based on the name of the methods using the <a href="https://docs.spring.io/spring-data/data-commons/docs/current/reference/html#repositories.query-methods.query-creation">Spring Data Query creation naming convention</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Cloud Firestore only supports filter components joined by AND, and the following operations:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>equals</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>greater than or equals</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>greater than</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>less than or equals</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>less than</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>is null</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>After writing a custom repository interface specifying just the signatures of these methods, implementations are generated for you and can be used with an auto-wired instance of the repository.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_transactions"><a class="link" href="#_transactions">Transactions</a></h3>
|
|
<div class="paragraph">
|
|
<p>Read-only and read-write transactions are provided by <code>TransactionalOperator</code> (see this <a href="https://spring.io/blog/2019/05/16/reactive-transactions-with-spring">blog post</a> on reactive transactions for details).
|
|
In order to use it, you would need to autowire <code>ReactiveFirestoreTransactionManager</code> like this:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class MyApplication {
|
|
@Autowired
|
|
ReactiveFirestoreTransactionManager txManager;
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>After that you will be able to use it to create an instance of <code>TransactionalOperator</code>.
|
|
Note that you can switch between read-only and read-write transactions using <code>TransactionDefinition</code> object:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
|
|
transactionDefinition.setReadOnly(false);
|
|
TransactionalOperator operator = TransactionalOperator.create(this.txManager, transactionDefinition);</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When you have an instance of <code>TransactionalOperator</code>, you can execute a sequence of Firestore operations in a transaction using <code>operator::transactional</code>:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">User alice = new User("Alice", 29);
|
|
User bob = new User("Bob", 60);
|
|
|
|
this.userRepository.save(alice)
|
|
.then(this.userRepository.save(bob))
|
|
.as(operator::transactional)
|
|
.block();
|
|
|
|
this.userRepository.findAll()
|
|
.flatMap(a -> {
|
|
a.setAge(a.getAge() - 1);
|
|
return this.userRepository.save(a);
|
|
})
|
|
.as(operator::transactional).collectList().block();
|
|
|
|
assertThat(this.userRepository.findAll().map(User::getAge).collectList().block())
|
|
.containsExactlyInAnyOrder(28, 59);</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
Read operations in a transaction can only happen before write operations.
|
|
All write operations are applied atomically.
|
|
Read documents are locked until the transaction finishes with a commit or a rollback, which are handled by Spring Data.
|
|
If an <code>Exception</code> is thrown within a transaction, the rollback operation is executed.
|
|
Otherwise, the commit operation is executed.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_reactive_repository_sample"><a class="link" href="#_reactive_repository_sample">Reactive Repository Sample</a></h3>
|
|
<div class="paragraph">
|
|
<p>A <a href="https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-data-firestore-sample">sample application</a> is available.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_cloud_firestore_spring_boot_starter"><a class="link" href="#_cloud_firestore_spring_boot_starter">Cloud Firestore Spring Boot Starter</a></h3>
|
|
<div class="paragraph">
|
|
<p>If you prefer using Firestore client only, Spring Cloud GCP provides a convenience starter which automatically configures authentication settings and client objects needed to begin using <a href="https://cloud.google.com/firestore/">Google Cloud Firestore</a> in native mode.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>See <a href="https://cloud.google.com/firestore/docs/">documentation</a> to learn more about Cloud Firestore.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To begin using this library, add the <code>spring-cloud-gcp-starter-firestore</code> artifact to your project.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Maven coordinates, using <a href="getting-started.html#_bill_of_materials">Spring Cloud GCP BOM</a>:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-gcp-starter-firestore</artifactId>
|
|
</dependency></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Gradle coordinates:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code>dependencies {
|
|
compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-firestore'
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_using_cloud_firestore"><a class="link" href="#_using_cloud_firestore">Using Cloud Firestore</a></h4>
|
|
<div class="paragraph">
|
|
<p>The starter automatically configures and registers a <code>Firestore</code> bean in the Spring application context. To start using it, simply use the <code>@Autowired</code> annotation.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Autowired
|
|
Firestore firestore;
|
|
|
|
void writeDocumentFromObject() throws ExecutionException, InterruptedException {
|
|
// Add document data with id "joe" using a custom User class
|
|
User data = new User("Joe",
|
|
Arrays.asList(
|
|
new Phone(12345, PhoneType.CELL),
|
|
new Phone(54321, PhoneType.WORK)));
|
|
|
|
// .get() blocks on response
|
|
WriteResult writeResult = this.firestore.document("users/joe").set(data).get();
|
|
|
|
LOGGER.info("Update time: " + writeResult.getUpdateTime());
|
|
}
|
|
|
|
User readDocumentToObject() throws ExecutionException, InterruptedException {
|
|
ApiFuture<DocumentSnapshot> documentFuture =
|
|
this.firestore.document("users/joe").get();
|
|
|
|
User user = documentFuture.get().toObject(User.class);
|
|
|
|
LOGGER.info("read: " + user);
|
|
|
|
return user;
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_sample"><a class="link" href="#_sample">Sample</a></h4>
|
|
<div class="paragraph">
|
|
<p>A <a href="https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-firestore-sample">sample application</a> is available.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript" src="js/tocbot/tocbot.min.js"></script>
|
|
<script type="text/javascript" src="js/toc.js"></script>
|
|
<link rel="stylesheet" href="js/highlight/styles/atom-one-dark-reasonable.min.css">
|
|
<script src="js/highlight/highlight.min.js"></script>
|
|
<script>hljs.initHighlighting()</script>
|
|
</body>
|
|
</html> |