{"id":3834,"date":"2012-11-30T06:45:26","date_gmt":"2012-11-30T04:45:26","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=3834"},"modified":"2012-11-30T15:41:06","modified_gmt":"2012-11-30T13:41:06","slug":"event-streaming-with-mongodb","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html","title":{"rendered":"Event streaming with MongoDB"},"content":{"rendered":"<p><a href=\"http:\/\/www.mongodb.org\/\">MongoDB<\/a> is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at <a href=\"http:\/\/softwaremill.com\/\">SoftwareMill<\/a>, we used it as a replicated event storage, from which we stream the events to other components.<\/p>\n<p><strong>Introduction<\/strong><\/p>\n<p>The basic idea is pretty simple (see also Martin Fowler\u2019s article on <a href=\"http:\/\/martinfowler.com\/eaaDev\/EventSourcing.html\">Event Sourcing<\/a>). Our system generates a series of events. These events are persisted in the event storage. Other components in the system follow the stream of events and do \u201csomething\u201d with them; for example they can get aggregated and written into a reporting database (this, on the other hand, resembles <a href=\"http:\/\/martinfowler.com\/bliki\/CQRS.html\">CQRS<\/a>). Such an approach has many advantages:<\/p>\n<ul>\n<li>reading and writing of the events is decoupled (asynchronous)<\/li>\n<li>any following-component may die and then \u201ccatch up\u201d, given that it wasn\u2019t dead for too long<\/li>\n<li>there may be multiple followers. The followers may read the data from slave replicas, for better scalability<\/li>\n<li>bursts of event activity have a reduced impact on event sinks; at worst, the reports will get generated slower<\/li>\n<\/ul>\n<p>The key component here is of course a fast and reliable event storage. The three key features of MongoDB that we used to implement one are:<\/p>\n<ul>\n<li>capped collections and tailable cursors<\/li>\n<li>fast collection appends<\/li>\n<li>replica sets<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n<strong>Collection<\/strong><\/p>\n<p>As the base, we are using a <a href=\"http:\/\/docs.mongodb.org\/manual\/core\/capped-collections\/\">capped collection<\/a>, which by definition is size-constrained. If writing a new event would cause the collection to exceed the size limit, the oldest events are overwritten. This gives us something similar to a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Circular_buffer\">circular buffer<\/a> for events. (Plus we are also quite safe from out-of-disk-space errors.)<\/p>\n<p>Until version 2.2, capped collection didn\u2019t have an _id field by default (and hence no index). However, as we wanted the events to be written reliably across the replica set, both the _id field and an index on it are mandatory.<br \/>\n<strong><\/strong><\/p>\n<p><strong>Writing events<\/strong><\/p>\n<p>Writing events is a simple Mongo insert operation; inserts can also be done in batches. Depending on how tolerant we are of event loss, we may use various Mongo <a href=\"http:\/\/api.mongodb.org\/java\/2.6\/com\/mongodb\/WriteConcern.html\">write concerns<\/a> (e.g. waiting for a write confirmation from a single-node or from multiple nodes).<\/p>\n<p>All of the events are immutable. Apart from nicer, thread-safe Java code, this is a necessity for event streaming; if the events were mutable, how would the event sink know what was updated? Also, this has good Mongo performance implications. As the data is never changed, the documents that are written to disk never shrink or expand, so there is no need to move blocks on disk. In fact, in a capped collection, Mongo doesn\u2019t allow to grow a document that was once written.<br \/>\n<strong><\/strong><div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p><strong>Reading events<\/strong><\/p>\n<p>Reading the event stream is a little bit more complex. First of all, there may be multiple readers, each with a different level of advancement in the stream. Secondly, if there are no events in the stream, we would like the reader to wait until some events are available, and avoid active polling. Finally, we would like to process the events in batches, to improve performance.<\/p>\n<p><a href=\"http:\/\/www.mongodb.org\/display\/DOCS\/Tailable+Cursors\">Tailable cursors<\/a> solve these problems. To create such a cursor we have to provide a starting point \u2013 an id of an event, from which we\u2019ll start reading; if an id is not provided, the cursor will return events from the oldest one available. Thus each reader must store the last event that it has read and processed.<\/p>\n<p>More importantly, tailable cursors can optionally block for some amount of time if no new data is available, solving the active polling problem.<\/p>\n<p>(By the way, the oplog collection that mongo uses to replicate data across a replica set, is also a capped collection. Slave Mongo instances tail this collection, streaming the \u201cevents\u201d, which are database operations, and applying them locally in order.)<br \/>\n<strong><\/strong><\/p>\n<p><strong>Reading events in Java<\/strong><\/p>\n<p>When using the Mongo <a href=\"https:\/\/github.com\/mongodb\/mongo-java-driver\">Java Driver<\/a>, there are a few \u201ccatches\u201d. First of all you need to initialise the cursor. To do that, we need to provide (1) the last event id, if present; (2) an order in which we want to read the events (here: natural, that is the insertion order); and (3) two crucial cursor options, that we want the cursor to be tailable, and that we want to block if there\u2019s no new data:<\/p>\n<pre class=\"brush:java\">DBObject query = lastReceivedEventId.isPresent()\r\n   ? BasicDBObjectBuilder.start('_id', BasicDBObjectBuilder\r\n         .start('$gte', lastReceivedEventId.get()).get())\r\n         .get()\r\n   : null;\r\n\r\nDBObject sortBy = BasicDBObjectBuilder.start('$natural', 1).get();\r\n\r\nDBCollection collection = ... \/\/ must be a capped collection\r\nDBCursor cursor = collection\r\n   .find(query)\r\n   .sort(sortBy)\r\n   .addOption(Bytes.QUERYOPTION_TAILABLE)\r\n   .addOption(Bytes.QUERYOPTION_AWAITDATA);<\/pre>\n<p>You may wonder why we used <code>&gt;= last_id<\/code> instead of <code>&gt;<\/code>. That is needed here because of the way Mongo ObjectIds are generated. With a simple <code>&gt; last_id<\/code> we may miss some events that have been generated in the same second as the <code>last_id<\/code> event, but after it. This also means that our Java code must take care of this fact and discard the first event that was received.<\/p>\n<p>The cursor\u2019s class extends the basic Java <code>Iterator<\/code> interface, so it\u2019s fairly easy to use. So now we can take care of batching. When iterating over a cursor, the driver receives the data from the Mongo server in batches; so we may simply call <code>hasNext()<\/code> and <code>next()<\/code>, as with any other iterator, to receive subsequent elements, and only some calls will actually cause network communication with the server.<\/p>\n<p>In the Mongo Java driver the call that is actually potentially blocking is <code>hasNext()<\/code>. If we want to process the events in batches, we need to (a) read the elements as long as they are available, and (b) have some way of knowing before getting blocked that there are no more events, and that we can process the events already batched. And as <code>hasNext()<\/code> can block, we can\u2019t do this directly.<\/p>\n<p>That\u2019s why we introduced an intermediate queue (<a href=\"http:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/util\/concurrent\/LinkedBlockingQueue.html\"><code>LinkedBlockingQueue<\/code><\/a>). In a separate thread, events read from the cursor are put on the queue as they come. If there are no events, the thread will block on <code>cursor.hasNext()<\/code>. The blocking queue has an optional size limit, so if it\u2019s full, putting an element will block as well until space is available. In the event-consumer thread, we first try to read a single element from the queue, in a blocking fashion (using <code>.poll<\/code>, so here we wait until any event is available). Then we try to drain the whole content of the queue to a temporary collection (using <code>.drainTo<\/code>, building the batch, and potentially getting 0 elements, but we always have the first one).<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/11\/mongo-streaming-1.png\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-3933\" title=\"mongo-streaming (1)\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/11\/mongo-streaming-1-300x241.png\" alt=\"\" width=\"300\" height=\"241\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/11\/mongo-streaming-1-300x241.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/11\/mongo-streaming-1.png 704w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>An important thing to mention is that if the collection is empty, Mongo won\u2019t block, so we have to fall back to active polling. We also have to take care of the fact that the cursor may die during this wait; to check this we should verify that <code>cursor.getCursorId() != 0<\/code>, where 0 is an id of a \u201cdead cursor\u201d. In such a case we simply need to re-instantiate the cursor.<\/p>\n<p><strong>Summing up<\/strong><\/p>\n<p>To sum up, we got a very fast event sourcing\/streaming solution. It is \u201cself regulating\u201d, in the sense that if there\u2019s a peak of event activity, they will be read by the event sinks with a delay, in large batches. If the event activity is low, they will be processed quickly in small batches.<\/p>\n<p>We\u2019re also using the same Mongo instance for other purposes; having a single DB system to cluster and maintain both for regular data and events is certainly great from an ops point of view.<br \/>\n&nbsp;<\/p>\n<p><strong><em>Reference: <\/em><\/strong><a href=\"http:\/\/www.warski.org\/blog\/2012\/11\/event-streaming-with-mongodb\/\">Event streaming with MongoDB <\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/p\/jcg.html\">JCG partner<\/a> Adam Warski at the <a href=\"http:\/\/www.warski.org\/blog\">Blog of Adam Warski<\/a> blog.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a replicated event storage, from which we stream the events to other components. Introduction The basic idea is pretty simple (see also Martin Fowler\u2019s article on Event Sourcing). &hellip;<\/p>\n","protected":false},"author":89,"featured_media":187,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[112],"class_list":["post-3834","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-mongodb"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Event streaming with MongoDB<\/title>\n<meta name=\"description\" content=\"MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Event streaming with MongoDB\" \/>\n<meta property=\"og:description\" content=\"MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2012-11-30T04:45:26+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2012-11-30T13:41:06+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/mongodb-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Adam Warski\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@http:\/\/twitter.com\/adamwarski\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adam Warski\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html\"},\"author\":{\"name\":\"Adam Warski\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/1974bff2e48a09ab944a3f9eada83438\"},\"headline\":\"Event streaming with MongoDB\",\"datePublished\":\"2012-11-30T04:45:26+00:00\",\"dateModified\":\"2012-11-30T13:41:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html\"},\"wordCount\":1207,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/mongodb-logo.jpg\",\"keywords\":[\"MongoDB\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html\",\"name\":\"Event streaming with MongoDB\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/mongodb-logo.jpg\",\"datePublished\":\"2012-11-30T04:45:26+00:00\",\"dateModified\":\"2012-11-30T13:41:06+00:00\",\"description\":\"MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/mongodb-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/mongodb-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/11\\\/event-streaming-with-mongodb.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Event streaming with MongoDB\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/1974bff2e48a09ab944a3f9eada83438\",\"name\":\"Adam Warski\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5c6fae14426526780cf8a2cb4c9d3e4941c61329d31a7ed9e451aa53b93407f0?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5c6fae14426526780cf8a2cb4c9d3e4941c61329d31a7ed9e451aa53b93407f0?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5c6fae14426526780cf8a2cb4c9d3e4941c61329d31a7ed9e451aa53b93407f0?s=96&d=mm&r=g\",\"caption\":\"Adam Warski\"},\"description\":\"Adam is one of the co-founders of SoftwareMill, a company specialising in delivering customised software solutions. He is also involved in open-source projects, as a founder, lead developer or contributor to: Hibernate Envers, a Hibernate core module, which provides entity versioning\\\/auditing capabilities; ElasticMQ, an SQS-compatible messaging server written in Scala; Veripacks, a tool to specify and verify inter-package dependencies, and others.\",\"sameAs\":[\"http:\\\/\\\/www.warski.org\\\/blog\",\"http:\\\/\\\/www.linkedin.com\\\/in\\\/adamwarski\",\"https:\\\/\\\/x.com\\\/http:\\\/\\\/twitter.com\\\/adamwarski\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/Adam-Warski\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Event streaming with MongoDB","description":"MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html","og_locale":"en_US","og_type":"article","og_title":"Event streaming with MongoDB","og_description":"MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a","og_url":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2012-11-30T04:45:26+00:00","article_modified_time":"2012-11-30T13:41:06+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/mongodb-logo.jpg","type":"image\/jpeg"}],"author":"Adam Warski","twitter_card":"summary_large_image","twitter_creator":"@http:\/\/twitter.com\/adamwarski","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Adam Warski","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html"},"author":{"name":"Adam Warski","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/1974bff2e48a09ab944a3f9eada83438"},"headline":"Event streaming with MongoDB","datePublished":"2012-11-30T04:45:26+00:00","dateModified":"2012-11-30T13:41:06+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html"},"wordCount":1207,"commentCount":2,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/mongodb-logo.jpg","keywords":["MongoDB"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html","url":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html","name":"Event streaming with MongoDB","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/mongodb-logo.jpg","datePublished":"2012-11-30T04:45:26+00:00","dateModified":"2012-11-30T13:41:06+00:00","description":"MongoDB is a really great \u201cNoSQL\u201d database, with a very wide range of applications. In one project that we are developing at SoftwareMill, we used it as a","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/mongodb-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/mongodb-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2012\/11\/event-streaming-with-mongodb.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Event streaming with MongoDB"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/1974bff2e48a09ab944a3f9eada83438","name":"Adam Warski","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/5c6fae14426526780cf8a2cb4c9d3e4941c61329d31a7ed9e451aa53b93407f0?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/5c6fae14426526780cf8a2cb4c9d3e4941c61329d31a7ed9e451aa53b93407f0?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5c6fae14426526780cf8a2cb4c9d3e4941c61329d31a7ed9e451aa53b93407f0?s=96&d=mm&r=g","caption":"Adam Warski"},"description":"Adam is one of the co-founders of SoftwareMill, a company specialising in delivering customised software solutions. He is also involved in open-source projects, as a founder, lead developer or contributor to: Hibernate Envers, a Hibernate core module, which provides entity versioning\/auditing capabilities; ElasticMQ, an SQS-compatible messaging server written in Scala; Veripacks, a tool to specify and verify inter-package dependencies, and others.","sameAs":["http:\/\/www.warski.org\/blog","http:\/\/www.linkedin.com\/in\/adamwarski","https:\/\/x.com\/http:\/\/twitter.com\/adamwarski"],"url":"https:\/\/www.javacodegeeks.com\/author\/Adam-Warski"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/3834","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=3834"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/3834\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/187"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=3834"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=3834"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=3834"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}