SlideShare a Scribd company logo
MongoDB Mobile
Bringing the Power of MongoDB to Your Device
This presentation contains “forward-looking statements” within the meaning of Section 27A of the Securities Act of 1933,
as amended, and Section 21E of the Securities Exchange Act of 1934, as amended. Such forward-looking statements are
subject to a number of risks, uncertainties, assumptions and other factors that could cause actual results and the timing of
certain events to differ materially from future results expressed or implied by the forward-looking statements. Factors that
could cause or contribute to such differences include, but are not limited to, those identified our filings with the Securities
and Exchange Commission. You should not rely upon forward-looking statements as predictions of future events.
Furthermore, such forward-looking statements speak only as of the date of this presentation.
In particular, the development, release, and timing of any features or functionality described for MongoDB products
remains at MongoDB’s sole discretion. This information is merely intended to outline our general product direction and it
should not be relied on in making a purchasing decision nor is this a commitment, promise or legal obligation to deliver
any material, code, or functionality. Except as required by law, we undertake no obligation to update any forward-looking
statements to reflect events or circumstances after the date of such statements.
Safe Harbor Statement
Jason Flax
Senior Engineer
Stitch
We've Come a Long Way
You'd be surprised how
difficult it is to relinquish
a cell phone.
Adrien Brody
Mobile
Is Transforming Everything
I actually have this
fantasy of giving up
my cell phone.
Julia Stiles
Mobile
Is Transforming Everything
My cell phone is my best
friend. It's my lifeline to
the outside world.
Carrie Underwood
Mobile
Is Transforming Everything
Technology can be our
best friend, and technology
can also be the biggest
party pooper of our lives.
Stephen Spielberg
Mobile
Is Transforming Everything
The most important impact on
society and the world is the cell
phone. Cell phones have actually
been one of the primary drivers in
productivity improvements.
Fabrice Grinda
Mobile
Is Transforming Everything
I have a cell phone that doesn't behave like a
phone: It behaves like a computer that makes
calls. Computers are becoming an integral part
of daily life. And if people don't start designing
them to be more user-friendly, then an even
larger part of the population is going to be left
out of even more stuff.
Alan Cooper
Mobile
Is Transforming Everything
A Complete Data Platform
Geographically distributed backend services
• MongoDB Atlas
• Point and click active/active global clusters
• Effortless High Availability, Disaster Recovery, and low-
latency access
• MongoDB Stitch, Serverless Platform
• Automatic scaling based on request volume
• Stitch Query Anywhere
• Stitch Functions
• Stitch Triggers
• Stitch Mobile Sync (Beta)
Geographically distributed frontend services
• MongoDB Mobile
• IoT and edge devices
• iOS and Android apps
• Supporting local offline storage
Stitch provides a seamless bridge between them
MongoDB Mobile
The Full Stack
Your Mobile Application
• iOS and Android devices
• Leveraging the power of MongoDB everywhere
• Allowing you to focus on building your GREAT THING™
MongoDB Stitch SDK
• Access to MongoDB and Cloud services from Android and iOS
• New Stitch interfaces for on-device (local) storage
• Bi-directional synchronization between local and remote
MongoDB Mobile Drivers
• Swift for iOS, Java for Android
• Existing drivers, extended to support local storage
MongoDB Mobile Database
• A lite version of MongoDB as a library
• C language interface to the library
• Fully passive, no background threads or tasks
MongoDB Mobile Storage Engine
• K/V storage on top of SQLite
• Very small disk footprint and minimal memory usage
• Energy efficient
The Mobile Database
lib = mongo_embedded_v1_lib_init (&params, status);
instance = mongo_embedded_v1_instance_create (lib, params.yaml_config,
status);
client = mongoc_embedded_v1_client_create (instance);
collection = mongoc_client_get_collection (client, "iot_test", "sensor_data");
insert = bson_new ();
BSON_APPEND_UTF8 (insert, "message", "Hey there!");
BSON_APPEND_UTF8 (insert, "from", "Matt Lord);
mongoc_collection_insert_one (collection, insert, NULL, NULL, &error);
query = bson_new ();
cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);
while (mongoc_cursor_next(cursor, &doc)) {
str = bson_as_canonical_extended_json (doc, NULL);
printf ("%sn", str);
bson_free (str);
}
Mobile Database
Lite version of MongoDB formed into a library
• C ABI
• Auth, Replication, Sharding, etc. removed
• Supports only the mobile storage engine
• Passive: no background threads
• Light: disk, memory, energy
C Interface
• Low level
• Drivers are extended to invoke it
Availability
• Builds out of MongoDB 4.0+ community tree
• Pre-built binary packages for mobile targets
* Complete example
The Mobile Drivers
Mobile Drivers
Existing drivers for the given language
• With a few extensions
• Open a local storage instance
• Close a local storage instance
• Support today for Swift, Java, and C
• Others created based on demand
Can be tested directly
• Swift: https://github.com/mongodb/swift-mongo-mobile/
• Java:
http://central.maven.org/maven2/org/mongodb/mongodb-
driver-embedded/
import MongoMobile
…
let client = MongoMobile.create(settings: MongoClientSettings [ dbPath: "test-
path" ])
let coll = try client.db("test").collection("foo")
let insertResult = try coll.insertOne([ "test": 42 ])
let findResult = try coll.find([ "_id": insertResult!.insertedId ])
let docs = Array(findResult)
…
* Complete example
Stitch
Stitch: What is it?
• Provide an interface for users to interact
with your app.
• Handle user actions and send requests to
the app server.
• Authenticate users and allow them to use
app features.
• Handle data requests and execute
business logic.
• Store and search persisted application
data.
• Manage data integrity, consistency, and
availability.
Stitch SDK
Packages the entire mobile stack together
Stitches the frontend and backend together
• End-to-end Mobile SDK
• API for local storage
• API for remote Stitch service invocation
• API for syncing between local and remote
• Provides a transparent bridge for applications
iOS SDK: https://github.com/mongodb/stitch-ios-sdk/
Android SDK: https://github.com/mongodb/stitch-android-sdk/
final StitchAppClient client = Stitch.getDefaultAppClient();
final MongoClient mongoClient = client.getServiceClient(LocalMongoDbService.ClientFactory);
MongoCollection<Document> items =
mongoClient.getDatabase(TodoItem.TODO_LIST_DATABASE).getCollection(TodoItem.TODO_LIST_COLLE
CTION);
public void updateChecked(final ObjectId itemId, final boolean isChecked) {
final Document updateDoc = new Document("$set", new Document(TodoItem.CHECKED_KEY, isChecked));
if (isChecked) {
updateDoc.append("$currentDate", new Document(TodoItem.DONE_DATE_KEY, true));
} else {
updateDoc.append("$unset", new Document(TodoItem.DONE_DATE_KEY, ""));
}
items.updateOne(new Document(TodoItem.ID_KEY, itemId), updateDoc);
...
}
private List<TodoItem> getItems() {
final ArrayList<TodoItem> todoItems = new ArrayList<>();
for (final Document doc : items.find()) {
if (TodoItem.isTodoItem(doc)) {
final TodoItem item = new TodoItem(doc);
todoItems.add(item);
}
}
return todoItems;
}
Stitch
Let’s build a chat app
User Authentication
Built-In Identity Providers
• Anonymous
• Email / Password
• OAuth 2.0 (Facebook & Google)
• API Key (Server & User)
• Custom (Bring Your Own Auth)
Application Users
• Associated with one or more identities
• Must authenticate to send requests
• Trigger authentication events
Custom User
data class User @BsonCreator constructor(
// The Stitch ID of the user
@BsonId val id: String,
// The username the user has chosen
@BsonProperty("name") val name: String,
// The default avatar that the user is assigned upon registration
@BsonProperty("defaultAvatarOrdinal") val defaultAvatarOrdinal: Int,
// The avatar the user has uploaded
@BsonProperty("avatar") val avatar: ByteArray?,
// The list of channels this user is subscribed to
@BsonProperty("channelsSubscribedTo") val channelsSubscribedTo: List<String>
)
Server-Side Rules
Declarative Expressions
• Specify rule conditions with a document
• Access specific request/document values.
Dynamic Evaluation
• Add complex and/or personalized rules with
expansions and operators.
Secure by Default
• If an action does not pass any rule, Stitch
prevents the action
Login Activity
class LoginActivity : ScopeActivity() {
private val usernameEditText by lazy {
findViewById<EditText>(R.id.username_edit_text)
}
private val loginButton by lazy {
findViewById<Button>(R.id.login_button)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
loginButton.setOnClickListener(::onLoginButtonClicked)
}
}
::onLoginButonClicked
if (usernameEditText.text.length < 3
|| usernameEditText.text.isEmpty()) {
return@launch
}
val stitchUser = Tasks.await(
stitch.auth.loginWithCredential(AnonymousCredential()))
Tasks.await(
usersCollection.sync().insertOne(
User(id = stitchUser.id,
name = usernameEditText.text.toString(),
defaultAvatarOrdinal = Random().nextInt(7),
channelsSubscribedTo = listOf("default"))))
startActivity(Intent(this@LoginActivity, ChannelActivity::class.java))
Channel
/**
* A channel for chatting to other [User]s. Channels act as an anchor for our
domain.
*
* @param id the human readable name of the channel that acts as the [BsonId]
* @param topic the topic or purpose of this channel
*/
data class Channel @BsonCreator constructor(
@BsonId val id: String,
@BsonProperty("topic") val topic: String)
ChannelSubscription
data class ChannelSubscription @BsonCreator constructor(
// The unique ID of this subscription
@BsonId val id: ObjectId,
// The ID of the channel associated with this subscription
@BsonProperty("channelId") val channelId: String,
// the user ID of the owner of this subscription
@BsonProperty("ownerId") val ownerId: String,
// the device ID of the owner of this subscription
@BsonProperty("deviceId") val deviceId: String,
// the local logical timestamp
@BsonProperty("localTimestamp") val localTimestamp: Long,
// the last recorded remote logical timestamp
@BsonProperty("remoteTimestamp") val remoteTimestamp: Long)
ChannelMessage
data class ChannelMessage @BsonCreator constructor(
@BsonId val id: ObjectId,
@BsonProperty("ownerId") val ownerId: String,
@BsonProperty("channelId") val channelId: String,
@BsonProperty("content") val content: String,
@BsonProperty("sentAt") val sentAt: Long,
@BsonProperty("remoteTimestamp") val remoteTimestamp: Long? = null)
Channel Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupToolbar()
}
Channel Fragment
class ChannelFragment : Fragment(), CoroutineScope {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
sendButton.setOnClickListener(::sendMessage)
sendButton.isEnabled = false
launch(IO) {
configureCollections()
initializeMessageCursor()
}
}
::configureCollections
channelMessageCollection.sync().configure(
SyncConfiguration.Builder()
.withChangeEventListener(channelMessageObserver)
.withConflictHandler(channelMessageObserver)
.build())
::configureCollections
channelSubscriptionCollection.sync().configure(
SyncConfiguration.Builder()
.withChangeEventListener(channelSubscriptionListener)
.withConflictHandler(channelSubscriptionListener)
.build())
::configureCollections
usersCollection.sync().configure(
SyncConfiguration.Builder()
.withChangeEventListener(userObserver)
.withConflictHandler(userObserver)
.build())
::configureCollections
channelMembersCollection.sync().configure(
SyncConfiguration.Builder()
.withChangeEventListener(channelMembersObserver)
.withConflictHandler(channelMembersObserver)
.build())
channelMembersCollection.sync()
.syncOne(BsonString("default"))
ChannelMembersObserver
class ChannelMembersObserver :
ConflictHandler<ChannelMembers>, ChangeEventListener<ChannelMembers>
::resolveConflict
override fun resolveConflict(documentId: BsonValue,
localEvent: ChangeEvent<ChannelMembers>,
remoteEvent: ChangeEvent<ChannelMembers>): ChannelMembers? {
if (remoteEvent.operationType == OperationType.DELETE) {
return null
}
val localChannelMembers = localEvent.fullDocument!!
val remoteChannelMembers = remoteEvent.fullDocument!!
return ChannelMembers(
remoteChannelMembers.id,
remoteChannelMembers.members.union(localChannelMembers.members).toList())
}
::onEvent
override fun onEvent(documentId: BsonValue,
event: ChangeEvent<ChannelMembers>) {
if (event.fullDocument == null) {
return
}
usersCollection.sync()
.syncMany(*event.fullDocument!!.members.map {
BsonString(it)
}.toTypedArray())
}
ChannelMessageObserver
class ChannelMessageObserver :
ChangeEventListener<ChannelMessage>,
ConflictHandler<ChannelMessage> by DefaultSyncConflictResolvers.remoteWins(),
LiveData<ChangeEvent<ChannelMessage>>() {
override fun onEvent(documentId: BsonValue, event: ChangeEvent<ChannelMessage>) {
value = event
}
}
UserObserver
class UserObserver :
ChangeEventListener<User>,
ConflictHandler<User> by DefaultSyncConflictResolvers.remoteWins(),
LiveData<ChangeEvent<User>>() {
override fun onEvent(documentId: BsonValue, event: ChangeEvent<User>) {
value = event
}
}
ChannelSubscriptionObserver
class ChannelSubscriptionObserver :
ConflictHandler<ChannelSubscription>,
ChangeEventListener<ChannelSubscription>,
LiveData<ChangeEvent<ChannelSubscription>>()
::resolveConflict
if (remoteEvent.operationType == OperationType.DELETE) {
return null
}
if (remoteEvent.operationType != OperationType.UPDATE || localEvent.operationType != OperationType.UPDATE) {
return remoteEvent.fullDocument
}
val remoteTimestamp = remoteEvent.updateDescription!!
.updatedFields[ChannelSubscription.KEY_REMOTE_TIMESTAMP]!! as BsonInt64
val channelId = localEvent.fullDocument!!.channelId
return ChannelSubscription(id = documentId.asObjectId().value, channelId = channelId,
ownerId = stitch.auth.user!!.id, deviceId = stitch.auth.user!!.deviceId,
localTimestamp = remoteTimestamp.value, remoteTimestamp = remoteTimestamp.value)
::onEvent
val subscription = event.fullDocument
if (event.hasUncommittedWrites()
|| event.operationType != OperationType.REPLACE
|| subscription == null
|| subscription.localTimestamp == subscription.remoteTimestamp) {
return
}
GlobalScope.launch { updateLocalVector(documentId, subscription) }
value = event
::updateLocalVector
val latestMessageIds = Tasks.await(
channelMessageCollection.withDocumentClass(Document::class.java).find(Document(mapOf(
"channelId" to subscription.channelId,
"remoteTimestamp" to mapOf(
"$gt" to subscription.localTimestamp,
"$lte" to subscription.remoteTimestamp
)
)))
.projection(Document(mapOf("_id" to true)))
.map { BsonObjectId(it["_id"] as ObjectId) }
.into(mutableListOf<BsonObjectId>())).toTypedArray()
::updateLocalVector
Tasks.await(channelMessageCollection.sync().syncMany(*latestMessageIds))
Tasks.await(channelSubscriptionCollection.sync().updateOne(
Document(mapOf("_id" to documentId)),
Document(mapOf("$set" to mapOf(
"localTimestamp" to subscription.localTimestamp)))
))
::initializeMessageCursor
if (Tasks.await(channelSubscriptionCollection.sync().find().first())
== null) {
subscribeToChannel()
} else {
adapter.cursor = LruMessageCursor(
channelId = "default",
count = Tasks.await(
channelMessageCollection.sync().count(
Document("channelId", "default")
)).toInt())
}
Functions & Triggers
exports = function(changeEvent) {
// Parse values from the insert change event
// changeEvent.operationType === "INSERT"
const insertedDoc = changeEvent.fullDocument
const { _id, name } = insertedDoc;
// Instantiate a MongoDB service client
const cluster = context.services.get("myCluster");
const myDb = cluster.db("myDb");
const myColl = myDb.collection("myColl");
myColl.updateOne({ _id }, {
"$set": { "someField": "$set" }
})
}
Invoke Serverless Functions
• Written in JavaScript (ES6+)
• Execute dynamically based on context
• Run as a specific application user
• Connect to your application components
• Callable from an SDK or another Function
Trigger Functions on Events
• React to changes in a MongoDB collection
• Execute logic when users are created or log in
• Schedule functions with CRON expressions
functions > subscribeToChannel
var mongo = context.services.get("mongodb-atlas");
var channelMembersCollection = mongo.db("chats").collection("channel_members");
var channelSubscriptionsCollection =
mongo.db("chats").collection("channel_subscriptions");
await channelMembersCollection.updateOne({ "_id" : channelId },
{ "$push": { "members" : userId },
"$set": {
"__stitch_sync_version" : {
"spv" : BSON.Int32(1), "id" : “0", "v" : BSON.Long(1) }}},
{ upsert: true });
functions > subscribeToChannel
var otherSubscription = await channelSubscriptionsCollection.findOne({
"channelId" : channelId
})
var insertOneResult = await channelSubscriptionsCollection.insertOne({
"ownerId" : userId, "deviceId": deviceId, "channelId" : channelId,
"localTimestamp" : 0,
"remoteTimestamp": otherSubscription ? otherSubscription .remoteTimestamp : 0 }
);
return insertOneResult.insertedId;
::subscribeToChannel
val subscriptionId = Tasks.await(
stitch.callFunction(
"subscribeToChannel",
listOf(stitch.auth.user!!.id,
stitch.auth.user!!.deviceId,
"default"),
BsonObjectId::class.java))
channelSubscriptionCollection.sync().syncOne(subscriptionId)
::subscribeToChannel
channelMessageObserver.observe(
this@ChannelFragment, object : Observer<ChangeEvent<ChannelMessage>> {
override fun onChanged(changeEvent: ChangeEvent<ChannelMessage>?) {
if (changeEvent == null) return
val subscription = Tasks.await(channelSubscriptionCollection.sync().find().first())
if (changeEvent.fullDocument?.remoteTimestamp == subscription.remoteTimestamp) {
adapter.cursor = LruMessageCursor(channelId = "default", count = Tasks.await(
channelMessageCollection.sync().count()).toInt())
launch(Main) {
channelMessageObserver.removeObserver(this)
}
}
}
})
::sendMessage
val messageEditText = v.rootView
.findViewById<EditText>(R.id.message_edit_text)
val channelMessage = ChannelMessage(
id = ObjectId(),
ownerId = stitch.auth.user!!.id,
channelId = "default",
content = messageEditText.text.toString(),
sentAt = System.currentTimeMillis())
::sendMessage
channelMessageCollection.sync()
.insertOne(channelMessage)
::sendMessage
channelMessageObserver.observe(
this, object : Observer<ChangeEvent<ChannelMessage>> {
override fun onChanged(changeEvent: ChangeEvent<ChannelMessage>?) {
if (changeEvent == null
|| changeEvent.documentKey["_id"] !=
BsonObjectId(channelMessage.id)
|| changeEvent.fullDocument == null) {
return
}
adapter.stackOnEnd(changeEvent.fullDocument!!)
channelMessageObserver.removeObserver(this)
}
})
triggers > channelMessageHasInserted
triggers > channelMessageHasInserted
var messageId = changeEvent.documentKey._id;
var channelId = changeEvent.fullDocument.channelId;
var messagesCollection = context.services
.get("mongodb-atlas").db("chats").collection("messages");
var subscriptionsCollection = context.services
.get("mongodb-atlas")
.db("chats").collection("channel_subscriptions");
triggers > channelMessageHasInserted
await subscriptionsCollection.updateMany(
{ "channelId" : channelId },
{ "$inc": { "remoteTimestamp" : 1 }});
await messagesCollection.updateOne(
{ "_id" : messageId },
{ "$set":
{
"sentAt" : Date.now(),
"remoteTimestamp": (await subscriptionsCollection.findOne(
{ "channelId" : channelId })).remoteTimestamp
}
});
MessageAdapter
class MessageAdapter(private val activity: FragmentActivity) :
MongoCursorAdapter<MessageViewHolder, ChannelMessage>() {
override suspend fun onBindViewHolder(
viewHolder: MessageViewHolder,
item: ChannelMessage) {
viewHolder.itemView.visibility = INVISIBLE
launch(Main) {
viewHolder.setMessage(item)
}.join()
}
}
The power of observation
sealed class MessageViewHolder(activity: FragmentActivity, itemView: View) :
RecyclerView.ViewHolder(itemView) {
private val observer = Observer { changeEvent: ChangeEvent<ChannelMessage>? ->
if (changeEvent == null ||
changeEvent.fullDocument == null ||
changeEvent.fullDocument?.id != message?.id) {
return@Observer
}
this.setMessage(changeEvent.fullDocument!!)
}
init {
channelMessageObserver.observe(activity, observer)
}
The power of observation
open fun setMessage(message: ChannelMessage) {
this.message = message
content.text = message.content
if (message.remoteTimestamp != null) {
content.setTextColor(
itemView.resources.getColor(android.R.color.black, null))
} else {
content.setTextColor(
itemView.resources.getColor(android.R.color.darker_gray, null))
}
itemView.visibility = VISIBLE
}
The power of observation
The power of observation
class FullMessageViewHolder(private val activity: FragmentActivity, itemView: View) :
MessageViewHolder(activity, itemView) {
private val observer = Observer { changeEvent: ChangeEvent<User>? ->
if (changeEvent == null || changeEvent.fullDocument?.id != currentMessage?.ownerId) {
return@Observer
}
this.setUser(changeEvent.fullDocument!!)
}
init {
userObserver.observe(activity, observer)
}
The power of observation
@MainThread
private fun setUser(user: User?) {
if (user == null) return
if (user.avatar != null) {
avatar.setImageBitmap(user.bitmapAvatar())
} else {
avatar.setImageResource(defaultAvatars[user.defaultAvatarOrdinal])
}
username.text = user.name
}
The power of observation
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
usersCollection.sync().updateOne(Document(mapOf("_id" to stitch.auth.user!!.id)),
Document(
mapOf("$set" to mapOf("avatar" to File(
ImagePicker
.getImagePathFromResult(
this@ChannelActivity,
requestCode,
resultCode,
data))
.readBytes()))))
}
The power of observation
Licensing,
Pricing, and
Support
What’s Next
Thank You!
Ad

More Related Content

Similar to MongoDB Mobile (20)

MongoDB Mobile: Bringing the Power of MongoDB to Your Device
MongoDB Mobile: Bringing the Power of MongoDB to Your DeviceMongoDB Mobile: Bringing the Power of MongoDB to Your Device
MongoDB Mobile: Bringing the Power of MongoDB to Your Device
MongoDB
 
MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...
MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...
MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...
MongoDB
 
MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...
MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...
MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...
MongoDB
 
We don’t need no stinkin app server! Building a Two-Tier Mobile App
We don’t need no stinkin app server! Building a Two-Tier Mobile AppWe don’t need no stinkin app server! Building a Two-Tier Mobile App
We don’t need no stinkin app server! Building a Two-Tier Mobile App
Pat Patterson
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB
 
Building Your First App with MongoDB Stitch
Building Your First App with MongoDB StitchBuilding Your First App with MongoDB Stitch
Building Your First App with MongoDB Stitch
MongoDB
 
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB StitchMongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB
 
Building serverless apps with Go & SAM
Building serverless apps with Go & SAMBuilding serverless apps with Go & SAM
Building serverless apps with Go & SAM
Leon Stigter
 
MongoDB.local Austin 2018: Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...
MongoDB.local Austin 2018:  Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...MongoDB.local Austin 2018:  Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...
MongoDB.local Austin 2018: Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...
MongoDB
 
Faites évoluer votre accès aux données avec MongoDB Stitch
Faites évoluer votre accès aux données avec MongoDB StitchFaites évoluer votre accès aux données avec MongoDB Stitch
Faites évoluer votre accès aux données avec MongoDB Stitch
MongoDB
 
Evolving your Data Access with MongoDB Stitch - Drew Di Palma
Evolving your Data Access with MongoDB Stitch - Drew Di PalmaEvolving your Data Access with MongoDB Stitch - Drew Di Palma
Evolving your Data Access with MongoDB Stitch - Drew Di Palma
MongoDB
 
Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...
Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...
Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...
MongoDB
 
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB AtlasMongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB
 
Developing Offline-Capable Apps with the Salesforce Mobile SDK and SmartStore
Developing Offline-Capable Apps with the Salesforce Mobile SDK and SmartStoreDeveloping Offline-Capable Apps with the Salesforce Mobile SDK and SmartStore
Developing Offline-Capable Apps with the Salesforce Mobile SDK and SmartStore
Salesforce Developers
 
Sukumar Nayak-Agile-DevOps-Cloud Management
Sukumar Nayak-Agile-DevOps-Cloud ManagementSukumar Nayak-Agile-DevOps-Cloud Management
Sukumar Nayak-Agile-DevOps-Cloud Management
Sukumar Nayak
 
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDBMongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB
 
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Danny Preussler
 
Creating HTML5 Applications with jQuery Mobile, Ruby and Database.com
Creating HTML5 Applications with jQuery Mobile, Ruby and Database.comCreating HTML5 Applications with jQuery Mobile, Ruby and Database.com
Creating HTML5 Applications with jQuery Mobile, Ruby and Database.com
Jeff Douglas
 
Tutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB StitchTutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB Stitch
MongoDB
 
JAM805 - Beyond the Device
JAM805 -  Beyond the DeviceJAM805 -  Beyond the Device
JAM805 - Beyond the Device
Dr. Ranbijay Kumar
 
MongoDB Mobile: Bringing the Power of MongoDB to Your Device
MongoDB Mobile: Bringing the Power of MongoDB to Your DeviceMongoDB Mobile: Bringing the Power of MongoDB to Your Device
MongoDB Mobile: Bringing the Power of MongoDB to Your Device
MongoDB
 
MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...
MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...
MongoDB.local Sydney 2019: MongoDB Mobile: Bringing the Power of MongoDB to Y...
MongoDB
 
MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...
MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...
MongoDB.local Seattle 2019: MongoDB Mobile: Bringing the Power of MongoDB to ...
MongoDB
 
We don’t need no stinkin app server! Building a Two-Tier Mobile App
We don’t need no stinkin app server! Building a Two-Tier Mobile AppWe don’t need no stinkin app server! Building a Two-Tier Mobile App
We don’t need no stinkin app server! Building a Two-Tier Mobile App
Pat Patterson
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB
 
Building Your First App with MongoDB Stitch
Building Your First App with MongoDB StitchBuilding Your First App with MongoDB Stitch
Building Your First App with MongoDB Stitch
MongoDB
 
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB StitchMongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB
 
Building serverless apps with Go & SAM
Building serverless apps with Go & SAMBuilding serverless apps with Go & SAM
Building serverless apps with Go & SAM
Leon Stigter
 
MongoDB.local Austin 2018: Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...
MongoDB.local Austin 2018:  Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...MongoDB.local Austin 2018:  Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...
MongoDB.local Austin 2018: Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch A...
MongoDB
 
Faites évoluer votre accès aux données avec MongoDB Stitch
Faites évoluer votre accès aux données avec MongoDB StitchFaites évoluer votre accès aux données avec MongoDB Stitch
Faites évoluer votre accès aux données avec MongoDB Stitch
MongoDB
 
Evolving your Data Access with MongoDB Stitch - Drew Di Palma
Evolving your Data Access with MongoDB Stitch - Drew Di PalmaEvolving your Data Access with MongoDB Stitch - Drew Di Palma
Evolving your Data Access with MongoDB Stitch - Drew Di Palma
MongoDB
 
Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...
Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...
Ch-Ch-Ch-Ch-Changes: Taking Your MongoDB Stitch Application to the Next Level...
MongoDB
 
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB AtlasMongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB
 
Developing Offline-Capable Apps with the Salesforce Mobile SDK and SmartStore
Developing Offline-Capable Apps with the Salesforce Mobile SDK and SmartStoreDeveloping Offline-Capable Apps with the Salesforce Mobile SDK and SmartStore
Developing Offline-Capable Apps with the Salesforce Mobile SDK and SmartStore
Salesforce Developers
 
Sukumar Nayak-Agile-DevOps-Cloud Management
Sukumar Nayak-Agile-DevOps-Cloud ManagementSukumar Nayak-Agile-DevOps-Cloud Management
Sukumar Nayak-Agile-DevOps-Cloud Management
Sukumar Nayak
 
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDBMongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB
 
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Danny Preussler
 
Creating HTML5 Applications with jQuery Mobile, Ruby and Database.com
Creating HTML5 Applications with jQuery Mobile, Ruby and Database.comCreating HTML5 Applications with jQuery Mobile, Ruby and Database.com
Creating HTML5 Applications with jQuery Mobile, Ruby and Database.com
Jeff Douglas
 
Tutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB StitchTutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB Stitch
MongoDB
 

More from MongoDB (20)

MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB
 
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB
 
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDBMongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB
 
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB
 
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series DataMongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB
 
MongoDB SoCal 2020: MongoDB Atlas Jump Start
 MongoDB SoCal 2020: MongoDB Atlas Jump Start MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB
 
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB
 
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB
 
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB
 
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB
 
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your MindsetMongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB
 
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas JumpstartMongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB
 
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB
 
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB
 
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB
 
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep DiveMongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB
 
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & GolangMongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB
 
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB
 
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB
 
MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...
MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...
MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...
MongoDB
 
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB
 
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB
 
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDBMongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB
 
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB
 
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series DataMongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB
 
MongoDB SoCal 2020: MongoDB Atlas Jump Start
 MongoDB SoCal 2020: MongoDB Atlas Jump Start MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB
 
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB
 
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB
 
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB
 
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB
 
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your MindsetMongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB
 
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas JumpstartMongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB
 
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB
 
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB
 
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB
 
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep DiveMongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB
 
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & GolangMongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB
 
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB
 
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB
 
MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...
MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...
MongoDB .local Paris 2020: Tout savoir sur le moteur de recherche Full Text S...
MongoDB
 
Ad

Recently uploaded (20)

TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul
 
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-UmgebungenHCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
panagenda
 
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Aqusag Technologies
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdfComplete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Software Company
 
2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx
Samuele Fogagnolo
 
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdfThe Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
Abi john
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
Quantum Computing Quick Research Guide by Arthur Morgan
Quantum Computing Quick Research Guide by Arthur MorganQuantum Computing Quick Research Guide by Arthur Morgan
Quantum Computing Quick Research Guide by Arthur Morgan
Arthur Morgan
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul
 
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-UmgebungenHCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
panagenda
 
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Aqusag Technologies
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdfComplete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Software Company
 
2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx
Samuele Fogagnolo
 
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdfThe Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
Abi john
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
Quantum Computing Quick Research Guide by Arthur Morgan
Quantum Computing Quick Research Guide by Arthur MorganQuantum Computing Quick Research Guide by Arthur Morgan
Quantum Computing Quick Research Guide by Arthur Morgan
Arthur Morgan
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
Ad

MongoDB Mobile

  • 1. MongoDB Mobile Bringing the Power of MongoDB to Your Device
  • 2. This presentation contains “forward-looking statements” within the meaning of Section 27A of the Securities Act of 1933, as amended, and Section 21E of the Securities Exchange Act of 1934, as amended. Such forward-looking statements are subject to a number of risks, uncertainties, assumptions and other factors that could cause actual results and the timing of certain events to differ materially from future results expressed or implied by the forward-looking statements. Factors that could cause or contribute to such differences include, but are not limited to, those identified our filings with the Securities and Exchange Commission. You should not rely upon forward-looking statements as predictions of future events. Furthermore, such forward-looking statements speak only as of the date of this presentation. In particular, the development, release, and timing of any features or functionality described for MongoDB products remains at MongoDB’s sole discretion. This information is merely intended to outline our general product direction and it should not be relied on in making a purchasing decision nor is this a commitment, promise or legal obligation to deliver any material, code, or functionality. Except as required by law, we undertake no obligation to update any forward-looking statements to reflect events or circumstances after the date of such statements. Safe Harbor Statement
  • 4. We've Come a Long Way
  • 5. You'd be surprised how difficult it is to relinquish a cell phone. Adrien Brody Mobile Is Transforming Everything
  • 6. I actually have this fantasy of giving up my cell phone. Julia Stiles Mobile Is Transforming Everything
  • 7. My cell phone is my best friend. It's my lifeline to the outside world. Carrie Underwood Mobile Is Transforming Everything
  • 8. Technology can be our best friend, and technology can also be the biggest party pooper of our lives. Stephen Spielberg Mobile Is Transforming Everything
  • 9. The most important impact on society and the world is the cell phone. Cell phones have actually been one of the primary drivers in productivity improvements. Fabrice Grinda Mobile Is Transforming Everything
  • 10. I have a cell phone that doesn't behave like a phone: It behaves like a computer that makes calls. Computers are becoming an integral part of daily life. And if people don't start designing them to be more user-friendly, then an even larger part of the population is going to be left out of even more stuff. Alan Cooper Mobile Is Transforming Everything
  • 11. A Complete Data Platform Geographically distributed backend services • MongoDB Atlas • Point and click active/active global clusters • Effortless High Availability, Disaster Recovery, and low- latency access • MongoDB Stitch, Serverless Platform • Automatic scaling based on request volume • Stitch Query Anywhere • Stitch Functions • Stitch Triggers • Stitch Mobile Sync (Beta) Geographically distributed frontend services • MongoDB Mobile • IoT and edge devices • iOS and Android apps • Supporting local offline storage Stitch provides a seamless bridge between them
  • 13. The Full Stack Your Mobile Application • iOS and Android devices • Leveraging the power of MongoDB everywhere • Allowing you to focus on building your GREAT THING™ MongoDB Stitch SDK • Access to MongoDB and Cloud services from Android and iOS • New Stitch interfaces for on-device (local) storage • Bi-directional synchronization between local and remote MongoDB Mobile Drivers • Swift for iOS, Java for Android • Existing drivers, extended to support local storage MongoDB Mobile Database • A lite version of MongoDB as a library • C language interface to the library • Fully passive, no background threads or tasks MongoDB Mobile Storage Engine • K/V storage on top of SQLite • Very small disk footprint and minimal memory usage • Energy efficient
  • 14. The Mobile Database lib = mongo_embedded_v1_lib_init (&params, status); instance = mongo_embedded_v1_instance_create (lib, params.yaml_config, status); client = mongoc_embedded_v1_client_create (instance); collection = mongoc_client_get_collection (client, "iot_test", "sensor_data"); insert = bson_new (); BSON_APPEND_UTF8 (insert, "message", "Hey there!"); BSON_APPEND_UTF8 (insert, "from", "Matt Lord); mongoc_collection_insert_one (collection, insert, NULL, NULL, &error); query = bson_new (); cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL); while (mongoc_cursor_next(cursor, &doc)) { str = bson_as_canonical_extended_json (doc, NULL); printf ("%sn", str); bson_free (str); } Mobile Database Lite version of MongoDB formed into a library • C ABI • Auth, Replication, Sharding, etc. removed • Supports only the mobile storage engine • Passive: no background threads • Light: disk, memory, energy C Interface • Low level • Drivers are extended to invoke it Availability • Builds out of MongoDB 4.0+ community tree • Pre-built binary packages for mobile targets * Complete example
  • 15. The Mobile Drivers Mobile Drivers Existing drivers for the given language • With a few extensions • Open a local storage instance • Close a local storage instance • Support today for Swift, Java, and C • Others created based on demand Can be tested directly • Swift: https://github.com/mongodb/swift-mongo-mobile/ • Java: http://central.maven.org/maven2/org/mongodb/mongodb- driver-embedded/ import MongoMobile … let client = MongoMobile.create(settings: MongoClientSettings [ dbPath: "test- path" ]) let coll = try client.db("test").collection("foo") let insertResult = try coll.insertOne([ "test": 42 ]) let findResult = try coll.find([ "_id": insertResult!.insertedId ]) let docs = Array(findResult) … * Complete example
  • 17. Stitch: What is it? • Provide an interface for users to interact with your app. • Handle user actions and send requests to the app server. • Authenticate users and allow them to use app features. • Handle data requests and execute business logic. • Store and search persisted application data. • Manage data integrity, consistency, and availability.
  • 18. Stitch SDK Packages the entire mobile stack together Stitches the frontend and backend together • End-to-end Mobile SDK • API for local storage • API for remote Stitch service invocation • API for syncing between local and remote • Provides a transparent bridge for applications iOS SDK: https://github.com/mongodb/stitch-ios-sdk/ Android SDK: https://github.com/mongodb/stitch-android-sdk/ final StitchAppClient client = Stitch.getDefaultAppClient(); final MongoClient mongoClient = client.getServiceClient(LocalMongoDbService.ClientFactory); MongoCollection<Document> items = mongoClient.getDatabase(TodoItem.TODO_LIST_DATABASE).getCollection(TodoItem.TODO_LIST_COLLE CTION); public void updateChecked(final ObjectId itemId, final boolean isChecked) { final Document updateDoc = new Document("$set", new Document(TodoItem.CHECKED_KEY, isChecked)); if (isChecked) { updateDoc.append("$currentDate", new Document(TodoItem.DONE_DATE_KEY, true)); } else { updateDoc.append("$unset", new Document(TodoItem.DONE_DATE_KEY, "")); } items.updateOne(new Document(TodoItem.ID_KEY, itemId), updateDoc); ... } private List<TodoItem> getItems() { final ArrayList<TodoItem> todoItems = new ArrayList<>(); for (final Document doc : items.find()) { if (TodoItem.isTodoItem(doc)) { final TodoItem item = new TodoItem(doc); todoItems.add(item); } } return todoItems; } Stitch
  • 19. Let’s build a chat app
  • 20. User Authentication Built-In Identity Providers • Anonymous • Email / Password • OAuth 2.0 (Facebook & Google) • API Key (Server & User) • Custom (Bring Your Own Auth) Application Users • Associated with one or more identities • Must authenticate to send requests • Trigger authentication events
  • 21. Custom User data class User @BsonCreator constructor( // The Stitch ID of the user @BsonId val id: String, // The username the user has chosen @BsonProperty("name") val name: String, // The default avatar that the user is assigned upon registration @BsonProperty("defaultAvatarOrdinal") val defaultAvatarOrdinal: Int, // The avatar the user has uploaded @BsonProperty("avatar") val avatar: ByteArray?, // The list of channels this user is subscribed to @BsonProperty("channelsSubscribedTo") val channelsSubscribedTo: List<String> )
  • 22. Server-Side Rules Declarative Expressions • Specify rule conditions with a document • Access specific request/document values. Dynamic Evaluation • Add complex and/or personalized rules with expansions and operators. Secure by Default • If an action does not pass any rule, Stitch prevents the action
  • 23. Login Activity class LoginActivity : ScopeActivity() { private val usernameEditText by lazy { findViewById<EditText>(R.id.username_edit_text) } private val loginButton by lazy { findViewById<Button>(R.id.login_button) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) loginButton.setOnClickListener(::onLoginButtonClicked) } }
  • 24. ::onLoginButonClicked if (usernameEditText.text.length < 3 || usernameEditText.text.isEmpty()) { return@launch } val stitchUser = Tasks.await( stitch.auth.loginWithCredential(AnonymousCredential())) Tasks.await( usersCollection.sync().insertOne( User(id = stitchUser.id, name = usernameEditText.text.toString(), defaultAvatarOrdinal = Random().nextInt(7), channelsSubscribedTo = listOf("default")))) startActivity(Intent(this@LoginActivity, ChannelActivity::class.java))
  • 25. Channel /** * A channel for chatting to other [User]s. Channels act as an anchor for our domain. * * @param id the human readable name of the channel that acts as the [BsonId] * @param topic the topic or purpose of this channel */ data class Channel @BsonCreator constructor( @BsonId val id: String, @BsonProperty("topic") val topic: String)
  • 26. ChannelSubscription data class ChannelSubscription @BsonCreator constructor( // The unique ID of this subscription @BsonId val id: ObjectId, // The ID of the channel associated with this subscription @BsonProperty("channelId") val channelId: String, // the user ID of the owner of this subscription @BsonProperty("ownerId") val ownerId: String, // the device ID of the owner of this subscription @BsonProperty("deviceId") val deviceId: String, // the local logical timestamp @BsonProperty("localTimestamp") val localTimestamp: Long, // the last recorded remote logical timestamp @BsonProperty("remoteTimestamp") val remoteTimestamp: Long)
  • 27. ChannelMessage data class ChannelMessage @BsonCreator constructor( @BsonId val id: ObjectId, @BsonProperty("ownerId") val ownerId: String, @BsonProperty("channelId") val channelId: String, @BsonProperty("content") val content: String, @BsonProperty("sentAt") val sentAt: Long, @BsonProperty("remoteTimestamp") val remoteTimestamp: Long? = null)
  • 28. Channel Activity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setupToolbar() }
  • 29. Channel Fragment class ChannelFragment : Fragment(), CoroutineScope { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupRecyclerView() sendButton.setOnClickListener(::sendMessage) sendButton.isEnabled = false launch(IO) { configureCollections() initializeMessageCursor() } }
  • 35. ::resolveConflict override fun resolveConflict(documentId: BsonValue, localEvent: ChangeEvent<ChannelMembers>, remoteEvent: ChangeEvent<ChannelMembers>): ChannelMembers? { if (remoteEvent.operationType == OperationType.DELETE) { return null } val localChannelMembers = localEvent.fullDocument!! val remoteChannelMembers = remoteEvent.fullDocument!! return ChannelMembers( remoteChannelMembers.id, remoteChannelMembers.members.union(localChannelMembers.members).toList()) }
  • 36. ::onEvent override fun onEvent(documentId: BsonValue, event: ChangeEvent<ChannelMembers>) { if (event.fullDocument == null) { return } usersCollection.sync() .syncMany(*event.fullDocument!!.members.map { BsonString(it) }.toTypedArray()) }
  • 37. ChannelMessageObserver class ChannelMessageObserver : ChangeEventListener<ChannelMessage>, ConflictHandler<ChannelMessage> by DefaultSyncConflictResolvers.remoteWins(), LiveData<ChangeEvent<ChannelMessage>>() { override fun onEvent(documentId: BsonValue, event: ChangeEvent<ChannelMessage>) { value = event } }
  • 38. UserObserver class UserObserver : ChangeEventListener<User>, ConflictHandler<User> by DefaultSyncConflictResolvers.remoteWins(), LiveData<ChangeEvent<User>>() { override fun onEvent(documentId: BsonValue, event: ChangeEvent<User>) { value = event } }
  • 40. ::resolveConflict if (remoteEvent.operationType == OperationType.DELETE) { return null } if (remoteEvent.operationType != OperationType.UPDATE || localEvent.operationType != OperationType.UPDATE) { return remoteEvent.fullDocument } val remoteTimestamp = remoteEvent.updateDescription!! .updatedFields[ChannelSubscription.KEY_REMOTE_TIMESTAMP]!! as BsonInt64 val channelId = localEvent.fullDocument!!.channelId return ChannelSubscription(id = documentId.asObjectId().value, channelId = channelId, ownerId = stitch.auth.user!!.id, deviceId = stitch.auth.user!!.deviceId, localTimestamp = remoteTimestamp.value, remoteTimestamp = remoteTimestamp.value)
  • 41. ::onEvent val subscription = event.fullDocument if (event.hasUncommittedWrites() || event.operationType != OperationType.REPLACE || subscription == null || subscription.localTimestamp == subscription.remoteTimestamp) { return } GlobalScope.launch { updateLocalVector(documentId, subscription) } value = event
  • 42. ::updateLocalVector val latestMessageIds = Tasks.await( channelMessageCollection.withDocumentClass(Document::class.java).find(Document(mapOf( "channelId" to subscription.channelId, "remoteTimestamp" to mapOf( "$gt" to subscription.localTimestamp, "$lte" to subscription.remoteTimestamp ) ))) .projection(Document(mapOf("_id" to true))) .map { BsonObjectId(it["_id"] as ObjectId) } .into(mutableListOf<BsonObjectId>())).toTypedArray()
  • 44. ::initializeMessageCursor if (Tasks.await(channelSubscriptionCollection.sync().find().first()) == null) { subscribeToChannel() } else { adapter.cursor = LruMessageCursor( channelId = "default", count = Tasks.await( channelMessageCollection.sync().count( Document("channelId", "default") )).toInt()) }
  • 45. Functions & Triggers exports = function(changeEvent) { // Parse values from the insert change event // changeEvent.operationType === "INSERT" const insertedDoc = changeEvent.fullDocument const { _id, name } = insertedDoc; // Instantiate a MongoDB service client const cluster = context.services.get("myCluster"); const myDb = cluster.db("myDb"); const myColl = myDb.collection("myColl"); myColl.updateOne({ _id }, { "$set": { "someField": "$set" } }) } Invoke Serverless Functions • Written in JavaScript (ES6+) • Execute dynamically based on context • Run as a specific application user • Connect to your application components • Callable from an SDK or another Function Trigger Functions on Events • React to changes in a MongoDB collection • Execute logic when users are created or log in • Schedule functions with CRON expressions
  • 46. functions > subscribeToChannel var mongo = context.services.get("mongodb-atlas"); var channelMembersCollection = mongo.db("chats").collection("channel_members"); var channelSubscriptionsCollection = mongo.db("chats").collection("channel_subscriptions"); await channelMembersCollection.updateOne({ "_id" : channelId }, { "$push": { "members" : userId }, "$set": { "__stitch_sync_version" : { "spv" : BSON.Int32(1), "id" : “0", "v" : BSON.Long(1) }}}, { upsert: true });
  • 47. functions > subscribeToChannel var otherSubscription = await channelSubscriptionsCollection.findOne({ "channelId" : channelId }) var insertOneResult = await channelSubscriptionsCollection.insertOne({ "ownerId" : userId, "deviceId": deviceId, "channelId" : channelId, "localTimestamp" : 0, "remoteTimestamp": otherSubscription ? otherSubscription .remoteTimestamp : 0 } ); return insertOneResult.insertedId;
  • 48. ::subscribeToChannel val subscriptionId = Tasks.await( stitch.callFunction( "subscribeToChannel", listOf(stitch.auth.user!!.id, stitch.auth.user!!.deviceId, "default"), BsonObjectId::class.java)) channelSubscriptionCollection.sync().syncOne(subscriptionId)
  • 49. ::subscribeToChannel channelMessageObserver.observe( this@ChannelFragment, object : Observer<ChangeEvent<ChannelMessage>> { override fun onChanged(changeEvent: ChangeEvent<ChannelMessage>?) { if (changeEvent == null) return val subscription = Tasks.await(channelSubscriptionCollection.sync().find().first()) if (changeEvent.fullDocument?.remoteTimestamp == subscription.remoteTimestamp) { adapter.cursor = LruMessageCursor(channelId = "default", count = Tasks.await( channelMessageCollection.sync().count()).toInt()) launch(Main) { channelMessageObserver.removeObserver(this) } } } })
  • 50. ::sendMessage val messageEditText = v.rootView .findViewById<EditText>(R.id.message_edit_text) val channelMessage = ChannelMessage( id = ObjectId(), ownerId = stitch.auth.user!!.id, channelId = "default", content = messageEditText.text.toString(), sentAt = System.currentTimeMillis())
  • 52. ::sendMessage channelMessageObserver.observe( this, object : Observer<ChangeEvent<ChannelMessage>> { override fun onChanged(changeEvent: ChangeEvent<ChannelMessage>?) { if (changeEvent == null || changeEvent.documentKey["_id"] != BsonObjectId(channelMessage.id) || changeEvent.fullDocument == null) { return } adapter.stackOnEnd(changeEvent.fullDocument!!) channelMessageObserver.removeObserver(this) } })
  • 54. triggers > channelMessageHasInserted var messageId = changeEvent.documentKey._id; var channelId = changeEvent.fullDocument.channelId; var messagesCollection = context.services .get("mongodb-atlas").db("chats").collection("messages"); var subscriptionsCollection = context.services .get("mongodb-atlas") .db("chats").collection("channel_subscriptions");
  • 55. triggers > channelMessageHasInserted await subscriptionsCollection.updateMany( { "channelId" : channelId }, { "$inc": { "remoteTimestamp" : 1 }}); await messagesCollection.updateOne( { "_id" : messageId }, { "$set": { "sentAt" : Date.now(), "remoteTimestamp": (await subscriptionsCollection.findOne( { "channelId" : channelId })).remoteTimestamp } });
  • 56. MessageAdapter class MessageAdapter(private val activity: FragmentActivity) : MongoCursorAdapter<MessageViewHolder, ChannelMessage>() { override suspend fun onBindViewHolder( viewHolder: MessageViewHolder, item: ChannelMessage) { viewHolder.itemView.visibility = INVISIBLE launch(Main) { viewHolder.setMessage(item) }.join() } }
  • 57. The power of observation sealed class MessageViewHolder(activity: FragmentActivity, itemView: View) : RecyclerView.ViewHolder(itemView) { private val observer = Observer { changeEvent: ChangeEvent<ChannelMessage>? -> if (changeEvent == null || changeEvent.fullDocument == null || changeEvent.fullDocument?.id != message?.id) { return@Observer } this.setMessage(changeEvent.fullDocument!!) } init { channelMessageObserver.observe(activity, observer) }
  • 58. The power of observation open fun setMessage(message: ChannelMessage) { this.message = message content.text = message.content if (message.remoteTimestamp != null) { content.setTextColor( itemView.resources.getColor(android.R.color.black, null)) } else { content.setTextColor( itemView.resources.getColor(android.R.color.darker_gray, null)) } itemView.visibility = VISIBLE }
  • 59. The power of observation
  • 60. The power of observation class FullMessageViewHolder(private val activity: FragmentActivity, itemView: View) : MessageViewHolder(activity, itemView) { private val observer = Observer { changeEvent: ChangeEvent<User>? -> if (changeEvent == null || changeEvent.fullDocument?.id != currentMessage?.ownerId) { return@Observer } this.setUser(changeEvent.fullDocument!!) } init { userObserver.observe(activity, observer) }
  • 61. The power of observation @MainThread private fun setUser(user: User?) { if (user == null) return if (user.avatar != null) { avatar.setImageBitmap(user.bitmapAvatar()) } else { avatar.setImageResource(defaultAvatars[user.defaultAvatarOrdinal]) } username.text = user.name }
  • 62. The power of observation override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) usersCollection.sync().updateOne(Document(mapOf("_id" to stitch.auth.user!!.id)), Document( mapOf("$set" to mapOf("avatar" to File( ImagePicker .getImagePathFromResult( this@ChannelActivity, requestCode, resultCode, data)) .readBytes())))) }
  • 63. The power of observation