diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/bulk-insert.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/bulk-insert.python.markdown new file mode 100644 index 0000000000..98b3571704 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/bulk-insert.python.markdown @@ -0,0 +1,47 @@ +# Bulk Insert Attachments + +--- + +{NOTE: } + +* [bulk_insert](../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation) is RavenDB's + high-performance data insertion operation. + Use its `attachments_for` interface to add attachments to multiple documents with great speed. +* Use `store` + +* In this page: + * [Usage flow](../../document-extensions/attachments/bulk-insert#usage-flow) + * [Usage example](../../document-extensions/attachments/bulk-insert#usage-example) + +{NOTE/} + +{PANEL: Usage flow} + +* Create a `bulk_insert` instance. + +* Pass the Document ID to the instance's `attachments_for` method. + +* To add an attachment, call the `store` method. + Pass it the attachment's name, stream, and type (optional). + `store` can be called repeatedly, as many times as needed. + +* Note: + If an attachment with the specified name already exists on the document, + the bulk insert operation will overwrite it. + +{PANEL/} + +{PANEL: Usage example} + +In this example, we attach a file to all User documents that match a query. +{CODE:python bulk_insert_attachment@DocumentExtensions\Attachments\BulkInsert.py /} + +{PANEL/} + +## Related articles + +### Attachments + +- [Storing](../../document-extensions/attachments/storing) +- [Loading](../../document-extensions/attachments/loading) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.js.markdown index 4697c5cd40..addd2fa1c0 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.js.markdown @@ -59,22 +59,22 @@ Use `session.advanced.attachments.rename` to rename an attachment. | Parameter | Type | Description | |---------------------------|----------|-----------------------------| -| __sourceEntity__ | `object` | Source entity | -| __destinationEntity__ | `object` | Destination entity | -| __sourceDocumentId__ | string | Source document Id | -| __destinationDocumentId__ | string | Destination document Id | -| __sourceName__ | string | Source attachment name | -| __destinationName__ | string | Destination attachment name | +| **sourceEntity** | `object` | Source entity | +| **destinationEntity** | `object` | Destination entity | +| **sourceDocumentId** | string | Source document Id | +| **destinationDocumentId** | string | Destination document Id | +| **sourceName** | string | Source attachment name | +| **destinationName** | string | Destination attachment name | {CODE:nodejs syntax_rename@documentExtensions\attachments\copyMoveRename.js /} | Parameter | Type | Description | |----------------|----------|---------------------------------| -| __entity__ | `object` | The document entity | -| __documentId__ | string | The document Id | -| __name__ | string | Current name of attachment | -| __newName__ | string | The new name for the attachment | +| **entity** | `object` | The document entity | +| **documentId** | string | The document Id | +| **name** | string | Current name of attachment | +| **newName** | string | The new name for the attachment | {PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.python.markdown new file mode 100644 index 0000000000..b0bd85e8af --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/copying-moving-renaming.python.markdown @@ -0,0 +1,56 @@ +# Attachments: Copy, Move, Rename + +Attachments can be copied, moved, or renamed using built-in session methods. +All of those actions are executed when `save_changes` is called and take place on the server-side, +removing the need to transfer the entire attachment binary data over the network in order to perform the action. + +{PANEL: Copy attachment} + +Attachment can be copied using one of the `session.advanced.attachments.copy` methods: + +### Syntax + +{CODE:python copy_0@DocumentExtensions\Attachments\CopyMoveRename.py /} + +### Example + +{CODE:python copy_1@DocumentExtensions\Attachments\CopyMoveRename.py /} + +{PANEL/} + +{PANEL: Move attachment} + +Attachment can be moved using one of the `session.advanced.attachments.move` methods: + +### Syntax + +{CODE:python move_0@DocumentExtensions\Attachments\CopyMoveRename.py /} + +### Example + +{CODE:python move_1@DocumentExtensions\Attachments\CopyMoveRename.py /} + +{PANEL/} + +{PANEL: Rename attachment} + +Attachment can be renamed using one of the `session.advanced.attachments.rename` methods: + +### Syntax + +{CODE:python rename_0@DocumentExtensions\Attachments\CopyMoveRename.py /} + +### Example + +{CODE:python rename_1@DocumentExtensions\Attachments\CopyMoveRename.py /} + +{PANEL/} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Loading](../../document-extensions/attachments/loading) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.dotnet.markdown new file mode 100644 index 0000000000..c47de4e47e --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.dotnet.markdown @@ -0,0 +1,22 @@ +# Attachments: Deleting Attachments + +**Delete** from `session.Advanced.Attachments` is used to remove an attachment from a document. + +## Syntax + +{CODE DeleteSyntax@DocumentExtensions\Attachments\Attachments.cs /} + +## Example + +{CODE-TABS} +{CODE-TAB:csharp:Sync DeleteAttachment@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TAB:csharp:Async DeleteAttachmentAsync@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TABS/} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Loading](../../document-extensions/attachments/loading) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.java.markdown new file mode 100644 index 0000000000..22cc5edfb9 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.java.markdown @@ -0,0 +1,19 @@ +# Attachments: Deleting Attachments + +**Delete** from `session.advanced().attachments()` is used to remove an attachment from a document. + +## Syntax + +{CODE:java DeleteSyntax@DocumentExtensions\Attachments\Attachments.java /} + +## Example + +{CODE:java DeleteAttachment@DocumentExtensions\Attachments\Attachments.java /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Loading](../../document-extensions/attachments/loading) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.js.markdown new file mode 100644 index 0000000000..02100e8f3e --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.js.markdown @@ -0,0 +1,19 @@ +# Attachments: Deleting Attachments + +The method `session.advanced.attachments.delete()` is used to remove an attachment from a document. + +## Syntax + +{CODE:nodejs DeleteSyntax@DocumentExtensions\Attachments\attachments.js /} + +## Example + +{CODE:nodejs DeleteAttachment@DocumentExtensions\Attachments\attachments.js /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Loading](../../document-extensions/attachments/loading) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.python.markdown new file mode 100644 index 0000000000..4431f3764e --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/deleting.python.markdown @@ -0,0 +1,19 @@ +# Attachments: Deleting Attachments + +**Delete** from `session.advanced.attachments` is used to remove an attachment from a document. + +## Syntax + +{CODE:python DeleteSyntax@DocumentExtensions\Attachments\Attachments.py /} + +## Example + +{CODE:python DeleteAttachment@DocumentExtensions\Attachments\Attachments.py /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Loading](../../document-extensions/attachments/loading) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.dotnet.markdown index fa0c5fe43d..39cedaa0e6 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.dotnet.markdown @@ -5,10 +5,10 @@ * Indexing attachments allows you to query for documents based on their attachments' details and content. -* __Static indexes__: +* **Static indexes**: Both attachments' details and content can be indexed within a static-index definition. -* __Auto-indexes__: +* **Auto-indexes**: Auto-indexing attachments via dynamic queries is not available at this time. diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.java.markdown index 65b157c152..f19121f192 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.java.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.java.markdown @@ -5,10 +5,10 @@ * Indexing attachments allows you to query for documents based on their attachments' details and content. -* __Static indexes__: +* **Static indexes**: Both attachments' details and content can be indexed within a static-index definition. -* __Auto-indexes__: +* **Auto-indexes**: Auto-indexing attachments via dynamic queries is not available at this time. * In this page: diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.js.markdown index f6158957e0..5b368ba95e 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.js.markdown @@ -5,10 +5,10 @@ * Indexing attachments allows you to query for documents based on their attachments' details and content. -* __Static indexes__: +* **Static indexes**: Both attachments' details and content can be indexed within a static-index definition. -* __Auto-indexes__: +* **Auto-indexes**: Auto-indexing attachments via dynamic queries is not available at this time. * In this page: @@ -26,13 +26,13 @@ {NOTE: } -__The index__: +**The index**: --- * To index attachments' details, call `attachmentsFor()` within the index definition. -* `attachmentsFor()` provides access to the __name__, __size__, __hash__, and __content-type__ of each attachment a document has. +* `attachmentsFor()` provides access to the **name**, **size**, **hash**, and **content-type** of each attachment a document has. These details can then be used when defining the index-fields. * To index attachments' content, see the examples below. @@ -43,7 +43,7 @@ __The index__: {NOTE: } -__Query the Index__: +**Query the Index**: --- @@ -64,7 +64,7 @@ where attachmentNames == "photo.jpg" and attachmentSizes > 20000 {NOTE: } -__Sample data__: +**Sample data**: --- @@ -79,11 +79,11 @@ __Sample data__: {NOTE: } -__The index__: +**The index**: --- -* To index the __details & content__ for a specific attachment, call `loadAttachment()` within the index definition. +* To index the **details & content** for a specific attachment, call `loadAttachment()` within the index definition. * In addition to accessing the attachment details, `loadAttachment()` provides access to the attachment's content, which can be used when defining the index-fields. @@ -94,7 +94,7 @@ __The index__: {NOTE: } -__Query the Index__: +**Query the Index**: --- @@ -116,11 +116,11 @@ where search(attachmentContent, "Colorado Dallas") {NOTE: } -__The index__: +**The index**: --- -* Use `loadAttachments()` to be able to index the __details & content__ of ALL attachments. +* Use `loadAttachments()` to be able to index the **details & content** of ALL attachments. * Note how the index example below is employing the [Fanout index](../../indexes/indexing-nested-data#fanout-index---multiple-index-entries-per-document) pattern. @@ -130,7 +130,7 @@ __The index__: {NOTE: } -__Query the Index__: +**Query the Index**: --- @@ -162,7 +162,7 @@ where attachmentSize > 20000 or search(attachmentContent, "Colorado Dallas") | Parameter | Type | Description | |--------------|----------|---------------------------------------------------------| -| __document__ | `object` | The document whose attachments details you want to load | +| **document** | `object` | The document whose attachments details you want to load | {CODE:nodejs syntax_2@documentExtensions\attachments\indexAttachments.js /} @@ -172,8 +172,8 @@ where attachmentSize > 20000 or search(attachmentContent, "Colorado Dallas") | Parameter | Type | Description | |---------------------|-----------|------------------------------------------------| -| __document__ | `object` | The document whose attachment you want to load | -| __attachmentName__ | `string` | The name of the attachment to load | +| **document** | `object` | The document whose attachment you want to load | +| **attachmentName** | `string` | The name of the attachment to load | {CODE:nodejs syntax_4@documentExtensions\attachments\indexAttachments.js /} diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.python.markdown new file mode 100644 index 0000000000..8d257a0311 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/indexing.python.markdown @@ -0,0 +1,113 @@ +# Index Attachments +--- + +{NOTE: } + +* Indexing attachments allows you to query for documents based on their attachments' details and content. + +* **Static indexes**: + Both attachments' details and content can be indexed within a static-index definition. + +* **Auto-indexes**: + Auto-indexing attachments via dynamic queries is not available at this time. + + +* In this page: + * [Syntax](../../document-extensions/attachments/indexing#syntax) + * [Examples](../../document-extensions/attachments/indexing#examples) + * [Leveraging indexed attachments](../../document-extensions/attachments/indexing#leveraging-indexed-attachments) + +{NOTE/} + +--- + +{PANEL: Syntax} + +### Using `AttachmentsFor` + +The `AttachmentsFor` method returns information about each attachment that extends +a specified document, including their names, sizes, and content type. + +{CODE-TABS} +{CODE-TAB:python:Method syntax@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TAB:python:Result result@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TABS/} + +The `AttachmentsFor` method is available in `AbstractIndexCreationTask`. + +### Using `LoadAttachment`/`LoadAttachments` + +`LoadAttachment` loads an attachment to the index by document and attachment name. +`LoadAttachments` loads all the attachments of a given document. + +{CODE:python syntax_2@DocumentExtensions\Attachments\IndexingAttachments.py /} + +| Parameter | Type | Description | +| - | - | - | +| **doc** | A server-side document, an entity | The document whose attachments you want to load | +| **name** | `string` | The name of the attachment you want to load | + +#### `GetContentAs` Methods + +To access the attachment content itself, use `GetContentAsStream`. To +convert the content into a `string`, use `GetContentAsString` with +the desired character encoding. + +{CODE-BLOCK: csharp} +public Stream GetContentAsStream(); +public string GetContentAsString(Encoding encoding); +public string GetContentAsString(); // Default: UTF-8 +{CODE-BLOCK/} + +{PANEL/} + +{PANEL: Examples} + +#### Indexes with `AttachmentsFor` + +{CODE-TABS} +{CODE-TAB:python:LINQ-syntax AttFor_index_LINQ@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TAB:python:JavaScript-syntax AttFor_index_JS@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TABS/} + +#### Indexes with `LoadAttachment` + +{CODE-TABS} +{CODE-TAB:python:LINQ-syntax LoadAtt_index_LINQ@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TAB:python:JavaScript-syntax LoadAtt_index_JS@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TABS/} + +#### Indexes with `LoadAttachments` + +{CODE-TABS} +{CODE-TAB:python:LINQ-syntax LoadAtts_index_LINQ@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TAB:python:JavaScript-syntax LoadAtts_index_JS@DocumentExtensions\Attachments\IndexingAttachments.py /} +{CODE-TABS/} + +#### Querying the Index + +{CODE:python query1@DocumentExtensions\Attachments\IndexingAttachments.py /} + +{PANEL/} + +{PANEL: Leveraging indexed attachments} + +* Access to the indexed attachment content opens a door to many different applications, + including ones that can be integrated directly into RavenDB. + +* In this [blog post](https://ayende.com/blog/192001-B/using-machine-learning-with-ravendb), + Oren Eini demonstrates how image recognition can be applied to indexed attachments using the + [additional sources](../../indexes/extending-indexes) feature. + The resulting index allows filtering and querying based on image content. + +{PANEL/} + +## Related Articles + +### Document Extensions + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) + +### Indexes + +- [What are Indexes](../../indexes/what-are-indexes) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.dotnet.markdown new file mode 100644 index 0000000000..c134a6b7da --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.dotnet.markdown @@ -0,0 +1,39 @@ +# Attachments: Loading Attachments + +There are a few methods that allow you to download attachments from a database: + +**session.Advanced.Attachments.Get** can be used to download an attachment or multiple attachments. +**session.Advanced.Attachments.GetNames** can be used to download all attachment names that are attached to a document. +**session.Advanced.Attachments.GetRevision** can be used to download an attachment of a revision document. +**session.Advanced.Attachments.Exists** can be used to determine if an attachment exists on a document. + +## Syntax + +{CODE-TABS} +{CODE-TAB:csharp:Sync GetSyntax@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TAB:csharp:Async GetSyntaxAsync@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TABS/} + +## Example I + +{CODE-TABS} +{CODE-TAB:csharp:Sync GetAttachment@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TAB:csharp:Async GetAttachmentAsync@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TABS/} + +## Example II +Here, we load multiple string attachments we previously created for a document. We then +go through them, and decode each attachment to its original text. +{CODE-TABS} +{CODE-TAB:csharp:Sync GetAllAttachments@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TAB:csharp:Async GetAllAttachmentsAsync@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TABS/} + + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.java.markdown new file mode 100644 index 0000000000..b9935a7b4b --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.java.markdown @@ -0,0 +1,24 @@ +# Attachments: Loading Attachments + +There are a few methods that allow you to download attachments from a database: + +**session.advanced().attachments().get** can be used to download an attachment. +**session.advanced().attachments().getNames** can be used to download all attachment names that are attached to a document. +**session.advanced().attachments().getRevision** can be used to download an attachment of a revision document. +**session.advanced().attachments().exists** can be used to determine if an attachment exists on a document. + +## Syntax + +{CODE:java GetSyntax@DocumentExtensions\Attachments\Attachments.java /} + +## Example + +{CODE:java GetAttachment@DocumentExtensions\Attachments\Attachments.java /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.js.markdown new file mode 100644 index 0000000000..e63bf07cdb --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.js.markdown @@ -0,0 +1,34 @@ +# Attachments: Loading Attachments + +There are a few methods that allow you to download attachments from a database: + +**session.advanced.attachments.get()** can be used to download an attachment. +**session.advanced.attachments.getNames()** can be used to download all attachment names that are attached to a document. +**session.advanced.attachments.getRevision()** can be used to download an attachment of a revision document. +**session.advanced.attachments.exists()** can be used to determine if an attachment exists on a document. + +## Syntax + +{CODE:nodejs GetSyntax@DocumentExtensions\Attachments\attachments.js /} + +| Parameters | | | +| ------------- | ------------- | ----- | +| **entity** or **documentId** | object or string | instance of the entity or the entity ID | +| **name** | string | attachment name | +| **changeVector** | string | change vector for revision identification | + +| Return Value | | +| ------------- | ------------- | +| `Promise` | Promise resolving to a Readable for attachment content | + +## Example + +{CODE:nodejs GetAttachment@DocumentExtensions\Attachments\attachments.js /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.python.markdown new file mode 100644 index 0000000000..3001c7f4ad --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/loading.python.markdown @@ -0,0 +1,24 @@ +# Attachments: Loading Attachments + +Several methods allow you to download attachments from a database: + +Use `session.advanced.attachments.get` to download an attachment or multiple attachments. +Use `session.advanced.attachments.get_names` to get all the names of a document's attachments. +Use `session.advanced.attachments.get_revision` to download an attachment of a document revision. +Use `session.advanced.attachments.exists` to determine if an attachment exists on a document. + +## Syntax + +{CODE:python GetSyntax@DocumentExtensions\Attachments\Attachments.py /} + +## Example I + +{CODE:python GetAttachment@DocumentExtensions\Attachments\Attachments.py /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Storing](../../document-extensions/attachments/storing) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.dotnet.markdown new file mode 100644 index 0000000000..f54c80a399 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.dotnet.markdown @@ -0,0 +1,26 @@ +# Attachments: Storing Attachments + +In order to store an attachment in RavenDB you need to create a document. Then you can attach an attachment to the document using the `session.Advanced.Attachments.Store` method. + +Attachments, just like documents, are a part of the session and will be only saved on the Server when `DocumentSession.SaveChanges` is executed (you can read more about saving changes in session [here](../../client-api/session/saving-changes)). + +## Syntax + +Attachments can be stored using one of the following `session.Advanced.Attachments.Store` methods: + +{CODE StoreSyntax@DocumentExtensions\Attachments\Attachments.cs /} + +## Example + +{CODE-TABS} +{CODE-TAB:csharp:Sync StoreAttachment@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TAB:csharp:Async StoreAttachmentAsync@DocumentExtensions\Attachments\Attachments.cs /} +{CODE-TABS/} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Loading](../../document-extensions/attachments/loading) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.java.markdown new file mode 100644 index 0000000000..43ab0c9ea0 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.java.markdown @@ -0,0 +1,23 @@ +# Attachments: Storing Attachments + +In order to store an attachment in RavenDB you need to create a document. Then you can attach an attachment to the document using the `session.advanced().attachments().store` method. + +Attachments, just like documents, are a part of the session and will be only saved on the Server when `DocumentSession.saveChanges` is executed (you can read more about saving changes in session [here](../../client-api/session/saving-changes)). + +## Syntax + +Attachments can be stored using one of the following `session.advanced().attachments().store` methods: + +{CODE:java StoreSyntax@DocumentExtensions\Attachments\Attachments.java /} + +## Example + +{CODE:java StoreAttachment@DocumentExtensions\Attachments\Attachments.java /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Loading](../../document-extensions/attachments/loading) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.js.markdown new file mode 100644 index 0000000000..2746329cce --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.js.markdown @@ -0,0 +1,30 @@ +# Attachments: Storing Attachments + +In order to store an attachment in RavenDB you need to create a document. Then you can attach an attachment to the document using the `session.advanced.attachments.store()` method. + +Attachments, just like documents, are a part of the session and will be only saved on the Server when `DocumentSession.saveChanges()` is executed. + +## Syntax + +Attachments can be stored using one of the following `session.advanced.attachments.store()` methods: + +{CODE:nodejs StoreSyntax@DocumentExtensions\Attachments\attachments.js /} + +| Parameters | | | +| ------------- | ------------- | ----- | +| **entity** or **documentId** | object or string | instance of the entity or the entity ID | +| **name** | string | attachment name | +| **stream** | `Readable` or `Buffer` | attachment content | +| **contentType** | string | attachment content type | + +## Example + +{CODE:nodejs StoreAttachment@DocumentExtensions\Attachments\attachments.js /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Loading](../../document-extensions/attachments/loading) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.python.markdown new file mode 100644 index 0000000000..de4e2add30 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/attachments/storing.python.markdown @@ -0,0 +1,25 @@ +# Attachments: Storing Attachments + +To store an attachment in RavenDB, you need to first create a document. +Then, you can attach an attachment to the document using the `session.advanced.attachments.store` method. + +Just like documents, sttachments are a part of the session and will be only saved on the server +when `save_changes` is executed (read more about saving changes in session [here](../../client-api/session/saving-changes)). + +## Syntax + +Attachments can be stored using `session.advanced.attachments.store`: + +{CODE:python StoreSyntax@DocumentExtensions\Attachments\Attachments.py /} + +## Example + +{CODE:python StoreAttachment@DocumentExtensions\Attachments\Attachments.py /} + +## Related Articles + +### Attachments + +- [What are Attachments](../../document-extensions/attachments/what-are-attachments) +- [Loading](../../document-extensions/attachments/loading) +- [Deleting](../../document-extensions/attachments/deleting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.dotnet.markdown new file mode 100644 index 0000000000..d47a9fe780 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.dotnet.markdown @@ -0,0 +1,258 @@ +# Counters and Other Features +--- + +{NOTE: } + +* This section describes the relationships between Counters and other RavenDB features: + * How Counters are supported by the different features. + * How Counters trigger features' execution. + +* In this page: + * [Counters and Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) + * [Counters and Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) + * [Counters and Revisions](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) + * [Counters and Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) + * [Counters and Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) + * [Counters and Ongoing Tasks](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) - `Backup`, `External replication`, `ETL`, `Data Subscription` + * [Counters and Other Features: summary](../../document-extensions/counters/counters-and-other-features#counters-and-other-features-summary) + * [Including Counters](../../document-extensions/counters/counters-and-other-features#including-counters) + * [Counters Bulk-Insert](../../document-extensions/counters/counters-and-other-features#counters-bulk-insert) +{NOTE/} + +--- + +{PANEL: } + +### Counters and Indexing + +Indexing Counters can speed-up finding them and the documents that contain them. + +* **Indexing Counter Values** + Dynamic indexes (aka auto-indexes) _cannot_ index counter values. To index counter values, + create a static index that inherits from `AbstractCountersIndexCreationTask` ([see here](../../document-extensions/counters/indexing)). + +* **Indexing Counter Names** + Re-indexing due to Counter-name modification is normally rare enough to pause no performance issues. + To index a document's Counters by name, use [CounterNamesFor](../../document-extensions/counters/indexing#section-1). + +--- + +###Counters and Queries + +Create queries **using code**, or send the server **raw queries** for execution. + +* Either way, you can query Counters **by name** but **not by value**. + This is because queries are generally [based on indexes](../../start/getting-started#example-iii---querying), and Counter values are [not indexed](../../document-extensions/counters/counters-and-other-features#counters-and-indexing). +* Counter values **can** be [projected](../../indexes/querying/projections) from query results, as demonstrated in the following examples. + This way a client can get Counter values from a query without downloading whole documents. + +* Use [Session.Query](../../client-api/session/querying/how-to-query#session.query) to code queries yourself. + * **Returned Counter Value**: **Accumulated** + A Counter's value is returned as a single sum, with no specification of the Counter's value on each node. + {CODE counters_region_query@DocumentExtensions\Counters\Counters.cs /} + +* Use [RawQuery](../../client-api/session/querying/how-to-query#session.advanced.rawquery) to send the server raw RQL expressions for execution. + * You can use the `counter` method. + **Returned Counter Value**: **Accumulated** + + * You can use the `counterRaw` method. + **Returned Counter Value**: **Distributed** + A Counter's value is returned as a series of values, each maintained by one of the nodes. + * It is not expected of you to use this in your application. + Applications normally use the Counter's overall value, and very rarely refer to the value each node gives it. + + + `counter` and `counterRaw` samples: + {CODE-TABS} + {CODE-TAB:csharp:counter counters_region_rawqueries_counter@DocumentExtensions\Counters\Counters.cs /} + {CODE-TAB:csharp:counterRaw counters_region_rawqueries_counterRaw@DocumentExtensions\Counters\Counters.cs /} + {CODE-TABS/} + +--- + +###Counters and Revisions + +A [document revision](../../document-extensions/revisions/overview) stores all the document Counters' +names and values when the revision was created. + +* **Stored Counter Values**: **Accumulated** + A revision stores a Counter's value as a single sum, with no specification of the Counter's value on each node. + +* Revisions-creation can be initiated by **Counter-name modification**. + * When the Revisions feature is enabled, the creation or deletion of a Counter initiates the creation of a new document revision. + * Counter **value** modifications do **not** cause the creation of new revisions. + +--- + +###Counters and Smuggler + +[Smuggler](../../client-api/smuggler/what-is-smuggler) is a DocumentStore property, that can be used +to [export](../../client-api/smuggler/what-is-smuggler#databasesmugglerexportoptions) chosen +database items to an external file or to [import](../../client-api/smuggler/what-is-smuggler#databasesmugglerimportoptions) +database items from an existing file into the database. + +* **Transferred Counter Value**: **Distributed** + Smuggler transfers the entire series of values that the different nodes maintain for a Counter. +* To make Smuggler handle Counters, include `DatabaseItemType.Counters` in `OperateOnTypes`'s list of entities to import or export. + {CODE smuggler_options@DocumentExtensions\Counters\Counters.cs /} + +--- + +###Counters and Changes API + +[Changes API](../../client-api/changes/what-is-changes-api#changes-api) is a Push service, that can inform you of various changes on the Server, including [changes in Counter values](../../client-api/changes/how-to-subscribe-to-counter-changes#changes-api--how-to-subscribe-to-counter-changes). +You can target all Counters, or specify the ones you wish to follow. + +* **Pushed Counter Value**: **Accumulated** + `Changes API` methods return a Counter's value as a single sum, without specifying its value on each node. +* The service is initiated by **Counter Value Modification**. + +--- + +###Counters and Ongoing Tasks: + +Each [ongoing task](../../studio/database/tasks/ongoing-tasks/general-info) relates to Counters in its own way. + +* **Counters** and the **Backup task** + There are two [backup](../../studio/database/tasks/backup-task) types: **logical-backup** and **snapshot**. + Both types store and restore **all** data, including Counters. + Both types operate as an ongoing backup routine, with a pre-set time schedule. + * Logical Backup: + **Backed-up Counter values**: **Distributed** + A logical backup is a higher-level implementation of [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler). + As with Smuggler, Counters are backed-up and restored including their values on all nodes. + * Snapshot: + A snapshot stores all data and settings as a single binary image. + All components, including Counters, are restored to the exact same state they've been at during backup. + +* **Counters** and the **External Replication task** + The ongoing [external replication](../../studio/database/tasks/ongoing-tasks/external-replication-task) task replicates all data, including Counters. + * **Replicated Counter Value**: **Distributed** + Counters are replicated along with their values on all nodes. + * Replication can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + +* **Counters** and the **ETL task** + [ETL](../../server/ongoing-tasks/etl/basics) is used to export data from RavenDB to an external (either Raven or SQL) database. + * [SQL ETL](../../server/ongoing-tasks/etl/sql) is **not supported**. + Counters cannot be exported to an SQL database over SQL ETL. + * [RavenDB ETL](../../server/ongoing-tasks/etl/raven) **is supported**. + Counters [are](../../server/ongoing-tasks/etl/raven#counters) exported over RavenDB ETL. + * Export can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + * **Exported Counter Value**: **Distributed** + Counters are exported along with their values on all nodes. + * Counters can be [exported using a script](../../server/ongoing-tasks/etl/raven#adding-counter-explicitly-in-a-script). + **Default behavior**: When an ETL script is not provided, Counters are exported. + +* **Counters** and the **[Data Subscriptions](../../client-api/data-subscriptions/what-are-data-subscriptions#data-subscriptions) task** + Data Subscriptions can be initiated by document changes, including those caused by **Counter Name updates**. + Documents will **not** be delivered in reaction to Counter Value modification. + + +{NOTE: } +###Counters and Other Features: Summary + +Use this table to find if and how various RavenDB features are triggered by Counters, +and how the various features handle Counter values. + +* In the **Triggered By** column: + * _Document Change_ - Feature is triggered by a Counter Name update. + * _Countrer Value Modification_ - Feature is triggered by a Counter Value modification. + * _Time Schedule_ - Feature is invoked by a pre-set time routine. + * _No Trigger_ - Feature is executed manually, through the Studio or by a Client. +* In the **Counter Value** column: + * _Accumulated_ - Counter Value is handled as a single accumulated sum. + * _Distributed_ - Counter Value is handled as a series of values maintained by cluster nodes. + +| **Feature** | **Triggered by** | **Counter Value** | +|-------------|:-------------|:-------------| +| [Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) | _Document Change_ | doesn't handle values | +| [LINQ Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | _Accumulated_ | +| [Raw Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | `counter()` - _Accumulated_
`counterRaw()` - _Distributed_ | +| [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) | _No trigger_ | _Distributed_ | +| [Backup Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Time Schedule_ | _Distributed_ | +| [RavenDB ETL Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [External Replication task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [Data Subscriptions Update Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_ | | +| [Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) | _Countrer Value Modification_ | _Accumulated_ | +| [Revision creation](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) | _Document Change_ | _Accumulated_ | + +{NOTE/} + +--- + +###Including Counters +You can [include](../../client-api/how-to/handle-document-relationships#includes) Counters while loading a document. +An included Counter is retrieved in the same request as its owner-document and is held by the session, +so it can be immediately retrieved when needed with no additional remote calls. + + +* **Including Counters when using [Session.Load](../../client-api/session/loading-entities#session--loading-entities)**: + * Include a single Counter using `IncludeCounter`. + * Include multiple Counters using `IncludeCounters`. + + `IncludeCounter` and `IncludeCounters` usage samples: + {CODE-TABS} + {CODE-TAB:csharp:IncludeCounter counters_region_load_include1@DocumentExtensions\Counters\Counters.cs /} + {CODE-TAB:csharp:IncludeCounters counters_region_load_include2@DocumentExtensions\Counters\Counters.cs /} + {CODE-TABS/} + +* **Including Counters when using [Session.Query](../../client-api/session/querying/how-to-query#session.query)**: + * Include a single Counter using `IncludeCounter`. + * Include multiple Counters using `IncludeCounters`. + + `IncludeCounter` and `IncludeCounters` usage samples: + {CODE-TABS} + {CODE-TAB:csharp:IncludeCounter counters_region_query_include_single_Counter@DocumentExtensions\Counters\Counters.cs /} + {CODE-TAB:csharp:IncludeCounters counters_region_query_include_multiple_Counters@DocumentExtensions\Counters\Counters.cs /} + {CODE-TABS/} + +--- + +###Counters Bulk-Insert +`store.BulkInsert` is RavenDB's high-performance data insertion operation. +Use its `CountersFor` interface's `Increment` method to add or update counters with great speed. + +* Syntax + + * `CountersFor` + {CODE CountersFor-definition@DocumentExtensions\Counters\BulkInsert.cs /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | `id` | `string` | Document ID | + + * `Increment` + {CODE Increment-definition@DocumentExtensions\Counters\BulkInsert.cs /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | `name` | `string` | Counter Name | + | `delta` | `long` | Default: 1L | + +* Usage Flow + + * Create a `store.BulkInsert` instance. + * Pass the instance's `CountersFor` interface, the document ID + * Call `Increment` as many times as you like. Pass it - + The Counter Name and Value (delta to be added). + +* Usage Sample + In this sample, we attach a counter to all User documents. + {CODE bulk-insert-counters@DocumentExtensions\Counters\BulkInsert.cs /} + + +{PANEL/} + +## Related articles +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.java.markdown new file mode 100644 index 0000000000..080871d2c8 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.java.markdown @@ -0,0 +1,257 @@ +# Counters And Other Features +--- + +{NOTE: } + +* This section describes the relationships between Counters and other RavenDB features: + * How Counters are supported by the different features. + * How Counters trigger features' execution. + +* In this page: + * [Counters and Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) + * [Counters and Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) + * [Counters and Revisions](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) + * [Counters and Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) + * [Counters and Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) + * [Counters and Ongoing Tasks](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) - `Backup`, `External replication`, `ETL`, `Data Subscription` + * [Counters and Other Features: summary](../../document-extensions/counters/counters-and-other-features#counters-and-other-features-summary) + * [Including Counters](../../document-extensions/counters/counters-and-other-features#including-counters) + * [Counters Bulk-Insert](../../document-extensions/counters/counters-and-other-features#counters-bulk-insert) +{NOTE/} + +--- + +{PANEL: } + +### Counters and Indexing + +Indexing Counters can speed-up finding them and the documents that contain them. + +* **Indexing Counter Values** + Dynamic indexes (aka auto-indexes) _cannot_ index counter values. To index counter values, + create a static index that inherits from `AbstractCountersIndexCreationTask`. + +* **Indexing Counter Names** + Re-indexing due to Counter-name modification is normally rare enough to pause no performance issues. + To index a document's Counters by name, use `counterNamesFor`. + +--- + +###Counters and Queries + +Create queries **using code**, or send the server **raw queries** for execution. + +* Either way, you can query Counters **by name** but **not by value**. + This is because queries are generally [based on indexes](../../start/getting-started#example-iii---querying), and Counter values are [not indexed](../../document-extensions/counters/counters-and-other-features#counters-and-indexing). +* Counter values **can** be projected from query results, as demonstrated in the following examples. + This way a client can get Counter values from a query without downloading whole documents. + +* Use `Session.Query` to code queries yourself. + * **Returned Counter Value**: **Accumulated** + A Counter's value is returned as a single sum, with no specification of the Counter's value on each node. + {CODE counters_region_query@DocumentExtensions\Counters\Counters.cs /} + +* Use `rawQuery` to send the server raw RQL expressions for execution. + * You can use the `counter` method. + **Returned Counter Value**: **Accumulated** + + * You can use the `counterRaw` method. + **Returned Counter Value**: **Distributed** + A Counter's value is returned as a series of values, each maintained by one of the nodes. + * It is not expected of you to use this in your application. + Applications normally use the Counter's overall value, and very rarely refer to the value each node gives it. + + + `counter` and `counterRaw` samples: + {CODE-TABS} + {CODE-TAB:java:counter counters_region_rawqueries_counter@DocumentExtensions\Counters\Counters.java /} + {CODE-TAB:java:counterRaw counters_region_rawqueries_counterRaw@DocumentExtensions\Counters\Counters.java /} + {CODE-TABS/} + +--- + +###Counters and Revisions + +A [document revision](../../document-extensions/revisions/overview) stores all the document Counters' +names and values when the revision was created. + +* **Stored Counter Values**: **Accumulated** + A revision stores a Counter's value as a single sum, with no specification of the Counter's value on each node. + +* Revisions-creation can be initiated by **Counter-name modification**. + * When the Revisions feature is enabled, the creation or deletion of a Counter initiates the creation of a new document revision. + * Counter **value** modifications do **not** cause the creation of new revisions. + +--- + +###Counters and Smuggler + +`Smuggler` is a DocumentStore property, that can be used +to **export** chosen database items to an external file or to +**import** database items from an existing file into the database. + +* **Transferred Counter Value**: **Distributed** + Smuggler transfers the entire series of values that the different nodes maintain for a Counter. +* To make Smuggler handle Counters, include `DatabaseItemType.COUNTERS` in `OperateOnTypes`'s list of entities to import or export. + {CODE:java smuggler_options@DocumentExtensions\Counters\Counters.java /} + +--- + +###Counters and Changes API + +[Changes API](../../client-api/changes/what-is-changes-api#changes-api) is a Push service, that can inform you of various changes on the Server, including [changes in Counter values](../../client-api/changes/how-to-subscribe-to-counter-changes#changes-api--how-to-subscribe-to-counter-changes). +You can target all Counters, or specify the ones you wish to follow. + +* **Pushed Counter Value**: **Accumulated** + `Changes API` methods return a Counter's value as a single sum, without specifying its value on each node. +* The service is initiated by **Counter Value Modification**. + +--- + +###Counters and Ongoing Tasks: + +Each [ongoing task](../../studio/database/tasks/ongoing-tasks/general-info) relates to Counters in its own way. + +* **Counters** and the **Backup task** + There are two backup types: **logical-backup** and **snapshot**. + Both types store and restore **all** data, including Counters. + Both types operate as an ongoing backup routine, with a pre-set time schedule. + * Logical Backup: + **Backed-up Counter values**: **Distributed** + A logical backup is a higher-level implementation of [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler). + As with Smuggler, Counters are backed-up and restored including their values on all nodes. + * Snapshot: + A snapshot stores all data and settings as a single binary image. + All components, including Counters, are restored to the exact same state they've been at during backup. + +* **Counters** and the **External Replication task** + The ongoing [external replication](../../studio/database/tasks/ongoing-tasks/external-replication-task) task replicates all data, including Counters. + * **Replicated Counter Value**: **Distributed** + Counters are replicated along with their values on all nodes. + * Replication can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + +* **Counters** and the **ETL task** + [ETL](../../server/ongoing-tasks/etl/basics) is used to export data from RavenDB to an external (either Raven or SQL) database. + * [SQL ETL](../../server/ongoing-tasks/etl/sql) is **not supported**. + Counters cannot be exported to an SQL database over SQL ETL. + * [RavenDB ETL](../../server/ongoing-tasks/etl/raven) **is supported**. + Counters [are](../../server/ongoing-tasks/etl/raven#counters) exported over RavenDB ETL. + * Export can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + * **Exported Counter Value**: **Distributed** + Counters are exported along with their values on all nodes. + * Counters can be [exported using a script](../../server/ongoing-tasks/etl/raven#adding-counter-explicitly-in-a-script). + **Default behavior**: When an ETL script is not provided, Counters are exported. + +* **Counters** and the **[Data Subscriptions](../../client-api/data-subscriptions/what-are-data-subscriptions#data-subscriptions) task** + Data Subscriptions can be initiated by document changes, including those caused by **Counter Name updates**. + Documents will **not** be delivered in reaction to Counter Value modification. + + +{NOTE: } +###Counters and Other Features: Summary + +Use this table to find if and how various RavenDB features are triggered by Counters, +and how the various features handle Counter values. + +* In the **Triggered By** column: + * _Document Change_ - Feature is triggered by a Counter Name update. + * _Countrer Value Modification_ - Feature is triggered by a Counter Value modification. + * _Time Schedule_ - Feature is invoked by a pre-set time routine. + * _No Trigger_ - Feature is executed manually, through the Studio or by a Client. +* In the **Counter Value** column: + * _Accumulated_ - Counter Value is handled as a single accumulated sum. + * _Distributed_ - Counter Value is handled as a series of values maintained by cluster nodes. + +| **Feature** | **Triggered by** | **Counter Value** | +|-------------|:-------------|:-------------| +| [Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) | _Document Change_ | doesn't handle values | +| [Raw Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | `counter()` - _Accumulated_
`counterRaw()` - _Distributed_ | +| [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) | _No trigger_ | _Distributed_ | +| [Backup Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Time Schedule_ | _Distributed_ | +| [RavenDB ETL Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [External Replication task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [Data Subscriptions Update Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_ | | +| [Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) | _Countrer Value Modification_ | _Accumulated_ | +| [Revision creation](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) | _Document Change_ | _Accumulated_ | + +{NOTE/} + +--- + +###Including Counters +You can `include` Counters while loading a document. +An included Counter is retrieved in the same request as its owner-document and is +held by the session, so it can be immediately retrieved when needed with no additional +remote calls. + +* **Including Counters when using `Session.load`**: + * Include a single Counter using `includeCounter`. + * Include multiple Counters using `includeCounters`. + + `includeCounter` and `includeCounters` usage samples: + {CODE-TABS} + {CODE-TAB:java:IncludeCounter counters_region_load_include1@DocumentExtensions\Counters\Counters.java /} + {CODE-TAB:java:IncludeCounters counters_region_load_include2@DocumentExtensions\Counters\Counters.java /} + {CODE-TABS/} + +* **Including Counters when using `Session.query`**: + * Include a single Counter using `includeCounter`. + * Include multiple Counters using `includeCounters`. + + `includeCounter` and `includeCounters` usage samples: + {CODE-TABS} + {CODE-TAB:java:IncludeCounter counters_region_query_include_single_Counter@DocumentExtensions\Counters\Counters.java /} + {CODE-TAB:java:IncludeCounters counters_region_query_include_multiple_Counters@DocumentExtensions\Counters\Counters.java /} + {CODE-TABS/} + + --- + +###Counters Bulk-Insert +`store.bulkInsert` is RavenDB's high-performance data insertion operation. +Use its `countersFor` interface's `increment` method to add or update counters with great speed. + +* Syntax + + * `countersFor` + {CODE:java CountersFor-definition@DocumentExtensions\Counters\Counters.java /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | `id` | `String` | Document ID | + + * `increment` + {CODE:java Increment-definition@DocumentExtensions\Counters\Counters.java /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | `name` | `String` | Counter Name | + | `id` | `String` | Document ID | + | `delta` | `long` | Default: 1L | + +* Usage Flow + + * Create a `store.bulkInsert` instance. + * Pass the instance's `countersFor` interface, the document ID + * Call `increment` as many times as you like. Pass it - + The Counter Name and Value (delta to be added). + +* Usage Sample + In this sample, we attach a counter to all User documents. + {CODE:java bulk-insert-counters@DocumentExtensions\Counters\Counters.java /} + + +{PANEL/} + +## Related articles +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.js.markdown new file mode 100644 index 0000000000..74bdf0dc96 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.js.markdown @@ -0,0 +1,277 @@ +# Counters and Other Features +--- + +{NOTE: } + +* This section describes the relationships between Counters and other RavenDB features: + * How Counters are supported by the different features. + * How Counters trigger features' execution. + +* In this page: + * [Counters and Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) + * [Counters and Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) + * [Counters and Revisions](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) + * [Counters and Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) + * [Counters and Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) + * [Counters and Ongoing Tasks](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) - `Backup`, `External replication`, `ETL`, `Data Subscription` + * [Counters and Other Features: summary](../../document-extensions/counters/counters-and-other-features#counters-and-other-features-summary) + * [Including Counters](../../document-extensions/counters/counters-and-other-features#including-counters) + * [Counters Bulk-Insert](../../document-extensions/counters/counters-and-other-features#counters-bulk-insert) +{NOTE/} + +--- + +{PANEL: } + +### Counters and Indexing + +Indexing Counters can speed-up finding them and the documents that contain them. + +* **Indexing Counter Values** + Dynamic indexes (aka auto-indexes) _cannot_ index counter values. To index counter values, + create a static index that inherits from `AbstractCountersIndexCreationTask` ([see here](../../document-extensions/counters/indexing)). + +* **Indexing Counter Names** + Re-indexing due to Counter-name modification is normally rare enough to pause no performance issues. + To index a document's Counters by name, use [CounterNamesFor](../../document-extensions/counters/indexing#section-1). + +--- + +###Counters and Queries + +Create queries **using code**, or send the server **raw queries** for execution. + +* Either way, you can query Counters **by name** but **not by value**. + This is because queries are generally [based on indexes](../../start/getting-started#example-iii---querying), and Counter values are [not indexed](../../document-extensions/counters/counters-and-other-features#counters-and-indexing). +* Counter values **can** be [projected](../../indexes/querying/projections) from query results, as demonstrated in the following examples. + This way a client can get Counter values from a query without downloading whole documents. + +* Use [Session.Query](../../client-api/session/querying/how-to-query#session.query) to code queries yourself. + * **Returned Counter Value**: **Accumulated** + A Counter's value is returned as a single sum, with no specification of the Counter's value on each node. + {CODE:nodejs counters_region_query@DocumentExtensions\counters\counters.js /} + +* Use [RawQuery](../../client-api/session/querying/how-to-query#session.advanced.rawquery) to send the server raw RQL expressions for execution. + * You can use the `counter` method. + **Returned Counter Value**: **Accumulated** + + * You can use the `counterRaw` method. + **Returned Counter Value**: **Distributed** + A Counter's value is returned as a series of values, each maintained by one of the nodes. + * It is not expected of you to use this in your application. + Applications normally use the Counter's overall value, and very rarely refer to the value each node gives it. + + + `counter` and `counterRaw` samples: + {CODE-TABS} + {CODE-TAB:nodejs:counter counters_region_rawqueries_counter@DocumentExtensions\counters\counters.js /} + {CODE-TAB:nodejs:counterRaw counters_region_rawqueries_counterRaw@DocumentExtensions\counters\counters.js /} + {CODE-TABS/} + +--- + +###Counters and Revisions + +A [document revision](../../document-extensions/revisions/overview) stores all the document Counters' +names and values when the revision was created. + +* **Stored Counter Values**: **Accumulated** + A revision stores a Counter's value as a single sum, with no specification of the Counter's value on each node. + +* Revisions-creation can be initiated by **Counter-name modification**. + * When the Revisions feature is enabled, the creation or deletion of a Counter initiates the creation of a new document revision. + * Counter **value** modifications do **not** cause the creation of new revisions. + +--- + +###Counters and Smuggler + +[Smuggler](../../client-api/smuggler/what-is-smuggler) is a DocumentStore property, that can be used +to [export](../../client-api/smuggler/what-is-smuggler#databasesmugglerexportoptions) chosen +database items to an external file or to [import](../../client-api/smuggler/what-is-smuggler#databasesmugglerimportoptions) +database items from an existing file into the database. + +* **Transferred Counter Value**: **Distributed** + Smuggler transfers the entire series of values that the different nodes maintain for a Counter. +* To make Smuggler handle Counters, use `DatabaseItemType` entities to import or export. + +`DatabaseItemType` options: +* `None` +* `Documents` +* `RevisionDocuments` +* `Indexes` +* `Identities` +* `Tombstones` +* `LegacyAttachments` +* `Conflicts` +* `CompareExchange` +* `LegacyDocumentDeletions` +* `LegacyAttachmentDeletions` +* `DatabaseRecord` +* `Unknown` +* `Attachments` +* `CounterGroups` +* `Subscriptions` +* `CompareExchangeTombstones` +* `TimeSeries` + +--- + +###Counters and Changes API + +[Changes API](../../client-api/changes/what-is-changes-api#changes-api) is a Push service, that can inform you of various changes on the Server, including [changes in Counter values](../../client-api/changes/how-to-subscribe-to-counter-changes#changes-api--how-to-subscribe-to-counter-changes). +You can target all Counters, or specify the ones you wish to follow. + +* **Pushed Counter Value**: **Accumulated** + `Changes API` methods return a Counter's value as a single sum, without specifying its value on each node. +* The service is initiated by **Counter Value Modification**. + +--- + +###Counters and Ongoing Tasks: + +Each [ongoing task](../../studio/database/tasks/ongoing-tasks/general-info) relates to Counters in its own way. + +* **Counters** and the **Backup task** + There are two [backup](../../studio/database/tasks/backup-task) types: **logical-backup** and **snapshot**. + Both types store and restore **all** data, including Counters. + Both types operate as an ongoing backup routine, with a pre-set time schedule. + * Logical Backup: + **Backed-up Counter values**: **Distributed** + A logical backup is a higher-level implementation of [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler). + As with Smuggler, Counters are backed-up and restored including their values on all nodes. + * Snapshot: + A snapshot stores all data and settings as a single binary image. + All components, including Counters, are restored to the exact same state they've been at during backup. + +* **Counters** and the **External Replication task** + The ongoing [external replication](../../studio/database/tasks/ongoing-tasks/external-replication-task) task replicates all data, including Counters. + * **Replicated Counter Value**: **Distributed** + Counters are replicated along with their values on all nodes. + * Replication can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + +* **Counters** and the **ETL task** + [ETL](../../server/ongoing-tasks/etl/basics) is used to export data from RavenDB to an external (either Raven or SQL) database. + * [SQL ETL](../../server/ongoing-tasks/etl/sql) is **not supported**. + Counters cannot be exported to an SQL database over SQL ETL. + * [RavenDB ETL](../../server/ongoing-tasks/etl/raven) **is supported**. + Counters [are](../../server/ongoing-tasks/etl/raven#counters) exported over RavenDB ETL. + * Export can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + * **Exported Counter Value**: **Distributed** + Counters are exported along with their values on all nodes. + * Counters can be [exported using a script](../../server/ongoing-tasks/etl/raven#adding-counter-explicitly-in-a-script). + **Default behavior**: When an ETL script is not provided, Counters are exported. + +* **Counters** and the **[Data Subscriptions](../../client-api/data-subscriptions/what-are-data-subscriptions#data-subscriptions) task** + Data Subscriptions can be initiated by document changes, including those caused by **Counter Name updates**. + Documents will **not** be delivered in reaction to Counter Value modification. + + +{NOTE: } +###Counters and Other Features: Summary + +Use this table to find if and how various RavenDB features are triggered by Counters, +and how the various features handle Counter values. + +* In the **Triggered By** column: + * _Document Change_ - Feature is triggered by a Counter Name update. + * _Countrer Value Modification_ - Feature is triggered by a Counter Value modification. + * _Time Schedule_ - Feature is invoked by a pre-set time routine. + * _No Trigger_ - Feature is executed manually, through the Studio or by a Client. +* In the **Counter Value** column: + * _Accumulated_ - Counter Value is handled as a single accumulated sum. + * _Distributed_ - Counter Value is handled as a series of values maintained by cluster nodes. + +| **Feature** | **Triggered by** | **Counter Value** | +|-------------|:-------------|:-------------| +| [Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) | _Document Change_ | doesn't handle values | +| [LINQ Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | _Accumulated_ | +| [Raw Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | `counter()` - _Accumulated_
`counterRaw()` - _Distributed_ | +| [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) | _No trigger_ | _Distributed_ | +| [Backup Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Time Schedule_ | _Distributed_ | +| [RavenDB ETL Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [External Replication task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [Data Subscriptions Update Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_ | | +| [Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) | _Countrer Value Modification_ | _Accumulated_ | +| [Revision creation](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) | _Document Change_ | _Accumulated_ | + +{NOTE/} + +--- + +###Including Counters +You can [include](../../client-api/how-to/handle-document-relationships#includes) Counters while loading a document. +An included Counter is retrieved in the same request as its owner-document and is held by the session, +so it can be immediately retrieved when needed with no additional remote calls. + + +* **Including Counters when using [Session.Load](../../client-api/session/loading-entities#session--loading-entities)**: + * Include a single Counter using `IncludeCounter`. + * Include multiple Counters using `IncludeCounters`. + + `IncludeCounter` and `IncludeCounters` usage samples: + {CODE-TABS} + {CODE-TAB:nodejs:IncludeCounter counters_region_load_include1@DocumentExtensions\counters\counters.js /} + {CODE-TAB:nodejs:IncludeCounters counters_region_load_include2@DocumentExtensions\counters\counters.js /} + {CODE-TABS/} + +* **Including Counters when using [Session.Query](../../client-api/session/querying/how-to-query#session.query)**: + * Include a single Counter using `IncludeCounter`. + * Include multiple Counters using `IncludeCounters`. + + `IncludeCounter` and `IncludeCounters` usage samples: + {CODE-TABS} + {CODE-TAB:nodejs:IncludeCounter counters_region_query_include_single_Counter@DocumentExtensions\counters\counters.js /} + {CODE-TAB:nodejs:IncludeCounters counters_region_query_include_multiple_Counters@DocumentExtensions\counters\counters.js /} + {CODE-TABS/} + +--- + +###Counters Bulk-Insert +`store.BulkInsert` is RavenDB's high-performance data insertion operation. +Use its `CountersFor` interface's `Increment` method to add or update counters with great speed. + +* Usage + + * `countersFor` + {CODE:nodejs CountersFor-definition@DocumentExtensions\counters\counters.js /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | `id` | `string` | Document ID | + + * `increment` + {CODE:nodejs Increment-definition@DocumentExtensions\counters\counters.js /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | `name` | `string` | Counter Name | + | `delta` | `long` | Default: 1L | + +* Usage Flow + + * Create a `store.BulkInsert` instance. + * Pass the instance's `CountersFor` interface, the document ID + * Call `Increment` as many times as you like. Pass it - + The Counter Name and Value (delta to be added). + +* Usage Sample + In this sample, we attach a counter to all User documents. + {CODE:nodejs bulk-insert-counters@DocumentExtensions\counters\counters.js /} + + +{PANEL/} + +## Related articles +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.python.markdown new file mode 100644 index 0000000000..415502c0f5 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.python.markdown @@ -0,0 +1,244 @@ +# Counters and Other Features +--- + +{NOTE: } + +* This section describes the relationships between Counters and other RavenDB features: + * How Counters are supported by the different features. + * How Counters trigger features' execution. + +* In this page: + * [Counters and Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) + * [Counters and Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) + * [Counters and Revisions](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) + * [Counters and Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) + * [Counters and Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) + * [Counters and Ongoing Tasks](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) - `Backup`, `External replication`, `ETL`, `Data Subscription` + * [Counters and Other Features: summary](../../document-extensions/counters/counters-and-other-features#counters-and-other-features-summary) + * [Including Counters](../../document-extensions/counters/counters-and-other-features#including-counters) + * [Counters Bulk-Insert](../../document-extensions/counters/counters-and-other-features#counters-bulk-insert) +{NOTE/} + +--- + +{PANEL: } + +### Counters and Indexing + +Indexing Counters can speed-up finding them and the documents that contain them. + +* **Indexing Counter Values** + Dynamic indexes (aka auto-indexes) _cannot_ index counter values. To index counter values, + create a static index that inherits from `AbstractCountersIndexCreationTask` ([see here](../../document-extensions/counters/indexing)). + +* **Indexing Counter Names** + Re-indexing due to Counter-name modification is normally rare enough to pause no performance issues. + To index a document's Counters by name, use [CounterNamesFor](../../document-extensions/counters/indexing#section-1). + +--- + +###Counters and Queries + +Create queries **using code**, or send the server **raw queries** for execution. + +* Either way, you can query Counters **by name** but **not by value**. + This is because queries are generally [based on indexes](../../start/getting-started#example-iii---querying), and Counter values are [not indexed](../../document-extensions/counters/counters-and-other-features#counters-and-indexing). +* Counter values **can** be [projected](../../indexes/querying/projections) from query results, as demonstrated in the following examples. + This way a client can get Counter values from a query without downloading whole documents. + +* Use [session.query](../../client-api/session/querying/how-to-query#session.query) to code queries yourself. + * **Returned Counter Value**: **Accumulated** + A Counter's value is returned as a single sum, with no specification of the Counter's value on each node. + {CODE:python counters_region_query@DocumentExtensions\Counters\Counters.py /} + +* Use [RawQuery](../../client-api/session/querying/how-to-query#session.advanced.rawquery) to send the server raw RQL expressions for execution. + * You can use the `counter` method. + **Returned Counter Value**: **Accumulated** + + * You can use the `counterRaw` method. + **Returned Counter Value**: **Distributed** + A Counter's value is returned as a series of values, each maintained by one of the nodes. + * It is not expected of you to use this in your application. + Applications normally use the Counter's overall value, and very rarely refer to the value each node gives it. + + + `counter` and `counterRaw` samples: + {CODE-TABS} + {CODE-TAB:python:counter counters_region_rawqueries_counter@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:counterRaw counters_region_rawqueries_counterRaw@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +--- + +###Counters and Revisions + +A [document revision](../../document-extensions/revisions/overview) stores all the document Counters' +names and values when the revision was created. + +* **Stored Counter Values**: **Accumulated** + A revision stores a Counter's value as a single sum, with no specification of the Counter's value on each node. + +* Revisions-creation can be initiated by **Counter-name modification**. + * When the Revisions feature is enabled, the creation or deletion of a Counter initiates the creation of a new document revision. + * Counter **value** modifications do **not** cause the creation of new revisions. + +--- + +###Counters and Changes API + +[Changes API](../../client-api/changes/what-is-changes-api#changes-api) is a Push service, that can inform you of various changes on the Server, including [changes in Counter values](../../client-api/changes/how-to-subscribe-to-counter-changes#changes-api--how-to-subscribe-to-counter-changes). +You can target all Counters, or specify the ones you wish to follow. + +* **Pushed Counter Value**: **Accumulated** + `Changes API` methods return a Counter's value as a single sum, without specifying its value on each node. +* The service is initiated by **Counter Value Modification**. + +--- + +###Counters and Ongoing Tasks: + +Each [ongoing task](../../studio/database/tasks/ongoing-tasks/general-info) relates to Counters in its own way. + +* **Counters** and the **Backup task** + There are two [backup](../../studio/database/tasks/backup-task) types: **logical-backup** and **snapshot**. + Both types store and restore **all** data, including Counters. + Both types operate as an ongoing backup routine, with a pre-set time schedule. + * Logical Backup: + **Backed-up Counter values**: **Distributed** + A logical backup is a higher-level implementation of [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler). + As with Smuggler, Counters are backed-up and restored including their values on all nodes. + * Snapshot: + A snapshot stores all data and settings as a single binary image. + All components, including Counters, are restored to the exact same state they've been at during backup. + +* **Counters** and the **External Replication task** + The ongoing [external replication](../../studio/database/tasks/ongoing-tasks/external-replication-task) task replicates all data, including Counters. + * **Replicated Counter Value**: **Distributed** + Counters are replicated along with their values on all nodes. + * Replication can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + +* **Counters** and the **ETL task** + [ETL](../../server/ongoing-tasks/etl/basics) is used to export data from RavenDB to an external (either Raven or SQL) database. + * [SQL ETL](../../server/ongoing-tasks/etl/sql) is **not supported**. + Counters cannot be exported to an SQL database over SQL ETL. + * [RavenDB ETL](../../server/ongoing-tasks/etl/raven) **is supported**. + Counters [are](../../server/ongoing-tasks/etl/raven#counters) exported over RavenDB ETL. + * Export can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + * **Exported Counter Value**: **Distributed** + Counters are exported along with their values on all nodes. + * Counters can be [exported using a script](../../server/ongoing-tasks/etl/raven#adding-counter-explicitly-in-a-script). + **Default behavior**: When an ETL script is not provided, Counters are exported. + +* **Counters** and the **[Data Subscriptions](../../client-api/data-subscriptions/what-are-data-subscriptions#data-subscriptions) task** + Data Subscriptions can be initiated by document changes, including those caused by **Counter Name updates**. + Documents will **not** be delivered in reaction to Counter Value modification. + + +{NOTE: } +###Counters and Other Features: Summary + +Use this table to find if and how various RavenDB features are triggered by Counters, +and how the various features handle Counter values. + +* In the **Triggered By** column: + * _Document Change_ - Feature is triggered by a Counter Name update. + * _Countrer Value Modification_ - Feature is triggered by a Counter Value modification. + * _Time Schedule_ - Feature is invoked by a pre-set time routine. + * _No Trigger_ - Feature is executed manually, through the Studio or by a Client. +* In the **Counter Value** column: + * _Accumulated_ - Counter Value is handled as a single accumulated sum. + * _Distributed_ - Counter Value is handled as a series of values maintained by cluster nodes. + +| **Feature** | **Triggered by** | **Counter Value** | +|-------------|:-------------|:-------------| +| [Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) | _Document Change_ | doesn't handle values | +| [LINQ Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | _Accumulated_ | +| [Raw Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | `counter()` - _Accumulated_
`counterRaw()` - _Distributed_ | +| [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) | _No trigger_ | _Distributed_ | +| [Backup Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Time Schedule_ | _Distributed_ | +| [RavenDB ETL Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [External Replication task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [Data Subscriptions Update Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_ | | +| [Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) | _Countrer Value Modification_ | _Accumulated_ | +| [Revision creation](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) | _Document Change_ | _Accumulated_ | + +{NOTE/} + +--- + +###Including Counters +You can [include](../../client-api/how-to/handle-document-relationships#includes) Counters while loading a document. +An included Counter is retrieved in the same request as its owner-document and is held by the session, +so it can be immediately retrieved when needed with no additional remote calls. + + +* **Including Counters when using [session.load](../../client-api/session/loading-entities#session--loading-entities)**: + * Include a single Counter using `include_counter` + * Include multiple Counters using `include_counters` + + `include_counter` and `include_counters` usage samples: + {CODE-TABS} + {CODE-TAB:python:IncludeCounter counters_region_load_include1@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:IncludeCounters counters_region_load_include2@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +* **Including Counters when using [Session.Query](../../client-api/session/querying/how-to-query#session--querying--how-to-query)**: + * Include a single Counter using `include_counter`. + * Include multiple Counters using `include_counters`. + + `include_counter` and `include_counters` usage samples: + {CODE-TABS} + {CODE-TAB:python:IncludeCounter counters_region_query_include_single_Counter@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:IncludeCounters counters_region_query_include_multiple_Counters@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +--- + +###Counters Bulk-Insert +`store.bulk_insert` is RavenDB's high-performance data insertion operation. +Use its `counters_for` interface's `increment` method to add or update counters with great speed. + +* Syntax + + * `counters_for` + {CODE:python CountersFor-definition@DocumentExtensions\Counters\BulkInsert.py /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | **id** | `str` | Document ID | + + * `Increment` + {CODE:python Increment-definition@DocumentExtensions\Counters\BulkInsert.py /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | **name** | `str` | Counter Name | + | **delta** | `int` | Default: 1L | + +* Usage Flow + + * Create a `store.bulk_insert` instance. + * Pass the instance's `counters_for` interface, the document ID + * Call `increment` as many times as you like. Pass it - + The Counter Name and Value (delta to be added). + +* Usage Sample + In this sample, we attach a counter to all User documents. + {CODE:python bulk-insert-counters@DocumentExtensions\Counters\BulkInsert.py /} + + +{PANEL/} + +## Related articles +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.dotnet.markdown index 894e373fb3..a1957ea657 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.dotnet.markdown @@ -21,7 +21,7 @@ {PANEL: `Increment` usage} - __Flow__: + **Flow**: * Open a session. * Create an instance of `CountersFor`. @@ -31,10 +31,10 @@ * Call `CountersFor.Increment`. * Call `session.SaveChanges` for the changes to take effect. -__Note__: +**Note**: * Modifying a Counter using `Increment` only takes effect when `session.SaveChanges()` is executed. -* To __decrease__ a Counter's value, pass the method a negative number to the `Increment` method. +* To **decrease** a Counter's value, pass the method a negative number to the `Increment` method. {PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.java.markdown index 3d3aebf566..816df9b115 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.java.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.java.markdown @@ -21,7 +21,7 @@ {PANEL: `increment` usage} -__Flow__: +**Flow**: * Open a session. * Create an instance of `countersFor`. @@ -30,10 +30,10 @@ __Flow__: * Call `countersFor.increment`. * Call `session.saveChanges` for the changes to take effect. -__Note__: +**Note**: * Modifying a Counter using `increment` only takes effect when `session.saveChanges()` is executed. -* To __decrease__ a Counter's value, pass the method a negative number to the `increment` method. +* To **decrease** a Counter's value, pass the method a negative number to the `increment` method. {PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.js.markdown index fdcb7786b3..b21d557cf7 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.js.markdown @@ -21,7 +21,7 @@ {PANEL: `Increment` usage} - __Flow__: + **Flow**: * Open a session. * Create an instance of `countersFor`. @@ -31,10 +31,10 @@ * Call `countersFor.increment`. * Call `session.saveChanges` for the changes to take effect. -__Note__: +**Note**: * Modifying a Counter using `increment` only takes effect when `session.saveChanges()` is executed. -* To __decrease__ a Counter's value, pass the method a negative number to the `increment` method. +* To **decrease** a Counter's value, pass the method a negative number to the `increment` method. {PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.python.markdown new file mode 100644 index 0000000000..775220e0a0 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/create-or-modify.python.markdown @@ -0,0 +1,71 @@ +# Create or Modify Counters +--- + +{NOTE: } + +* Use the `counters_for .increment` method to **create** a new Counter or **modify** an existing Counter's value. + +* If the Counter exists, `increment` will add the specified number to the Counter's current value. + If the Counter doesn't exist, `increment` will create it and set its initial value. + +* For all other `counters_for ` methods see this [Overview](../../document-extensions/counters/overview#counter-methods-and-the--object). + +* In this page: + - [`increment` usage](../../document-extensions/counters/create-or-modify#increment-usage) + - [Example](../../document-extensions/counters/create-or-modify#example) + - [Syntax](../../document-extensions/counters/create-or-modify#syntax) + +{NOTE/} + +--- + +{PANEL: `increment` usage} + + **Flow**: + +* Open a session. +* Create an instance of `counters_for `. + * Either pass `counters_for ` an explicit document ID, -or- + * Pass it an [entity tracked by the session](../../client-api/session/loading-entities), + e.g. a document object returned from [session.Query](../../client-api/session/querying/how-to-query) or from [session.Load](../../client-api/session/loading-entities#load). +* Call `counters_for .increment`. +* Call `session.save_changes` for the changes to take effect. + +**Note**: + +* Modifying a Counter using `increment` only takes effect when `session.aave_changes()` is executed. +* To **decrease** a Counter's value, pass the method a negative number to the `increment` method. + +{PANEL/} + +{PANEL: Example} + +{CODE:python counters_region_Increment@DocumentExtensions\Counters\Counters.py /} + +{PANEL/} + +{PANEL: Syntax} + +{CODE:python Increment-definition@DocumentExtensions\Counters\Counters.py /} + +| Parameter | Type | Description | +|------------------|-------|-----------------| +| **counter_name** | `str` | Counter's name | +| **delta** | `int` | Increase Counter by this value.
Default value is 1.
For a new Counter, this number will be its initial value. | + +{PANEL/} + +## Related articles + +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters and other features](../../document-extensions/counters/counters-and-other-features) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.dotnet.markdown index fe779476c4..f49b600348 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.dotnet.markdown @@ -20,7 +20,7 @@ {PANEL: `Delete ` usage} -__Flow__: +**Flow**: * Open a session. * Create an instance of `CountersFor`. @@ -30,7 +30,7 @@ __Flow__: * Call `CountersFor.Delete`. * Call `session.SaveChanges` for the changes to take effect. -__Note__: +**Note**: * A Counter you deleted will be removed only after the execution of `SaveChanges()`. * `Delete` will **not** generate an error if the Counter doesn't exist. diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.java.markdown index 174b7113f5..4bc4fb91e9 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.java.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.java.markdown @@ -20,7 +20,7 @@ {PANEL: `delete ` usage} -__Flow__: +**Flow**: * Open a session. * Create an instance of `countersFor`. @@ -29,7 +29,7 @@ __Flow__: * Call `countersFor.delete`. * Call `session.saveChanges` for the changes to take effect. -__Note__: +**Note**: * A Counter you deleted will be removed only after the execution of `saveChanges()`. * `delete` will **not** generate an error if the Counter doesn't exist. diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.js.markdown index c81e7e7c77..64115dcb16 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.js.markdown @@ -20,7 +20,7 @@ {PANEL: `delete ` usage} -__Flow__: +**Flow**: * Open a session. * Create an instance of `countersFor`. @@ -30,7 +30,7 @@ __Flow__: * Call `countersFor.delete`. * Call `session.saveChanges` for the changes to take effect. -__Note__: +**Note**: * A Counter you deleted will be removed only after the execution of `saveChanges()`. * `delete` will **not** generate an error if the Counter doesn't exist. diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.python.markdown new file mode 100644 index 0000000000..a0213d9690 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/delete.python.markdown @@ -0,0 +1,64 @@ +# Delete Counter +--- + +{NOTE: } + +* Use the `counters_for.delete` method to remove a specific Counter from a document. + +* All the document's Counters are deleted when the document itself is deleted. + +* For all other `counters_for` methods see this [Overview](../../document-extensions/counters/overview#counter-methods-and-the--object). + +* In this page: + * [`delete ` usage](../../document-extensions/counters/delete#delete-usage) + * [Example](../../document-extensions/counters/delete#example) + * [Syntax](../../document-extensions/counters/delete#syntax) + +{NOTE/} + +--- + +{PANEL: `delete ` usage} + +**Flow**: + +* Open a session. +* Create an instance of `counters_for`. + * Either pass `counters_for` an explicit document ID, -or- + * Pass it an [entity tracked by the session](../../client-api/session/loading-entities), + e.g. a document object returned from [session.query](../../client-api/session/querying/how-to-query) or from [session.load](../../client-api/session/loading-entities#load). +* Call `document_counters.delete`. +* Call `ession.save_changes` for the changes to take effect. + +**Note**: + +* A Counter you deleted will be removed only after the execution of `save_changes()`. +* `delete` will **not** generate an error if the Counter doesn't exist. +* Deleting a document deletes all its Counters as well. + +{PANEL/} + +{PANEL: Syntax} + +{CODE:python Delete-definition@DocumentExtensions\Counters\Counters.py /} + +| Parameter | Type | Description | +|---------------|--------|----------------| +| **counter** | `str` | Counter name ([see example](../../document-extensions/counters/overview#managing-counters)) | + +{PANEL/} + +## Related articles + +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters and other features](../../document-extensions/counters/counters-and-other-features) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.dotnet.markdown new file mode 100644 index 0000000000..f759c11b43 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.dotnet.markdown @@ -0,0 +1,101 @@ +# Indexes: Indexing Counters +--- + +{NOTE: } + +* To index counters, create a [static index](../../indexes/creating-and-deploying#static-indexes) +that inherits from `AbstractCountersIndexCreationTask` or `AbstractJavaScriptCountersIndexCreationTask`. + +* Auto-indexes for counters are not available at this time. + +* In this page: + * [Syntax](../../document-extensions/counters/indexing#syntax) + * [AbstractJavaScriptCountersIndexCreationTask](../../document-extensions/counters/indexing#section) + * [CounterNamesFor](../../document-extensions/counters/indexing#section-1) + * [Querying the Index](../../document-extensions/counters/indexing#querying-the-index) + +{NOTE/} + +--- + +{PANEL:Syntax} + +In order to index counter values, create an index that inherits from `AbstractCountersIndexCreationTask`. +Next, choose one of these two methods which take the index expression: + +{CODE-BLOCK:csharp } +protected void AddMapForAll(Expression, IEnumerable>> map) + +protected void AddMap(string counter, Expression, IEnumerable>> map) +{CODE-BLOCK/} + +`AddMapForAll` indexes all the counters in the indexed documents. `AddMap` only indexes the counters with +the specified name. + +Examples of indexes using each method: + +{CODE-TABS} +{CODE-TAB:csharp:AddMap index_1@Indexes\IndexingCounters.cs /} +{CODE-TAB:csharp:AddMapForAll index_2@Indexes\IndexingCounters.cs /} +{CODE-TABS/} +
+ +--- + +### `AbstractJavaScriptCountersIndexCreationTask` + +Creating an index inheriting from `AbstractJavaScriptCountersIndexCreationTask` allows +you to write your map and reduce functions in JavaScript. +Learn more about JavaScript indexes [here](../../indexes/javascript-indexes). + +{CODE-BLOCK: csharp} +public class AbstractJavaScriptCountersIndexCreationTask : AbstractCountersIndexCreationTask +{ + public HashSet Maps; + protected string Reduce; +} +{CODE-BLOCK/} + +| Property | Type | Description | +| - | - | - | +| **Maps** | `HashSet` | The set of javascript map functions | +| **Reduce** | `string` | The javascript reduce function | + +Example: + +{CODE:csharp index_3@DocumentExtensions\Counters\IndexingCounters.cs /} + +--- + +### `CounterNamesFor` + +While indexes inheriting from `AbstractIndexCreationTask` cannot index counter _values_, the `CounterNamesFor` +method is available which returns the names of all counters for a specified document: + +{CODE:csharp syntax@Indexes\IndexingCounters.cs /} + +Example of index using `CounterNamesFor`: + +{CODE:csharp index_0@Indexes\IndexingCounters.cs /} + +{PANEL/} + +{PANEL: Querying the Index} + +{CODE-TABS} +{CODE-TAB:csharp:Sync query1@Indexes\IndexingCounters.cs /} +{CODE-TAB:csharp:Async query2@Indexes\IndexingCounters.cs /} +{CODE-TAB:csharp:DocumentQuery query3@Indexes\IndexingCounters.cs /} +{CODE-TABS/} + +{PANEL/} + +## Related Articles + +### Indexes +- [Indexing Related Documents](../../indexes/indexing-related-documents) +- [Map-Reduce Indexes](../../indexes/map-reduce-indexes) +- [Creating and Deploying Indexes](../../indexes/creating-and-deploying) + +### Document Extensions +- [Counters: Overview](../../document-extensions/counters/overview) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.java.markdown new file mode 100644 index 0000000000..ee7d5b9228 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.java.markdown @@ -0,0 +1,131 @@ +# Indexes: Indexing Counters +--- + +{NOTE: } + +* To index counters, create a [static index](../../indexes/creating-and-deploying#static-indexes) +that inherits from `AbstractCountersIndexCreationTask` or `AbstractJavaScriptCountersIndexCreationTask`. + +* Auto-indexes for counters are not available at this time. + +* In this page: + * [Syntax](../../document-extensions/counters/indexing#syntax) + * [AbstractJavaScriptCountersIndexCreationTask](../../document-extensions/counters/indexing#section) + * [CounterNamesFor](../../document-extensions/counters/indexing#section-1) + * [Querying the Index](../../document-extensions/counters/indexing#querying-the-index) + +{NOTE/} + +--- + +{PANEL:Syntax} + +In order to index counter values, create an index that inherits from `AbstractCountersIndexCreationTask`. +Next, use these method which take the index expression: + +{CODE-BLOCK:java } + protected void addMap(String map) +{CODE-BLOCK/} + +`addMap` only indexes the counters with +the specified name. + +Examples of indexes using each method: + +{CODE-TABS} +{CODE-TAB:java:addMap index_1@Indexes\IndexingCounters.java /} +{CODE-TABS/} +
+ +--- + +### `AbstractJavaScriptCountersIndexCreationTask` + +Creating an index inheriting from `AbstractJavaScriptCountersIndexCreationTask` allows +you to write your map and reduce functions in JavaScript. +Learn more about JavaScript indexes [here](../../indexes/javascript-indexes). + +{CODE-BLOCK: java} +public class AbstractJavaScriptCountersIndexCreationTask extends AbstractIndexCreationTaskBase +{ + private final CountersIndexDefinition _definition = new CountersIndexDefinition(); + + public Set getMaps() { + return _definition.getMaps(); + } + + public void setMaps(Set maps) { + _definition.setMaps(maps); + } + + public Map getFields() { + return _definition.getFields(); + } + + public void setFields(Map fields) { + _definition.setFields(fields); + } + + protected String getReduce() { + return _definition.getReduce(); + } + + protected void setReduce(String reduce) { + _definition.setReduce(reduce); + } + + @Override + public boolean isMapReduce() { + return getReduce() != null; + } + + /** + * @return If not null than each reduce result will be created as a document in the specified collection name. + */ + protected String getOutputReduceToCollection() { + return _definition.getOutputReduceToCollection(); + } +} + + +{CODE-BLOCK/} + +| Property | Type | Description | +| - | - | - | +| **Maps** | `Set` | The set of javascript map functions | +| **Reduce** | `String` | The javascript reduce function | + +Example: + +{CODE:java index_3@DocumentExtensions\Counters\IndexingCounters.java /} + +--- + +### `CounterNamesFor` + +While indexes inheriting from `AbstractIndexCreationTask` cannot index counter _values_, the `counterNamesFor` +method is available which returns the names of all counters for a specified document: + +{CODE:java syntax@Indexes\IndexingCounters.java /} + +Example of index using `counterNamesFor`: + +{CODE:java index_0@Indexes\IndexingCounters.java /} + +{PANEL/} + +{PANEL: Querying the Index} + +{CODE:java query1@Indexes\IndexingCounters.java /} + +{PANEL/} + +## Related Articles + +### Indexes +- [Indexing Related Documents](../../indexes/indexing-related-documents) +- [Map-Reduce Indexes](../../indexes/map-reduce-indexes) +- [Creating and Deploying Indexes](../../indexes/creating-and-deploying) + +### Document Extensions +- [Counters: Overview](../../document-extensions/counters/overview) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.js.markdown new file mode 100644 index 0000000000..bf9fe199c9 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.js.markdown @@ -0,0 +1,79 @@ +# indexes: Indexing Counters +--- + +{NOTE: } + +* To index counters, create a [static index](../../indexes/creating-and-deploying#static-indexes) +that inherits from `AbstractCountersIndexCreationTask ` or `AbstractRawJavaScriptCountersIndexCreationTask `. + +* Auto-indexes for counters are not available at this time. + +* In this page: + * [Usage](../../document-extensions/counters/indexing#usage) + * [AbstractCsharpCountersIndexCreationTask ](../../document-extensions/counters/indexing#section) + * [CounterNamesFor](../../document-extensions/counters/indexing#section-1) + * [Querying the Index](../../document-extensions/counters/indexing#querying-the-index) + +{NOTE/} + +--- + +{PANEL:Usage} + +In order to index counter values, create an index that inherits from `AbstractCountersIndexCreationTask`. +Next, choose one of these two methods which take the index expression: + +{CODE-BLOCK:javascript } +this.map("map"); +{CODE-BLOCK/} + +`map ` only indexes the counters with +the specified name. + +Examples of indexes using each method: + +{CODE-TABS} +{CODE-TAB:nodejs:map index_1@documentExtensions\counters\indexingCounters.js /} +{CODE-TABS/} +
+ +--- + +### `AbstractRawJavaScriptCountersIndexCreationTask ` + +Creating an index inheriting from `AbstractCsharpCountersIndexCreationTask ` allows +you to write your map and reduce functions in JavaScript. +Learn more about JavaScript indexes [here](../../indexes/javascript-indexes). + +{CODE:nodejs index_3@documentExtensions\counters\indexingCounters.js /} + +--- + +### `CounterNamesFor` + +While indexes inheriting from `AbstractIndexCreationTask` cannot index counter _values_, the `counterNamesFor()` +method is available which returns the names of all counters for a specified document: + +Example of index using `CounterNamesFor`: + +{CODE:nodejs index_0@documentExtensions\counters\indexingCounters.js /} + +{PANEL/} + +{PANEL: Querying the Index} + +{CODE-TABS} +{CODE-TAB:nodejs:Query query1@documentExtensions\counters\indexingCounters.js /} +{CODE-TABS/} + +{PANEL/} + +## Related Articles + +### indexes +- [Indexing Related Documents](../../indexes/indexing-related-documents) +- [Map-Reduce indexes](../../indexes/map-reduce-indexes) +- [Creating and Deploying indexes](../../indexes/creating-and-deploying) + +### Document Extensions +- [Counters: Overview](../../document-extensions/counters/overview) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.python.markdown new file mode 100644 index 0000000000..2a52eb1931 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/indexing.python.markdown @@ -0,0 +1,74 @@ +# Indexes: Indexing Counters +--- + +{NOTE: } + +* To index counters, create a [static index](../../indexes/creating-and-deploying#static-indexes) +that inherits from `AbstractCountersIndexCreationTask` or `AbstractJavaScriptCountersIndexCreationTask`. + +* Auto-indexes for counters are not available at this time. + +* In this page: + * [Syntax](../../document-extensions/counters/indexing#syntax) + * [AbstractJavaScriptCountersIndexCreationTask](../../document-extensions/counters/indexing#section) + * [CounterNamesFor](../../document-extensions/counters/indexing#section) + +{NOTE/} + +--- + +{PANEL:Syntax} + +To index counter values, create an index that inherits from `AbstractCountersIndexCreationTask` +and use `map` as follows. +{CODE:python index_1@DocumentExtensions\Counters\IndexingCounters.py /} + +--- + +### AbstractJavaScriptCountersIndexCreationTask + +Creating an index inheriting from `AbstractJavaScriptCountersIndexCreationTask` allows +you to write your map and reduce functions in JavaScript. +Learn more about JavaScript indexes [here](../../indexes/javascript-indexes). + +{CODE-BLOCK: csharp} +public class AbstractJavaScriptCountersIndexCreationTask : AbstractCountersIndexCreationTask +{ + public HashSet Maps; + protected string Reduce; +} +{CODE-BLOCK/} + +| Property | Type | Description | +| - | - | - | +| **maps** | `Set[str]` | The set of javascript map functions | +| **reduce** | `str` | The javascript reduce function | + +Example: + +{CODE:python index_3@DocumentExtensions\Counters\IndexingCounters.py /} + +--- + +### `CounterNamesFor` + +While indexes inheriting from `AbstractIndexCreationTask` cannot index counter _values_, the `CounterNamesFor` +method is available which returns the names of all counters for a specified document: + +{CODE:python syntax@DocumentExtensions\Counters\IndexingCounters.py /} + +Example of index using `CounterNamesFor`: + +{CODE:python index_0@DocumentExtensions\Counters\IndexingCounters.py /} + +{PANEL/} + +## Related Articles + +### Indexes +- [Indexing Related Documents](../../indexes/indexing-related-documents) +- [Map-Reduce Indexes](../../indexes/map-reduce-indexes) +- [Creating and Deploying Indexes](../../indexes/creating-and-deploying) + +### Document Extensions +- [Counters: Overview](../../document-extensions/counters/overview) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.dotnet.markdown index aae6a5ebf8..ab90d2ce50 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.dotnet.markdown @@ -161,7 +161,7 @@ When all Counters are removed from a document, the server automatically removes Managing Counters is performed using the `CountersFor` Session object. -* __Counter methods__: +* **Counter methods**: | Method | Description | |-------------------------|-----------------------------------------------------------------------------------------| @@ -171,7 +171,7 @@ Managing Counters is performed using the `CountersFor` Session object. | `CountersFor.GetAll` | Get *all* the Counters of a document and their values | -* __Usage flow__: +* **Usage flow**: * Open a session. * Create an instance of `CountersFor`. * Either pass `CountersFor` an explicit document ID, -or- @@ -180,12 +180,12 @@ Managing Counters is performed using the `CountersFor` Session object. * Use Counter methods to manage the document's Counters. * If you execute [Increment](../../document-extensions/counters/create-or-modify) or [Delete](../../document-extensions/counters/delete), call `session.SaveChanges` for the action to take effect on the server. -* __Success and failure__: +* **Success and failure**: * As long as the document exists, Counter actions (Increment, Get, Delete etc.) always succeed. * When a transaction that includes a Counter modification fails for any reason (e.g. a document concurrency conflict), the Counter modification is reverted. -* __`CountersFor` usage samples__: +* **`CountersFor` usage samples**: * You can Use `CountersFor` by **explicitly passing it a document ID** (without pre-loading the document). * You can also use `CountersFor` by passing it **the document object**. diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.js.markdown index 7d292a92dd..3a999c4dfc 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.js.markdown @@ -161,7 +161,7 @@ When all Counters are removed from a document, the server automatically removes Managing Counters is performed using the `countersFor` Session object. -* __Counter methods__: +* **Counter methods**: | Method | Description | |-------------------------|-----------------------------------------------------------------------------------------| @@ -171,7 +171,7 @@ Managing Counters is performed using the `countersFor` Session object. | `countersFor.getAll` | Get *all* the Counters of a document and their values | -* __Usage flow__: +* **Usage flow**: * Open a session. * Create an instance of `countersFor`. * Either pass `countersFor` an explicit document ID, -or- @@ -180,12 +180,12 @@ Managing Counters is performed using the `countersFor` Session object. * Use Counter methods to manage the document's Counters. * If you execute [increment](../../document-extensions/counters/create-or-modify) or [delete](../../document-extensions/counters/delete), call `session.saveChanges` for the action to take effect on the server. -* __Success and failure__: +* **Success and failure**: * As long as the document exists, Counter actions (Increment, Get, Delete etc.) always succeed. * When a transaction that includes a Counter modification fails for any reason (e.g. a document concurrency conflict), the Counter modification is reverted. -* __`countersFor` usage samples__: +* **`countersFor` usage samples**: * You can Use `countersFor` by **explicitly passing it a document ID** (without pre-loading the document). * You can also use `countersFor` by passing it **the document object**. diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.python.markdown new file mode 100644 index 0000000000..c57985faa8 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/overview.python.markdown @@ -0,0 +1,219 @@ +# Counters Overview + + +{NOTE: } + +* RavenDB's distributed counters, **Counters** for short, are numeric data variables that can be added to documents. + Use a Counter to count anything that needs counting, like: + * Sold products + * Voting results + * Any event related to the document + +* Counters interact with and can trigger other RavenDB features. + To find out how to use counters with other features, read [Counters and Other Features](../../../csharp/document-extensions/counters/counters-and-other-features). + +* Create and manage Counters using API methods, or through the [Studio](../../studio/database/document-extensions/counters). + +* In this page: + * [Why use Counters?](../../document-extensions/counters/overview#why-use-counters?) + * [Overview](../../document-extensions/counters/overview#overview) + * [Managing Counters](../../document-extensions/counters/overview#managing-counters) + * [Counter Methods and the `counters_for` object](../../document-extensions/counters/overview#counter-methods-and-the--object) + * [Managing Counters using `Operations`](../../document-extensions/counters/overview#managing-counters-using-) +{NOTE/} + +--- + +{PANEL: Why use Counters?} + +#### Convenient Counting Mechanism + +Counters are very easy to manage, using simple API methods or through the Studio. + +E.g. Use counters when you want to - + +- Keep track of the number of times a document has been viewed or rated. +- Count how many visitors from certain countries or regions read a document. +- Continuously record the number of visitors on an event page. +- Avoid having to update the whole document for just a numeric value change. +- Have a need for a high-throughput counter (also see **Distributed Values** below). + +--- + +#### Distributed Values + +A Counter's value is [distributed between cluster nodes](../../document-extensions/counters/counters-in-clusters). +Among the advantages of this: + +* The cluster **remains available** even when nodes crash. +* Any node can provide or modify a Counter's value immediately, without checking or coordinating this with other nodes. + +--- + +#### High Performance, Low Resources + +A document includes the Counter's _name_, while the Counter's actual _value_ is kept in a separate location. +Modifying a Counter's value doesn't require the modification of the document itself. +This results in highly efficient operation. + +--- + +#### High-Frequency Counting + +Counters are especially useful when a very large number of counting operations is required, +because of their speed and low resources usage. + +E.g. Use Counters - + +- For an online election page, to continuously update a Number-Of-Votes Counter for each candidate. +- To continuously update Counters with the number of visitors in different sections of a big online store. + +{PANEL/} + +{PANEL: Overview} + +#### Design + +A document's metadata contains only the ***Counters' names-list*** for this document. +***Counter Values*** are not kept in the document's metadata, but in a separate location. + +Therefore, changes like adding a new counter or deleting an existing counter trigger a document change, +while simply modifying the Counter Value does not. + +--- + +#### Cumulative Counter Actions + +* Counter value-modification actions are cumulative, the order in which they are executed doesn't matter. + E.g., It doesn't matter if a Counter has been incremented by 2 and then by 7, or by 7 first and then by 2. + +* When a Counter is deleted, the sequence of Counter actions becomes non-cumulative and may require + [special attention](../../document-extensions/counters/counters-in-clusters#concurrent-delete-and-increment). + +--- + +#### Counters and Conflicts + +Counter actions (for either name or value) almost never cause conflicts. +The only exception to this is [concurrent `delete` and `increment`](../../document-extensions/counters/counters-in-clusters#concurrent-delete-and-increment) +actions by multiple cluster nodes. + +- Counter actions can be executed concurrently or in any order, without causing a conflict. +- You can successfully modify Counters while their document is being modified by a different client. + +{NOTE: } +Counter actions **can still be performed** when their related documents are in a conflicted state. +{NOTE/} + +--- + +#### Counters Cost + +Counters are designated to lower the cost of counting, but do come with a price. + +* **All the names** of a document's Counters are added to its content, increasing its size. +* **Counter values** occupy storage space. + +{NOTE: } +Be aware that the negligible amount of resources required by a few Counters, +may become significant when there are many. +A single document with thousands of Counters is probably an indication of a modeling mistake, +for example. +{NOTE/} + +--- + +#### Counters Naming Convention + +* Valid characters: All visible characters, [including Unicode symbols](../../studio/database/document-extensions/counters#section) +* Length: Up to 512 bytes +* Encoding: UTF-8 + +--- + +#### Counter Values + +* Valid range: Signed 64-bit integer (-9223372036854775808 to 9223372036854775807) +* Only integer additions are supported (no floats or other mathematical operations). + +--- + +#### Number of Counters Per Document + +RavenDB doesn't limit the number of Counters you can create. + +{NOTE: } +Note that the Counter names are stored in the document metadata and [do impact the size of the document](../../document-extensions/counters/overview#counters-cost). +{NOTE/} + +--- + +#### The `HasCounters` Flag + +When a Counter is added to a document, RavenDB automatically sets a `HasCounters` Flag in the document's metadata. +When all Counters are removed from a document, the server automatically removes this flag. + +{PANEL/} + +{PANEL: Managing Counters} + +#### Counter Methods and the `counters_for` Object + +Managing Counters is performed using the `counters_for` session object. + +* **Counter methods**: + + | Method | Description | + |-------------------------|-----------------------------------------------------------------------------------------| + | `counters_for.increment` | Increment the value of an existing Counter, or create a new Counter if it doesn't exist | + | `counters_for.delete` | Delete a Counter | + | `counters_for.get` | Get the current value of a Counter | + | `counters_for.get_all` | Get *all* the Counters of a document and their values | + + +* **Usage flow**: + * Open a session. + * Create an instance of `counters_for`. + * Either pass `counters_for` an explicit document ID, -or- + * Pass it an [entity tracked by the session](../../client-api/session/loading-entities), + e.g. a document object returned from [session.query](../../client-api/session/querying/how-to-query) or from [session.load](../../client-api/session/loading-entities#load). + * Use Counter methods to manage the document's Counters. + * If you execute [increment](../../document-extensions/counters/create-or-modify) or [delete](../../document-extensions/counters/delete), call `session.save_changes` for the action to take effect on the server. + +* **Success and failure**: + * As long as the document exists, Counter actions (Increment, Get, Delete etc.) always succeed. + * When a transaction that includes a Counter modification fails for any reason (e.g. a document concurrency conflict), + the Counter modification is reverted. + +* **`counters_for` usage samples**: + * You can Use `counters_for` by **explicitly passing it a document ID** (without pre-loading the document). + * You can also use `counters_for` by passing it **the document object**. + + {CODE-TABS} + {CODE-TAB:python:Pass-CountersFor-Document-ID counters_region_CountersFor_without_document_load@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:Pass-CountersFor-Document-Object counters_region_CountersFor_with_document_load@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +--- + +#### Managing Counters using `Operations` + +* In addition to working with the high-level Session, you can manage Counters using the low-level [Operations](../../client-api/operations/what-are-operations). + +* [CounterBatchOperation](../../client-api/operations/counters/counter-batch) +can operate on a set of Counters of different documents in a single request. +{PANEL/} + +## Related articles +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters and other features](../../document-extensions/counters/counters-and-other-features) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.dotnet.markdown index 52b5340f1c..02063794f6 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.dotnet.markdown @@ -3,22 +3,22 @@ {NOTE: } -* Use `CountersFor.Get` to retrieve the value of a __single Counter__, - or `CountersFor.GetAll` to retrieve the names and values of __all Counters__ associated with a document. +* Use `CountersFor.Get` to retrieve the value of a **single Counter**, + or `CountersFor.GetAll` to retrieve the names and values of **all Counters** associated with a document. * For all other `CountersFor` methods see this [Overview](../../document-extensions/counters/overview#counter-methods-and-the--object). * In this page: * [Get a single Counter's value](../../document-extensions/counters/retrieve-counter-values#get-a-single-counter) - * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) - * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) - * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) + * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) + * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) + * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) * [Get all Counters of a document](../../document-extensions/counters/retrieve-counter-values#get-all-counters-of-a-document) - * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) - * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-exmaple) - * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) + * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) + * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-exmaple) + * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) {NOTE/} @@ -26,9 +26,7 @@ {PANEL: Get a single Counter's value} -{NOTE: } - - __Get usage__: +#### Get usage: * Open a session * Create an instance of `CountersFor`. @@ -37,17 +35,15 @@ e.g. a document object returned from [session.Query](../../client-api/session/querying/how-to-query) or from [session.Load](../../client-api/session/loading-entities#load). * Call `CountersFor.Get` to retrieve the current value of a single Counter. -{NOTE/} -{NOTE: } +--- - __Get example__: +#### Get example: {CODE counters_region_Get@DocumentExtensions\Counters\Counters.cs /} -{NOTE/} -{NOTE: } +--- - __Get syntax__: +#### Get syntax: {CODE Get-definition@DocumentExtensions\Counters\Counters.cs /} @@ -59,14 +55,13 @@ |--------------|-------------------------| | `long` | Counter's current value | -{NOTE/} {PANEL/} {PANEL: Get all Counters of a document} -{NOTE: } +--- - __GetAll usage__: +#### GetAll usage: * Open a session. * Create an instance of `CountersFor`. @@ -75,17 +70,15 @@ e.g. a document object returned from [session.Query](../../client-api/session/querying/how-to-query) or from [session.Load](../../client-api/session/loading-entities#load). * Call `CountersFor.GetAll` to retrieve the names and values of all counters associated with the document. -{NOTE/} -{NOTE: } +--- - __GetAll example__: +#### GetAll example: {CODE counters_region_GetAll@DocumentExtensions\Counters\Counters.cs /} -{NOTE/} -{NOTE: } +--- - __GetAll syntax__: +#### GetAll syntax: {CODE GetAll-definition@DocumentExtensions\Counters\Counters.cs /} @@ -93,7 +86,6 @@ |--------------------------|---------------------------------| | Dictionary | Map of Counter names and values | -{NOTE/} {PANEL/} ## Related articles diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.java.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.java.markdown index 59da5c941d..da3ec20047 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.java.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.java.markdown @@ -3,22 +3,22 @@ {NOTE: } -* Use `countersFor.get` to retrieve the value of a __single Counter__, - or `countersFor.getAll` to retrieve the names and values of __all Counters__ associated with a document. +* Use `countersFor.get` to retrieve the value of a **single Counter**, + or `countersFor.getAll` to retrieve the names and values of **all Counters** associated with a document. * For all other `CountersFor` methods see this [Overview](../../document-extensions/counters/overview#counter-methods-and-the--object). * In this page: * [Get a single Counter's value](../../document-extensions/counters/retrieve-counter-values#get-a-single-counter) - * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) - * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) - * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) + * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) + * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) + * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) * [Get all Counters of a document](../../document-extensions/counters/retrieve-counter-values#get-all-counters-of-a-document) - * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) - * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-exmaple) - * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) + * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) + * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-exmaple) + * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) {NOTE/} @@ -26,9 +26,9 @@ {PANEL: Get a single Counter's value} -{NOTE: } +--- - __Get usage__: +#### Get usage: * Open a session * Create an instance of `countersFor`. @@ -36,17 +36,15 @@ * Pass it an entity tracked by the session, e.g. a document object returned from `session.query` or from `session.load`. * Call `countersFor.get` to retrieve the current value of a single Counter. -{NOTE/} -{NOTE: } +--- - __Get example__: +#### Get example: {CODE:java counters_region_Get@DocumentExtensions\Counters\Counters.java /} -{NOTE/} -{NOTE: } +--- - __Get syntax__: +#### Get syntax: {CODE Get-definition@DocumentExtensions\Counters\Counters.cs /} @@ -58,14 +56,13 @@ |--------------|-------------------------| | `long` | Counter's current value | -{NOTE/} {PANEL/} {PANEL: Get all Counters of a document} -{NOTE: } +--- - __GetAll usage__: +#### GetAll usage: * Open a session. * Create an instance of `countersFor`. @@ -73,17 +70,15 @@ * Pass it an entity tracked by the session, e.g. a document object returned from session.query or from session.load. * Call `countersFor.getAll` to retrieve the names and values of all counters associated with the document. -{NOTE/} -{NOTE: } +--- - __GetAll example__: +#### GetAll example: {CODE:java counters_region_GetAll@DocumentExtensions\Counters\Counters.java /} -{NOTE/} -{NOTE: } +--- - __GetAll syntax__: +#### GetAll syntax: {CODE:java getAll-definition@DocumentExtensions\Counters\Counters.java /} @@ -91,7 +86,6 @@ |-------------------|---------------------------------| | Map | Map of Counter names and values | -{NOTE/} {PANEL/} ## Related articles diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.js.markdown index c95848f900..84135e072c 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.js.markdown @@ -3,22 +3,22 @@ {NOTE: } -* Use `countersFor.get` to retrieve the value of a __single Counter__, - or `countersFor.getAll` to retrieve the names and values of __all Counters__ associated with a document. +* Use `countersFor.get` to retrieve the value of a **single Counter**, + or `countersFor.getAll` to retrieve the names and values of **all Counters** associated with a document. * For all other `countersFor` methods see this [Overview](../../document-extensions/counters/overview#counter-methods-and-the--object). * In this page: * [Get a single Counter's value](../../document-extensions/counters/retrieve-counter-values#get-a-single-counter) - * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) - * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) - * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) + * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) + * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) + * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) * [Get all Counters of a document](../../document-extensions/counters/retrieve-counter-values#get-all-counters-of-a-document) - * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) - * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-exmaple) - * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) + * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) + * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-exmaple) + * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) {NOTE/} @@ -28,7 +28,7 @@ {NOTE: } - __Get usage__: + **Get usage**: * Open a session * Create an instance of `countersFor`. @@ -40,14 +40,14 @@ {NOTE/} {NOTE: } - __Get example__: + **Get example**: {CODE:nodejs getCounter@documentExtensions\counters\get.js /} {NOTE/} {NOTE: } - __Get syntax__: + **Get syntax**: {CODE:nodejs syntax_1@documentExtensions\counters\get.js /} @@ -66,7 +66,7 @@ {NOTE: } - __GetAll usage__: + **GetAll usage**: * Open a session. * Create an instance of `countersFor`. @@ -78,14 +78,14 @@ {NOTE/} {NOTE: } - __GetAll example__: + **GetAll example**: {CODE:nodejs getAllCounters@documentExtensions\counters\get.js /} {NOTE/} {NOTE: } - __GetAll syntax__: + **GetAll syntax**: {CODE:nodejs syntax_2@documentExtensions\counters\get.js /} diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.python.markdown new file mode 100644 index 0000000000..6ca62c2f4b --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/counters/retrieve-counter-values.python.markdown @@ -0,0 +1,104 @@ +# Get Counter Values +--- + +{NOTE: } + +* Use `counters_for.get` to retrieve the value of a **single Counter**, + or `counters_for.get_all` to retrieve the names and values of **all Counters** associated with a document. + +* For all other `counters_for` methods see this [Overview](../../document-extensions/counters/overview#counter-methods-and-the--object). + +* In this page: + + * [Get a single Counter's value](../../document-extensions/counters/retrieve-counter-values#get-a-single-counter) + * [Get usage](../../document-extensions/counters/retrieve-counter-values#get-usage) + * [Get example](../../document-extensions/counters/retrieve-counter-values#get-example) + * [Get syntax](../../document-extensions/counters/retrieve-counter-values#get-syntax) + + * [Get all Counters of a document](../../document-extensions/counters/retrieve-counter-values#get-all-counters-of-a-document) + * [GetAll usage](../../document-extensions/counters/retrieve-counter-values#getall-usage) + * [GetAll example](../../document-extensions/counters/retrieve-counter-values#getall-example) + * [GetAll Syntax](../../document-extensions/counters/retrieve-counter-values#getall-syntax) + +{NOTE/} + +--- + +{PANEL: Get a single Counter's value} + +#### Get usage: + +* Open a session +* Create an instance of `counters_for`. + * Either pass `counters_for` an explicit document ID, -or- + * Pass it an [entity tracked by the session](../../client-api/session/loading-entities), + e.g. a document object returned from [session.Query](../../client-api/session/querying/how-to-query) or from [session.Load](../../client-api/session/loading-entities#load). +* Call `counters_for.get` to retrieve the current value of a single Counter. + +--- + +#### Get example: + +{CODE:python counters_region_Get@DocumentExtensions\Counters\Counters.py /} + +--- + +#### Get syntax: + +{CODE:python Get-definition@DocumentExtensions\Counters\Counters.py /} + +| Parameter | Type | Description | +|---------------|--------|----------------| +| `counter` | str | Counter name | + +| Return Type | Description | +|--------------|-------------------------| +| `int` | Counter's current value | + +{PANEL/} + +{PANEL: Get all Counters of a document} + +--- + +#### GetAll usage: + +* Open a session. +* Create an instance of `counters_for`. + * Either pass `counters_for` an explicit document ID, -or- + * Pass it an [entity tracked by the session](../../client-api/session/loading-entities), + e.g. a document object returned from [session.query](../../client-api/session/querying/how-to-query) or from [session.Load](../../client-api/session/loading-entities#load). +* Call `counters_for.get_all` to retrieve the names and values of all counters associated with the document. + +--- + +#### GetAll example: + +{CODE:python counters_region_GetAll@DocumentExtensions\Counters\Counters.py /} + +--- + +#### GetAll syntax: + +{CODE:python GetAll-definition@DocumentExtensions\Counters\Counters.py /} + +| Return Type | Description | +|------------------|---------------------------------| +| `Dict[str, int]` | Map of Counter names and values | + +{PANEL/} + +## Related articles + +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Counters and other features](../../document-extensions/counters/counters-and-other-features) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Attachments/Attachments.cs b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Attachments/Attachments.cs new file mode 100644 index 0000000000..535f29a448 --- /dev/null +++ b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Attachments/Attachments.cs @@ -0,0 +1,391 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Raven.Client.Documents; +using Raven.Client.Documents.Linq; +using Raven.Client.Documents.Operations.Attachments; +using Raven.Client.ServerWide; +using Raven.Client.ServerWide.Operations; + +namespace Raven.Documentation.Samples.ClientApi.Session.Attachments +{ + public class Attachments + { + private interface IFoo + { + #region StoreSyntax + void Store(string documentId, string name, Stream stream, string contentType = null); + void Store(object entity, string name, Stream stream, string contentType = null); + #endregion + + #region GetSyntax + AttachmentResult Get(string documentId, string name); + AttachmentResult Get(object entity, string name); + IEnumerator Get(IEnumerable attachments); + AttachmentName[] GetNames(object entity); + AttachmentResult GetRevision(string documentId, string name, string changeVector); + bool Exists(string documentId, string name); + #endregion + + #region GetSyntaxAsync + Task GetAsync(string documentId, string name, CancellationToken token = default); + Task GetAsync(object entity, string name, CancellationToken token = default); + Task> GetAsync(IEnumerable attachments, CancellationToken token = default); + Task GetRevisionAsync(string documentId, string name, string changeVector, CancellationToken token = default); + Task ExistsAsync(string documentId, string name, CancellationToken token = default); + #endregion + + #region DeleteSyntax + void Delete(string documentId, string name); + void Delete(object entity, string name); + #endregion + } + + public void StoreAttachment() + { + using (var store = new DocumentStore()) + { + #region StoreAttachment + using (var session = store.OpenSession()) + using (var file1 = File.Open("001.jpg", FileMode.Open)) + using (var file2 = File.Open("002.jpg", FileMode.Open)) + using (var file3 = File.Open("003.jpg", FileMode.Open)) + using (var file4 = File.Open("004.mp4", FileMode.Open)) + { + var album = new Album + { + Name = "Holidays", + Description = "Holidays travel pictures of the all family", + Tags = new[] { "Holidays Travel", "All Family" }, + }; + session.Store(album, "albums/1"); + + session.Advanced.Attachments.Store("albums/1", "001.jpg", file1, "image/jpeg"); + session.Advanced.Attachments.Store("albums/1", "002.jpg", file2, "image/jpeg"); + session.Advanced.Attachments.Store("albums/1", "003.jpg", file3, "image/jpeg"); + session.Advanced.Attachments.Store("albums/1", "004.mp4", file4, "video/mp4"); + + session.SaveChanges(); + } + #endregion + } + } + + public async Task StoreAttachmentAsync() + { + using (var store = new DocumentStore()) + { + #region StoreAttachmentAsync + using (var asyncSession = store.OpenAsyncSession()) + using (var file1 = File.Open("001.jpg", FileMode.Open)) + using (var file2 = File.Open("002.jpg", FileMode.Open)) + using (var file3 = File.Open("003.jpg", FileMode.Open)) + using (var file4 = File.Open("004.mp4", FileMode.Open)) + { + var album = new Album + { + Name = "Holidays", + Description = "Holidays travel pictures of the all family", + Tags = new[] { "Holidays Travel", "All Family" }, + }; + await asyncSession.StoreAsync(album, "albums/1"); + + asyncSession.Advanced.Attachments.Store("albums/1", "001.jpg", file1, "image/jpeg"); + asyncSession.Advanced.Attachments.Store("albums/1", "002.jpg", file2, "image/jpeg"); + asyncSession.Advanced.Attachments.Store("albums/1", "003.jpg", file3, "image/jpeg"); + asyncSession.Advanced.Attachments.Store("albums/1", "004.mp4", file4, "video/mp4"); + + await asyncSession.SaveChangesAsync(); + } + #endregion + } + } + + public void GetAttachment() + { + using (var store = new DocumentStore()) + { + #region GetAttachment + using (var session = store.OpenSession()) + { + Album album = session.Load("albums/1"); + + using (AttachmentResult file1 = session.Advanced.Attachments.Get(album, "001.jpg")) + using (AttachmentResult file2 = session.Advanced.Attachments.Get("albums/1", "002.jpg")) + { + Stream stream = file1.Stream; + + AttachmentDetails attachmentDetails = file1.Details; + string name = attachmentDetails.Name; + string contentType = attachmentDetails.ContentType; + string hash = attachmentDetails.Hash; + long size = attachmentDetails.Size; + string documentId = attachmentDetails.DocumentId; + string changeVector = attachmentDetails.ChangeVector; + } + + AttachmentName[] attachmentNames = session.Advanced.Attachments.GetNames(album); + foreach (AttachmentName attachmentName in attachmentNames) + { + string name = attachmentName.Name; + string contentType = attachmentName.ContentType; + string hash = attachmentName.Hash; + long size = attachmentName.Size; + } + + bool exists = session.Advanced.Attachments.Exists("albums/1", "003.jpg"); + } + #endregion + } + } + + public async Task GetAttachmentAsync() + { + using (var store = new DocumentStore()) + { + #region GetAttachmentAsync + using (var asyncSession = store.OpenAsyncSession()) + { + Album album = await asyncSession.LoadAsync("albums/1"); + + using (AttachmentResult file1 = await asyncSession.Advanced.Attachments.GetAsync(album, "001.jpg")) + using (AttachmentResult file2 = await asyncSession.Advanced.Attachments.GetAsync("albums/1", "002.jpg")) + { + Stream stream = file1.Stream; + + AttachmentDetails attachmentDetails = file1.Details; + string name = attachmentDetails.Name; + string contentType = attachmentDetails.ContentType; + string hash = attachmentDetails.Hash; + long size = attachmentDetails.Size; + string documentId = attachmentDetails.DocumentId; + string changeVector = attachmentDetails.ChangeVector; + } + + AttachmentName[] attachmentNames = asyncSession.Advanced.Attachments.GetNames(album); + foreach (AttachmentName attachmentName in attachmentNames) + { + string name = attachmentName.Name; + string contentType = attachmentName.ContentType; + string hash = attachmentName.Hash; + long size = attachmentName.Size; + } + + bool exists = await asyncSession.Advanced.Attachments.ExistsAsync("albums/1", "003.jpg"); + } + #endregion + } + } + + public void DeleteAttachment() + { + using (var store = new DocumentStore()) + { + #region DeleteAttachment + using (var session = store.OpenSession()) + { + Album album = session.Load("albums/1"); + session.Advanced.Attachments.Delete(album, "001.jpg"); + session.Advanced.Attachments.Delete("albums/1", "002.jpg"); + + session.SaveChanges(); + } + #endregion + } + } + + public async Task DeleteAttachmentAsync() + { + using (var store = new DocumentStore()) + { + #region DeleteAttachmentAsync + using (var asyncSession = store.OpenAsyncSession()) + { + Album album = await asyncSession.LoadAsync("albums/1"); + asyncSession.Advanced.Attachments.Delete(album, "001.jpg"); + asyncSession.Advanced.Attachments.Delete("albums/1", "002.jpg"); + + await asyncSession.SaveChangesAsync(); + } + #endregion + } + } + + public class Album + { + public string Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string[] Tags { get; set; } + } + + + // attachments multi-get + // BulkInsert.a few attachments and then get them with a single request + public async void AttachmentsMultiGet() + { + using (var store = getDocumentStore()) + { + // Create documents to add attachments to + using (var session = store.OpenSession()) + { + var user1 = new User + { + Name = "Lilly", + Age = 20 + }; + session.Store(user1); + + var user2 = new User + { + Name = "Betty", + Age = 25 + }; + session.Store(user2); + + var user3 = new User + { + Name = "Robert", + Age = 29 + }; + session.Store(user3); + + session.SaveChanges(); + } + + List result; + + using (var session = store.OpenSession()) + { + IRavenQueryable query = session.Query() + .Where(u => u.Age < 30); + + result = query.ToList(); + } + + // Query for users younger than 30, add an attachment + using (var bulkInsert = store.BulkInsert()) + { + for (var user = 0; user < result.Count; user++) + { + byte[] byteArray = Encoding.UTF8.GetBytes("some contents here"); + var stream = new MemoryStream(byteArray); + + string userId = result[user].Id; + var attachmentsFor = bulkInsert.AttachmentsFor(userId); + + for (var attNum = 0; attNum < 10; attNum++) + { + stream.Position = 0; + await attachmentsFor.StoreAsync(result[user].Name + attNum, stream); + } + + } + } + + // attachments multi-get (sync) + using (var session = store.OpenSession()) + { + for (var userCnt = 0; userCnt < result.Count; userCnt++) + { + string userId = result[userCnt].Id; + #region GetAllAttachments + // Load a user profile + var user = session.Load(userId); + + // Get the names of files attached to this document + IEnumerable attachmentNames = session.Advanced.Attachments.GetNames(user).Select(x => new AttachmentRequest(userId, x.Name)); + + // Get the attached files + IEnumerator attachmentsEnumerator = session.Advanced.Attachments.Get(attachmentNames); + + // Go through the document's attachments + while (attachmentsEnumerator.MoveNext()) + { + AttachmentEnumeratorResult res = attachmentsEnumerator.Current; + + AttachmentDetails attachmentDetails = res.Details; // attachment details + + Stream attachmentStream = res.Stream; // attachment contents + + // In this case it is a string attachment, that can be decoded back to text + var ms = new MemoryStream(); + attachmentStream.CopyTo(ms); + string decodedStream = Encoding.UTF8.GetString(ms.ToArray()); + } + #endregion + } + } + + // attachments multi-get (Async) + using (var session = store.OpenAsyncSession()) + { + for (var userCnt = 0; userCnt < result.Count; userCnt++) + { + string userId = result[userCnt].Id; + #region GetAllAttachmentsAsync + // Load a user profile + var user = await session.LoadAsync(userId); + + // Get the names of files attached to this document + IEnumerable attachmentNames = session.Advanced.Attachments.GetNames(user).Select(x => new AttachmentRequest(userId, x.Name)); + + // Get the attached files + IEnumerator attachmentsEnumerator = await session.Advanced.Attachments.GetAsync(attachmentNames); + + // Go through the document's attachments + while (attachmentsEnumerator.MoveNext()) + { + AttachmentEnumeratorResult res = attachmentsEnumerator.Current; + + AttachmentDetails attachmentDetails = res.Details; // attachment details + + Stream attachmentStream = res.Stream; // attachment contents + + // In this case it is a string attachment, that can be decoded back to text + var ms = new MemoryStream(); + attachmentStream.CopyTo(ms); + string decodedStream = Encoding.UTF8.GetString(ms.ToArray()); + } + #endregion + } + } + + } + } + + public DocumentStore getDocumentStore() + { + DocumentStore store = new DocumentStore + { + Urls = new[] { "http://localhost:8080" }, + Database = "TestDatabase" + }; + store.Initialize(); + + var parameters = new DeleteDatabasesOperation.Parameters + { + DatabaseNames = new[] { "TestDatabase" }, + HardDelete = true, + }; + store.Maintenance.Server.Send(new DeleteDatabasesOperation(parameters)); + store.Maintenance.Server.Send(new CreateDatabaseOperation(new DatabaseRecord("TestDatabase"))); + + return store; + } + + private class User + { + public string Id { get; set; } + public string Name { get; set; } + public string LastName { get; set; } + public string AddressId { get; set; } + public int Count { get; set; } + public int Age { get; set; } + } + + } +} diff --git a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Counters/BulkInsert.cs b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Counters/BulkInsert.cs new file mode 100644 index 0000000000..04fe53a8c0 --- /dev/null +++ b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Counters/BulkInsert.cs @@ -0,0 +1,132 @@ +using System.Linq; +using Raven.Client.Documents; +using Xunit; +using Xunit.Abstractions; +using System.Collections.Generic; +using Raven.Client.Documents.Linq; +using Raven.Client.ServerWide.Operations; +using Raven.Client.ServerWide; +using System.IO; +using System.Text; + +namespace Documentation.Samples.DocumentExtensions.TimeSeries +{ + public class BulkInsertCounters + { + private BulkInsertCounters(ITestOutputHelper output) + { + } + + public DocumentStore getDocumentStore() + { + DocumentStore store = new DocumentStore + { + Urls = new[] { "http://localhost:8080" }, + Database = "TestDatabase" + }; + store.Initialize(); + + var parameters = new DeleteDatabasesOperation.Parameters + { + DatabaseNames = new[] { "TestDatabase" }, + HardDelete = true, + }; + store.Maintenance.Server.Send(new DeleteDatabasesOperation(parameters)); + store.Maintenance.Server.Send(new CreateDatabaseOperation(new DatabaseRecord("TestDatabase"))); + + return store; + } + + // bulk insert Counters + // Use BulkInsert.TimeSeriesBulkInsert.Append with doubles + [Fact] + public async void BulkInsertCounters2() + { + using (var store = getDocumentStore()) + { + // Create documents to bulk-insert to + using (var session = store.OpenSession()) + { + var user1 = new User + { + Name = "Lilly", + Age = 20 + }; + session.Store(user1); + + var user2 = new User + { + Name = "Betty", + Age = 25 + }; + session.Store(user2); + + var user3 = new User + { + Name = "Robert", + Age = 29 + }; + session.Store(user3); + + session.SaveChanges(); + } + + List result; + + #region bulk-insert-counters + // Choose user profiles to add counters to + using (var session = store.OpenSession()) + { + IRavenQueryable query = session.Query() + .Where(u => u.Age < 30); + + result = query.ToList(); + } + + using (var bulkInsert = store.BulkInsert()) + { + for (var user = 0; user < result.Count; user++) + { + string userId = result[user].Id; + + // Choose document + var countersFor = bulkInsert.CountersFor(userId); + + // Add or Increment a counter + await bulkInsert.CountersFor(userId).IncrementAsync("downloaded", 100); + } + } + #endregion + } + } + + public class User + { + public string Id { get; set; } + public string Name { get; set; } + public string LastName { get; set; } + public string AddressId { get; set; } + public int Count { get; set; } + public int Age { get; set; } + } + + #region CountersFor-definition + public CountersBulkInsert CountersFor(string id) + #endregion + { + return new CountersBulkInsert(); + } + + public struct CountersBulkInsert + { + } + + #region Increment-definition + public void Increment(string name, long delta = 1L) + #endregion + { + } + + } +} + diff --git a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Counters/IndexingCounters.cs b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Counters/IndexingCounters.cs new file mode 100644 index 0000000000..051fcecfbc --- /dev/null +++ b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/Counters/IndexingCounters.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Raven.Client.Documents; +using Raven.Client.Documents.Indexes; +using Raven.Client.Documents.Indexes.Counters; +using Raven.Documentation.Samples.Orders; + +namespace Raven.Documentation.Samples.DocumentExtensions +{ + public class IndexingCounters + { + private interface IFoo + { + #region syntax + IEnumerable CounterNamesFor(object doc); + #endregion + } + + #region index_0 + public class Companies_ByCounterNames : AbstractIndexCreationTask + { + public class Result + { + public string[] CounterNames { get; set; } + } + + public Companies_ByCounterNames() + { + Map = employees => from e in employees + let counterNames = CounterNamesFor(e) + select new Result + { + CounterNames = counterNames.ToArray() + }; + } + } + #endregion + + #region index_1 + private class MyCounterIndex : AbstractCountersIndexCreationTask + { + public MyCounterIndex() + { + AddMap("Likes", counters => from counter in counters + select new + { + Likes = counter.Value, + Name = counter.Name, + User = counter.DocumentId + }); + } + } + #endregion + + #region index_2 + private class MyCounterIndex_AllCounters : AbstractCountersIndexCreationTask + { + public MyCounterIndex_AllCounters() + { + AddMapForAll(counters => from counter in counters + select new + { + Count = counter.Value, + Name = counter.Name, + User = counter.DocumentId + }); + } + } + #endregion + + #region index_3 + private class MyMultiMapCounterIndex : AbstractJavaScriptCountersIndexCreationTask + { + public MyMultiMapCounterIndex() + { + Maps = new HashSet + { + @"counters.map('Blogposts', 'Likes', function (counter) { + return { + Likes: counter.Value, + Name: counter.Name, + Blog Post: counter.DocumentId + }; + })" + }; + } + } + #endregion + public async Task Sample() + { + using (var store = new DocumentStore()) + { + using (var session = store.OpenSession()) + { + #region query1 + // return all companies that have 'Likes' counter + List companies = session + .Query() + .Where(x => x.CounterNames.Contains("Likes")) + .OfType() + .ToList(); + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region query2 + // return all companies that have 'Likes' counter + List companies = await asyncSession + .Query() + .Where(x => x.CounterNames.Contains("Likes")) + .OfType() + .ToListAsync(); + #endregion + } + + using (var session = store.OpenSession()) + { + #region query3 + // return all companies that have 'Likes' counter + List companies = session + .Advanced + .DocumentQuery() + .ContainsAny("CounterNames", new[] { "Likes" }) + .ToList(); + #endregion + } + } + } + + #region counter_entry + public class CounterEntry + { + public string DocumentId { get; set; } + public string Name { get; set; } + public long Value { get; set; } + } + #endregion + } +} diff --git a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/Indexes/IndexingCounters.cs b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/Indexes/IndexingCounters.cs new file mode 100644 index 0000000000..03ef18bee2 --- /dev/null +++ b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/Indexes/IndexingCounters.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Raven.Client.Documents; +using Raven.Client.Documents.Indexes; +using Raven.Client.Documents.Indexes.Counters; +using Raven.Documentation.Samples.Orders; + +namespace Raven.Documentation.Samples.Indexes +{ + public class IndexingCounters + { + private interface IFoo + { + #region syntax + IEnumerable CounterNamesFor(object doc); + #endregion + } + + #region index_0 + public class Companies_ByCounterNames : AbstractIndexCreationTask + { + public class Result + { + public string[] CounterNames { get; set; } + } + + public Companies_ByCounterNames() + { + Map = employees => from e in employees + let counterNames = CounterNamesFor(e) + select new Result + { + CounterNames = counterNames.ToArray() + }; + } + } + #endregion + + #region index_1 + private class MyCounterIndex : AbstractCountersIndexCreationTask + { + public MyCounterIndex() + { + AddMap("Likes", counters => from counter in counters + select new + { + Likes = counter.Value, + Name = counter.Name, + User = counter.DocumentId + }); + } + } + #endregion + + #region index_2 + private class MyCounterIndex_AllCounters : AbstractCountersIndexCreationTask + { + public MyCounterIndex_AllCounters() + { + AddMapForAll(counters => from counter in counters + select new + { + Count = counter.Value, + Name = counter.Name, + User = counter.DocumentId + }); + } + } + #endregion + + public async Task Sample() + { + using (var store = new DocumentStore()) + { + using (var session = store.OpenSession()) + { + #region query1 + // return all companies that have 'Likes' counter + List companies = session + .Query() + .Where(x => x.CounterNames.Contains("Likes")) + .OfType() + .ToList(); + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region query2 + // return all companies that have 'Likes' counter + List companies = await asyncSession + .Query() + .Where(x => x.CounterNames.Contains("Likes")) + .OfType() + .ToListAsync(); + #endregion + } + + using (var session = store.OpenSession()) + { + #region query3 + // return all companies that have 'Likes' counter + List companies = session + .Advanced + .DocumentQuery() + .ContainsAny("CounterNames", new[] { "Likes" }) + .ToList(); + #endregion + } + } + } + + #region counter_entry + public class CounterEntry + { + public string DocumentId { get; set; } + public string Name { get; set; } + public long Value { get; set; } + } + #endregion + } +} diff --git a/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Attachments/Attachments.java b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Attachments/Attachments.java new file mode 100644 index 0000000000..9e209e89b7 --- /dev/null +++ b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Attachments/Attachments.java @@ -0,0 +1,166 @@ +package net.ravendb.ClientApi.Session.attachments; + +import net.ravendb.client.documents.DocumentStore; +import net.ravendb.client.documents.IDocumentStore; +import net.ravendb.client.documents.operations.attachments.AttachmentDetails; +import net.ravendb.client.documents.operations.attachments.AttachmentName; +import net.ravendb.client.documents.operations.attachments.CloseableAttachmentResult; +import net.ravendb.client.documents.session.IDocumentSession; + +import java.io.FileInputStream; +import java.io.InputStream; + +public class Attachments { + private interface IFoo { + //region StoreSyntax + void store(String documentId, String name, InputStream stream); + + void store(String documentId, String name, InputStream stream, String contentType); + + void store(Object entity, String name, InputStream stream); + + void store(Object entity, String name, InputStream stream, String contentType); + //endregion + + //region GetSyntax + AttachmentName[] getNames(Object entity); + + boolean exists(String documentId, String name); + + CloseableAttachmentResult get(String documentId, String name); + + CloseableAttachmentResult get(Object entity, String name); + + CloseableAttachmentResult getRevision(String documentId, String name, String changeVector); + //endregion + + //region DeleteSyntax + void delete(String documentId, String name); + + void delete(Object entity, String name); + //endregion + } + + public Attachments() throws Exception { + try (IDocumentStore store = new DocumentStore()) { + //region StoreAttachment + try (IDocumentSession session = store.openSession()) { + try ( + FileInputStream file1 = new FileInputStream("001.jpg"); + FileInputStream file2 = new FileInputStream("002.jpg"); + FileInputStream file3 = new FileInputStream("003.jpg"); + FileInputStream file4 = new FileInputStream("004.mp4") + ) { + Album album = new Album(); + album.setName("Holidays"); + album.setDescription("Holidays travel pictures of the all family"); + album.setTags(new String[] { "Holidays Travel", "All Family" }); + session.store(album, "albums/1"); + + session.advanced().attachments() + .store("albums/1", "001.jpg", file1, "image/jpeg"); + session.advanced().attachments() + .store("albums/1", "002.jpg", file2, "image/jpeg"); + session.advanced().attachments() + .store("albums/1", "003.jpg", file3, "image/jpeg"); + session.advanced().attachments() + .store("albums/1", "004.mp4", file4, "video/mp4"); + + session.saveChanges(); + } + } + //endregion + } + } + + public void getAttachment() throws Exception { + try (IDocumentStore store = new DocumentStore()) { + //region GetAttachment + try (IDocumentSession session = store.openSession()) { + Album album = session.load(Album.class, "albums/1"); + + try (CloseableAttachmentResult file1 = session + .advanced().attachments().get(album, "001.jpg"); + CloseableAttachmentResult file2 = session + .advanced().attachments().get("albums/1", "002.jpg")) { + + InputStream inputStream = file1 + .getData(); + + AttachmentDetails attachmentDetails = file1.getDetails(); + String name = attachmentDetails.getName(); + String contentType = attachmentDetails.getContentType(); + String hash = attachmentDetails.getHash(); + long size = attachmentDetails.getSize(); + String documentId = attachmentDetails.getDocumentId(); + String changeVector = attachmentDetails.getChangeVector(); + } + + AttachmentName[] attachmentNames = session.advanced().attachments().getNames(album); + for (AttachmentName attachmentName : attachmentNames) { + + String name = attachmentName.getName(); + String contentType = attachmentName.getContentType(); + String hash = attachmentName.getHash(); + long size = attachmentName.getSize(); + } + + boolean exists = session.advanced().attachments().exists("albums/1", "003.jpg"); + } + //endregion + } + } + + public void deleteAttachment() { + try (IDocumentStore store = new DocumentStore()) { + //region DeleteAttachment + try (IDocumentSession session = store.openSession()) { + Album album = session.load(Album.class, "albums/1"); + session.advanced().attachments().delete(album, "001.jpg"); + session.advanced().attachments().delete("albums/1", "002.jpg"); + + session.saveChanges(); + } + //endregion + } + } + + public static class Album { + private String id; + private String name; + private String description; + private String[] tags; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String[] getTags() { + return tags; + } + + public void setTags(String[] tags) { + this.tags = tags; + } + } +} diff --git a/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/Counters.java b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/Counters.java index bcfd62a343..c5cdf54caa 100644 --- a/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/Counters.java +++ b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/Counters.java @@ -1,5 +1,4 @@ -package net.ravendb.ClientApi.Session.Counters; - +import net.ravendb.client.documents.BulkInsertOperation; import net.ravendb.client.documents.DocumentStore; import net.ravendb.client.documents.IDocumentStore; import net.ravendb.client.documents.session.IDocumentQuery; @@ -7,14 +6,14 @@ import net.ravendb.client.documents.session.ISessionDocumentCounters; import net.ravendb.client.documents.smuggler.DatabaseItemType; import net.ravendb.client.documents.smuggler.DatabaseSmugglerExportOptions; +import net.ravendb.client.documents.BulkInsertOperation.*; + +import java.util.*; -import java.util.Date; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; public class Counters { + void test() { DocumentStore docStore = new DocumentStore(); //region counters_region_CountersFor_with_document_load @@ -189,13 +188,32 @@ void test() { .toList(); //endregion } + List result = new ArrayList<>(); + //region bulk-insert-counters + try (IDocumentSession session = docStore.openSession()) { + IDocumentQuery query = session.query(User.class) + .whereLessThan("age", 30); + + result = query.toList(); + } + + try (BulkInsertOperation bulkInsert = docStore.bulkInsert()) { + for (User user : result) { + String userId = user.getId(); + CountersBulkInsert countersFor = bulkInsert.countersFor(userId); + bulkInsert.countersFor(userId).increment("downloaded", 100); + } + } + + //endregion } + private class CounterResult { private Long productPrice; private Long productLikes; private String productSection; - private String name; + private String name; public Long getProductPrice() { return productPrice; @@ -208,8 +226,8 @@ public void setProductPrice(Long productPrice) { public Long getProductLikes() { return productLikes; } - - public String getName() { + + public String getName() { return name; } @@ -224,8 +242,8 @@ public String getProductSection() { public void setProductSection(String productSection) { this.productSection = productSection; } - - public void setName(String name) { + + public void setName(String name) { this.name = name; } } @@ -314,7 +332,8 @@ public class CounterItem { private interface IFoo { //region Increment-definition void increment(String counterName); - void increment(String counterName, long incrementValue); + + void increment(String id, String name, long delta); //endregion //region Delete-definition @@ -341,4 +360,39 @@ public void sample() { //endregion } } + + private interface IFoo3 { + //region CountersFor-definition + public CountersBulkInsert countersFor(String id); + //endregion + + //region Increment-definition + public void increment(String id, String name, long delta); + //endregion + } +} + +class User { + String id; + String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } + + diff --git a/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/IndexingCounters.java b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/IndexingCounters.java new file mode 100644 index 0000000000..b468f4bbc5 --- /dev/null +++ b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/DocumentExtensions/Counters/IndexingCounters.java @@ -0,0 +1,87 @@ +package net.ravendb.DocumentExtensions.Counters; + +import net.ravendb.client.documents.DocumentStore; +import net.ravendb.client.documents.IDocumentStore; +import net.ravendb.client.documents.indexes.AbstractIndexCreationTask; +import net.ravendb.client.documents.indexes.counters.AbstractCountersIndexCreationTask; +import net.ravendb.client.documents.indexes.counters.AbstractJavaScriptCountersIndexCreationTask; +import net.ravendb.client.documents.session.IDocumentSession; + + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class IndexingCounters { + private interface IFoo { + //region syntax + List counterNamesFor(Object doc); + //endregion + } + + //region index + public static class Companies_ByCounterNames extends AbstractIndexCreationTask { + public Companies_ByCounterNames() { + map = "from e in docs.Employees\n" + + "let counterNames = counterNamesFor(e)\n" + + "select new\n" + + "{\n" + + " counterNames = counterNames.ToArray()\n" + + "}"; + } + } + //endregion + + public void sample() { + try (IDocumentStore store = new DocumentStore()) { + try (IDocumentSession session = store.openSession()) { + //region query1 + // return all companies that have 'Likes' counter + List companies = session + .query(Company.class, Companies_ByCounterNames.class) + .containsAny("counterNames", Arrays.asList("companies_likes")) + .selectFields(Company.class, "likes") + .toList(); + //endregion + } + } + } + /* + //region + protected void addMap(String map); + //endregion + + */ + + + //region index_1 + public static class MyCounterIndex extends AbstractCountersIndexCreationTask { + public MyCounterIndex() { + map = "counters.Companies.HeartRate.Select(counter => new {\n" + + " heartBeat = counter.Value,\n" + + " name = counter.Name,\n" + + " user = counter.DocumentId\n" + + "})"; + } + } + //endregion + + //region index_3 + public static class MyMultiMapCounterIndex extends AbstractJavaScriptCountersIndexCreationTask { + public MyMultiMapCounterIndex() { + setMaps(Collections.singleton("counters.map('Blogposts', 'Likes', function (counter) {\n" + + "return {\n" + + " ikes: counter.Value,\n" + + " name: counter.Name,\n" + + " bolg post: counter.DocumentId\n" + + "};\n" + + "})")); + } + } + //endregion + + class Company{ + + } + +} diff --git a/Documentation/5.4/Samples/java/src/test/java/net/ravendb/Indexes/IndexingCounters.java b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/Indexes/IndexingCounters.java new file mode 100644 index 0000000000..9f4eb2881b --- /dev/null +++ b/Documentation/5.4/Samples/java/src/test/java/net/ravendb/Indexes/IndexingCounters.java @@ -0,0 +1,87 @@ +package net.ravendb.Indexes; + +import com.google.common.collect.Lists; +import net.ravendb.client.documents.DocumentStore; +import net.ravendb.client.documents.IDocumentStore; +import net.ravendb.client.documents.indexes.AbstractIndexCreationTask; +import net.ravendb.client.documents.indexes.counters.AbstractCountersIndexCreationTask; +import net.ravendb.client.documents.indexes.counters.AbstractJavaScriptCountersIndexCreationTask; +import net.ravendb.client.documents.session.IDocumentSession; + + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class IndexingCounters { + private interface IFoo { + //region syntax + List counterNamesFor(Object doc); + //endregion + } + + //region index_0 + public static class Companies_ByCounterNames extends AbstractIndexCreationTask { + public Companies_ByCounterNames() { + map = "from e in docs.Employees\n" + + "let counterNames = counterNamesFor(e)\n" + + "select new\n" + + "{\n" + + " counterNames = counterNames.ToArray()\n" + + "}"; + } + } + //endregion + + public void sample() { + try (IDocumentStore store = new DocumentStore()) { + try (IDocumentSession session = store.openSession()) { + //region query1 + // return all companies that have 'Likes' counter + List companies = session + .query(Company.class, Companies_ByCounterNames.class) + .containsAny("counterNames", Arrays.asList("companies_likes")) + .selectFields(Company.class, "likes") + .toList(); + //endregion + } + } + } + + //region + protected void addMap(String map) + //endregion + { + + } + + //region index_1 + public static class MyCounterIndex extends AbstractCountersIndexCreationTask { + public MyCounterIndex() { + map = "counters.Companies.HeartRate.Select(counter => new {\n" + + " heartBeat = counter.Value,\n" + + " name = counter.Name,\n" + + " user = counter.DocumentId\n" + + "})"; + } + } + //endregion + + //region index_3 + public static class MyMultiMapCounterIndex extends AbstractJavaScriptCountersIndexCreationTask { + public MyMultiMapCounterIndex() { + setMaps(Collections.singleton("counters.map('Blogposts', 'Likes', function (counter) {\n" + + "return {\n" + + " ikes: counter.Value,\n" + + " name: counter.Name,\n" + + " bolg post: counter.DocumentId\n" + + "};\n" + + "})")); + } + } + //endregion + + class Company{ + + } +} diff --git a/Documentation/5.4/Samples/nodejs/documentExtensions/attachments/attachments.js b/Documentation/5.4/Samples/nodejs/documentExtensions/attachments/attachments.js new file mode 100644 index 0000000000..13d5c48356 --- /dev/null +++ b/Documentation/5.4/Samples/nodejs/documentExtensions/attachments/attachments.js @@ -0,0 +1,112 @@ +import * as assert from "assert"; +import * as fs from "fs"; +import { DocumentStore } from "ravendb"; + +const store = new DocumentStore(); +const session = store.openSession(); + +{ + let documentId, contentType, stream, entity, name, changeVector; + //region StoreSyntax + session.advanced.attachments.store(documentId, name, stream, [contentType]); + + session.advanced.attachments.store(entity, name, stream, [contentType]); + //endregion + + //region GetSyntax + session.advanced.attachments.getNames(entity); + + session.advanced.attachments.exists(documentId, name); + + session.advanced.attachments.get(documentId, name); + + session.advanced.attachments.get(entity, name); + + session.advanced.attachments.getRevision(documentId, name, changeVector); + //endregion + + //region DeleteSyntax + session.advanced.attachments.delete(documentId, name); + + session.advanced.attachments.delete(entity, name); + //endregion +} + +class Album {} + +async function storeAttachment() { + { + //region StoreAttachment + const session = store.openSession(); + + const file1 = fs.createReadStream("001.jpg"); + const file2 = fs.createReadStream("002.jpg"); + const file3 = fs.createReadStream("003.jpg"); + const file4 = fs.createReadStream("004.mp4"); + + const album = new Album(); + album.name = "Holidays"; + album.description = "Holidays travel pictures of the all family"; + album.tags = [ "Holidays Travel", "All Family" ]; + await session.store(album, "albums/1"); + + session.advanced.attachments + .store("albums/1", "001.jpg", file1, "image/jpeg"); + session.advanced.attachments + .store("albums/1", "002.jpg", file2, "image/jpeg"); + session.advanced.attachments + .store("albums/1", "003.jpg", file3, "image/jpeg"); + session.advanced.attachments + .store("albums/1", "004.mp4", file4, "video/mp4"); + + await session.saveChanges(); + //endregion + } +} + +async function getAttachment() { + { + //region GetAttachment + const album = await session.load("albums/1"); + + const file1 = await session.advanced.attachments.get(album, "001.jpg"); + const file2 = await session.advanced.attachments.get("albums/1", "002.jpg"); + + const inputStream = file1.data; + + const attachmentDetails = file1.details; + // { + // name: '001.jpg', + // documentId: 'albums/1', + // contentType: 'image/jpeg', + // hash: 'MvUEcrFHSVDts5ZQv2bQ3r9RwtynqnyJzIbNYzu1ZXk=', + // changeVector: '"A:3-K5TR36dafUC98AItzIa6ow"', + // size: 25793 + // } + + const attachmentNames = await session.advanced.attachments.getNames(album); + for (const attachmentName of attachmentNames) { + const name = attachmentName.name; + const contentType = attachmentName.contentType; + const hash = attachmentName.hash; + const size = attachmentName.size; + } + + const exists = session.advanced.attachments.exists("albums/1", "003.jpg"); + // true + + //endregion + } +} + +async function deleteAttachment() { + //region DeleteAttachment + const session = store.openSession(); + const album = await session.load("albums/1"); + session.advanced.attachments.delete(album, "001.jpg"); + + session.advanced.attachments.delete("albums/1", "002.jpg"); + + await session.saveChanges(); + //endregion +} diff --git a/Documentation/5.4/Samples/nodejs/documentExtensions/counters/counters.js b/Documentation/5.4/Samples/nodejs/documentExtensions/counters/counters.js new file mode 100644 index 0000000000..235d320260 --- /dev/null +++ b/Documentation/5.4/Samples/nodejs/documentExtensions/counters/counters.js @@ -0,0 +1,125 @@ +import { + DocumentStore, + +} from "ravendb"; + + +class Product { +} + +const store = new DocumentStore(); +{ + //region counters_region_query + const session = store.openSession(); + const query = session.query({collection: "Products"}) + .selectFields("ProductLikes"); + const queryResults = query.all(); + + for (let counterValue in queryResults) { + console.log("ProductLikes: " + counterValue); + } + //endregion +} + +const session = store.openSession(); +{ + //region counters_region_rawqueries_counter + //Various RQL expressions sent to the server using counter() + //Returned Counter value is accumulated + const rawquery1 = session.advanced + .rawQuery("from products as p select counter(p, \"ProductLikes\")") + .all(); + + const rawquery2 = session.advanced + .rawQuery("from products select counter(\"ProductLikes\") as ProductLikesCount") + .all(); + + const rawquery3 = session.advanced + .rawQuery("from products where PricePerUnit > 50 select Name, counter(\"ProductLikes\")") + .all(); + //endregion + + // +} + +{ + //region counters_region_rawqueries_counterRaw + //An RQL expression sent to the server using counterRaw() + //Returned Counter value is distributed + const query = session.advanced + .rawQuery("from users as u select counterRaw(u, \"downloads\")") + .all(); + //endregion +} + + +{ + + + //region counters_region_load_include1 + const productPage = await session.load("orders/1-A", { + includes: includeBuilder => includeBuilder + .includeDocuments("products/1-C") + .includeCounters(["ProductLikes", "ProductDislikes"]) + }); + //endregion +} + +{ + //region counters_region_load_include2 + const productPage = await session.load("orders/1-A", { + documentType: Product, + includes: includeBuilder => + includeBuilder.includeDocuments("products/1-C") + .includeCounters(["ProductLikes", "ProductDislikes"]) + } + ); + //endregion +} + +{ + //region counters_region_query_include_single_Counter + const query = session.query({collection: "Product"}) + .include(includeBuilder => + includeBuilder.includeCounter("ProductLikes")); + //endregion +} + +{ + //region counters_region_query_include_multiple_Counters + const query = session.query({collection: "Product"}) + .include(includeBuilder => + includeBuilder.includeCounters("ProductLikes", "ProductDownloads")); + //endregion +} + +{ + //region CountersFor-definition + + const counter = session.countersFor("documentid") + //endregion + + //region Increment-definition + const incerment = store.openSession(); + session.countersFor("documentid").increment("likes", 100); + ////endregion +} + +{ + //region bulk-insert-counters + const query = session.query({collection: "User"}) + .whereBetween("Age", 0, 30) + const result = query.all(); + + const bulkInsert = store.bulkInsert(); + for (let user = 0; user < result.length; user++) { + let userId = result[user].id; + + // Choose document + let countersFor = bulkInsert.countersFor(userId); + + // Add or Increment a counter + await bulkInsert.countersFor(userId).increment("downloaded", 100); + } + //endregion +} diff --git a/Documentation/5.4/Samples/nodejs/documentExtensions/counters/indexingCounters.js b/Documentation/5.4/Samples/nodejs/documentExtensions/counters/indexingCounters.js new file mode 100644 index 0000000000..55de2ac4e6 --- /dev/null +++ b/Documentation/5.4/Samples/nodejs/documentExtensions/counters/indexingCounters.js @@ -0,0 +1,73 @@ +import { + AbstractCountersIndexCreationTask, AbstractRawJavaScriptCountersIndexCreationTask, + DocumentStore +} from "ravendb"; + +const store = new DocumentStore(); +const session = store.openSession(); + +//region index_1 +export class MyCounterIndex extends AbstractCountersIndexCreationTask { + constructor() { + super(); + this.map = `from counter in docs.counters select new { + Likes = counter.Value, + Name = counter.Name, + User = counter.DocumentId + }`; + } +} +//endregion + +let map,reduce; +//region javaScriptIndexCreationTask +class CsharpCountersIndexCreationTask extends AbstractCountersIndexCreationTask { + public constructor() { + super(); + + this.map = map; + + this.reduce = reduce; + } +} +//endregion + +//region index_3 +class MyCounterIndex extends AbstractRawJavaScriptCountersIndexCreationTask { + public constructor() { + super(); + + this.maps.add( + "counters.map('Companies', 'HeartRate', function (counter) {\n" + + "return {\n" + + " heartBeat: counter.Value,\n" + + " name: counter.Name,\n" + + " user: counter.DocumentId\n" + + "};\n" + + "})" + ); + } +} +//endregion + +//region index_0 +class Companies_ByCounterNames extends AbstractCountersIndexCreationTask{ + constructor() { + super(); + this.map = "docs.Companies.Select(e => new {\n"+ + "e = e,\n"+ + " counterNames = this.CounterNamesFor(e)\n"+ + "}).Select(this0 => new {\n"+ + " CounterNames = Enumerable.ToArray(this0.counterNames)\n"+ + "})" + } +} +//endregion + + +//region query1 +const companies = session + .query({index: "Companies_ByCounterNames"}) + .containsAny("counterNames", ["Likes"]) + .all(); +//endregion \ No newline at end of file diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/Attachments.py b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/Attachments.py new file mode 100644 index 0000000000..7529948156 --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/Attachments.py @@ -0,0 +1,119 @@ +from typing import Union, List + +import requests +from ravendb.documents.operations.attachments import CloseableAttachmentResult, AttachmentDetails, AttachmentName + +from examples_base import ExampleBase + + +class Foo: + # region StoreSyntax + def store( + self, + entity_or_document_id: Union[object, str], + name: str, + stream: bytes, + content_type: str = None, + change_vector: str = None, + ): ... + + # endregion + # region GetSyntax + def get(self, entity_or_document_id: str = None, name: str = None) -> CloseableAttachmentResult: ... + + class CloseableAttachmentResult: + def __init__(self, response: requests.Response, details: AttachmentDetails): + self.__details = details + self.__response = response + + class AttachmentDetails(AttachmentName): + def __init__( + self, name: str, hash: str, content_type: str, size: int, change_vector: str = None, document_id: str = None + ): + super().__init__(...) + ... + + class AttachmentName: + def __init__(self, name: str, hash: str, content_type: str, size: int): ... + + def get_names(self, entity: object) -> List[AttachmentName]: ... + + def exists(self, document_id: str, name: str) -> bool: ... + + # endregion + + # region DeleteSyntax + def delete(self, entity_or_document_id, name): ... + + # endregion + + +class Album: + def __init__(self, Id: str = None, name: str = None, description: str = None, tags: List[str] = None): + self.Id = Id + self.name = name + self.description = description + self.tags = tags + + +class GetStoreDeleteAttachments(ExampleBase): + def setUp(self): + super().setUp() + + def test_get_store_delete_attachments(self): + with self.embedded_server.get_document_store("GetStoreDeleteAttachments") as store: + # region StoreAttachment + with store.open_session() as session: + with open("001.jpg", "r") as file1: + file1_data = file1.read() + file2_data = b"file_2_content" # Mock + file3_data = b"file_3_content" # Mock + file4_data = b"file_4_content" # Mock + album = Album( + name="Holidays", + description="Holidays travel pictures of the all family", + tags=["Holidays Travel", "All Family"], + ) + session.store(album, "albums/1") + + session.advanced.attachments.store("albums/1", "001.jpg", file1_data, "image/jpeg") + session.advanced.attachments.store("albums/1", "002.jpg", file2_data, "image/jpeg") + session.advanced.attachments.store("albums/1", "003.jpg", file3_data, "image/jpeg") + session.advanced.attachments.store("albums/1", "004.jpg", file4_data, "image/jpeg") + + session.save_changes() + # endregion + + # region GetAttachment + with store.open_session() as session: + album = session.load("albums/1", Album) + + with session.advanced.attachments.get(album, "001.jpg") as file1: + with session.advanced.attachments.get("albums/1", "002.jpg") as file2: + bytes_data = file1.data + + attachment_details = file1.details + name = attachment_details.name + content_type = attachment_details.content_type + hash_ = attachment_details.hash + size = attachment_details.size + document_id = attachment_details.document_id + change_vector = attachment_details.change_vector + + attachment_names = session.advanced.attachments.get_names(album) + for attachment_name in attachment_names: + name = attachment_name.name + content_type = attachment_name.content_type + hash_ = attachment_name.hash + size = attachment_name.size + + exists = session.advanced.attachments.exists("albums/1", "003.jpg") + # endregion + # region DeleteAttachment + with store.open_session() as session: + album = session.load("albums/1") + session.advanced.attachments.delete(album, "001.jpg") + session.advanced.attachments.delete("albums/1", "002.jpg") + + session.save_changes() + # endregion diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/BulkInsert.py b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/BulkInsert.py new file mode 100644 index 0000000000..e6c657c388 --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/BulkInsert.py @@ -0,0 +1,40 @@ +from examples_base import ExampleBase, User + + +class BulkInsertAttachments(ExampleBase): + def setUp(self): + super().setUp() + + def test_append_using_bulk_insert(self): + with self.embedded_server.get_document_store("BulkInsertAttachments") as store: + # Create documents to bulk-insert to + with store.open_session() as session: + user1 = User("users/1-A", "Lilly", 20) + user2 = User("users/2-A", "Betty", 25) + user3 = User("users/3-A", "Robert", 29) + session.store(user1) + session.store(user2) + session.store(user3) + session.save_changes() + + # region bulk_insert_attachment + # Choose user profiles for which to attach a file + with store.open_session() as session: + user_ids = [ + session.advanced.get_document_id(user) + for user in list(session.query(object_type=User).where_less_than("Age", 30)) + ] + + # Prepare content to attach + bytes_to_attach = b"some contents here" + + # Create a BulkInsert instance + with store.bulk_insert() as bulk_insert: + for user_id in user_ids: + # Call 'attachments_for', pass the document ID for which to attach the file + attachments_bulk_insert = bulk_insert.attachments_for(user_id) + + # Call 'store' to add the file to the BulkInsert instance + # The data stored in bulk_insert will be streamed to the server in batches + attachments_bulk_insert.store("AttachmentName", bytes_to_attach) + # endregion diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/CopyMoveRename.py b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/CopyMoveRename.py new file mode 100644 index 0000000000..c742f243ce --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/CopyMoveRename.py @@ -0,0 +1,65 @@ +from typing import Union + +from examples_base import ExampleBase, Employee + + +class Foo: + # region copy_0 + def copy( + self, + entity_or_document_id: Union[object, str], + source_name: str, + destination_entity_or_document_id: object, + destination_name: str, + ) -> None: ... + + # endregion + + # region rename_0 + def rename(self, entity_or_document_id: Union[str, object], name: str, new_name: str) -> None: ... + + # endregion + # region move_0 + def move( + self, + source_entity_or_document_id: Union[str, object], + source_name: str, + destination_entity_or_document_id: Union[str, object], + destination_name: str, + ) -> None: ... + + # endregion + + +class CopyMoveRename(ExampleBase): + def setUp(self): + super().setUp() + + def test_copy_move_rename(self): + with self.embedded_server.get_document_store("CopyMoveRename") as store: + with store.open_session() as session: + # region copy_1 + employee_1 = session.load("employees/1-A") + employee_2 = session.load("employees/2-A") + + session.advanced.attachments.copy(employee_1, "photo.jpg", employee_2, "photo-copy.jpg") + + session.save_changes() + # endregion + + # region rename_1 + employee = session.load("employees/1-A", Employee) + + session.advanced.attachments.rename(employee, "photo.jpg", "photo-new.jpg") + + session.save_changes() + # endregion + + # region move_1 + employee1 = session.load("employees/1-A") + employee2 = session.load("employees/2-A") + + session.advanced.attachments.move(employee1, "photo.jpg", employee2, "photo.jpg") + + session.save_changes() + # endregion diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/IndexingAttachments.py b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/IndexingAttachments.py new file mode 100644 index 0000000000..996499f3e8 --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Attachments/IndexingAttachments.py @@ -0,0 +1,200 @@ +from typing import List + +from ravendb import AbstractIndexCreationTask +from ravendb.documents.indexes.abstract_index_creation_tasks import AbstractJavaScriptIndexCreationTask + +from examples_base import ExampleBase + + +class IndexingAttachments: + """ + # region syntax + IEnumerable AttachmentsFor(object doc); + # endregion + + # region syntax_2 + public IAttachmentObject LoadAttachment(object doc, string name); + public IEnumerable LoadAttachments(object doc); + # endregion + + # region result + public string Name; + public string Hash; + public string ContentType; + public long Size; + # endregion + """ + + +# region AttFor_index_LINQ +class Employees_ByAttachmentNames(AbstractIndexCreationTask): + class Result: + def __init__(self, attachment_names: List[str] = None): + self.attachment_names = attachment_names + + def __init__(self): + super().__init__() + self.map = ( + "from e in employees " + "let attachments = AttachmentsFor(e) " + "select new " + "{" + " attachment_names = attachments.Select(x => x.Name).ToArray()" + "}" + ) + + +# endregion + + +# region AttFor_index_JS +class Employees_ByAttachmentNames_JS(AbstractJavaScriptIndexCreationTask): + class Result: + def __init__(self, attachment_names: List[str] = None): + self.attachment_names = attachment_names + + def __init__(self): + super().__init__() + self.maps = { + """ + map('Employees', function (e) { + var attachments = attachmentsFor(e); + return { + attachment_names: attachments.map( + function(attachment) { + return attachment.Name; + } + }; + }) + """ + } + + +# endregion + + +# region LoadAtt_index_LINQ +class Companies_With_Attachments(AbstractJavaScriptIndexCreationTask): + class Result: + def __init__(self, attachment_names: List[str] = None): + self.attachment_names = attachment_names + + def __init__(self): + super().__init__() + self.maps = { + """ + map('Employees', function (e) { + var attachments = attachmentsFor(e); + return { + attachment_names: attachments.map( + function(attachment) { + return attachment.Name; + } + }; + }) + """ + } + + +# endregion + + +# region LoadAtt_index_LINQ +class Companies_With_Attachments(AbstractIndexCreationTask): + def __init__(self): + super().__init__() + self.map = ( + "from company in companies" + "let attachments = LoadAttachment(company, company.ExternalId)" + "select new" + "{" + " company_name = company.Name," + " attachment_name = attachment.Name," + " attachment_content_type = attachment.ContentType," + " attachment_hash = attachment.Hash," + " attachment_content = attachment.GetContentAsString(Encoding.UTF8)," + "}" + ) + + +# endregion + + +# region LoadAtt_index_JS +class Companies_With_Attachments_JavaScript(AbstractJavaScriptIndexCreationTask): + def __init__(self): + super().__init__() + self.maps = { + """ + map('Companies', function (company) { + var attachment = loadAttachment(company, company.ExternalId); + return { + company_name: company.Name, + attachment_name: attachment.Name, + attachment_content_type: attachment.ContentType, + attachment_hash: attachment.Hash, + attachment_size: attachment.Size, + attachment_content: attachment.getContentAsString('utf8') + }; + }) + """ + } + + +# endregion + + +# region LoadAtts_index_LINQ +class Companies_With_All_Attachments(AbstractIndexCreationTask): + def __init__(self): + super().__init__() + self.map = ( + "from company in companies " + "let attachments = LoadAttachments(company)" + "from attachment in attachments" + "select new" + "{" + " attachment_name = attachment.Name," + " attachment_content = attachment.GetContentAsString(Encoding.UTF8)" + "}" + ) + + +# endregion + + +# region LoadAtts_index_JS +class Companies_With_All_Attachments_JS(AbstractJavaScriptIndexCreationTask): + def __init__(self): + super().__init__() + self.maps = { + """ + map('Companies', function (company) { + var attachments = loadAttachments(company); + return attachments.map(attachment => ({ + attachment_name: attachment.Name, + attachment_content: attachment.getContentAsString('utf8') + })); + }) + """ + } + + +# endregion + + +class IndexingAttachments(ExampleBase): + def setUp(self): + super().__init__() + + def test_indexing_attachments(self): + with self.embedded_server.get_document_store("IndexingAttachments") as store: + with store.open_session() as session: + # region query1 + # return all employees that have an attachment called "cv.pdf" + employees = list( + session.query_index_type( + Employees_ByAttachmentNames, Employees_ByAttachmentNames.Result + ).contains_any("attachment_names", ["cv.pdf"]) + ) + # endregion diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Counters/BulkInsert.py b/Documentation/5.4/Samples/python/DocumentExtensions/Counters/BulkInsert.py new file mode 100644 index 0000000000..27979a5292 --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Counters/BulkInsert.py @@ -0,0 +1,46 @@ +from examples_base import ExampleBase, User + + +class BulkInsertCounters(ExampleBase): + def setUp(self): + super().setUp() + + def test_bulk_insert(self): + with self.embedded_server.get_document_store("CountersBulkInsert") as store: + with store.open_session() as session: + user1 = User(name="Lilly", age=20) + user2 = User(name="Betty", age=25) + user3 = User(name="Robert", age=29) + session.store(user1) + session.store(user2) + session.store(user3) + session.save_changes() + + # region bulk-insert-counters + with store.open_session() as session: + result = list(session.query(object_type=User).where_less_than("Age", 30)) + users_ids = [session.advanced.get_document_id(user) for user in result] + + with store.bulk_insert() as bulk_insert: + for user_id in users_ids: + # Choose document + counters_for = bulk_insert.counters_for(user_id) + + # Add or Increment a counter + bulk_insert.counters_for(user_id).increment("download", 100) + + # endregion + + +class Foo: + """ + # region CountersFor-definition + def counters_for(self, id_: str) -> CountersBulkInsert: + ... + # endregion + """ + + # region Increment-definition + def increment(self, name: str, delta: int = 1) -> None: ... + + # endregion diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Counters/Counters.py b/Documentation/5.4/Samples/python/DocumentExtensions/Counters/Counters.py new file mode 100644 index 0000000000..fa9cbbfc21 --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Counters/Counters.py @@ -0,0 +1,200 @@ +from typing import Dict + +from examples_base import ExampleBase, Product + + +class CountersExample(ExampleBase): + def setUp(self): + super().setUp() + + def test_counters(self): + with self.embedded_server.get_document_store("CountersExample") as store: + # region counters_region_CountersFor_with_document_load + # Use counters_for_entity by passing it a document object + + # 1. Open a session + with store.open_session() as session: + # 2. Use the session to load a document. + document = session.load("products/1-C") + + # 3. Create an instance of 'CountersFor' + # Pass the document object returned from session.load as a param. + document_counters = session.counters_for_entity(document) + + # 4. Use 'CountersFor' methods to manage the product document's counters + document_counters.delete("ProductLikes") # Delete the "ProductLikes" counter + document_counters.increment("ProductModified", 15) # Add 15 to Counter "ProductModified" + counter = document_counters.get("DaysLeftForSale") # Get value of "DaysLeftForSale" + + # 5. Execute all changes by calling save_changes + session.save_changes() + # endregion + + # region counters_region_CountersFor_without_document_load + # Use CountersFor without loading a document + + # 1. Open a session + with store.open_session() as session: + # 2. pass an explicit document ID to the CountersFor constructor + document_counters = session.counters_for("products/1-C") + + # 3. Use 'CountersFor' methods to manage the product document's counters + document_counters.delete("ProductLikes") # Delete the "ProductLikes" counter + document_counters.increment("ProductModified", 15) # Add 15 to Counter "ProductModified" + counter = document_counters.get("DaysLeftForSale") # Get "DaysLeftForSale"'s value + + # 4. Execute all changes by calling save_changes + session.save_changes() + # endregion + + # Increment a counter's value + # region counters_region_Increment + # Open a session + with store.open_session() as session: + # Pass CountersFor's constructor a document ID + document_counters = session.counters_for("products/1-A") + + # Use 'CountersFor.increment' + # =========================== + + # Increase "ProductLikes" by 1, or create it if doesn't exist with a value of 1 + document_counters.increment("ProductLikes") + + # Increase "ProductPageViews" by 15, or create it if doesn't exist with a value of 15 + document_counters.increment("ProductPageViews", 15) + + # Decrease "DaysLeftForSale" by 10, or create it if doesn't exist with a value of -10 + document_counters.increment("DaysLeftForSale", -10) + + # Execute all changes by calling save_changes + session.save_changes() + + # endregion + + # get a counter's value by the counter's name + # region counters_region_Get + # 1. Open a session + with store.open_session() as session: + # 2. pass CountersFor's constructor a document ID + document_counters = session.counters_for("products/1-C") + + # 3. Use 'CountersFor.Get' to retrieve a Counter's value + days_left = document_counters.get("DaysLeftForSale") + print(f"Days Left For Sale: {days_left}") + # endregion + + # region counters_region_GetAll + # 1. Open a session + with store.open_session() as session: + # 2. pass CountersFor's constructor a document ID + document_counters = session.counters_for("products/1-C") + + # 3. Use GetAll to retrieve all of the document's counters' names and values + counters = document_counters.get_all() + + # list counters' names and values + for counter_name, counter_value in counters.items(): + print(f"counter name: {counter_name}, counter value: {counter_value}") + # endregion + + with store.open_session() as session: + # region counters_region_load_include1 + # include single Counters + product_page = session.load( + "products/1-C", + include_builder=lambda builder: builder.include_counter("ProductLikes") + .include_counter("ProductDislikes") + .include_counter("ProductDownloads"), + ) + # endregion + + with store.open_session() as session: + # region counters_region_load_include2 + # include multiple Counters + # note that you can combine the inclusion of Counters and documents. + product_page = session.load( + "orders/1-A", + include_builder=lambda builder: builder.include_documents("products/1-C").include_counters( + ["ProductLikes", "ProductDislikes"] + ), + ) + # endregion + + with store.open_session() as session: + # region counters_region_query_include_single_Counter + # include a single Counter + query = session.query(object_type=Product).include(lambda builder: builder.include_counter("ProductLikes")) + # endregion + + with store.open_session() as session: + # region counters_region_query_include_multiple_Counters + # include multiple Counters + query = session.query("Products").include( + lambda builder: builder.include_counters(["ProductLikes", "ProductDownloads"]) + ) + # endregion + + with store.open_session() as session: + # region counters_region_rawqueries_counter + # Various RQL expressions sent to the server using counter() + # Returned Counter value is accumulated + rawquery1 = list(session.advanced.raw_query("from products as p select counter(p, 'ProductLikes')")) + + rawquery2 = list( + session.advanced.raw_query("from products select counter('ProductLikes') as ProductLikesCount") + ) + + rawquery3 = list( + session.advanced.raw_query("from products where PricePerUnit > 50 select Name, counter('ProductLikes')") + ) + # endregion + + # region counters_region_rawqueries_counterRaw + # An RQL expression sent to the server using counterRaw() + # Returned Counter value is distributed + query = list(session.advanced.raw_query("from users as u select counterRaw(u, 'downloads')")) + # endregion + + +class CounterResult: + def __init__(self, product_price: int = None, product_likes: int = None, product_section: str = None): + self.product_price = product_price + self.product_likes = product_likes + self.product_section = product_section + + +class CounterResultRaw: + def __init__(self, downloads: Dict[str, int]): + self.downloads = downloads + + +# region counters_region_CounterItem +# The value given to a Counter by each node, is placed in a CounterItem object. +class CounterItem: + def __init__(self, name: str = None, doc_id: str = None, change_vector: str = None, value: int = None): + self.name = name + self.doc_id = doc_id + self.change_vector = change_vector + self.value = value + + +# endregion + + +class Foo: + # region Increment-definition + def increment(self, counter: str, delta: int = 1) -> None: ... + + # endregion + # region Delete-definition + def delete(self, counter: str) -> None: ... + + # endregion + # region Get-definition + def get(self, counter) -> int: ... + + # endregion + # region GetAll-definition + def get_all(self) -> Dict[str, int]: ... + + # endregion diff --git a/Documentation/5.4/Samples/python/DocumentExtensions/Counters/IndexingCounters.py b/Documentation/5.4/Samples/python/DocumentExtensions/Counters/IndexingCounters.py new file mode 100644 index 0000000000..b447f25c39 --- /dev/null +++ b/Documentation/5.4/Samples/python/DocumentExtensions/Counters/IndexingCounters.py @@ -0,0 +1,89 @@ +from typing import List + +from ravendb import AbstractIndexCreationTask +from ravendb.documents.indexes.counters import ( + AbstractCountersIndexCreationTask, + AbstractJavaScriptCountersIndexCreationTask, +) + +from examples_base import ExampleBase + + +class IndexingCounters(ExampleBase): + def setUp(self): + super().setUp() + + class Foo: + """ + # region syntax + IEnumerable CounterNamesFor(object doc); + # endregion + """ + + def test_indexing_counters(self): + with self.embedded_server.get_document_store("IndexingCounters") as store: + with store.open_session() as session: + # region query_1 + companies = list( + session.query_index_type(Companies_ByCounterNames, Companies_ByCounterNames.Result).contains_any( + "counter_names", ["Likes"] + ) + ) + # endregion + + +# region index_0 +class Companies_ByCounterNames(AbstractIndexCreationTask): + class Result: + def __init__(self, counter_names: List[str] = None): + self.counter_names = counter_names + + def __init__(self): + super().__init__() + self.map = ( + "from e in docs.Employees " + "let counterNames = CounterNamesFor(e) " + "select new { counter_names = counterNames.ToArray() }" + ) + + +# endregion +# region index_1 +class MyCounterIndex(AbstractCountersIndexCreationTask): + def __init__(self): + super().__init__() + self.map = ( + "from counter in counters " + "select new { likes = counter.Value, name = counter.Name, user = counter.DocumentId }" + ) + + +# endregion +# region index_3 +class MyMultiMapCounterIndex(AbstractJavaScriptCountersIndexCreationTask): + def __init__(self): + super().__init__() + self.maps = """ + counters.map('Blogposts', 'Likes', function (counter) { + return { + Likes: counter.Value, + Name: counter.Name, + Blog Post: counter.DocumentId + }; + }) + """ + + +# endregion + + +""" +# region counter_entry +public class CounterEntry + { + public string DocumentId { get; set; } + public string Name { get; set; } + public long Value { get; set; } + } +# endregion +""" diff --git a/Documentation/6.0/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.python.markdown b/Documentation/6.0/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.python.markdown new file mode 100644 index 0000000000..415502c0f5 --- /dev/null +++ b/Documentation/6.0/Raven.Documentation.Pages/document-extensions/counters/counters-and-other-features.python.markdown @@ -0,0 +1,244 @@ +# Counters and Other Features +--- + +{NOTE: } + +* This section describes the relationships between Counters and other RavenDB features: + * How Counters are supported by the different features. + * How Counters trigger features' execution. + +* In this page: + * [Counters and Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) + * [Counters and Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) + * [Counters and Revisions](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) + * [Counters and Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) + * [Counters and Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) + * [Counters and Ongoing Tasks](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) - `Backup`, `External replication`, `ETL`, `Data Subscription` + * [Counters and Other Features: summary](../../document-extensions/counters/counters-and-other-features#counters-and-other-features-summary) + * [Including Counters](../../document-extensions/counters/counters-and-other-features#including-counters) + * [Counters Bulk-Insert](../../document-extensions/counters/counters-and-other-features#counters-bulk-insert) +{NOTE/} + +--- + +{PANEL: } + +### Counters and Indexing + +Indexing Counters can speed-up finding them and the documents that contain them. + +* **Indexing Counter Values** + Dynamic indexes (aka auto-indexes) _cannot_ index counter values. To index counter values, + create a static index that inherits from `AbstractCountersIndexCreationTask` ([see here](../../document-extensions/counters/indexing)). + +* **Indexing Counter Names** + Re-indexing due to Counter-name modification is normally rare enough to pause no performance issues. + To index a document's Counters by name, use [CounterNamesFor](../../document-extensions/counters/indexing#section-1). + +--- + +###Counters and Queries + +Create queries **using code**, or send the server **raw queries** for execution. + +* Either way, you can query Counters **by name** but **not by value**. + This is because queries are generally [based on indexes](../../start/getting-started#example-iii---querying), and Counter values are [not indexed](../../document-extensions/counters/counters-and-other-features#counters-and-indexing). +* Counter values **can** be [projected](../../indexes/querying/projections) from query results, as demonstrated in the following examples. + This way a client can get Counter values from a query without downloading whole documents. + +* Use [session.query](../../client-api/session/querying/how-to-query#session.query) to code queries yourself. + * **Returned Counter Value**: **Accumulated** + A Counter's value is returned as a single sum, with no specification of the Counter's value on each node. + {CODE:python counters_region_query@DocumentExtensions\Counters\Counters.py /} + +* Use [RawQuery](../../client-api/session/querying/how-to-query#session.advanced.rawquery) to send the server raw RQL expressions for execution. + * You can use the `counter` method. + **Returned Counter Value**: **Accumulated** + + * You can use the `counterRaw` method. + **Returned Counter Value**: **Distributed** + A Counter's value is returned as a series of values, each maintained by one of the nodes. + * It is not expected of you to use this in your application. + Applications normally use the Counter's overall value, and very rarely refer to the value each node gives it. + + + `counter` and `counterRaw` samples: + {CODE-TABS} + {CODE-TAB:python:counter counters_region_rawqueries_counter@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:counterRaw counters_region_rawqueries_counterRaw@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +--- + +###Counters and Revisions + +A [document revision](../../document-extensions/revisions/overview) stores all the document Counters' +names and values when the revision was created. + +* **Stored Counter Values**: **Accumulated** + A revision stores a Counter's value as a single sum, with no specification of the Counter's value on each node. + +* Revisions-creation can be initiated by **Counter-name modification**. + * When the Revisions feature is enabled, the creation or deletion of a Counter initiates the creation of a new document revision. + * Counter **value** modifications do **not** cause the creation of new revisions. + +--- + +###Counters and Changes API + +[Changes API](../../client-api/changes/what-is-changes-api#changes-api) is a Push service, that can inform you of various changes on the Server, including [changes in Counter values](../../client-api/changes/how-to-subscribe-to-counter-changes#changes-api--how-to-subscribe-to-counter-changes). +You can target all Counters, or specify the ones you wish to follow. + +* **Pushed Counter Value**: **Accumulated** + `Changes API` methods return a Counter's value as a single sum, without specifying its value on each node. +* The service is initiated by **Counter Value Modification**. + +--- + +###Counters and Ongoing Tasks: + +Each [ongoing task](../../studio/database/tasks/ongoing-tasks/general-info) relates to Counters in its own way. + +* **Counters** and the **Backup task** + There are two [backup](../../studio/database/tasks/backup-task) types: **logical-backup** and **snapshot**. + Both types store and restore **all** data, including Counters. + Both types operate as an ongoing backup routine, with a pre-set time schedule. + * Logical Backup: + **Backed-up Counter values**: **Distributed** + A logical backup is a higher-level implementation of [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler). + As with Smuggler, Counters are backed-up and restored including their values on all nodes. + * Snapshot: + A snapshot stores all data and settings as a single binary image. + All components, including Counters, are restored to the exact same state they've been at during backup. + +* **Counters** and the **External Replication task** + The ongoing [external replication](../../studio/database/tasks/ongoing-tasks/external-replication-task) task replicates all data, including Counters. + * **Replicated Counter Value**: **Distributed** + Counters are replicated along with their values on all nodes. + * Replication can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + +* **Counters** and the **ETL task** + [ETL](../../server/ongoing-tasks/etl/basics) is used to export data from RavenDB to an external (either Raven or SQL) database. + * [SQL ETL](../../server/ongoing-tasks/etl/sql) is **not supported**. + Counters cannot be exported to an SQL database over SQL ETL. + * [RavenDB ETL](../../server/ongoing-tasks/etl/raven) **is supported**. + Counters [are](../../server/ongoing-tasks/etl/raven#counters) exported over RavenDB ETL. + * Export can be initiated by both **Counter-name update** _and_ **Counter-value modification**. + * **Exported Counter Value**: **Distributed** + Counters are exported along with their values on all nodes. + * Counters can be [exported using a script](../../server/ongoing-tasks/etl/raven#adding-counter-explicitly-in-a-script). + **Default behavior**: When an ETL script is not provided, Counters are exported. + +* **Counters** and the **[Data Subscriptions](../../client-api/data-subscriptions/what-are-data-subscriptions#data-subscriptions) task** + Data Subscriptions can be initiated by document changes, including those caused by **Counter Name updates**. + Documents will **not** be delivered in reaction to Counter Value modification. + + +{NOTE: } +###Counters and Other Features: Summary + +Use this table to find if and how various RavenDB features are triggered by Counters, +and how the various features handle Counter values. + +* In the **Triggered By** column: + * _Document Change_ - Feature is triggered by a Counter Name update. + * _Countrer Value Modification_ - Feature is triggered by a Counter Value modification. + * _Time Schedule_ - Feature is invoked by a pre-set time routine. + * _No Trigger_ - Feature is executed manually, through the Studio or by a Client. +* In the **Counter Value** column: + * _Accumulated_ - Counter Value is handled as a single accumulated sum. + * _Distributed_ - Counter Value is handled as a series of values maintained by cluster nodes. + +| **Feature** | **Triggered by** | **Counter Value** | +|-------------|:-------------|:-------------| +| [Indexing](../../document-extensions/counters/counters-and-other-features#counters-and-indexing) | _Document Change_ | doesn't handle values | +| [LINQ Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | _Accumulated_ | +| [Raw Queries](../../document-extensions/counters/counters-and-other-features#counters-and-queries) | _No trigger_ | `counter()` - _Accumulated_
`counterRaw()` - _Distributed_ | +| [Smuggler](../../document-extensions/counters/counters-and-other-features#counters-and-smuggler) | _No trigger_ | _Distributed_ | +| [Backup Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Time Schedule_ | _Distributed_ | +| [RavenDB ETL Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [External Replication task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_,
_Countrer Value Modification_ | _Distributed_ | +| [Data Subscriptions Update Task](../../document-extensions/counters/counters-and-other-features#counters-and-ongoing-tasks) | _Document Change_ | | +| [Changes API](../../document-extensions/counters/counters-and-other-features#counters-and-changes-api) | _Countrer Value Modification_ | _Accumulated_ | +| [Revision creation](../../document-extensions/counters/counters-and-other-features#counters-and-revisions) | _Document Change_ | _Accumulated_ | + +{NOTE/} + +--- + +###Including Counters +You can [include](../../client-api/how-to/handle-document-relationships#includes) Counters while loading a document. +An included Counter is retrieved in the same request as its owner-document and is held by the session, +so it can be immediately retrieved when needed with no additional remote calls. + + +* **Including Counters when using [session.load](../../client-api/session/loading-entities#session--loading-entities)**: + * Include a single Counter using `include_counter` + * Include multiple Counters using `include_counters` + + `include_counter` and `include_counters` usage samples: + {CODE-TABS} + {CODE-TAB:python:IncludeCounter counters_region_load_include1@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:IncludeCounters counters_region_load_include2@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +* **Including Counters when using [Session.Query](../../client-api/session/querying/how-to-query#session--querying--how-to-query)**: + * Include a single Counter using `include_counter`. + * Include multiple Counters using `include_counters`. + + `include_counter` and `include_counters` usage samples: + {CODE-TABS} + {CODE-TAB:python:IncludeCounter counters_region_query_include_single_Counter@DocumentExtensions\Counters\Counters.py /} + {CODE-TAB:python:IncludeCounters counters_region_query_include_multiple_Counters@DocumentExtensions\Counters\Counters.py /} + {CODE-TABS/} + +--- + +###Counters Bulk-Insert +`store.bulk_insert` is RavenDB's high-performance data insertion operation. +Use its `counters_for` interface's `increment` method to add or update counters with great speed. + +* Syntax + + * `counters_for` + {CODE:python CountersFor-definition@DocumentExtensions\Counters\BulkInsert.py /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | **id** | `str` | Document ID | + + * `Increment` + {CODE:python Increment-definition@DocumentExtensions\Counters\BulkInsert.py /} + + | Parameters | Type | Description | + |:-------------|:-------------|:-------------| + | **name** | `str` | Counter Name | + | **delta** | `int` | Default: 1L | + +* Usage Flow + + * Create a `store.bulk_insert` instance. + * Pass the instance's `counters_for` interface, the document ID + * Call `increment` as many times as you like. Pass it - + The Counter Name and Value (delta to be added). + +* Usage Sample + In this sample, we attach a counter to all User documents. + {CODE:python bulk-insert-counters@DocumentExtensions\Counters\BulkInsert.py /} + + +{PANEL/} + +## Related articles +**Studio Articles**: +[Studio Counters Management](../../studio/database/document-extensions/counters#counters) + +**Client-API - Session Articles**: +[Counters Overview](../../document-extensions/counters/overview) +[Creating and Modifying Counters](../../document-extensions/counters/create-or-modify) +[Deleting a Counter](../../document-extensions/counters/delete) +[Retrieving Counter Values](../../document-extensions/counters/retrieve-counter-values) +[Counters In Clusters](../../document-extensions/counters/counters-in-clusters) + +**Client-API - Operations Articles**: +[Counters Operations](../../client-api/operations/counters/get-counters#operations--counters--how-to-get-counters) diff --git a/Documentation/6.0/Samples/python/DocumentExtensions/Counters/BulkInsert.py b/Documentation/6.0/Samples/python/DocumentExtensions/Counters/BulkInsert.py new file mode 100644 index 0000000000..27979a5292 --- /dev/null +++ b/Documentation/6.0/Samples/python/DocumentExtensions/Counters/BulkInsert.py @@ -0,0 +1,46 @@ +from examples_base import ExampleBase, User + + +class BulkInsertCounters(ExampleBase): + def setUp(self): + super().setUp() + + def test_bulk_insert(self): + with self.embedded_server.get_document_store("CountersBulkInsert") as store: + with store.open_session() as session: + user1 = User(name="Lilly", age=20) + user2 = User(name="Betty", age=25) + user3 = User(name="Robert", age=29) + session.store(user1) + session.store(user2) + session.store(user3) + session.save_changes() + + # region bulk-insert-counters + with store.open_session() as session: + result = list(session.query(object_type=User).where_less_than("Age", 30)) + users_ids = [session.advanced.get_document_id(user) for user in result] + + with store.bulk_insert() as bulk_insert: + for user_id in users_ids: + # Choose document + counters_for = bulk_insert.counters_for(user_id) + + # Add or Increment a counter + bulk_insert.counters_for(user_id).increment("download", 100) + + # endregion + + +class Foo: + """ + # region CountersFor-definition + def counters_for(self, id_: str) -> CountersBulkInsert: + ... + # endregion + """ + + # region Increment-definition + def increment(self, name: str, delta: int = 1) -> None: ... + + # endregion diff --git a/Documentation/6.0/Samples/python/DocumentExtensions/Counters/Counters.py b/Documentation/6.0/Samples/python/DocumentExtensions/Counters/Counters.py new file mode 100644 index 0000000000..fa9cbbfc21 --- /dev/null +++ b/Documentation/6.0/Samples/python/DocumentExtensions/Counters/Counters.py @@ -0,0 +1,200 @@ +from typing import Dict + +from examples_base import ExampleBase, Product + + +class CountersExample(ExampleBase): + def setUp(self): + super().setUp() + + def test_counters(self): + with self.embedded_server.get_document_store("CountersExample") as store: + # region counters_region_CountersFor_with_document_load + # Use counters_for_entity by passing it a document object + + # 1. Open a session + with store.open_session() as session: + # 2. Use the session to load a document. + document = session.load("products/1-C") + + # 3. Create an instance of 'CountersFor' + # Pass the document object returned from session.load as a param. + document_counters = session.counters_for_entity(document) + + # 4. Use 'CountersFor' methods to manage the product document's counters + document_counters.delete("ProductLikes") # Delete the "ProductLikes" counter + document_counters.increment("ProductModified", 15) # Add 15 to Counter "ProductModified" + counter = document_counters.get("DaysLeftForSale") # Get value of "DaysLeftForSale" + + # 5. Execute all changes by calling save_changes + session.save_changes() + # endregion + + # region counters_region_CountersFor_without_document_load + # Use CountersFor without loading a document + + # 1. Open a session + with store.open_session() as session: + # 2. pass an explicit document ID to the CountersFor constructor + document_counters = session.counters_for("products/1-C") + + # 3. Use 'CountersFor' methods to manage the product document's counters + document_counters.delete("ProductLikes") # Delete the "ProductLikes" counter + document_counters.increment("ProductModified", 15) # Add 15 to Counter "ProductModified" + counter = document_counters.get("DaysLeftForSale") # Get "DaysLeftForSale"'s value + + # 4. Execute all changes by calling save_changes + session.save_changes() + # endregion + + # Increment a counter's value + # region counters_region_Increment + # Open a session + with store.open_session() as session: + # Pass CountersFor's constructor a document ID + document_counters = session.counters_for("products/1-A") + + # Use 'CountersFor.increment' + # =========================== + + # Increase "ProductLikes" by 1, or create it if doesn't exist with a value of 1 + document_counters.increment("ProductLikes") + + # Increase "ProductPageViews" by 15, or create it if doesn't exist with a value of 15 + document_counters.increment("ProductPageViews", 15) + + # Decrease "DaysLeftForSale" by 10, or create it if doesn't exist with a value of -10 + document_counters.increment("DaysLeftForSale", -10) + + # Execute all changes by calling save_changes + session.save_changes() + + # endregion + + # get a counter's value by the counter's name + # region counters_region_Get + # 1. Open a session + with store.open_session() as session: + # 2. pass CountersFor's constructor a document ID + document_counters = session.counters_for("products/1-C") + + # 3. Use 'CountersFor.Get' to retrieve a Counter's value + days_left = document_counters.get("DaysLeftForSale") + print(f"Days Left For Sale: {days_left}") + # endregion + + # region counters_region_GetAll + # 1. Open a session + with store.open_session() as session: + # 2. pass CountersFor's constructor a document ID + document_counters = session.counters_for("products/1-C") + + # 3. Use GetAll to retrieve all of the document's counters' names and values + counters = document_counters.get_all() + + # list counters' names and values + for counter_name, counter_value in counters.items(): + print(f"counter name: {counter_name}, counter value: {counter_value}") + # endregion + + with store.open_session() as session: + # region counters_region_load_include1 + # include single Counters + product_page = session.load( + "products/1-C", + include_builder=lambda builder: builder.include_counter("ProductLikes") + .include_counter("ProductDislikes") + .include_counter("ProductDownloads"), + ) + # endregion + + with store.open_session() as session: + # region counters_region_load_include2 + # include multiple Counters + # note that you can combine the inclusion of Counters and documents. + product_page = session.load( + "orders/1-A", + include_builder=lambda builder: builder.include_documents("products/1-C").include_counters( + ["ProductLikes", "ProductDislikes"] + ), + ) + # endregion + + with store.open_session() as session: + # region counters_region_query_include_single_Counter + # include a single Counter + query = session.query(object_type=Product).include(lambda builder: builder.include_counter("ProductLikes")) + # endregion + + with store.open_session() as session: + # region counters_region_query_include_multiple_Counters + # include multiple Counters + query = session.query("Products").include( + lambda builder: builder.include_counters(["ProductLikes", "ProductDownloads"]) + ) + # endregion + + with store.open_session() as session: + # region counters_region_rawqueries_counter + # Various RQL expressions sent to the server using counter() + # Returned Counter value is accumulated + rawquery1 = list(session.advanced.raw_query("from products as p select counter(p, 'ProductLikes')")) + + rawquery2 = list( + session.advanced.raw_query("from products select counter('ProductLikes') as ProductLikesCount") + ) + + rawquery3 = list( + session.advanced.raw_query("from products where PricePerUnit > 50 select Name, counter('ProductLikes')") + ) + # endregion + + # region counters_region_rawqueries_counterRaw + # An RQL expression sent to the server using counterRaw() + # Returned Counter value is distributed + query = list(session.advanced.raw_query("from users as u select counterRaw(u, 'downloads')")) + # endregion + + +class CounterResult: + def __init__(self, product_price: int = None, product_likes: int = None, product_section: str = None): + self.product_price = product_price + self.product_likes = product_likes + self.product_section = product_section + + +class CounterResultRaw: + def __init__(self, downloads: Dict[str, int]): + self.downloads = downloads + + +# region counters_region_CounterItem +# The value given to a Counter by each node, is placed in a CounterItem object. +class CounterItem: + def __init__(self, name: str = None, doc_id: str = None, change_vector: str = None, value: int = None): + self.name = name + self.doc_id = doc_id + self.change_vector = change_vector + self.value = value + + +# endregion + + +class Foo: + # region Increment-definition + def increment(self, counter: str, delta: int = 1) -> None: ... + + # endregion + # region Delete-definition + def delete(self, counter: str) -> None: ... + + # endregion + # region Get-definition + def get(self, counter) -> int: ... + + # endregion + # region GetAll-definition + def get_all(self) -> Dict[str, int]: ... + + # endregion