diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..14d4fa1d4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,440 @@ +The Couchbase Developer Documentation © 2024 by Couchbase Inc. is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0). + +See https://creativecommons.org/licenses/by-nc-sa/4.0/ for details. + +Attribution-NonCommercial-ShareAlike 4.0 International +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. \ No newline at end of file diff --git a/README.md b/README.md index fea1fc776..128c8c91f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,117 @@ -# docs-devex -Devex documentation shared across Server, Capella, and Elixir +# Couchbase Developer Documentation + +This repository contains the developer documentation shared across Couchbase Server and Couchbase Capella. + +The developer documentation includes introductions, tutorials, developer guides, and reference guides for specific Couchbase services. + +This repository is the implementation of the striping strategy that the Documentation team discussed at the 2023 Docs Summit. + +## How Does This Work? + +The goal of this repository is to create a consistent experience for shared content across Server and Capella. + +This repository contains branches for the different products and versions you would need to support with devex docs. + +By using an included partial `nav.adoc` file, you can seamlessly include documentation from this repository into the Server and Capella documentation. + +The workflow for developing documentation in this repository should look similar to the following: + +1. Choose your base product for developing the documentation. For example, you could decide to start writing your docs in a new feature branch based on the `release/7.2` branch for Server, or directly on that branch in a new folder under `modules`. + +2. Write your documentation files as normal. + +3. Create a ToC in the `partials` folder for those documentation files: + +``` +* xref:my-new-module:intro.adoc[] +** xref:my-new-module:new-content.adoc[] +``` + +4. Copy your new documentation files into the `capella` branch, or a new Capella feature branch based on your Server feature branch. + +5. Make the necessary tweaks for the documentation to apply to Capella. + +6. If you created feature branches for your work, merge them into the `release/7.2` or `capella` branches in this repository. + +7. Go to the `docs-server` and `couchbase-cloud` repositories, as described in [Configure Your Local nav.adoc Files](#configure-your-local-navadoc-files), and add your partials to those nav.adoc files. + +Ta-da, you've created devex documentation! + +## How to Build Docs With This Repository + +To add the content from the docs-devex repository to your local Antora builds: + +1. [Configure Your local-antora-playbook.yml](#configure-your-local-antora-playbookyml). + +2. [Configure Your Local nav.adoc Files](#configure-your-local-navadoc-files). + +3. In a terminal, run `antora local-antora-playbook.yml`. + +> **NOTE**: If you run into unexpected behavior when attempting to build (like files not appearing as expected, other errors), add the `--fetch` flag to the end of the `antora local-antora-playbook.yml` command. + +### Configure Your local-antora-playbook.yml + +You need to start by including this repository in your `local-antora-playbook.yml` file: + +1. In the `docs-site` repository, open your `local-antora-playbook.yml` file in a text editor. + +2. Under the `sources` key, add a new `url` entry for https://github.com/couchbaselabs/docs-devex. + +3. In the `branches` key for the new `url`, add the branches that you want to include in your build. For example, `[capella,release/7.2]` for the Couchbase Capella and Couchbase Server 7.2 branches. + +4. Make sure that your `sources` key includes `url` keys for your local copies of the `couchbase-cloud` and `docs-server` repositories. + +> **NOTE**: If you want to create a build using a local copy of two different branches from the `docs-devex` repository, see [Use Worktrees to Create a Fully Local Build](#use-worktrees-to-create-a-fully-local-build). + +### Configure Your Local nav.adoc Files + +Then, make sure that you include the nav partial files into the navigation for Server and Capella: + +1. In your local copy of the `docs-server` repository, go to **modules** > **ROOT**. + +2. Open the `nav.adoc` file in a text editor. + +3. In the ToC structure, choose where you want to include the navigation for the devex branch. + +4. Add an include for the `nav.adoc` partial from the devex branch: + +``` +include:::partial$nav.adoc[] +``` + +5. Repeat Steps 2-4 for the `couchbase-cloud` repository's `nav.adoc` file, located in **docs** > **public** > **modules** > **ROOT**. + + +### Use Worktrees to Create a Fully Local Build + +If you're creating new branches in the docs-devex repository and want to create a fully local build, you'll need to use git worktrees: + +1. Open your `docs-devex` repository in a terminal window. + +2. In the terminal, enter `git worktree add `. It's recommended to give your local folder the same name as the branch. + +3. Repeat Step 2 for all of the branches you need on your local machine. + +4. In the `docs-site` repository, open your `local-antora-playbook.yml` file in a text editor. + +5. Change the `url` key for the `docs-devex` branch to point to your local copy of the repository. + +6. Set the `branches` key for the `docs-devex` branch to include the branches you added as worktrees. + +7. Under the `branches` key, add a `worktrees` key set to `true`: + +``` +- url: ../docs-devex + branches: [my-server-branch, my-capella-branch] + worktrees: true +``` + +You should be able to build your documentation using the local copies of your branches. + +When you want to make changes, edit the files in the specific worktree folder for your branch. + +## License + +The Couchbase Developer Documentation © 2024 by Couchbase Inc. is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International. + +See the LICENSE file or the [Creative Commons CC BY-NC-SA 4.0 license page](https://creativecommons.org/licenses/by-nc-sa/4.0/) for details. \ No newline at end of file diff --git a/antora.yml b/antora.yml index 598fa4529..295ba91d4 100644 --- a/antora.yml +++ b/antora.yml @@ -1,2 +1,6 @@ -name: server -version: '7.2' +name: cloud +version: ~ +asciidoc: + attributes: + ui-name: Capella UI + product-name: Capella diff --git a/diagrams.sh b/diagrams.sh new file mode 100755 index 000000000..dfb8c285c --- /dev/null +++ b/diagrams.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +[[ -d ./build ]] || mkdir ./build + +# install-rr +[[ -f ./build/rr-2.0-java11.zip ]] || curl -L -o ./build/rr-2.0-java11.zip https://github.com/GuntherRademacher/rr/releases/download/v2.0/rr-2.0-java11.zip + +# extract-rr +[[ -f ./build/rr/rr.war ]] || unzip ./build/rr-2.0-java11.zip -d ./build/rr + +for file in n1ql dcl ddl dml dql tcl hints utility +do + + # generate-rr + java -jar ./build/rr/rr.war -png -noembedded -out:./build/railroads.zip -width:776 -keeprecursion -nofactoring -noinline ./modules/n1ql/partials/grammar/${file}.ebnf + + # extract-diagrams + unzip -o ./build/railroads.zip -d ./build/tmp + mv -f ./build/tmp/diagram/*.png ./modules/n1ql/assets/images/n1ql-language-reference + +done \ No newline at end of file diff --git a/modules/ROOT/images/capella-logo.svg b/modules/ROOT/images/capella-logo.svg new file mode 100644 index 000000000..c03d2f24b --- /dev/null +++ b/modules/ROOT/images/capella-logo.svg @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/modules/ROOT/images/couchbase-logo.svg b/modules/ROOT/images/couchbase-logo.svg new file mode 100644 index 000000000..36cf6df44 --- /dev/null +++ b/modules/ROOT/images/couchbase-logo.svg @@ -0,0 +1,50 @@ + + + + + + + \ No newline at end of file diff --git a/modules/ROOT/partials/component-signpost.adoc b/modules/ROOT/partials/component-signpost.adoc new file mode 100644 index 000000000..e8ada1c2c --- /dev/null +++ b/modules/ROOT/partials/component-signpost.adoc @@ -0,0 +1,17 @@ +// `flag-devex-escape-hatch` is a flag to hide the feature from production until ready. +// Use `no-escape-hatch` to turn off the escape hatch for individual pages. +// Use `escape-hatch` to override the escape hatch xref for individual pages. +ifdef::flag-devex-escape-hatch[] +[.signpost] +icon:cloud[fw] +This page is for Couchbase Capella. +ifndef::no-escape-hatch[] +For Couchbase Server, see +ifdef::escape-hatch[] +xref:{escape-hatch}[]. +endif::escape-hatch[] +ifndef::escape-hatch[] +xref:server:{page-module}:{docname}.adoc[]. +endif::escape-hatch[] +endif::no-escape-hatch[] +endif::flag-devex-escape-hatch[] \ No newline at end of file diff --git a/modules/ROOT/partials/query-context.adoc b/modules/ROOT/partials/query-context.adoc new file mode 100644 index 000000000..4d9fa0310 --- /dev/null +++ b/modules/ROOT/partials/query-context.adoc @@ -0,0 +1,24 @@ +// tag::statement[] +To use the examples on this page, you must set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. +// end::statement[] + +// tag::step[] +Set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. +// end::step[] + +// tag::section[] +To try the examples in this section, set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. +// end::section[] + +// tag::example[] +For this example, set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. +// end::example[] + +// tag::unset[] +For this example, unset the query context. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. +// end::unset[] \ No newline at end of file diff --git a/modules/develop/pages/intro.adoc b/modules/develop/pages/intro.adoc new file mode 100644 index 000000000..eef28f590 --- /dev/null +++ b/modules/develop/pages/intro.adoc @@ -0,0 +1,102 @@ += Developer Intro +:page-role: tiles -toc +:description: This section contains tutorials, how-to guides, and information about Couchbase Services to help you develop applications. +:!sectids: +:page-aliases: concepts:application-development,guides:intro.adoc + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +{description} +It also provides links to the documentation for software development kits and other integrations. + +include::ROOT:partial$component-signpost.adoc[] + +== Developer Tutorial + +This tutorial provides an introductory worked example for developers, showing how to use a software development kit with a simple database. + +* xref:tutorials:couchbase-tutorial-student-records.adoc[] + +== Connect + +Choose how you want to connect your app to Couchbase Capella. + +* xref:cloud:get-started:connect.adoc[] + +== Data + +Use the Data Service for key-value (CRUD) operations and to import or export data. + +* xref:guides:data.adoc[] + +== Query + +Use the Query Service and the Index Service to issue {sqlpp} queries to extract and manipulate data. + +* xref:n1ql:query.adoc[] + +== Vector Search + +Vector Search builds on the Search Service to provide support for vector indexes. +You can use vector indexes with existing Large Language Models to develop AI applications. + +* xref:vector-search:vector-search.adoc[] + +== Search + +Use the Search Service for full-text search with natural language processing across multiple data types and languages. +Use custom text analysis, Geospatial search, and more. + +* xref:search:search.adoc[] + +== Eventing + +Use the Eventing Service to respond to changes to your data in near real-time. +Execute custom code in response to mutations, or as scheduled by timers. + +* xref:eventing:eventing-overview.adoc[] + +== Analytics + +Use the Analytics Service for online analytical processing (OLAP) for large datasets, with complex analytical or ad hoc queries. + +* xref:clusters:analytics-service/analytics-service.adoc[] + +== Mobile + +Use App Services in combination with Couchbase Mobile to develop mobile apps. + +* xref:mobile-guides:intro.adoc[] + +== SDKs + +Couchbase offers numerous software development kits (SDKs) that provide programmatic access to Couchbase Capella. + +* xref:home:ROOT:sdk.adoc[] + +== Integrations + +Integrations that Couchbase or partners have developed to enhance Couchbase, Capella, and partner services -- +a vital tool for many larger development projects. + +* xref:third-party:integrations.adoc[] + +== Migration + +A tutorial exercise demonstrating how to migrate your data from a MySQL server over to Couchbase Capella. + +* xref:tutorials:migration-tutorial-capella/sql-migration-tutorial-capella.adoc[] diff --git a/modules/develop/partials/nav.adoc b/modules/develop/partials/nav.adoc new file mode 100644 index 000000000..b66adb7d6 --- /dev/null +++ b/modules/develop/partials/nav.adoc @@ -0,0 +1 @@ +* xref:develop:intro.adoc[] \ No newline at end of file diff --git a/modules/eventing/assets/attachments/examples/high_risk/cards.json b/modules/eventing/assets/attachments/examples/high_risk/cards.json new file mode 100644 index 000000000..8d9bc7868 --- /dev/null +++ b/modules/eventing/assets/attachments/examples/high_risk/cards.json @@ -0,0 +1,169 @@ +[ + { + "type": "card", + "cardnumber": "4273-6623-8686-4599", + "firstname": "Winfred", + "lastname": "Raftery", + "street": "3965 I-80 E Off Ramp", + "mobile": "+1-617-555-1371", + "sms": true, + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "issued": "11/15", + "expiry": "6/19", + "ccv": 736, + "issuer": "Helena National Bank", + "maxcredit": 1000, + "threshold": 9500, + "country": "US", + "currency": "USD" + }, + { + "type": "card", + "cardnumber": "4163-4174-9281-3991", + "firstname": "Francoise", + "lastname": "Navar", + "street": "134 Yacht Rd", + "mobile": "+1-334-555-9369", + "sms": true, + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "issued": "1/17", + "expiry": "3/21", + "ccv": 213, + "issuer": "First National Bank of Las Animas", + "maxcredit": 15000, + "threshold": 12000, + "country": "US", + "currency": "USD" + }, + { + "type": "card", + "cardnumber": "5677-7414-8288-4326", + "firstname": "Exie", + "lastname": "Barclift", + "street": "4907 Lomita Ave", + "mobile": "+1-334-555-9369", + "sms": true, + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "issued": "5/16", + "expiry": "9/20", + "ccv": 467, + "issuer": "Waterford Bank, National Association", + "maxcredit": 25000, + "threshold": 22000, + "country": "US", + "currency": "USD" + }, + { + "type": "card", + "cardnumber": "5920-7728-6813-5867", + "firstname": "Krista", + "lastname": "Barde", + "street": "4582 Clinton Park", + "mobile": "+1-502-555-124", + "sms": true, + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "issued": "2/14", + "expiry": "4/18", + "ccv": 649, + "issuer": "Superior National Bank & Trust Company", + "maxcredit": 30000, + "threshold": 25000, + "country": "US", + "currency": "USD" + }, + { + "type": "card", + "cardnumber": "4205-1834-8271-9835", + "firstname": "Eli", + "lastname": "Stenn", + "street": "4364 Mcallister St", + "mobile": "+1-717-555-3607", + "sms": true, + "city": { + "name": "Koppel", + "code": "PA", + "state": "Pennsylvania", + "county": "Beaver", + "display": "Koppel" + }, + "issued": "7/16", + "expiry": "5/20", + "ccv": 952, + "issuer": "American National Bank - Fox Cities", + "maxcredit": 10000, + "threshold": 7000, + "country": "US", + "currency": "USD" + }, + { + "type": "card", + "cardnumber": "3205-9894-1221-0005", + "firstname": "Jake", + "lastname": "Smith", + "street": "3250 Olcott Street", + "mobile": "+1-916-555-1836", + "sms": true, + "city": { + "name": "Santa Clara", + "code": "CA", + "state": "California", + "county": "Santa Clara", + "display": "Santa Clara" + }, + "issued": "10/15", + "expiry": "9/20", + "ccv": 912, + "issuer": "Chase JP Morgan", + "maxcredit": 10000, + "threshold": 7000, + "country": "US", + "currency": "USD" + }, + { + "type": "card", + "cardnumber": "4885-1834-8271-9888", + "firstname": "Eli", + "lastname": "Stenn", + "street": "45 St. John's Road", + "mobile": "+44-20-8759-9036", + "sms": true, + "city": { + "name": "Motherwell", + "code": "ML12 6MX", + "county": "Biggar", + "display": "Motherwell Biggar" + }, + "issued": "8/17", + "expiry": "5/22", + "ccv": 321, + "issuer": "Barclays PLC", + "maxcredit": 2500, + "threshold": 1000, + "country": "UK", + "currency": "GBP" + } +] diff --git a/modules/eventing/assets/attachments/examples/high_risk/exchange_rates.json b/modules/eventing/assets/attachments/examples/high_risk/exchange_rates.json new file mode 100644 index 000000000..600fa57cd --- /dev/null +++ b/modules/eventing/assets/attachments/examples/high_risk/exchange_rates.json @@ -0,0 +1,5910 @@ +[ + { + "type": "exchange_rates", + "erid": "er-2017-08-06", + "to_USD": { + "CAD": 1.2571621166, + "INR": 63.619396697, + "EUR": 0.8426019548, + "USD": 1, + "SGD": 1.3563363667, + "GBP": 0.7607010448, + "CNY": 6.7203404112, + "AUD": 1.2544657904 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-07", + "to_USD": { + "CAD": 1.268034246, + "INR": 63.8302110706, + "EUR": 0.8476731372, + "USD": 1, + "SGD": 1.3633127066, + "GBP": 0.7665932017, + "CNY": 6.7204373993, + "AUD": 1.2637958803 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-08", + "to_USD": { + "CAD": 1.2662095819, + "INR": 63.6418655832, + "EUR": 0.8464533604, + "USD": 1, + "SGD": 1.3604198409, + "GBP": 0.7675469782, + "CNY": 6.7007787371, + "AUD": 1.259691891 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-09", + "to_USD": { + "CAD": 1.2680078425, + "INR": 63.8598584946, + "EUR": 0.852442247, + "USD": 1, + "SGD": 1.3628846646, + "GBP": 0.7700792771, + "CNY": 6.6759867019, + "AUD": 1.2683488194 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-10", + "to_USD": { + "CAD": 1.2719911354, + "INR": 64.1050119332, + "EUR": 0.8523695875, + "USD": 1, + "SGD": 1.3637913399, + "GBP": 0.7697153086, + "CNY": 6.6542788953, + "AUD": 1.2690078418 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-11", + "to_USD": { + "CAD": 1.2712282193, + "INR": 64.1699957501, + "EUR": 0.8499787505, + "USD": 1, + "SGD": 1.3643858904, + "GBP": 0.7704632384, + "CNY": 6.6650233744, + "AUD": 1.2717382065 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-12", + "to_USD": { + "CAD": 1.2712282193, + "INR": 64.1699957501, + "EUR": 0.8499787505, + "USD": 1, + "SGD": 1.3643858904, + "GBP": 0.7704632384, + "CNY": 6.6650233744, + "AUD": 1.2717382065 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-13", + "to_USD": { + "CAD": 1.2712282193, + "INR": 64.1699957501, + "EUR": 0.8499787505, + "USD": 1, + "SGD": 1.3643858904, + "GBP": 0.7704632384, + "CNY": 6.6650233744, + "AUD": 1.2717382065 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-14", + "to_USD": { + "CAD": 1.269390523, + "INR": 64.1171484276, + "EUR": 0.8476731372, + "USD": 1, + "SGD": 1.3616173603, + "GBP": 0.7708315673, + "CNY": 6.6722895651, + "AUD": 1.2703229635 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-15", + "to_USD": { + "CAD": 1.2738419619, + "INR": 64.119976158, + "EUR": 0.8514986376, + "USD": 1, + "SGD": 1.3659741144, + "GBP": 0.7760984332, + "CNY": 6.6832425068, + "AUD": 1.2755449591 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-16", + "to_USD": { + "CAD": 1.2730999146, + "INR": 64.1900085397, + "EUR": 0.853970965, + "USD": 1, + "SGD": 1.3682322801, + "GBP": 0.7770538002, + "CNY": 6.6945345858, + "AUD": 1.2726729291 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-17", + "to_USD": { + "CAD": 1.2624604599, + "INR": 64.1698726169, + "EUR": 0.854920065, + "USD": 1, + "SGD": 1.3659912798, + "GBP": 0.7770795931, + "CNY": 6.6777806275, + "AUD": 1.2615200479 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-18", + "to_USD": { + "CAD": 1.2656729131, + "INR": 64.145229983, + "EUR": 0.8517887564, + "USD": 1, + "SGD": 1.3640545145, + "GBP": 0.7767291312, + "CNY": 6.6722316865, + "AUD": 1.2632027257 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-19", + "to_USD": { + "CAD": 1.2656729131, + "INR": 64.145229983, + "EUR": 0.8517887564, + "USD": 1, + "SGD": 1.3640545145, + "GBP": 0.7767291312, + "CNY": 6.6722316865, + "AUD": 1.2632027257 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-20", + "to_USD": { + "CAD": 1.2656729131, + "INR": 64.145229983, + "EUR": 0.8517887564, + "USD": 1, + "SGD": 1.3640545145, + "GBP": 0.7767291312, + "CNY": 6.6722316865, + "AUD": 1.2632027257 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-21", + "to_USD": { + "CAD": 1.2596717966, + "INR": 64.142930023, + "EUR": 0.8502678344, + "USD": 1, + "SGD": 1.3624691778, + "GBP": 0.776447581, + "CNY": 6.671371482, + "AUD": 1.2610322252 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-22", + "to_USD": { + "CAD": 1.2578370572, + "INR": 64.0994817772, + "EUR": 0.8495454932, + "USD": 1, + "SGD": 1.3619913346, + "GBP": 0.7791436581, + "CNY": 6.6629853029, + "AUD": 1.2647183757 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-23", + "to_USD": { + "CAD": 1.2584117298, + "INR": 64.0795830155, + "EUR": 0.8475294516, + "USD": 1, + "SGD": 1.3620645817, + "GBP": 0.7808543097, + "CNY": 6.6602254428, + "AUD": 1.265869989 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-24", + "to_USD": { + "CAD": 1.2522446214, + "INR": 64.0322717262, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3611722853, + "GBP": 0.7792647806, + "CNY": 6.6615280366, + "AUD": 1.2663899712 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-25", + "to_USD": { + "CAD": 1.2507621951, + "INR": 64.0222730352, + "EUR": 0.8468834688, + "USD": 1, + "SGD": 1.3596714092, + "GBP": 0.7798357046, + "CNY": 6.6561653117, + "AUD": 1.2634654472 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-26", + "to_USD": { + "CAD": 1.2507621951, + "INR": 64.0222730352, + "EUR": 0.8468834688, + "USD": 1, + "SGD": 1.3596714092, + "GBP": 0.7798357046, + "CNY": 6.6561653117, + "AUD": 1.2634654472 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-27", + "to_USD": { + "CAD": 1.2507621951, + "INR": 64.0222730352, + "EUR": 0.8468834688, + "USD": 1, + "SGD": 1.3596714092, + "GBP": 0.7798357046, + "CNY": 6.6561653117, + "AUD": 1.2634654472 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-28", + "to_USD": { + "CAD": 1.2466247379, + "INR": 63.9048218029, + "EUR": 0.8385744235, + "USD": 1, + "SGD": 1.3548008386, + "GBP": 0.7742389937, + "CNY": 6.6229769392, + "AUD": 1.2585324948 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-29", + "to_USD": { + "CAD": 1.2480909695, + "INR": 64.0222443559, + "EUR": 0.8300132802, + "USD": 1, + "SGD": 1.3515106242, + "GBP": 0.7716218459, + "CNY": 6.5958665339, + "AUD": 1.2542330677 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-30", + "to_USD": { + "CAD": 1.2555387714, + "INR": 64.0252601544, + "EUR": 0.8392077878, + "USD": 1, + "SGD": 1.3567472306, + "GBP": 0.774135616, + "CNY": 6.5927324606, + "AUD": 1.2601544142 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-08-31", + "to_USD": { + "CAD": 1.265961945, + "INR": 63.9319238901, + "EUR": 0.8456659619, + "USD": 1, + "SGD": 1.3610147992, + "GBP": 0.7777843552, + "CNY": 6.6011839323, + "AUD": 1.2698520085 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-01", + "to_USD": { + "CAD": 1.2441275168, + "INR": 64.0331375839, + "EUR": 0.8389261745, + "USD": 1, + "SGD": 1.3545302013, + "GBP": 0.7724412752, + "CNY": 6.5591442953, + "AUD": 1.2601510067 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-02", + "to_USD": { + "CAD": 1.2441275168, + "INR": 64.0331375839, + "EUR": 0.8389261745, + "USD": 1, + "SGD": 1.3545302013, + "GBP": 0.7724412752, + "CNY": 6.5591442953, + "AUD": 1.2601510067 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-03", + "to_USD": { + "CAD": 1.2441275168, + "INR": 64.0331375839, + "EUR": 0.8389261745, + "USD": 1, + "SGD": 1.3545302013, + "GBP": 0.7724412752, + "CNY": 6.5591442953, + "AUD": 1.2601510067 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-04", + "to_USD": { + "CAD": 1.2409911802, + "INR": 64.039899202, + "EUR": 0.8399832003, + "USD": 1, + "SGD": 1.3565728685, + "GBP": 0.7715665687, + "CNY": 6.5290214196, + "AUD": 1.2566148677 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-05", + "to_USD": { + "CAD": 1.2390243902, + "INR": 64.1274179983, + "EUR": 0.8410428932, + "USD": 1, + "SGD": 1.3553406224, + "GBP": 0.7715727502, + "CNY": 6.5487804878, + "AUD": 1.2533221194 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-06", + "to_USD": { + "CAD": 1.2393764144, + "INR": 64.1123962786, + "EUR": 0.8381527114, + "USD": 1, + "SGD": 1.3521917693, + "GBP": 0.766306261, + "CNY": 6.5250188584, + "AUD": 1.2539602716 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-07", + "to_USD": { + "CAD": 1.2185281096, + "INR": 64.015119873, + "EUR": 0.8353521009, + "USD": 1, + "SGD": 1.3441650656, + "GBP": 0.7635368808, + "CNY": 6.4905187537, + "AUD": 1.2468465458 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-08", + "to_USD": { + "CAD": 1.2087064677, + "INR": 63.7848258706, + "EUR": 0.8291873964, + "USD": 1, + "SGD": 1.3369817579, + "GBP": 0.7567827529, + "CNY": 6.4615257048, + "AUD": 1.2339137645 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-09", + "to_USD": { + "CAD": 1.2087064677, + "INR": 63.7848258706, + "EUR": 0.8291873964, + "USD": 1, + "SGD": 1.3369817579, + "GBP": 0.7567827529, + "CNY": 6.4615257048, + "AUD": 1.2339137645 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-10", + "to_USD": { + "CAD": 1.2087064677, + "INR": 63.7848258706, + "EUR": 0.8291873964, + "USD": 1, + "SGD": 1.3369817579, + "GBP": 0.7567827529, + "CNY": 6.4615257048, + "AUD": 1.2339137645 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-11", + "to_USD": { + "CAD": 1.2120530133, + "INR": 63.9109777444, + "EUR": 0.8335417188, + "USD": 1, + "SGD": 1.3444194382, + "GBP": 0.7566474952, + "CNY": 6.5290489289, + "AUD": 1.2432274735 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-12", + "to_USD": { + "CAD": 1.2131903126, + "INR": 64.0563982234, + "EUR": 0.838012235, + "USD": 1, + "SGD": 1.3470208665, + "GBP": 0.7531886366, + "CNY": 6.5385066622, + "AUD": 1.2441967653 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-13", + "to_USD": { + "CAD": 1.2139577594, + "INR": 63.9999165206, + "EUR": 0.8347942232, + "USD": 1, + "SGD": 1.345521329, + "GBP": 0.7533433509, + "CNY": 6.5321813173, + "AUD": 1.2445947074 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-14", + "to_USD": { + "CAD": 1.2201093816, + "INR": 64.1224232225, + "EUR": 0.8413967186, + "USD": 1, + "SGD": 1.3506941523, + "GBP": 0.7498779975, + "CNY": 6.5559949516, + "AUD": 1.2517458982 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-15", + "to_USD": { + "CAD": 1.2137423723, + "INR": 64.083005935, + "EUR": 0.8359107247, + "USD": 1, + "SGD": 1.3433085346, + "GBP": 0.7359608794, + "CNY": 6.5450973836, + "AUD": 1.2464264817 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-16", + "to_USD": { + "CAD": 1.2137423723, + "INR": 64.083005935, + "EUR": 0.8359107247, + "USD": 1, + "SGD": 1.3433085346, + "GBP": 0.7359608794, + "CNY": 6.5450973836, + "AUD": 1.2464264817 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-17", + "to_USD": { + "CAD": 1.2137423723, + "INR": 64.083005935, + "EUR": 0.8359107247, + "USD": 1, + "SGD": 1.3433085346, + "GBP": 0.7359608794, + "CNY": 6.5450973836, + "AUD": 1.2464264817 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-18", + "to_USD": { + "CAD": 1.2203716103, + "INR": 64.1375125544, + "EUR": 0.8369601607, + "USD": 1, + "SGD": 1.3460830264, + "GBP": 0.7386424506, + "CNY": 6.5718111818, + "AUD": 1.2510043522 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-19", + "to_USD": { + "CAD": 1.2290344136, + "INR": 64.3312729703, + "EUR": 0.8352823254, + "USD": 1, + "SGD": 1.3490644838, + "GBP": 0.7402439024, + "CNY": 6.5846976278, + "AUD": 1.2503341129 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-20", + "to_USD": { + "CAD": 1.224369118, + "INR": 64.2929124677, + "EUR": 0.8328475056, + "USD": 1, + "SGD": 1.3432164571, + "GBP": 0.738569168, + "CNY": 6.5751644874, + "AUD": 1.2401932206 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-21", + "to_USD": { + "CAD": 1.2357832843, + "INR": 64.8042839143, + "EUR": 0.8399832003, + "USD": 1, + "SGD": 1.3523729525, + "GBP": 0.741201176, + "CNY": 6.5921881562, + "AUD": 1.2601427971 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-22", + "to_USD": { + "CAD": 1.226904105, + "INR": 64.7947496029, + "EUR": 0.8360504975, + "USD": 1, + "SGD": 1.3454560655, + "GBP": 0.737020316, + "CNY": 6.5884959452, + "AUD": 1.2549954017 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-23", + "to_USD": { + "CAD": 1.226904105, + "INR": 64.7947496029, + "EUR": 0.8360504975, + "USD": 1, + "SGD": 1.3454560655, + "GBP": 0.737020316, + "CNY": 6.5884959452, + "AUD": 1.2549954017 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-24", + "to_USD": { + "CAD": 1.226904105, + "INR": 64.7947496029, + "EUR": 0.8360504975, + "USD": 1, + "SGD": 1.3454560655, + "GBP": 0.737020316, + "CNY": 6.5884959452, + "AUD": 1.2549954017 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-25", + "to_USD": { + "CAD": 1.2328305385, + "INR": 65.1078621387, + "EUR": 0.8426729586, + "USD": 1, + "SGD": 1.35088902, + "GBP": 0.7410297464, + "CNY": 6.6233251875, + "AUD": 1.2570152524 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-26", + "to_USD": { + "CAD": 1.2390769492, + "INR": 65.4903707474, + "EUR": 0.8483922966, + "USD": 1, + "SGD": 1.3547128192, + "GBP": 0.7446763383, + "CNY": 6.6334945279, + "AUD": 1.267837448 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-27", + "to_USD": { + "CAD": 1.2395877694, + "INR": 65.7124606081, + "EUR": 0.8517162082, + "USD": 1, + "SGD": 1.3596797547, + "GBP": 0.7458052977, + "CNY": 6.6420236777, + "AUD": 1.2736564177 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-28", + "to_USD": { + "CAD": 1.2467311938, + "INR": 65.473764646, + "EUR": 0.8490405841, + "USD": 1, + "SGD": 1.3593139752, + "GBP": 0.7440567159, + "CNY": 6.6595347258, + "AUD": 1.2781456954 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-29", + "to_USD": { + "CAD": 1.2440284601, + "INR": 65.2795188887, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3578688802, + "GBP": 0.7468914111, + "CNY": 6.6520413349, + "AUD": 1.2768931052 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-09-30", + "to_USD": { + "CAD": 1.2440284601, + "INR": 65.2795188887, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3578688802, + "GBP": 0.7468914111, + "CNY": 6.6520413349, + "AUD": 1.2768931052 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-01", + "to_USD": { + "CAD": 1.2440284601, + "INR": 65.2795188887, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3578688802, + "GBP": 0.7468914111, + "CNY": 6.6520413349, + "AUD": 1.2768931052 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-02", + "to_USD": { + "CAD": 1.2511069482, + "INR": 65.3069652589, + "EUR": 0.8514986376, + "USD": 1, + "SGD": 1.3626532698, + "GBP": 0.7528780654, + "CNY": 6.6534400545, + "AUD": 1.2803133515 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-03", + "to_USD": { + "CAD": 1.2500638135, + "INR": 65.504126606, + "EUR": 0.8508465924, + "USD": 1, + "SGD": 1.3627159023, + "GBP": 0.7554922148, + "CNY": 6.6428146005, + "AUD": 1.2795881902 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-04", + "to_USD": { + "CAD": 1.2452702129, + "INR": 65.0216340036, + "EUR": 0.8483922966, + "USD": 1, + "SGD": 1.3593789768, + "GBP": 0.7531008738, + "CNY": 6.6312887079, + "AUD": 1.2714006957 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-05", + "to_USD": { + "CAD": 1.2480838017, + "INR": 65.1477601771, + "EUR": 0.8516436723, + "USD": 1, + "SGD": 1.3624595469, + "GBP": 0.7592658832, + "CNY": 6.6520183955, + "AUD": 1.2787429739 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-06", + "to_USD": { + "CAD": 1.257452806, + "INR": 65.3831041257, + "EUR": 0.854189801, + "USD": 1, + "SGD": 1.3664474246, + "GBP": 0.7647988383, + "CNY": 6.6533697788, + "AUD": 1.2864098403 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-07", + "to_USD": { + "CAD": 1.257452806, + "INR": 65.3831041257, + "EUR": 0.854189801, + "USD": 1, + "SGD": 1.3664474246, + "GBP": 0.7647988383, + "CNY": 6.6533697788, + "AUD": 1.2864098403 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-08", + "to_USD": { + "CAD": 1.257452806, + "INR": 65.3831041257, + "EUR": 0.854189801, + "USD": 1, + "SGD": 1.3664474246, + "GBP": 0.7647988383, + "CNY": 6.6533697788, + "AUD": 1.2864098403 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-09", + "to_USD": { + "CAD": 1.2541290652, + "INR": 65.3520347352, + "EUR": 0.8513536523, + "USD": 1, + "SGD": 1.3632726034, + "GBP": 0.7593648902, + "CNY": 6.6225097906, + "AUD": 1.2891197003 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-10", + "to_USD": { + "CAD": 1.2498940409, + "INR": 65.2470967195, + "EUR": 0.8476731372, + "USD": 1, + "SGD": 1.3563617869, + "GBP": 0.757904552, + "CNY": 6.5787064508, + "AUD": 1.2846486395 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-11", + "to_USD": { + "CAD": 1.250887574, + "INR": 65.1445477599, + "EUR": 0.8453085376, + "USD": 1, + "SGD": 1.3562130178, + "GBP": 0.7583262891, + "CNY": 6.592476754, + "AUD": 1.2836855452 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-12", + "to_USD": { + "CAD": 1.2470479082, + "INR": 65.0300269906, + "EUR": 0.8434547908, + "USD": 1, + "SGD": 1.3541666667, + "GBP": 0.7610914305, + "CNY": 6.5883097166, + "AUD": 1.2799426451 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-13", + "to_USD": { + "CAD": 1.249872989, + "INR": 64.9555461473, + "EUR": 0.8467400508, + "USD": 1, + "SGD": 1.3558848434, + "GBP": 0.7534292972, + "CNY": 6.5902624894, + "AUD": 1.2768839966 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-14", + "to_USD": { + "CAD": 1.249872989, + "INR": 64.9555461473, + "EUR": 0.8467400508, + "USD": 1, + "SGD": 1.3558848434, + "GBP": 0.7534292972, + "CNY": 6.5902624894, + "AUD": 1.2768839966 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-15", + "to_USD": { + "CAD": 1.249872989, + "INR": 64.9555461473, + "EUR": 0.8467400508, + "USD": 1, + "SGD": 1.3558848434, + "GBP": 0.7534292972, + "CNY": 6.5902624894, + "AUD": 1.2768839966 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-16", + "to_USD": { + "CAD": 1.2539184953, + "INR": 64.7424383631, + "EUR": 0.8472422266, + "USD": 1, + "SGD": 1.3518596967, + "GBP": 0.7519528933, + "CNY": 6.5900194866, + "AUD": 1.2705244429 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-17", + "to_USD": { + "CAD": 1.2535929926, + "INR": 65.0306148482, + "EUR": 0.85041245, + "USD": 1, + "SGD": 1.3565779403, + "GBP": 0.758125691, + "CNY": 6.6201207586, + "AUD": 1.2751084276 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-18", + "to_USD": { + "CAD": 1.2528725849, + "INR": 65.0527704485, + "EUR": 0.8511362669, + "USD": 1, + "SGD": 1.3585837093, + "GBP": 0.7599199932, + "CNY": 6.6275427696, + "AUD": 1.277470423 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-19", + "to_USD": { + "CAD": 1.2458171371, + "INR": 65.0278857529, + "EUR": 0.8450228156, + "USD": 1, + "SGD": 1.3567686328, + "GBP": 0.7589572418, + "CNY": 6.6173736691, + "AUD": 1.2703227987 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-20", + "to_USD": { + "CAD": 1.2493653749, + "INR": 65.009984769, + "EUR": 0.8461668641, + "USD": 1, + "SGD": 1.3584362836, + "GBP": 0.7583601286, + "CNY": 6.618463361, + "AUD": 1.2739042139 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-21", + "to_USD": { + "CAD": 1.2493653749, + "INR": 65.009984769, + "EUR": 0.8461668641, + "USD": 1, + "SGD": 1.3584362836, + "GBP": 0.7583601286, + "CNY": 6.618463361, + "AUD": 1.2739042139 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-22", + "to_USD": { + "CAD": 1.2493653749, + "INR": 65.009984769, + "EUR": 0.8461668641, + "USD": 1, + "SGD": 1.3584362836, + "GBP": 0.7583601286, + "CNY": 6.618463361, + "AUD": 1.2739042139 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-23", + "to_USD": { + "CAD": 1.2636286201, + "INR": 65.022572402, + "EUR": 0.8517887564, + "USD": 1, + "SGD": 1.3625212947, + "GBP": 0.7588586031, + "CNY": 6.6402896082, + "AUD": 1.2792163543 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-24", + "to_USD": { + "CAD": 1.2647734036, + "INR": 65.1126604881, + "EUR": 0.8502678344, + "USD": 1, + "SGD": 1.362384151, + "GBP": 0.7593146841, + "CNY": 6.6339596973, + "AUD": 1.2853498852 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-25", + "to_USD": { + "CAD": 1.2696648282, + "INR": 64.9249045397, + "EUR": 0.8485362749, + "USD": 1, + "SGD": 1.3616461604, + "GBP": 0.7542044972, + "CNY": 6.6454815443, + "AUD": 1.2967331353 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-26", + "to_USD": { + "CAD": 1.2797583596, + "INR": 64.8600357356, + "EUR": 0.8508465924, + "USD": 1, + "SGD": 1.3622053944, + "GBP": 0.7573385519, + "CNY": 6.6368586744, + "AUD": 1.297370884 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-27", + "to_USD": { + "CAD": 1.2891856958, + "INR": 65.0598879793, + "EUR": 0.8616975442, + "USD": 1, + "SGD": 1.3700129255, + "GBP": 0.7637483843, + "CNY": 6.6544592848, + "AUD": 1.3094355881 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-28", + "to_USD": { + "CAD": 1.2891856958, + "INR": 65.0598879793, + "EUR": 0.8616975442, + "USD": 1, + "SGD": 1.3700129255, + "GBP": 0.7637483843, + "CNY": 6.6544592848, + "AUD": 1.3094355881 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-29", + "to_USD": { + "CAD": 1.2891856958, + "INR": 65.0598879793, + "EUR": 0.8616975442, + "USD": 1, + "SGD": 1.3700129255, + "GBP": 0.7637483843, + "CNY": 6.6544592848, + "AUD": 1.3094355881 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-30", + "to_USD": { + "CAD": 1.2847054771, + "INR": 64.8949362728, + "EUR": 0.8611780916, + "USD": 1, + "SGD": 1.3637616259, + "GBP": 0.757664485, + "CNY": 6.6452807441, + "AUD": 1.3045125732 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-10-31", + "to_USD": { + "CAD": 1.2892249527, + "INR": 64.7499570373, + "EUR": 0.8592541674, + "USD": 1, + "SGD": 1.3627771095, + "GBP": 0.7548805637, + "CNY": 6.6314658876, + "AUD": 1.3069255886 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-01", + "to_USD": { + "CAD": 1.2905614881, + "INR": 64.5995521874, + "EUR": 0.8611780916, + "USD": 1, + "SGD": 1.3613503272, + "GBP": 0.7525404754, + "CNY": 6.611005856, + "AUD": 1.3034791595 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-02", + "to_USD": { + "CAD": 1.2846715328, + "INR": 64.6019750966, + "EUR": 0.8587376556, + "USD": 1, + "SGD": 1.3604980678, + "GBP": 0.7616144268, + "CNY": 6.6132245599, + "AUD": 1.298153714 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-03", + "to_USD": { + "CAD": 1.2721969632, + "INR": 64.5226044437, + "EUR": 0.8578536502, + "USD": 1, + "SGD": 1.360041177, + "GBP": 0.7628292013, + "CNY": 6.6226301793, + "AUD": 1.3025649824 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-04", + "to_USD": { + "CAD": 1.2721969632, + "INR": 64.5226044437, + "EUR": 0.8578536502, + "USD": 1, + "SGD": 1.360041177, + "GBP": 0.7628292013, + "CNY": 6.6226301793, + "AUD": 1.3025649824 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-05", + "to_USD": { + "CAD": 1.2721969632, + "INR": 64.5226044437, + "EUR": 0.8578536502, + "USD": 1, + "SGD": 1.360041177, + "GBP": 0.7628292013, + "CNY": 6.6226301793, + "AUD": 1.3025649824 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-06", + "to_USD": { + "CAD": 1.2758412425, + "INR": 64.6725625539, + "EUR": 0.8628127696, + "USD": 1, + "SGD": 1.3646246764, + "GBP": 0.7626402071, + "CNY": 6.6340811044, + "AUD": 1.3045729077 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-07", + "to_USD": { + "CAD": 1.2766822349, + "INR": 64.9948105864, + "EUR": 0.864902266, + "USD": 1, + "SGD": 1.364123854, + "GBP": 0.761442657, + "CNY": 6.6381248919, + "AUD": 1.3070403044 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-08", + "to_USD": { + "CAD": 1.272907679, + "INR": 64.9874892148, + "EUR": 0.8628127696, + "USD": 1, + "SGD": 1.3620362381, + "GBP": 0.762769629, + "CNY": 6.6296807593, + "AUD": 1.3023295945 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-09", + "to_USD": { + "CAD": 1.2707652623, + "INR": 64.969905417, + "EUR": 0.8598452279, + "USD": 1, + "SGD": 1.360189166, + "GBP": 0.7621066208, + "CNY": 6.6374032674, + "AUD": 1.3021496131 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-10", + "to_USD": { + "CAD": 1.2670327784, + "INR": 65.1621760769, + "EUR": 0.8580744809, + "USD": 1, + "SGD": 1.360391282, + "GBP": 0.7582804187, + "CNY": 6.6425261713, + "AUD": 1.3040157886 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-11", + "to_USD": { + "CAD": 1.2670327784, + "INR": 65.1621760769, + "EUR": 0.8580744809, + "USD": 1, + "SGD": 1.360391282, + "GBP": 0.7582804187, + "CNY": 6.6425261713, + "AUD": 1.3040157886 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-12", + "to_USD": { + "CAD": 1.2670327784, + "INR": 65.1621760769, + "EUR": 0.8580744809, + "USD": 1, + "SGD": 1.360391282, + "GBP": 0.7582804187, + "CNY": 6.6425261713, + "AUD": 1.3040157886 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-13", + "to_USD": { + "CAD": 1.2705044612, + "INR": 65.4521276596, + "EUR": 0.8579272478, + "USD": 1, + "SGD": 1.361273164, + "GBP": 0.7637096774, + "CNY": 6.641214825, + "AUD": 1.3088538092 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-14", + "to_USD": { + "CAD": 1.271434653, + "INR": 65.4022988506, + "EUR": 0.8514261388, + "USD": 1, + "SGD": 1.3604086845, + "GBP": 0.7627501064, + "CNY": 6.6368667518, + "AUD": 1.3078756918 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-15", + "to_USD": { + "CAD": 1.2755912162, + "INR": 65.2153716216, + "EUR": 0.8445945946, + "USD": 1, + "SGD": 1.3558277027, + "GBP": 0.759375, + "CNY": 6.6219594595, + "AUD": 1.3160472973 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-16", + "to_USD": { + "CAD": 1.2764421035, + "INR": 65.3224025147, + "EUR": 0.8495454932, + "USD": 1, + "SGD": 1.3568091071, + "GBP": 0.7576501572, + "CNY": 6.6319768924, + "AUD": 1.3173901962 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-17", + "to_USD": { + "CAD": 1.2762187368, + "INR": 65.0122933446, + "EUR": 0.8478168716, + "USD": 1, + "SGD": 1.3563374311, + "GBP": 0.7578211106, + "CNY": 6.6332344214, + "AUD": 1.3253073336 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-18", + "to_USD": { + "CAD": 1.2762187368, + "INR": 65.0122933446, + "EUR": 0.8478168716, + "USD": 1, + "SGD": 1.3563374311, + "GBP": 0.7578211106, + "CNY": 6.6332344214, + "AUD": 1.3253073336 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-19", + "to_USD": { + "CAD": 1.2762187368, + "INR": 65.0122933446, + "EUR": 0.8478168716, + "USD": 1, + "SGD": 1.3563374311, + "GBP": 0.7578211106, + "CNY": 6.6332344214, + "AUD": 1.3253073336 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-20", + "to_USD": { + "CAD": 1.2788388083, + "INR": 65.1027077498, + "EUR": 0.8488243782, + "USD": 1, + "SGD": 1.3557422969, + "GBP": 0.754944402, + "CNY": 6.6339869281, + "AUD": 1.3234869705 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-21", + "to_USD": { + "CAD": 1.280593958, + "INR": 64.9176480628, + "EUR": 0.8533879502, + "USD": 1, + "SGD": 1.3550093873, + "GBP": 0.7552312681, + "CNY": 6.6329578426, + "AUD": 1.3198498037 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-22", + "to_USD": { + "CAD": 1.2740658779, + "INR": 64.8999914886, + "EUR": 0.8511362669, + "USD": 1, + "SGD": 1.35202996, + "GBP": 0.7558941186, + "CNY": 6.6180100434, + "AUD": 1.3195165546 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-23", + "to_USD": { + "CAD": 1.2680621202, + "INR": 64.577987846, + "EUR": 0.8440243079, + "USD": 1, + "SGD": 1.3459655638, + "GBP": 0.7512238352, + "CNY": 6.5733457124, + "AUD": 1.310938555 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-24", + "to_USD": { + "CAD": 1.2707754483, + "INR": 64.6800538857, + "EUR": 0.8419634588, + "USD": 1, + "SGD": 1.3460469816, + "GBP": 0.7503578345, + "CNY": 6.6049507451, + "AUD": 1.3122000505 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-25", + "to_USD": { + "CAD": 1.2707754483, + "INR": 64.6800538857, + "EUR": 0.8419634588, + "USD": 1, + "SGD": 1.3460469816, + "GBP": 0.7503578345, + "CNY": 6.6049507451, + "AUD": 1.3122000505 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-26", + "to_USD": { + "CAD": 1.2707754483, + "INR": 64.6800538857, + "EUR": 0.8419634588, + "USD": 1, + "SGD": 1.3460469816, + "GBP": 0.7503578345, + "CNY": 6.6049507451, + "AUD": 1.3122000505 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-27", + "to_USD": { + "CAD": 1.2680722892, + "INR": 64.5021753681, + "EUR": 0.8366800535, + "USD": 1, + "SGD": 1.34395917, + "GBP": 0.7477827979, + "CNY": 6.6018239625, + "AUD": 1.3099062918 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-28", + "to_USD": { + "CAD": 1.2792732167, + "INR": 64.4174798116, + "EUR": 0.8411843876, + "USD": 1, + "SGD": 1.3444650067, + "GBP": 0.753179677, + "CNY": 6.5974932705, + "AUD": 1.313845895 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-29", + "to_USD": { + "CAD": 1.2831656379, + "INR": 64.3121670753, + "EUR": 0.8455229559, + "USD": 1, + "SGD": 1.3464953073, + "GBP": 0.7465375835, + "CNY": 6.6040415997, + "AUD": 1.3212987233 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-11-30", + "to_USD": { + "CAD": 1.2884631614, + "INR": 64.4674656089, + "EUR": 0.8439530762, + "USD": 1, + "SGD": 1.3491433876, + "GBP": 0.7425521141, + "CNY": 6.6146510254, + "AUD": 1.321546122 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-01", + "to_USD": { + "CAD": 1.2874211191, + "INR": 64.4972654607, + "EUR": 0.8413967186, + "USD": 1, + "SGD": 1.3474127051, + "GBP": 0.7413967186, + "CNY": 6.6092553639, + "AUD": 1.3204038704 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-02", + "to_USD": { + "CAD": 1.2874211191, + "INR": 64.4972654607, + "EUR": 0.8413967186, + "USD": 1, + "SGD": 1.3474127051, + "GBP": 0.7413967186, + "CNY": 6.6092553639, + "AUD": 1.3204038704 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-03", + "to_USD": { + "CAD": 1.2874211191, + "INR": 64.4972654607, + "EUR": 0.8413967186, + "USD": 1, + "SGD": 1.3474127051, + "GBP": 0.7413967186, + "CNY": 6.6092553639, + "AUD": 1.3204038704 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-04", + "to_USD": { + "CAD": 1.2670880742, + "INR": 64.398651496, + "EUR": 0.8428150021, + "USD": 1, + "SGD": 1.3478297514, + "GBP": 0.7393594606, + "CNY": 6.6187947745, + "AUD": 1.3135271808 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-05", + "to_USD": { + "CAD": 1.2632734025, + "INR": 64.4057567317, + "EUR": 0.8440955516, + "USD": 1, + "SGD": 1.3465856335, + "GBP": 0.7443487803, + "CNY": 6.6139951042, + "AUD": 1.3093610197 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-06", + "to_USD": { + "CAD": 1.2662266227, + "INR": 64.5197596683, + "EUR": 0.84623847, + "USD": 1, + "SGD": 1.3476347635, + "GBP": 0.7475247525, + "CNY": 6.6149614961, + "AUD": 1.3171701786 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-07", + "to_USD": { + "CAD": 1.2838113015, + "INR": 64.5774647887, + "EUR": 0.8484642797, + "USD": 1, + "SGD": 1.3504157475, + "GBP": 0.7472255218, + "CNY": 6.6191243849, + "AUD": 1.3305616834 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-08", + "to_USD": { + "CAD": 1.2835973429, + "INR": 64.4502640095, + "EUR": 0.8516436723, + "USD": 1, + "SGD": 1.3531766309, + "GBP": 0.7454011242, + "CNY": 6.6197411003, + "AUD": 1.3302674161 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-09", + "to_USD": { + "CAD": 1.2835973429, + "INR": 64.4502640095, + "EUR": 0.8516436723, + "USD": 1, + "SGD": 1.3531766309, + "GBP": 0.7454011242, + "CNY": 6.6197411003, + "AUD": 1.3302674161 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-10", + "to_USD": { + "CAD": 1.2835973429, + "INR": 64.4502640095, + "EUR": 0.8516436723, + "USD": 1, + "SGD": 1.3531766309, + "GBP": 0.7454011242, + "CNY": 6.6197411003, + "AUD": 1.3302674161 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-11", + "to_USD": { + "CAD": 1.2858596134, + "INR": 64.4120888437, + "EUR": 0.8477449983, + "USD": 1, + "SGD": 1.3509664293, + "GBP": 0.748134961, + "CNY": 6.6182604273, + "AUD": 1.3287555103 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-12", + "to_USD": { + "CAD": 1.2831888492, + "INR": 64.3974162842, + "EUR": 0.8499065103, + "USD": 1, + "SGD": 1.351436342, + "GBP": 0.7484956655, + "CNY": 6.6186469488, + "AUD": 1.3208397076 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-13", + "to_USD": { + "CAD": 1.2859577369, + "INR": 64.4316632584, + "EUR": 0.8520790729, + "USD": 1, + "SGD": 1.3525903204, + "GBP": 0.7490201091, + "CNY": 6.6199727335, + "AUD": 1.3209781868 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-14", + "to_USD": { + "CAD": 1.282904179, + "INR": 64.3701983959, + "EUR": 0.8442380751, + "USD": 1, + "SGD": 1.3465597298, + "GBP": 0.7443056142, + "CNY": 6.6085268046, + "AUD": 1.3045166737 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-15", + "to_USD": { + "CAD": 1.2764695917, + "INR": 64.0424360495, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3465187193, + "GBP": 0.7475266813, + "CNY": 6.6086735558, + "AUD": 1.3028968321 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-16", + "to_USD": { + "CAD": 1.2764695917, + "INR": 64.0424360495, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3465187193, + "GBP": 0.7475266813, + "CNY": 6.6086735558, + "AUD": 1.3028968321 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-17", + "to_USD": { + "CAD": 1.2764695917, + "INR": 64.0424360495, + "EUR": 0.8470269355, + "USD": 1, + "SGD": 1.3465187193, + "GBP": 0.7475266813, + "CNY": 6.6086735558, + "AUD": 1.3028968321 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-18", + "to_USD": { + "CAD": 1.2874099195, + "INR": 64.234421365, + "EUR": 0.8478168716, + "USD": 1, + "SGD": 1.3483679525, + "GBP": 0.7478423061, + "CNY": 6.6176345909, + "AUD": 1.3049597287 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-19", + "to_USD": { + "CAD": 1.2862217711, + "INR": 64.0298570583, + "EUR": 0.8458090163, + "USD": 1, + "SGD": 1.346527954, + "GBP": 0.7485409794, + "CNY": 6.6030618286, + "AUD": 1.3030533705 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-20", + "to_USD": { + "CAD": 1.2850147742, + "INR": 64.1177712115, + "EUR": 0.8442380751, + "USD": 1, + "SGD": 1.3457154918, + "GBP": 0.745631068, + "CNY": 6.5788096243, + "AUD": 1.3024060785 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-21", + "to_USD": { + "CAD": 1.2803777722, + "INR": 64.0252129185, + "EUR": 0.84324142, + "USD": 1, + "SGD": 1.3451387132, + "GBP": 0.7484863817, + "CNY": 6.5850408972, + "AUD": 1.3028923181 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-22", + "to_USD": { + "CAD": 1.2703113136, + "INR": 64.0399055092, + "EUR": 0.8436682696, + "USD": 1, + "SGD": 1.3438791867, + "GBP": 0.7472201131, + "CNY": 6.5759723277, + "AUD": 1.2957057285 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-23", + "to_USD": { + "CAD": 1.2703113136, + "INR": 64.0399055092, + "EUR": 0.8436682696, + "USD": 1, + "SGD": 1.3438791867, + "GBP": 0.7472201131, + "CNY": 6.5759723277, + "AUD": 1.2957057285 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-24", + "to_USD": { + "CAD": 1.2703113136, + "INR": 64.0399055092, + "EUR": 0.8436682696, + "USD": 1, + "SGD": 1.3438791867, + "GBP": 0.7472201131, + "CNY": 6.5759723277, + "AUD": 1.2957057285 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-25", + "to_USD": { + "CAD": 1.2703113136, + "INR": 64.0399055092, + "EUR": 0.8436682696, + "USD": 1, + "SGD": 1.3438791867, + "GBP": 0.7472201131, + "CNY": 6.5759723277, + "AUD": 1.2957057285 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-26", + "to_USD": { + "CAD": 1.2703113136, + "INR": 64.0399055092, + "EUR": 0.8436682696, + "USD": 1, + "SGD": 1.3438791867, + "GBP": 0.7472201131, + "CNY": 6.5759723277, + "AUD": 1.2957057285 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-27", + "to_USD": { + "CAD": 1.2633879781, + "INR": 64.1551071879, + "EUR": 0.8406893653, + "USD": 1, + "SGD": 1.3398066414, + "GBP": 0.7447919294, + "CNY": 6.5552753258, + "AUD": 1.2875998319 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-28", + "to_USD": { + "CAD": 1.2610189375, + "INR": 64.0799396682, + "EUR": 0.8379420144, + "USD": 1, + "SGD": 1.3380258086, + "GBP": 0.7438243674, + "CNY": 6.5360315066, + "AUD": 1.2845651081 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-29", + "to_USD": { + "CAD": 1.2539814892, + "INR": 63.8751771867, + "EUR": 0.8338197282, + "USD": 1, + "SGD": 1.3361127324, + "GBP": 0.7397898774, + "CNY": 6.5074626866, + "AUD": 1.2795797549 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-30", + "to_USD": { + "CAD": 1.2539814892, + "INR": 63.8751771867, + "EUR": 0.8338197282, + "USD": 1, + "SGD": 1.3361127324, + "GBP": 0.7397898774, + "CNY": 6.5074626866, + "AUD": 1.2795797549 + } + }, + { + "type": "exchange_rates", + "erid": "er-2017-12-31", + "to_USD": { + "CAD": 1.2539814892, + "INR": 63.8751771867, + "EUR": 0.8338197282, + "USD": 1, + "SGD": 1.3361127324, + "GBP": 0.7397898774, + "CNY": 6.5074626866, + "AUD": 1.2795797549 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-01", + "to_USD": { + "CAD": 1.2539814892, + "INR": 63.8751771867, + "EUR": 0.8338197282, + "USD": 1, + "SGD": 1.3361127324, + "GBP": 0.7397898774, + "CNY": 6.5074626866, + "AUD": 1.2795797549 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-02", + "to_USD": { + "CAD": 1.2538748446, + "INR": 63.4898466639, + "EUR": 0.828843763, + "USD": 1, + "SGD": 1.3287194364, + "GBP": 0.7372813925, + "CNY": 6.4929962702, + "AUD": 1.2774968918 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-03", + "to_USD": { + "CAD": 1.251517924, + "INR": 63.4995425435, + "EUR": 0.8317391666, + "USD": 1, + "SGD": 1.3297845796, + "GBP": 0.7372535973, + "CNY": 6.5015387175, + "AUD": 1.2758047076 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-04", + "to_USD": { + "CAD": 1.2527144633, + "INR": 63.4048901782, + "EUR": 0.828843763, + "USD": 1, + "SGD": 1.3297140489, + "GBP": 0.7385246581, + "CNY": 6.496477414, + "AUD": 1.2762536262 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-05", + "to_USD": { + "CAD": 1.2509755085, + "INR": 63.3698630137, + "EUR": 0.8302200083, + "USD": 1, + "SGD": 1.3277708593, + "GBP": 0.73792445, + "CNY": 6.4882523869, + "AUD": 1.2753009548 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-06", + "to_USD": { + "CAD": 1.2509755085, + "INR": 63.3698630137, + "EUR": 0.8302200083, + "USD": 1, + "SGD": 1.3277708593, + "GBP": 0.73792445, + "CNY": 6.4882523869, + "AUD": 1.2753009548 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-07", + "to_USD": { + "CAD": 1.2509755085, + "INR": 63.3698630137, + "EUR": 0.8302200083, + "USD": 1, + "SGD": 1.3277708593, + "GBP": 0.73792445, + "CNY": 6.4882523869, + "AUD": 1.2753009548 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-08", + "to_USD": { + "CAD": 1.2427962917, + "INR": 63.5074751524, + "EUR": 0.8352125616, + "USD": 1, + "SGD": 1.3326651633, + "GBP": 0.7384364821, + "CNY": 6.4992900693, + "AUD": 1.2769564854 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-09", + "to_USD": { + "CAD": 1.242541066, + "INR": 63.712286289, + "EUR": 0.8380824673, + "USD": 1, + "SGD": 1.3352329869, + "GBP": 0.7397753939, + "CNY": 6.5257291317, + "AUD": 1.2774052967 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-10", + "to_USD": { + "CAD": 1.2450800534, + "INR": 63.5948965977, + "EUR": 0.8338892595, + "USD": 1, + "SGD": 1.3326384256, + "GBP": 0.7394096064, + "CNY": 6.5040026684, + "AUD": 1.2749332889 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-11", + "to_USD": { + "CAD": 1.2559707082, + "INR": 63.6876924357, + "EUR": 0.8321544479, + "USD": 1, + "SGD": 1.3319464093, + "GBP": 0.7412415744, + "CNY": 6.5013730548, + "AUD": 1.2716152118 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-12", + "to_USD": { + "CAD": 1.2518744336, + "INR": 63.6001483068, + "EUR": 0.8239268353, + "USD": 1, + "SGD": 1.3267693829, + "GBP": 0.7331548159, + "CNY": 6.4609870643, + "AUD": 1.270248002 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-13", + "to_USD": { + "CAD": 1.2518744336, + "INR": 63.6001483068, + "EUR": 0.8239268353, + "USD": 1, + "SGD": 1.3267693829, + "GBP": 0.7331548159, + "CNY": 6.4609870643, + "AUD": 1.270248002 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-14", + "to_USD": { + "CAD": 1.2518744336, + "INR": 63.6001483068, + "EUR": 0.8239268353, + "USD": 1, + "SGD": 1.3267693829, + "GBP": 0.7331548159, + "CNY": 6.4609870643, + "AUD": 1.270248002 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-15", + "to_USD": { + "CAD": 1.2432190274, + "INR": 63.5175531482, + "EUR": 0.8145312373, + "USD": 1, + "SGD": 1.3214140262, + "GBP": 0.7252830496, + "CNY": 6.4380548994, + "AUD": 1.2571475116 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-16", + "to_USD": { + "CAD": 1.2423548651, + "INR": 64.0474243663, + "EUR": 0.8176614881, + "USD": 1, + "SGD": 1.3233851186, + "GBP": 0.7265739984, + "CNY": 6.4415372036, + "AUD": 1.2574816026 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-17", + "to_USD": { + "CAD": 1.2443661395, + "INR": 63.9277226911, + "EUR": 0.819470622, + "USD": 1, + "SGD": 1.3236908957, + "GBP": 0.7257887405, + "CNY": 6.4351389003, + "AUD": 1.2549373105 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-18", + "to_USD": { + "CAD": 1.2447078055, + "INR": 63.8504290969, + "EUR": 0.8173273396, + "USD": 1, + "SGD": 1.3220269718, + "GBP": 0.7209480997, + "CNY": 6.4227217, + "AUD": 1.2514098897 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-19", + "to_USD": { + "CAD": 1.2440636475, + "INR": 63.8425132599, + "EUR": 0.8159934721, + "USD": 1, + "SGD": 1.3201142391, + "GBP": 0.7210526316, + "CNY": 6.403998368, + "AUD": 1.2486332109 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-20", + "to_USD": { + "CAD": 1.2440636475, + "INR": 63.8425132599, + "EUR": 0.8159934721, + "USD": 1, + "SGD": 1.3201142391, + "GBP": 0.7210526316, + "CNY": 6.403998368, + "AUD": 1.2486332109 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-21", + "to_USD": { + "CAD": 1.2440636475, + "INR": 63.8425132599, + "EUR": 0.8159934721, + "USD": 1, + "SGD": 1.3201142391, + "GBP": 0.7210526316, + "CNY": 6.403998368, + "AUD": 1.2486332109 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-22", + "to_USD": { + "CAD": 1.2476509519, + "INR": 63.9124928507, + "EUR": 0.8170602173, + "USD": 1, + "SGD": 1.319633957, + "GBP": 0.7197074924, + "CNY": 6.4036277474, + "AUD": 1.2490399542 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-23", + "to_USD": { + "CAD": 1.2481835252, + "INR": 63.775002041, + "EUR": 0.816393175, + "USD": 1, + "SGD": 1.3194546494, + "GBP": 0.7170381256, + "CNY": 6.4059106866, + "AUD": 1.2543881133 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-24", + "to_USD": { + "CAD": 1.2329177461, + "INR": 63.6925194301, + "EUR": 0.8095854922, + "USD": 1, + "SGD": 1.309990285, + "GBP": 0.7058209197, + "CNY": 6.3729760363, + "AUD": 1.2394753886 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-25", + "to_USD": { + "CAD": 1.2322882244, + "INR": 63.5649230273, + "EUR": 0.8059966148, + "USD": 1, + "SGD": 1.3058757153, + "GBP": 0.7015233336, + "CNY": 6.3310228097, + "AUD": 1.237849601 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-26", + "to_USD": { + "CAD": 1.2323094243, + "INR": 63.6100836282, + "EUR": 0.8041170794, + "USD": 1, + "SGD": 1.3074139595, + "GBP": 0.7022756513, + "CNY": 6.3278385333, + "AUD": 1.2367320682 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-27", + "to_USD": { + "CAD": 1.2323094243, + "INR": 63.6100836282, + "EUR": 0.8041170794, + "USD": 1, + "SGD": 1.3074139595, + "GBP": 0.7022756513, + "CNY": 6.3278385333, + "AUD": 1.2367320682 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-28", + "to_USD": { + "CAD": 1.2323094243, + "INR": 63.6100836282, + "EUR": 0.8041170794, + "USD": 1, + "SGD": 1.3074139595, + "GBP": 0.7022756513, + "CNY": 6.3278385333, + "AUD": 1.2367320682 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-29", + "to_USD": { + "CAD": 1.2334598918, + "INR": 63.5798529768, + "EUR": 0.8078196946, + "USD": 1, + "SGD": 1.3102835447, + "GBP": 0.7103966395, + "CNY": 6.3319331125, + "AUD": 1.2361256967 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-30", + "to_USD": { + "CAD": 1.2321069157, + "INR": 63.6478544401, + "EUR": 0.8050881572, + "USD": 1, + "SGD": 1.3106835198, + "GBP": 0.7079140166, + "CNY": 6.3252556155, + "AUD": 1.2354077772 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-01-31", + "to_USD": { + "CAD": 1.2274223328, + "INR": 63.562655535, + "EUR": 0.8027614996, + "USD": 1, + "SGD": 1.3075379305, + "GBP": 0.7057076343, + "CNY": 6.2888335875, + "AUD": 1.2328008349 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-01", + "to_USD": { + "CAD": 1.2318805683, + "INR": 64.0227947668, + "EUR": 0.802632635, + "USD": 1, + "SGD": 1.3124648848, + "GBP": 0.7024640822, + "CNY": 6.2967332852, + "AUD": 1.249458223 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-02", + "to_USD": { + "CAD": 1.2317483189, + "INR": 64.0573967339, + "EUR": 0.8005123279, + "USD": 1, + "SGD": 1.3135606788, + "GBP": 0.7032500801, + "CNY": 6.2880243356, + "AUD": 1.2512007685 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-03", + "to_USD": { + "CAD": 1.2317483189, + "INR": 64.0573967339, + "EUR": 0.8005123279, + "USD": 1, + "SGD": 1.3135606788, + "GBP": 0.7032500801, + "CNY": 6.2880243356, + "AUD": 1.2512007685 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-04", + "to_USD": { + "CAD": 1.2317483189, + "INR": 64.0573967339, + "EUR": 0.8005123279, + "USD": 1, + "SGD": 1.3135606788, + "GBP": 0.7032500801, + "CNY": 6.2880243356, + "AUD": 1.2512007685 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-05", + "to_USD": { + "CAD": 1.2434083601, + "INR": 64.1024919614, + "EUR": 0.8038585209, + "USD": 1, + "SGD": 1.3172829582, + "GBP": 0.7119614148, + "CNY": 6.2900321543, + "AUD": 1.2591639871 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-06", + "to_USD": { + "CAD": 1.2562251602, + "INR": 64.272447076, + "EUR": 0.8110957904, + "USD": 1, + "SGD": 1.3232216725, + "GBP": 0.7209424933, + "CNY": 6.2816124584, + "AUD": 1.2756914592 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-07", + "to_USD": { + "CAD": 1.2518236343, + "INR": 64.2450153996, + "EUR": 0.8105041336, + "USD": 1, + "SGD": 1.320392284, + "GBP": 0.7187145404, + "CNY": 6.2745988005, + "AUD": 1.2711946831 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-08", + "to_USD": { + "CAD": 1.2571008815, + "INR": 64.2927685276, + "EUR": 0.8161932746, + "USD": 1, + "SGD": 1.3294156056, + "GBP": 0.7142752204, + "CNY": 6.3294972249, + "AUD": 1.2809337251 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-09", + "to_USD": { + "CAD": 1.260897906, + "INR": 64.3726065347, + "EUR": 0.8147967082, + "USD": 1, + "SGD": 1.3298297075, + "GBP": 0.7230505989, + "CNY": 6.3034302941, + "AUD": 1.280941905 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-10", + "to_USD": { + "CAD": 1.260897906, + "INR": 64.3726065347, + "EUR": 0.8147967082, + "USD": 1, + "SGD": 1.3298297075, + "GBP": 0.7230505989, + "CNY": 6.3034302941, + "AUD": 1.280941905 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-11", + "to_USD": { + "CAD": 1.260897906, + "INR": 64.3726065347, + "EUR": 0.8147967082, + "USD": 1, + "SGD": 1.3298297075, + "GBP": 0.7230505989, + "CNY": 6.3034302941, + "AUD": 1.280941905 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-12", + "to_USD": { + "CAD": 1.2580119057, + "INR": 64.3349914377, + "EUR": 0.8154611433, + "USD": 1, + "SGD": 1.3256136345, + "GBP": 0.7224985729, + "CNY": 6.3283046563, + "AUD": 1.2757889587 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-13", + "to_USD": { + "CAD": 1.2603583881, + "INR": 64.2771426255, + "EUR": 0.8108327252, + "USD": 1, + "SGD": 1.3227925079, + "GBP": 0.7211140842, + "CNY": 6.3442795751, + "AUD": 1.2742236277 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-14", + "to_USD": { + "CAD": 1.2575315841, + "INR": 64.072319404, + "EUR": 0.8098477486, + "USD": 1, + "SGD": 1.3192419825, + "GBP": 0.7210884354, + "CNY": 6.3444282475, + "AUD": 1.2720278588 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-15", + "to_USD": { + "CAD": 1.2490194509, + "INR": 63.9149923957, + "EUR": 0.800448251, + "USD": 1, + "SGD": 1.3115344593, + "GBP": 0.7096774194, + "CNY": 6.3444328824, + "AUD": 1.2612663091 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-16", + "to_USD": { + "CAD": 1.2505616175, + "INR": 64.2201540436, + "EUR": 0.8023106547, + "USD": 1, + "SGD": 1.3106546855, + "GBP": 0.7124759307, + "CNY": 6.3444319641, + "AUD": 1.2592265725 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-17", + "to_USD": { + "CAD": 1.2505616175, + "INR": 64.2201540436, + "EUR": 0.8023106547, + "USD": 1, + "SGD": 1.3106546855, + "GBP": 0.7124759307, + "CNY": 6.3444319641, + "AUD": 1.2592265725 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-18", + "to_USD": { + "CAD": 1.2505616175, + "INR": 64.2201540436, + "EUR": 0.8023106547, + "USD": 1, + "SGD": 1.3106546855, + "GBP": 0.7124759307, + "CNY": 6.3444319641, + "AUD": 1.2592265725 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-19", + "to_USD": { + "CAD": 1.2564061241, + "INR": 64.2526188558, + "EUR": 0.8058017728, + "USD": 1, + "SGD": 1.3130539887, + "GBP": 0.7138597905, + "CNY": 6.3443996777, + "AUD": 1.263174859 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-20", + "to_USD": { + "CAD": 1.2603727715, + "INR": 64.8322528363, + "EUR": 0.8103727715, + "USD": 1, + "SGD": 1.3186385737, + "GBP": 0.7144894652, + "CNY": 6.3444084279, + "AUD": 1.2680713128 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-21", + "to_USD": { + "CAD": 1.2671377518, + "INR": 64.7575536062, + "EUR": 0.8122157245, + "USD": 1, + "SGD": 1.321231319, + "GBP": 0.7185103964, + "CNY": 6.3443794672, + "AUD": 1.2738791423 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-22", + "to_USD": { + "CAD": 1.2698761812, + "INR": 65.0777940697, + "EUR": 0.8145975888, + "USD": 1, + "SGD": 1.3222548061, + "GBP": 0.7196399479, + "CNY": 6.3607852721, + "AUD": 1.2788367546 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-23", + "to_USD": { + "CAD": 1.2695341085, + "INR": 64.7625823238, + "EUR": 0.8130742337, + "USD": 1, + "SGD": 1.3215708594, + "GBP": 0.7150174811, + "CNY": 6.3349865843, + "AUD": 1.2781526953 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-24", + "to_USD": { + "CAD": 1.2695341085, + "INR": 64.7625823238, + "EUR": 0.8130742337, + "USD": 1, + "SGD": 1.3215708594, + "GBP": 0.7150174811, + "CNY": 6.3349865843, + "AUD": 1.2781526953 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-25", + "to_USD": { + "CAD": 1.2695341085, + "INR": 64.7625823238, + "EUR": 0.8130742337, + "USD": 1, + "SGD": 1.3215708594, + "GBP": 0.7150174811, + "CNY": 6.3349865843, + "AUD": 1.2781526953 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-26", + "to_USD": { + "CAD": 1.2676136364, + "INR": 64.7751623377, + "EUR": 0.8116883117, + "USD": 1, + "SGD": 1.3171266234, + "GBP": 0.7128246753, + "CNY": 6.3086850649, + "AUD": 1.2751623377 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-27", + "to_USD": { + "CAD": 1.2720104057, + "INR": 64.8752133973, + "EUR": 0.8129420372, + "USD": 1, + "SGD": 1.3198113974, + "GBP": 0.7186407609, + "CNY": 6.3137143322, + "AUD": 1.27615641 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-02-28", + "to_USD": { + "CAD": 1.2778778451, + "INR": 65.1899459636, + "EUR": 0.8187326019, + "USD": 1, + "SGD": 1.3232356312, + "GBP": 0.72388243, + "CNY": 6.327574914, + "AUD": 1.2802521696 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-01", + "to_USD": { + "CAD": 1.2861720483, + "INR": 65.1750061622, + "EUR": 0.8216251746, + "USD": 1, + "SGD": 1.326924657, + "GBP": 0.7273026046, + "CNY": 6.3503409744, + "AUD": 1.2937309999 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-02", + "to_USD": { + "CAD": 1.2880116959, + "INR": 65.2375730994, + "EUR": 0.8122157245, + "USD": 1, + "SGD": 1.3207439896, + "GBP": 0.7254710851, + "CNY": 6.3451104613, + "AUD": 1.2902046784 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-03", + "to_USD": { + "CAD": 1.2880116959, + "INR": 65.2375730994, + "EUR": 0.8122157245, + "USD": 1, + "SGD": 1.3207439896, + "GBP": 0.7254710851, + "CNY": 6.3451104613, + "AUD": 1.2902046784 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-04", + "to_USD": { + "CAD": 1.2880116959, + "INR": 65.2375730994, + "EUR": 0.8122157245, + "USD": 1, + "SGD": 1.3207439896, + "GBP": 0.7254710851, + "CNY": 6.3451104613, + "AUD": 1.2902046784 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-05", + "to_USD": { + "CAD": 1.293085236, + "INR": 65.1072560332, + "EUR": 0.8125457057, + "USD": 1, + "SGD": 1.3194117169, + "GBP": 0.7237344601, + "CNY": 6.3402941415, + "AUD": 1.2908913626 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-06", + "to_USD": { + "CAD": 1.2886149384, + "INR": 64.9299008944, + "EUR": 0.8057368463, + "USD": 1, + "SGD": 1.3153654017, + "GBP": 0.718435259, + "CNY": 6.3280960438, + "AUD": 1.2762871646 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-07", + "to_USD": { + "CAD": 1.293065958, + "INR": 64.8932914553, + "EUR": 0.8053475074, + "USD": 1, + "SGD": 1.3145687364, + "GBP": 0.7208907143, + "CNY": 6.3206893775, + "AUD": 1.2812273496 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-08", + "to_USD": { + "CAD": 1.2916834393, + "INR": 65.1300217374, + "EUR": 0.8050881572, + "USD": 1, + "SGD": 1.31543354, + "GBP": 0.7202721198, + "CNY": 6.3357217615, + "AUD": 1.2810562757 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-09", + "to_USD": { + "CAD": 1.2893987471, + "INR": 65.1952648279, + "EUR": 0.8136034497, + "USD": 1, + "SGD": 1.3183630299, + "GBP": 0.7232365145, + "CNY": 6.3375640713, + "AUD": 1.2832153608 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-10", + "to_USD": { + "CAD": 1.2893987471, + "INR": 65.1952648279, + "EUR": 0.8136034497, + "USD": 1, + "SGD": 1.3183630299, + "GBP": 0.7232365145, + "CNY": 6.3375640713, + "AUD": 1.2832153608 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-11", + "to_USD": { + "CAD": 1.2893987471, + "INR": 65.1952648279, + "EUR": 0.8136034497, + "USD": 1, + "SGD": 1.3183630299, + "GBP": 0.7232365145, + "CNY": 6.3375640713, + "AUD": 1.2832153608 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-12", + "to_USD": { + "CAD": 1.2828808324, + "INR": 65.0125995773, + "EUR": 0.8128759551, + "USD": 1, + "SGD": 1.3145829946, + "GBP": 0.7201268086, + "CNY": 6.3311656641, + "AUD": 1.2714192814 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-13", + "to_USD": { + "CAD": 1.283729197, + "INR": 64.8602359024, + "EUR": 0.8078849572, + "USD": 1, + "SGD": 1.3107125545, + "GBP": 0.7161900145, + "CNY": 6.3229116174, + "AUD": 1.2670059783 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-14", + "to_USD": { + "CAD": 1.2929905409, + "INR": 64.8374969682, + "EUR": 0.8084727949, + "USD": 1, + "SGD": 1.3091599968, + "GBP": 0.7165494381, + "CNY": 6.313283208, + "AUD": 1.2647748403 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-15", + "to_USD": { + "CAD": 1.298517138, + "INR": 64.950166113, + "EUR": 0.8103071064, + "USD": 1, + "SGD": 1.3112389596, + "GBP": 0.7169597277, + "CNY": 6.3176403857, + "AUD": 1.2750182319 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-16", + "to_USD": { + "CAD": 1.3077798553, + "INR": 64.9272416877, + "EUR": 0.8129420372, + "USD": 1, + "SGD": 1.3155028047, + "GBP": 0.7174457361, + "CNY": 6.3255019917, + "AUD": 1.2893260711 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-17", + "to_USD": { + "CAD": 1.3077798553, + "INR": 64.9272416877, + "EUR": 0.8129420372, + "USD": 1, + "SGD": 1.3155028047, + "GBP": 0.7174457361, + "CNY": 6.3255019917, + "AUD": 1.2893260711 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-18", + "to_USD": { + "CAD": 1.3077798553, + "INR": 64.9272416877, + "EUR": 0.8129420372, + "USD": 1, + "SGD": 1.3155028047, + "GBP": 0.7174457361, + "CNY": 6.3255019917, + "AUD": 1.2893260711 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-19", + "to_USD": { + "CAD": 1.3083922333, + "INR": 65.1925420424, + "EUR": 0.812413681, + "USD": 1, + "SGD": 1.3179787148, + "GBP": 0.7116175156, + "CNY": 6.3322771955, + "AUD": 1.2993744415 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-20", + "to_USD": { + "CAD": 1.3066145324, + "INR": 65.1979472141, + "EUR": 0.8145975888, + "USD": 1, + "SGD": 1.3175301401, + "GBP": 0.714524275, + "CNY": 6.3330074943, + "AUD": 1.297979798 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-21", + "to_USD": { + "CAD": 1.2979814423, + "INR": 65.2099951164, + "EUR": 0.8139345597, + "USD": 1, + "SGD": 1.3183298063, + "GBP": 0.7114032232, + "CNY": 6.3299690705, + "AUD": 1.3018069347 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-22", + "to_USD": { + "CAD": 1.2901104255, + "INR": 65.1047417993, + "EUR": 0.8119519324, + "USD": 1, + "SGD": 1.3159304969, + "GBP": 0.7080220851, + "CNY": 6.3345241962, + "AUD": 1.2970120169 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-23", + "to_USD": { + "CAD": 1.2852745829, + "INR": 65.0048598736, + "EUR": 0.8099789405, + "USD": 1, + "SGD": 1.31346185, + "GBP": 0.7069901183, + "CNY": 6.3158107889, + "AUD": 1.2941843512 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-24", + "to_USD": { + "CAD": 1.2852745829, + "INR": 65.0048598736, + "EUR": 0.8099789405, + "USD": 1, + "SGD": 1.31346185, + "GBP": 0.7069901183, + "CNY": 6.3158107889, + "AUD": 1.2941843512 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-25", + "to_USD": { + "CAD": 1.2852745829, + "INR": 65.0048598736, + "EUR": 0.8099789405, + "USD": 1, + "SGD": 1.31346185, + "GBP": 0.7069901183, + "CNY": 6.3158107889, + "AUD": 1.2941843512 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-26", + "to_USD": { + "CAD": 1.2889372331, + "INR": 64.8702763677, + "EUR": 0.8057368463, + "USD": 1, + "SGD": 1.3112561437, + "GBP": 0.7029892837, + "CNY": 6.2786238015, + "AUD": 1.293046491 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-27", + "to_USD": { + "CAD": 1.2887039431, + "INR": 64.9749515191, + "EUR": 0.8080155139, + "USD": 1, + "SGD": 1.3096315449, + "GBP": 0.7105688429, + "CNY": 6.2807045895, + "AUD": 1.2984809308 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-28", + "to_USD": { + "CAD": 1.2884336183, + "INR": 65.1722051944, + "EUR": 0.8065817067, + "USD": 1, + "SGD": 1.3077915793, + "GBP": 0.7066059042, + "CNY": 6.2889982255, + "AUD": 1.3011776093 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-29", + "to_USD": { + "CAD": 1.2900738576, + "INR": 65.1700348998, + "EUR": 0.8116224332, + "USD": 1, + "SGD": 1.3114195276, + "GBP": 0.7100884668, + "CNY": 6.2874766659, + "AUD": 1.301517734 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-30", + "to_USD": { + "CAD": 1.2900738576, + "INR": 65.1700348998, + "EUR": 0.8116224332, + "USD": 1, + "SGD": 1.3114195276, + "GBP": 0.7100884668, + "CNY": 6.2874766659, + "AUD": 1.301517734 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-03-31", + "to_USD": { + "CAD": 1.2900738576, + "INR": 65.1700348998, + "EUR": 0.8116224332, + "USD": 1, + "SGD": 1.3114195276, + "GBP": 0.7100884668, + "CNY": 6.2874766659, + "AUD": 1.301517734 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-01", + "to_USD": { + "CAD": 1.2900738576, + "INR": 65.1700348998, + "EUR": 0.8116224332, + "USD": 1, + "SGD": 1.3114195276, + "GBP": 0.7100884668, + "CNY": 6.2874766659, + "AUD": 1.301517734 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-02", + "to_USD": { + "CAD": 1.2900738576, + "INR": 65.1700348998, + "EUR": 0.8116224332, + "USD": 1, + "SGD": 1.3114195276, + "GBP": 0.7100884668, + "CNY": 6.2874766659, + "AUD": 1.301517734 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-03", + "to_USD": { + "CAD": 1.2851803705, + "INR": 65.0097497563, + "EUR": 0.812479688, + "USD": 1, + "SGD": 1.3092297693, + "GBP": 0.7111065973, + "CNY": 6.2846116347, + "AUD": 1.299480013 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-04", + "to_USD": { + "CAD": 1.2834799609, + "INR": 65.1303356142, + "EUR": 0.8145975888, + "USD": 1, + "SGD": 1.3144346693, + "GBP": 0.7133675464, + "CNY": 6.3057184751, + "AUD": 1.3015640274 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-05", + "to_USD": { + "CAD": 1.2772430669, + "INR": 64.927406199, + "EUR": 0.8156606852, + "USD": 1, + "SGD": 1.314274062, + "GBP": 0.7128466558, + "CNY": 6.3052202284, + "AUD": 1.3001631321 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-06", + "to_USD": { + "CAD": 1.2792218408, + "INR": 64.9673042341, + "EUR": 0.8173941475, + "USD": 1, + "SGD": 1.3191106752, + "GBP": 0.713544221, + "CNY": 6.3052149747, + "AUD": 1.3024358346 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-07", + "to_USD": { + "CAD": 1.2792218408, + "INR": 64.9673042341, + "EUR": 0.8173941475, + "USD": 1, + "SGD": 1.3191106752, + "GBP": 0.713544221, + "CNY": 6.3052149747, + "AUD": 1.3024358346 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-08", + "to_USD": { + "CAD": 1.2792218408, + "INR": 64.9673042341, + "EUR": 0.8173941475, + "USD": 1, + "SGD": 1.3191106752, + "GBP": 0.713544221, + "CNY": 6.3052149747, + "AUD": 1.3024358346 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-09", + "to_USD": { + "CAD": 1.2781209363, + "INR": 64.9825260078, + "EUR": 0.8127438231, + "USD": 1, + "SGD": 1.3132314694, + "GBP": 0.7078023407, + "CNY": 6.3138816645, + "AUD": 1.3044538362 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-10", + "to_USD": { + "CAD": 1.2656742982, + "INR": 64.9927190357, + "EUR": 0.8089960359, + "USD": 1, + "SGD": 1.3107353774, + "GBP": 0.705307014, + "CNY": 6.2892160828, + "AUD": 1.292452067 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-11", + "to_USD": { + "CAD": 1.2617086563, + "INR": 65.3048288114, + "EUR": 0.8074935401, + "USD": 1, + "SGD": 1.3084625323, + "GBP": 0.7054263566, + "CNY": 6.2835109819, + "AUD": 1.290374677 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-12", + "to_USD": { + "CAD": 1.2591901323, + "INR": 65.2576482999, + "EUR": 0.8114907084, + "USD": 1, + "SGD": 1.3109632395, + "GBP": 0.703927615, + "CNY": 6.2851578349, + "AUD": 1.2897021829 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-13", + "to_USD": { + "CAD": 1.2569619225, + "INR": 65.2074368759, + "EUR": 0.8118860112, + "USD": 1, + "SGD": 1.3118454169, + "GBP": 0.7014695137, + "CNY": 6.2809937485, + "AUD": 1.2828610863 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-14", + "to_USD": { + "CAD": 1.2569619225, + "INR": 65.2074368759, + "EUR": 0.8118860112, + "USD": 1, + "SGD": 1.3118454169, + "GBP": 0.7014695137, + "CNY": 6.2809937485, + "AUD": 1.2828610863 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-15", + "to_USD": { + "CAD": 1.2569619225, + "INR": 65.2074368759, + "EUR": 0.8118860112, + "USD": 1, + "SGD": 1.3118454169, + "GBP": 0.7014695137, + "CNY": 6.2809937485, + "AUD": 1.2828610863 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-16", + "to_USD": { + "CAD": 1.2607922393, + "INR": 65.4951495554, + "EUR": 0.8084074373, + "USD": 1, + "SGD": 1.3113177041, + "GBP": 0.6989894907, + "CNY": 6.2834276475, + "AUD": 1.2876313662 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-17", + "to_USD": { + "CAD": 1.255239945, + "INR": 65.6372906045, + "EUR": 0.8092579105, + "USD": 1, + "SGD": 1.3103504087, + "GBP": 0.6982277252, + "CNY": 6.2829974913, + "AUD": 1.2875293356 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-18", + "to_USD": { + "CAD": 1.2570229254, + "INR": 65.6651598321, + "EUR": 0.8072328059, + "USD": 1, + "SGD": 1.3106231837, + "GBP": 0.7031401356, + "CNY": 6.2823700355, + "AUD": 1.2877784953 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-19", + "to_USD": { + "CAD": 1.260377968, + "INR": 65.787433371, + "EUR": 0.8076239703, + "USD": 1, + "SGD": 1.308996931, + "GBP": 0.7024309482, + "CNY": 6.2766112098, + "AUD": 1.2834760136 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-20", + "to_USD": { + "CAD": 1.2638719636, + "INR": 66.1223495004, + "EUR": 0.812413681, + "USD": 1, + "SGD": 1.313835405, + "GBP": 0.7117393777, + "CNY": 6.2920627183, + "AUD": 1.2984807864 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-21", + "to_USD": { + "CAD": 1.2638719636, + "INR": 66.1223495004, + "EUR": 0.812413681, + "USD": 1, + "SGD": 1.313835405, + "GBP": 0.7117393777, + "CNY": 6.2920627183, + "AUD": 1.2984807864 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-22", + "to_USD": { + "CAD": 1.2638719636, + "INR": 66.1223495004, + "EUR": 0.812413681, + "USD": 1, + "SGD": 1.313835405, + "GBP": 0.7117393777, + "CNY": 6.2920627183, + "AUD": 1.2984807864 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-23", + "to_USD": { + "CAD": 1.2787220134, + "INR": 66.4197581304, + "EUR": 0.8171269815, + "USD": 1, + "SGD": 1.3227651577, + "GBP": 0.7161300866, + "CNY": 6.308873999, + "AUD": 1.3082202974 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-24", + "to_USD": { + "CAD": 1.2824039957, + "INR": 66.3854089904, + "EUR": 0.8187996397, + "USD": 1, + "SGD": 1.322688938, + "GBP": 0.7161876689, + "CNY": 6.3057397855, + "AUD": 1.3131908622 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-25", + "to_USD": { + "CAD": 1.2887977021, + "INR": 66.975379565, + "EUR": 0.8206811654, + "USD": 1, + "SGD": 1.3294214198, + "GBP": 0.7171112023, + "CNY": 6.3231842429, + "AUD": 1.3227739023 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-26", + "to_USD": { + "CAD": 1.283530572, + "INR": 66.7521367521, + "EUR": 0.8218277449, + "USD": 1, + "SGD": 1.3265121631, + "GBP": 0.7158119658, + "CNY": 6.3249506903, + "AUD": 1.3206771861 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-27", + "to_USD": { + "CAD": 1.2882352941, + "INR": 66.6648715824, + "EUR": 0.8285004143, + "USD": 1, + "SGD": 1.326014913, + "GBP": 0.7265948633, + "CNY": 6.3394366197, + "AUD": 1.3235294118 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-28", + "to_USD": { + "CAD": 1.2882352941, + "INR": 66.6648715824, + "EUR": 0.8285004143, + "USD": 1, + "SGD": 1.326014913, + "GBP": 0.7265948633, + "CNY": 6.3394366197, + "AUD": 1.3235294118 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-29", + "to_USD": { + "CAD": 1.2882352941, + "INR": 66.6648715824, + "EUR": 0.8285004143, + "USD": 1, + "SGD": 1.326014913, + "GBP": 0.7265948633, + "CNY": 6.3394366197, + "AUD": 1.3235294118 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-04-30", + "to_USD": { + "CAD": 1.2866959185, + "INR": 66.3701465353, + "EUR": 0.8278831029, + "USD": 1, + "SGD": 1.3259375776, + "GBP": 0.7282059773, + "CNY": 6.3394320722, + "AUD": 1.3256892127 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-01", + "to_USD": { + "CAD": 1.2866959185, + "INR": 66.3701465353, + "EUR": 0.8278831029, + "USD": 1, + "SGD": 1.3259375776, + "GBP": 0.7282059773, + "CNY": 6.3394320722, + "AUD": 1.3256892127 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-02", + "to_USD": { + "CAD": 1.2826684434, + "INR": 66.6656950112, + "EUR": 0.8328475056, + "USD": 1, + "SGD": 1.3346381278, + "GBP": 0.7332389439, + "CNY": 6.3590405597, + "AUD": 1.3314733072 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-03", + "to_USD": { + "CAD": 1.2845230153, + "INR": 66.6248332221, + "EUR": 0.8338892595, + "USD": 1, + "SGD": 1.331054036, + "GBP": 0.735323549, + "CNY": 6.3488158773, + "AUD": 1.3280520347 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-04", + "to_USD": { + "CAD": 1.2874926894, + "INR": 66.8618932242, + "EUR": 0.8354916869, + "USD": 1, + "SGD": 1.3336118306, + "GBP": 0.7371960899, + "CNY": 6.3591778762, + "AUD": 1.3296850196 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-05", + "to_USD": { + "CAD": 1.2874926894, + "INR": 66.8618932242, + "EUR": 0.8354916869, + "USD": 1, + "SGD": 1.3336118306, + "GBP": 0.7371960899, + "CNY": 6.3591778762, + "AUD": 1.3296850196 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-06", + "to_USD": { + "CAD": 1.2874926894, + "INR": 66.8618932242, + "EUR": 0.8354916869, + "USD": 1, + "SGD": 1.3336118306, + "GBP": 0.7371960899, + "CNY": 6.3591778762, + "AUD": 1.3296850196 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-07", + "to_USD": { + "CAD": 1.2886909763, + "INR": 67.134935305, + "EUR": 0.8401949252, + "USD": 1, + "SGD": 1.3373382625, + "GBP": 0.7394555537, + "CNY": 6.3668291044, + "AUD": 1.3343975802 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-08", + "to_USD": { + "CAD": 1.2972198821, + "INR": 67.0850884583, + "EUR": 0.8424599832, + "USD": 1, + "SGD": 1.3380791912, + "GBP": 0.7407750632, + "CNY": 6.3678180286, + "AUD": 1.3419545072 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-09", + "to_USD": { + "CAD": 1.2879030221, + "INR": 67.2623958246, + "EUR": 0.8418217022, + "USD": 1, + "SGD": 1.340264332, + "GBP": 0.7361309875, + "CNY": 6.3665291691, + "AUD": 1.3404326964 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-10", + "to_USD": { + "CAD": 1.277319414, + "INR": 67.2592187237, + "EUR": 0.8418925745, + "USD": 1, + "SGD": 1.3407139249, + "GBP": 0.7392658697, + "CNY": 6.3494696077, + "AUD": 1.3356625695 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-11", + "to_USD": { + "CAD": 1.2734204793, + "INR": 67.3370202782, + "EUR": 0.8379420144, + "USD": 1, + "SGD": 1.3337523043, + "GBP": 0.7373889727, + "CNY": 6.3324953913, + "AUD": 1.324032177 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-12", + "to_USD": { + "CAD": 1.2734204793, + "INR": 67.3370202782, + "EUR": 0.8379420144, + "USD": 1, + "SGD": 1.3337523043, + "GBP": 0.7373889727, + "CNY": 6.3324953913, + "AUD": 1.324032177 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-13", + "to_USD": { + "CAD": 1.2734204793, + "INR": 67.3370202782, + "EUR": 0.8379420144, + "USD": 1, + "SGD": 1.3337523043, + "GBP": 0.7373889727, + "CNY": 6.3324953913, + "AUD": 1.324032177 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-14", + "to_USD": { + "CAD": 1.276359693, + "INR": 67.5296129463, + "EUR": 0.8341675008, + "USD": 1, + "SGD": 1.3329996663, + "GBP": 0.7360694027, + "CNY": 6.3374207541, + "AUD": 1.3230730731 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-15", + "to_USD": { + "CAD": 1.2835984179, + "INR": 68.0568879912, + "EUR": 0.8415383321, + "USD": 1, + "SGD": 1.3387191787, + "GBP": 0.7397121939, + "CNY": 6.3625347135, + "AUD": 1.3344273332 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-16", + "to_USD": { + "CAD": 1.286575017, + "INR": 67.797437203, + "EUR": 0.8486082824, + "USD": 1, + "SGD": 1.3428377461, + "GBP": 0.7418363883, + "CNY": 6.3761880516, + "AUD": 1.3357942974 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-17", + "to_USD": { + "CAD": 1.2771706904, + "INR": 67.7378229564, + "EUR": 0.847098687, + "USD": 1, + "SGD": 1.3422278695, + "GBP": 0.7399407031, + "CNY": 6.3679796696, + "AUD": 1.3283354511 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-18", + "to_USD": { + "CAD": 1.2795178678, + "INR": 68.0005941771, + "EUR": 0.8488243782, + "USD": 1, + "SGD": 1.3435192259, + "GBP": 0.7412358883, + "CNY": 6.3786605551, + "AUD": 1.330362448 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-19", + "to_USD": { + "CAD": 1.2795178678, + "INR": 68.0005941771, + "EUR": 0.8488243782, + "USD": 1, + "SGD": 1.3435192259, + "GBP": 0.7412358883, + "CNY": 6.3786605551, + "AUD": 1.330362448 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-20", + "to_USD": { + "CAD": 1.2795178678, + "INR": 68.0005941771, + "EUR": 0.8488243782, + "USD": 1, + "SGD": 1.3435192259, + "GBP": 0.7412358883, + "CNY": 6.3786605551, + "AUD": 1.330362448 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-21", + "to_USD": { + "CAD": 1.2874394081, + "INR": 68.1418487967, + "EUR": 0.85041245, + "USD": 1, + "SGD": 1.3439067948, + "GBP": 0.7453014712, + "CNY": 6.3863423761, + "AUD": 1.3282592057 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-22", + "to_USD": { + "CAD": 1.2774292013, + "INR": 68.009581143, + "EUR": 0.847888757, + "USD": 1, + "SGD": 1.3372901475, + "GBP": 0.7434966932, + "CNY": 6.3686620315, + "AUD": 1.317873495 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-23", + "to_USD": { + "CAD": 1.2904851384, + "INR": 68.4194567817, + "EUR": 0.8541168432, + "USD": 1, + "SGD": 1.3455756748, + "GBP": 0.7512213871, + "CNY": 6.388537752, + "AUD": 1.327639221 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-24", + "to_USD": { + "CAD": 1.2884549795, + "INR": 68.3773874488, + "EUR": 0.8526603001, + "USD": 1, + "SGD": 1.340893588, + "GBP": 0.7458645975, + "CNY": 6.3836971351, + "AUD": 1.3232435198 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-25", + "to_USD": { + "CAD": 1.2955888651, + "INR": 67.7948608137, + "EUR": 0.8565310493, + "USD": 1, + "SGD": 1.3406423983, + "GBP": 0.7498072805, + "CNY": 6.3906638116, + "AUD": 1.3211134904 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-26", + "to_USD": { + "CAD": 1.2955888651, + "INR": 67.7948608137, + "EUR": 0.8565310493, + "USD": 1, + "SGD": 1.3406423983, + "GBP": 0.7498072805, + "CNY": 6.3906638116, + "AUD": 1.3211134904 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-27", + "to_USD": { + "CAD": 1.2955888651, + "INR": 67.7948608137, + "EUR": 0.8565310493, + "USD": 1, + "SGD": 1.3406423983, + "GBP": 0.7498072805, + "CNY": 6.3906638116, + "AUD": 1.3211134904 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-28", + "to_USD": { + "CAD": 1.2980075575, + "INR": 67.4407420131, + "EUR": 0.858811405, + "USD": 1, + "SGD": 1.3410340089, + "GBP": 0.7511593954, + "CNY": 6.3988320165, + "AUD": 1.3234283751 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-29", + "to_USD": { + "CAD": 1.3028205572, + "INR": 67.8369960201, + "EUR": 0.865201592, + "USD": 1, + "SGD": 1.3466862779, + "GBP": 0.7539626233, + "CNY": 6.4175462883, + "AUD": 1.3294687662 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-30", + "to_USD": { + "CAD": 1.2975412655, + "INR": 67.3899587345, + "EUR": 0.8596973865, + "USD": 1, + "SGD": 1.3400962861, + "GBP": 0.7522352132, + "CNY": 6.4196182944, + "AUD": 1.3247077029 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-05-31", + "to_USD": { + "CAD": 1.2854090093, + "INR": 67.3578938371, + "EUR": 0.8547739123, + "USD": 1, + "SGD": 1.3382340371, + "GBP": 0.7494657663, + "CNY": 6.4066159501, + "AUD": 1.3175485084 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-01", + "to_USD": { + "CAD": 1.297626189, + "INR": 67.1128631417, + "EUR": 0.8569714629, + "USD": 1, + "SGD": 1.3383323335, + "GBP": 0.7513925786, + "CNY": 6.4172594053, + "AUD": 1.3277915845 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-02", + "to_USD": { + "CAD": 1.297626189, + "INR": 67.1128631417, + "EUR": 0.8569714629, + "USD": 1, + "SGD": 1.3383323335, + "GBP": 0.7513925786, + "CNY": 6.4172594053, + "AUD": 1.3277915845 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-03", + "to_USD": { + "CAD": 1.297626189, + "INR": 67.1128631417, + "EUR": 0.8569714629, + "USD": 1, + "SGD": 1.3383323335, + "GBP": 0.7513925786, + "CNY": 6.4172594053, + "AUD": 1.3277915845 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-04", + "to_USD": { + "CAD": 1.2906194087, + "INR": 67.0631336798, + "EUR": 0.8520064752, + "USD": 1, + "SGD": 1.333816137, + "GBP": 0.746979637, + "CNY": 6.4041918719, + "AUD": 1.3045071143 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-05", + "to_USD": { + "CAD": 1.2983297645, + "INR": 67.1498929336, + "EUR": 0.8565310493, + "USD": 1, + "SGD": 1.3355888651, + "GBP": 0.7485224839, + "CNY": 6.4042826552, + "AUD": 1.313490364 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-06", + "to_USD": { + "CAD": 1.2877178071, + "INR": 66.9196770081, + "EUR": 0.8499787505, + "USD": 1, + "SGD": 1.3331916702, + "GBP": 0.7452868678, + "CNY": 6.3943901402, + "AUD": 1.3059923502 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-07", + "to_USD": { + "CAD": 1.2937647854, + "INR": 67.1155795877, + "EUR": 0.844880027, + "USD": 1, + "SGD": 1.3312774586, + "GBP": 0.7445336262, + "CNY": 6.3923622846, + "AUD": 1.3059310578 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-08", + "to_USD": { + "CAD": 1.29947252, + "INR": 67.5021269355, + "EUR": 0.8507742045, + "USD": 1, + "SGD": 1.3358856559, + "GBP": 0.7464097329, + "CNY": 6.409137315, + "AUD": 1.3183597073 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-09", + "to_USD": { + "CAD": 1.29947252, + "INR": 67.5021269355, + "EUR": 0.8507742045, + "USD": 1, + "SGD": 1.3358856559, + "GBP": 0.7464097329, + "CNY": 6.409137315, + "AUD": 1.3183597073 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-10", + "to_USD": { + "CAD": 1.29947252, + "INR": 67.5021269355, + "EUR": 0.8507742045, + "USD": 1, + "SGD": 1.3358856559, + "GBP": 0.7464097329, + "CNY": 6.409137315, + "AUD": 1.3183597073 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-11", + "to_USD": { + "CAD": 1.3017811705, + "INR": 67.4283290925, + "EUR": 0.8481764207, + "USD": 1, + "SGD": 1.3347752332, + "GBP": 0.7479219678, + "CNY": 6.4052586938, + "AUD": 1.3147582697 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-12", + "to_USD": { + "CAD": 1.3008992195, + "INR": 67.442738378, + "EUR": 0.8483203258, + "USD": 1, + "SGD": 1.3350865287, + "GBP": 0.7480064472, + "CNY": 6.4044791313, + "AUD": 1.3154054971 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-13", + "to_USD": { + "CAD": 1.301683101, + "INR": 67.6079564774, + "EUR": 0.8500510031, + "USD": 1, + "SGD": 1.3355151309, + "GBP": 0.7498299898, + "CNY": 6.4002890173, + "AUD": 1.3180890853 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-14", + "to_USD": { + "CAD": 1.2976982097, + "INR": 67.5980392157, + "EUR": 0.852514919, + "USD": 1, + "SGD": 1.3354646206, + "GBP": 0.7475106564, + "CNY": 6.394629156, + "AUD": 1.3225916454 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-15", + "to_USD": { + "CAD": 1.3127802691, + "INR": 68.0152638841, + "EUR": 0.8623663332, + "USD": 1, + "SGD": 1.3469299759, + "GBP": 0.7530182822, + "CNY": 6.421438427, + "AUD": 1.3382200759 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-16", + "to_USD": { + "CAD": 1.3127802691, + "INR": 68.0152638841, + "EUR": 0.8623663332, + "USD": 1, + "SGD": 1.3469299759, + "GBP": 0.7530182822, + "CNY": 6.421438427, + "AUD": 1.3382200759 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-17", + "to_USD": { + "CAD": 1.3127802691, + "INR": 68.0152638841, + "EUR": 0.8623663332, + "USD": 1, + "SGD": 1.3469299759, + "GBP": 0.7530182822, + "CNY": 6.421438427, + "AUD": 1.3382200759 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-18", + "to_USD": { + "CAD": 1.3180917937, + "INR": 68.0396968914, + "EUR": 0.8611039352, + "USD": 1, + "SGD": 1.3502109705, + "GBP": 0.7548006544, + "CNY": 6.4393352278, + "AUD": 1.3441832429 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-19", + "to_USD": { + "CAD": 1.328160222, + "INR": 68.3778394312, + "EUR": 0.8670019074, + "USD": 1, + "SGD": 1.3598924918, + "GBP": 0.7602999827, + "CNY": 6.4821397607, + "AUD": 1.3607594937 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-20", + "to_USD": { + "CAD": 1.3299360857, + "INR": 68.1119364312, + "EUR": 0.8637070306, + "USD": 1, + "SGD": 1.3575747107, + "GBP": 0.7590084643, + "CNY": 6.4737433063, + "AUD": 1.3549835896 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-21", + "to_USD": { + "CAD": 1.3330733229, + "INR": 67.9619518114, + "EUR": 0.8667013347, + "USD": 1, + "SGD": 1.3619344774, + "GBP": 0.7572369561, + "CNY": 6.4982665973, + "AUD": 1.3576009707 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-22", + "to_USD": { + "CAD": 1.3271806319, + "INR": 67.8485576923, + "EUR": 0.8585164835, + "USD": 1, + "SGD": 1.3583447802, + "GBP": 0.7526013049, + "CNY": 6.4980254121, + "AUD": 1.3462396978 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-23", + "to_USD": { + "CAD": 1.3271806319, + "INR": 67.8485576923, + "EUR": 0.8585164835, + "USD": 1, + "SGD": 1.3583447802, + "GBP": 0.7526013049, + "CNY": 6.4980254121, + "AUD": 1.3462396978 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-24", + "to_USD": { + "CAD": 1.3271806319, + "INR": 67.8485576923, + "EUR": 0.8585164835, + "USD": 1, + "SGD": 1.3583447802, + "GBP": 0.7526013049, + "CNY": 6.4980254121, + "AUD": 1.3462396978 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-25", + "to_USD": { + "CAD": 1.3283760684, + "INR": 68.0726495726, + "EUR": 0.8547008547, + "USD": 1, + "SGD": 1.3615384615, + "GBP": 0.7524786325, + "CNY": 6.5357264957, + "AUD": 1.3454700855 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-26", + "to_USD": { + "CAD": 1.33216244, + "INR": 68.2912097327, + "EUR": 0.8567511995, + "USD": 1, + "SGD": 1.3615490062, + "GBP": 0.7553118574, + "CNY": 6.5754797807, + "AUD": 1.3517820425 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-27", + "to_USD": { + "CAD": 1.3294593664, + "INR": 68.6070936639, + "EUR": 0.8608815427, + "USD": 1, + "SGD": 1.3631198347, + "GBP": 0.7590650826, + "CNY": 6.5985709366, + "AUD": 1.3537362259 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-28", + "to_USD": { + "CAD": 1.329361996, + "INR": 68.7930587931, + "EUR": 0.8633341967, + "USD": 1, + "SGD": 1.3667443667, + "GBP": 0.7642234309, + "CNY": 6.6241906242, + "AUD": 1.3621686955 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-29", + "to_USD": { + "CAD": 1.3245839767, + "INR": 68.4620003431, + "EUR": 0.8577800652, + "USD": 1, + "SGD": 1.3635271916, + "GBP": 0.7600360268, + "CNY": 6.6194887631, + "AUD": 1.3541773889 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-06-30", + "to_USD": { + "CAD": 1.3245839767, + "INR": 68.4620003431, + "EUR": 0.8577800652, + "USD": 1, + "SGD": 1.3635271916, + "GBP": 0.7600360268, + "CNY": 6.6194887631, + "AUD": 1.3541773889 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-01", + "to_USD": { + "CAD": 1.3245839767, + "INR": 68.4620003431, + "EUR": 0.8577800652, + "USD": 1, + "SGD": 1.3635271916, + "GBP": 0.7600360268, + "CNY": 6.6194887631, + "AUD": 1.3541773889 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-02", + "to_USD": { + "CAD": 1.3181544806, + "INR": 68.7949995704, + "EUR": 0.859180342, + "USD": 1, + "SGD": 1.3682446946, + "GBP": 0.7616633731, + "CNY": 6.6660366011, + "AUD": 1.3596528911 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-03", + "to_USD": { + "CAD": 1.3153879126, + "INR": 68.5220745821, + "EUR": 0.8572653236, + "USD": 1, + "SGD": 1.3648521217, + "GBP": 0.7573939134, + "CNY": 6.6421774539, + "AUD": 1.3511358766 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-04", + "to_USD": { + "CAD": 1.3147225563, + "INR": 68.7399072324, + "EUR": 0.8589589418, + "USD": 1, + "SGD": 1.3649716544, + "GBP": 0.7568115444, + "CNY": 6.6317643017, + "AUD": 1.3539769799 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-05", + "to_USD": { + "CAD": 1.3130070886, + "INR": 68.9469638739, + "EUR": 0.8540438979, + "USD": 1, + "SGD": 1.3634810829, + "GBP": 0.7542061662, + "CNY": 6.6335297634, + "AUD": 1.3511828508 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-06", + "to_USD": { + "CAD": 1.3132889799, + "INR": 68.8723984988, + "EUR": 0.8529512112, + "USD": 1, + "SGD": 1.3602865916, + "GBP": 0.7556721256, + "CNY": 6.6476458547, + "AUD": 1.3484305698 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-07", + "to_USD": { + "CAD": 1.3132889799, + "INR": 68.8723984988, + "EUR": 0.8529512112, + "USD": 1, + "SGD": 1.3602865916, + "GBP": 0.7556721256, + "CNY": 6.6476458547, + "AUD": 1.3484305698 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-08", + "to_USD": { + "CAD": 1.3132889799, + "INR": 68.8723984988, + "EUR": 0.8529512112, + "USD": 1, + "SGD": 1.3602865916, + "GBP": 0.7556721256, + "CNY": 6.6476458547, + "AUD": 1.3484305698 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-09", + "to_USD": { + "CAD": 1.3075748579, + "INR": 68.6729154296, + "EUR": 0.8482483671, + "USD": 1, + "SGD": 1.3528713207, + "GBP": 0.7493850199, + "CNY": 6.6135380439, + "AUD": 1.3364153024 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-10", + "to_USD": { + "CAD": 1.3132416973, + "INR": 68.8269444207, + "EUR": 0.8537522411, + "USD": 1, + "SGD": 1.3568684368, + "GBP": 0.7541876547, + "CNY": 6.6393750534, + "AUD": 1.3437206523 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-11", + "to_USD": { + "CAD": 1.3141031104, + "INR": 68.7724755006, + "EUR": 0.852151683, + "USD": 1, + "SGD": 1.3607158074, + "GBP": 0.7540008522, + "CNY": 6.6773753728, + "AUD": 1.3522795058 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-12", + "to_USD": { + "CAD": 1.3183221822, + "INR": 68.5199004975, + "EUR": 0.8577800652, + "USD": 1, + "SGD": 1.3629267456, + "GBP": 0.7571024189, + "CNY": 6.6718133471, + "AUD": 1.3534053869 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-13", + "to_USD": { + "CAD": 1.3190758396, + "INR": 68.4806321395, + "EUR": 0.8588851671, + "USD": 1, + "SGD": 1.3672592974, + "GBP": 0.7600103066, + "CNY": 6.7003349652, + "AUD": 1.3539465773 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-14", + "to_USD": { + "CAD": 1.3190758396, + "INR": 68.4806321395, + "EUR": 0.8588851671, + "USD": 1, + "SGD": 1.3672592974, + "GBP": 0.7600103066, + "CNY": 6.7003349652, + "AUD": 1.3539465773 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-15", + "to_USD": { + "CAD": 1.3190758396, + "INR": 68.4806321395, + "EUR": 0.8588851671, + "USD": 1, + "SGD": 1.3672592974, + "GBP": 0.7600103066, + "CNY": 6.7003349652, + "AUD": 1.3539465773 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-16", + "to_USD": { + "CAD": 1.3139078498, + "INR": 68.5593003413, + "EUR": 0.8532423208, + "USD": 1, + "SGD": 1.3612627986, + "GBP": 0.7531569966, + "CNY": 6.6785836177, + "AUD": 1.3458191126 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-17", + "to_USD": { + "CAD": 1.3157085504, + "INR": 68.4551977449, + "EUR": 0.854189801, + "USD": 1, + "SGD": 1.3616639617, + "GBP": 0.7578799009, + "CNY": 6.6903561971, + "AUD": 1.3504740753 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-18", + "to_USD": { + "CAD": 1.3253811041, + "INR": 68.6280251486, + "EUR": 0.8612522608, + "USD": 1, + "SGD": 1.3679269658, + "GBP": 0.7675307898, + "CNY": 6.7213848936, + "AUD": 1.3602618207 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-19", + "to_USD": { + "CAD": 1.3247324819, + "INR": 69.0503106662, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3728857439, + "GBP": 0.770607525, + "CNY": 6.7788229203, + "AUD": 1.3638246462 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-20", + "to_USD": { + "CAD": 1.3233076264, + "INR": 68.8269065981, + "EUR": 0.8568980291, + "USD": 1, + "SGD": 1.3676092545, + "GBP": 0.7664524422, + "CNY": 6.7874892888, + "AUD": 1.3554413025 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-21", + "to_USD": { + "CAD": 1.3233076264, + "INR": 68.8269065981, + "EUR": 0.8568980291, + "USD": 1, + "SGD": 1.3676092545, + "GBP": 0.7664524422, + "CNY": 6.7874892888, + "AUD": 1.3554413025 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-22", + "to_USD": { + "CAD": 1.3233076264, + "INR": 68.8269065981, + "EUR": 0.8568980291, + "USD": 1, + "SGD": 1.3676092545, + "GBP": 0.7664524422, + "CNY": 6.7874892888, + "AUD": 1.3554413025 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-23", + "to_USD": { + "CAD": 1.3133321953, + "INR": 68.8571184705, + "EUR": 0.8535336292, + "USD": 1, + "SGD": 1.3638613861, + "GBP": 0.7610959372, + "CNY": 6.7862751792, + "AUD": 1.3503755548 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-24", + "to_USD": { + "CAD": 1.3149666838, + "INR": 68.9475482658, + "EUR": 0.8542627712, + "USD": 1, + "SGD": 1.3640013668, + "GBP": 0.7618144541, + "CNY": 6.7966000342, + "AUD": 1.3494788997 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-25", + "to_USD": { + "CAD": 1.3123182207, + "INR": 68.745936698, + "EUR": 0.8554319932, + "USD": 1, + "SGD": 1.3627887083, + "GBP": 0.7600940975, + "CNY": 6.7619332763, + "AUD": 1.3486740804 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-26", + "to_USD": { + "CAD": 1.304796859, + "INR": 68.6650734039, + "EUR": 0.8535336292, + "USD": 1, + "SGD": 1.3607886651, + "GBP": 0.7584499829, + "CNY": 6.7825196313, + "AUD": 1.3479003073 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-27", + "to_USD": { + "CAD": 1.3069247312, + "INR": 68.6851612903, + "EUR": 0.8602150538, + "USD": 1, + "SGD": 1.3643010753, + "GBP": 0.7640688172, + "CNY": 6.8347526882, + "AUD": 1.3561290323 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-28", + "to_USD": { + "CAD": 1.3069247312, + "INR": 68.6851612903, + "EUR": 0.8602150538, + "USD": 1, + "SGD": 1.3643010753, + "GBP": 0.7640688172, + "CNY": 6.8347526882, + "AUD": 1.3561290323 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-29", + "to_USD": { + "CAD": 1.3069247312, + "INR": 68.6851612903, + "EUR": 0.8602150538, + "USD": 1, + "SGD": 1.3643010753, + "GBP": 0.7640688172, + "CNY": 6.8347526882, + "AUD": 1.3561290323 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-30", + "to_USD": { + "CAD": 1.3047757617, + "INR": 68.6378808627, + "EUR": 0.855871277, + "USD": 1, + "SGD": 1.3620335502, + "GBP": 0.7623245464, + "CNY": 6.8223211229, + "AUD": 1.351848682 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-07-31", + "to_USD": { + "CAD": 1.3035105658, + "INR": 68.545074983, + "EUR": 0.8520790729, + "USD": 1, + "SGD": 1.3612815269, + "GBP": 0.7602249489, + "CNY": 6.831799591, + "AUD": 1.3466257669 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-01", + "to_USD": { + "CAD": 1.3022400821, + "INR": 68.3742305062, + "EUR": 0.8549931601, + "USD": 1, + "SGD": 1.3613201094, + "GBP": 0.7612859097, + "CNY": 6.7988201094, + "AUD": 1.3480677155 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-02", + "to_USD": { + "CAD": 1.3036067832, + "INR": 68.6851166394, + "EUR": 0.8608074374, + "USD": 1, + "SGD": 1.3667039683, + "GBP": 0.76736679, + "CNY": 6.8449685805, + "AUD": 1.3584402169 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-03", + "to_USD": { + "CAD": 1.3017777011, + "INR": 68.6158094581, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3667587159, + "GBP": 0.76846738, + "CNY": 6.8342250604, + "AUD": 1.3539005868 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-04", + "to_USD": { + "CAD": 1.3017777011, + "INR": 68.6158094581, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3667587159, + "GBP": 0.76846738, + "CNY": 6.8342250604, + "AUD": 1.3539005868 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-05", + "to_USD": { + "CAD": 1.3017777011, + "INR": 68.6158094581, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3667587159, + "GBP": 0.76846738, + "CNY": 6.8342250604, + "AUD": 1.3539005868 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-06", + "to_USD": { + "CAD": 1.3022611106, + "INR": 68.8642467296, + "EUR": 0.8663259118, + "USD": 1, + "SGD": 1.3687083081, + "GBP": 0.7734557741, + "CNY": 6.8496924543, + "AUD": 1.3539807676 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-07", + "to_USD": { + "CAD": 1.2969315635, + "INR": 68.6821237718, + "EUR": 0.8619203586, + "USD": 1, + "SGD": 1.3637303913, + "GBP": 0.7712721944, + "CNY": 6.8239096707, + "AUD": 1.3445095673 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-08", + "to_USD": { + "CAD": 1.307964449, + "INR": 68.6249892139, + "EUR": 0.8628872206, + "USD": 1, + "SGD": 1.3645698507, + "GBP": 0.7773319527, + "CNY": 6.8367417379, + "AUD": 1.3501596341 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-09", + "to_USD": { + "CAD": 1.3034589839, + "INR": 68.6470283792, + "EUR": 0.8625894937, + "USD": 1, + "SGD": 1.3633226947, + "GBP": 0.7758129906, + "CNY": 6.8190287242, + "AUD": 1.3478823428 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-10", + "to_USD": { + "CAD": 1.3095321229, + "INR": 68.8303072626, + "EUR": 0.8729050279, + "USD": 1, + "SGD": 1.3711592179, + "GBP": 0.7827775838, + "CNY": 6.8495111732, + "AUD": 1.3682786313 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-11", + "to_USD": { + "CAD": 1.3095321229, + "INR": 68.8303072626, + "EUR": 0.8729050279, + "USD": 1, + "SGD": 1.3711592179, + "GBP": 0.7827775838, + "CNY": 6.8495111732, + "AUD": 1.3682786313 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-12", + "to_USD": { + "CAD": 1.3095321229, + "INR": 68.8303072626, + "EUR": 0.8729050279, + "USD": 1, + "SGD": 1.3711592179, + "GBP": 0.7827775838, + "CNY": 6.8495111732, + "AUD": 1.3682786313 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-13", + "to_USD": { + "CAD": 1.3150925195, + "INR": 70.017100763, + "EUR": 0.8769622029, + "USD": 1, + "SGD": 1.3758660002, + "GBP": 0.7833903359, + "CNY": 6.8873980531, + "AUD": 1.374199772 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-14", + "to_USD": { + "CAD": 1.3071190601, + "INR": 69.9031211643, + "EUR": 0.8767315448, + "USD": 1, + "SGD": 1.3737506575, + "GBP": 0.7829212695, + "CNY": 6.8812905488, + "AUD": 1.3761178327 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-15", + "to_USD": { + "CAD": 1.3102199452, + "INR": 69.9262432647, + "EUR": 0.8833141949, + "USD": 1, + "SGD": 1.3803550923, + "GBP": 0.7872979419, + "CNY": 6.9161734829, + "AUD": 1.3840650119 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-16", + "to_USD": { + "CAD": 1.3141600704, + "INR": 70.1908531223, + "EUR": 0.8795074758, + "USD": 1, + "SGD": 1.3762532982, + "GBP": 0.7871416007, + "CNY": 6.8949868074, + "AUD": 1.3761653474 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-17", + "to_USD": { + "CAD": 1.3147221491, + "INR": 70.1602142042, + "EUR": 0.8778860504, + "USD": 1, + "SGD": 1.3739794575, + "GBP": 0.7863664296, + "CNY": 6.8843824072, + "AUD": 1.375647441 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-18", + "to_USD": { + "CAD": 1.3147221491, + "INR": 70.1602142042, + "EUR": 0.8778860504, + "USD": 1, + "SGD": 1.3739794575, + "GBP": 0.7863664296, + "CNY": 6.8843824072, + "AUD": 1.375647441 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-19", + "to_USD": { + "CAD": 1.3147221491, + "INR": 70.1602142042, + "EUR": 0.8778860504, + "USD": 1, + "SGD": 1.3739794575, + "GBP": 0.7863664296, + "CNY": 6.8843824072, + "AUD": 1.375647441 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-20", + "to_USD": { + "CAD": 1.3070928196, + "INR": 69.8248686515, + "EUR": 0.8756567426, + "USD": 1, + "SGD": 1.3717162872, + "GBP": 0.7835201401, + "CNY": 6.8608581436, + "AUD": 1.3687390543 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-21", + "to_USD": { + "CAD": 1.3022083116, + "INR": 69.8152495218, + "EUR": 0.869414015, + "USD": 1, + "SGD": 1.3681098939, + "GBP": 0.780212137, + "CNY": 6.846461485, + "AUD": 1.3612415232 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-22", + "to_USD": { + "CAD": 1.3021694215, + "INR": 69.8949724518, + "EUR": 0.8608815427, + "USD": 1, + "SGD": 1.3653581267, + "GBP": 0.7741735537, + "CNY": 6.8414256198, + "AUD": 1.3589015152 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-23", + "to_USD": { + "CAD": 1.3031349858, + "INR": 70.1109767683, + "EUR": 0.863632438, + "USD": 1, + "SGD": 1.3700664997, + "GBP": 0.7762155627, + "CNY": 6.8782278262, + "AUD": 1.3721392175 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-24", + "to_USD": { + "CAD": 1.3067828788, + "INR": 69.909820504, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3689161201, + "GBP": 0.7783914394, + "CNY": 6.8455298585, + "AUD": 1.369347601 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-25", + "to_USD": { + "CAD": 1.3067828788, + "INR": 69.909820504, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3689161201, + "GBP": 0.7783914394, + "CNY": 6.8455298585, + "AUD": 1.369347601 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-26", + "to_USD": { + "CAD": 1.3067828788, + "INR": 69.909820504, + "EUR": 0.8629616845, + "USD": 1, + "SGD": 1.3689161201, + "GBP": 0.7783914394, + "CNY": 6.8455298585, + "AUD": 1.369347601 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-27", + "to_USD": { + "CAD": 1.3050803748, + "INR": 70.1650477091, + "EUR": 0.8596234849, + "USD": 1, + "SGD": 1.3654259434, + "GBP": 0.7767987621, + "CNY": 6.8250666208, + "AUD": 1.3655978681 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-28", + "to_USD": { + "CAD": 1.2918872758, + "INR": 70.1080273271, + "EUR": 0.853970965, + "USD": 1, + "SGD": 1.3616567037, + "GBP": 0.7743808711, + "CNY": 6.8011101623, + "AUD": 1.3598633646 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-29", + "to_USD": { + "CAD": 1.2944253859, + "INR": 70.6179245283, + "EUR": 0.8576329331, + "USD": 1, + "SGD": 1.3671526587, + "GBP": 0.7761578045, + "CNY": 6.8289879931, + "AUD": 1.3712692967 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-30", + "to_USD": { + "CAD": 1.2929353404, + "INR": 70.7449538146, + "EUR": 0.8552856654, + "USD": 1, + "SGD": 1.3657201505, + "GBP": 0.7676873076, + "CNY": 6.8326205953, + "AUD": 1.3697399932 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-08-31", + "to_USD": { + "CAD": 1.3039224101, + "INR": 71.002059909, + "EUR": 0.8582954253, + "USD": 1, + "SGD": 1.3702686465, + "GBP": 0.7702343147, + "CNY": 6.837524676, + "AUD": 1.3843446914 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-01", + "to_USD": { + "CAD": 1.3039224101, + "INR": 71.002059909, + "EUR": 0.8582954253, + "USD": 1, + "SGD": 1.3702686465, + "GBP": 0.7702343147, + "CNY": 6.837524676, + "AUD": 1.3843446914 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-02", + "to_USD": { + "CAD": 1.3039224101, + "INR": 71.002059909, + "EUR": 0.8582954253, + "USD": 1, + "SGD": 1.3702686465, + "GBP": 0.7702343147, + "CNY": 6.837524676, + "AUD": 1.3843446914 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-03", + "to_USD": { + "CAD": 1.3071754673, + "INR": 71.2150055991, + "EUR": 0.8614006374, + "USD": 1, + "SGD": 1.3717805151, + "GBP": 0.7766215867, + "CNY": 6.8239297097, + "AUD": 1.3876302868 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-04", + "to_USD": { + "CAD": 1.3175921121, + "INR": 71.5849334025, + "EUR": 0.864902266, + "USD": 1, + "SGD": 1.3761459955, + "GBP": 0.7789136828, + "CNY": 6.8395606296, + "AUD": 1.3917142363 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-05", + "to_USD": { + "CAD": 1.3178207563, + "INR": 71.7522880332, + "EUR": 0.8634087377, + "USD": 1, + "SGD": 1.3784320497, + "GBP": 0.7798998446, + "CNY": 6.8319806596, + "AUD": 1.3938870661 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-06", + "to_USD": { + "CAD": 1.3183771704, + "INR": 71.9593433041, + "EUR": 0.859549596, + "USD": 1, + "SGD": 1.3752793536, + "GBP": 0.7720818291, + "CNY": 6.8292074953, + "AUD": 1.389375967 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-07", + "to_USD": { + "CAD": 1.3119242359, + "INR": 71.7348256565, + "EUR": 0.8609556608, + "USD": 1, + "SGD": 1.3754627637, + "GBP": 0.7686181662, + "CNY": 6.8425312096, + "AUD": 1.3963839862 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-08", + "to_USD": { + "CAD": 1.3119242359, + "INR": 71.7348256565, + "EUR": 0.8609556608, + "USD": 1, + "SGD": 1.3754627637, + "GBP": 0.7686181662, + "CNY": 6.8425312096, + "AUD": 1.3963839862 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-09", + "to_USD": { + "CAD": 1.3119242359, + "INR": 71.7348256565, + "EUR": 0.8609556608, + "USD": 1, + "SGD": 1.3754627637, + "GBP": 0.7686181662, + "CNY": 6.8425312096, + "AUD": 1.3963839862 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-10", + "to_USD": { + "CAD": 1.3195056607, + "INR": 72.4548440066, + "EUR": 0.8642295394, + "USD": 1, + "SGD": 1.3798288826, + "GBP": 0.7721026705, + "CNY": 6.863106041, + "AUD": 1.4049779621 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-11", + "to_USD": { + "CAD": 1.3159668222, + "INR": 72.659841023, + "EUR": 0.8640055296, + "USD": 1, + "SGD": 1.377656817, + "GBP": 0.7695524451, + "CNY": 6.86875756, + "AUD": 1.4091930188 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-12", + "to_USD": { + "CAD": 1.3066033664, + "INR": 72.2231333621, + "EUR": 0.8631851532, + "USD": 1, + "SGD": 1.3763487268, + "GBP": 0.7684764782, + "CNY": 6.8699179974, + "AUD": 1.4042296073 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-13", + "to_USD": { + "CAD": 1.3005163511, + "INR": 72.0309810671, + "EUR": 0.8605851979, + "USD": 1, + "SGD": 1.3716006885, + "GBP": 0.7659208262, + "CNY": 6.8452667814, + "AUD": 1.3913080895 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-14", + "to_USD": { + "CAD": 1.3008811703, + "INR": 71.8162374882, + "EUR": 0.8555051758, + "USD": 1, + "SGD": 1.3698348875, + "GBP": 0.7633501583, + "CNY": 6.8543074686, + "AUD": 1.3910514159 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-15", + "to_USD": { + "CAD": 1.3008811703, + "INR": 71.8162374882, + "EUR": 0.8555051758, + "USD": 1, + "SGD": 1.3698348875, + "GBP": 0.7633501583, + "CNY": 6.8543074686, + "AUD": 1.3910514159 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-16", + "to_USD": { + "CAD": 1.3008811703, + "INR": 71.8162374882, + "EUR": 0.8555051758, + "USD": 1, + "SGD": 1.3698348875, + "GBP": 0.7633501583, + "CNY": 6.8543074686, + "AUD": 1.3910514159 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-17", + "to_USD": { + "CAD": 1.3017736269, + "INR": 72.5177791106, + "EUR": 0.856824608, + "USD": 1, + "SGD": 1.3723759746, + "GBP": 0.7615028704, + "CNY": 6.8665067261, + "AUD": 1.3930254477 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-18", + "to_USD": { + "CAD": 1.302641703, + "INR": 72.9768316662, + "EUR": 0.854920065, + "USD": 1, + "SGD": 1.3705223562, + "GBP": 0.7605625374, + "CNY": 6.8664614859, + "AUD": 1.3887321535 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-19", + "to_USD": { + "CAD": 1.2973343619, + "INR": 72.3849318591, + "EUR": 0.857118368, + "USD": 1, + "SGD": 1.370789406, + "GBP": 0.7612325362, + "CNY": 6.8554898431, + "AUD": 1.3807319791 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-20", + "to_USD": { + "CAD": 1.2893193984, + "INR": 72.0120655961, + "EUR": 0.8496898632, + "USD": 1, + "SGD": 1.3649417962, + "GBP": 0.7527402498, + "CNY": 6.845016569, + "AUD": 1.372928881 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-21", + "to_USD": { + "CAD": 1.2923718003, + "INR": 72.19193809, + "EUR": 0.85041245, + "USD": 1, + "SGD": 1.3642316524, + "GBP": 0.7602687303, + "CNY": 6.8460753465, + "AUD": 1.3737562718 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-22", + "to_USD": { + "CAD": 1.2923718003, + "INR": 72.19193809, + "EUR": 0.85041245, + "USD": 1, + "SGD": 1.3642316524, + "GBP": 0.7602687303, + "CNY": 6.8460753465, + "AUD": 1.3737562718 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-23", + "to_USD": { + "CAD": 1.2923718003, + "INR": 72.19193809, + "EUR": 0.85041245, + "USD": 1, + "SGD": 1.3642316524, + "GBP": 0.7602687303, + "CNY": 6.8460753465, + "AUD": 1.3737562718 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-24", + "to_USD": { + "CAD": 1.2937229253, + "INR": 72.6802853988, + "EUR": 0.8494011722, + "USD": 1, + "SGD": 1.3642232226, + "GBP": 0.7598573006, + "CNY": 6.8571307228, + "AUD": 1.3749256774 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-25", + "to_USD": { + "CAD": 1.295915768, + "INR": 72.6946590813, + "EUR": 0.8491126773, + "USD": 1, + "SGD": 1.3656279188, + "GBP": 0.7593190116, + "CNY": 6.8742464125, + "AUD": 1.3784495203 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-26", + "to_USD": { + "CAD": 1.2962426514, + "INR": 72.6071398143, + "EUR": 0.8520064752, + "USD": 1, + "SGD": 1.3655107779, + "GBP": 0.7589673682, + "CNY": 6.8744142455, + "AUD": 1.3804208912 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-27", + "to_USD": { + "CAD": 1.3069958145, + "INR": 72.5916118562, + "EUR": 0.854189801, + "USD": 1, + "SGD": 1.364653626, + "GBP": 0.7599982916, + "CNY": 6.8804988468, + "AUD": 1.3837874776 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-28", + "to_USD": { + "CAD": 1.3013130615, + "INR": 72.4913614375, + "EUR": 0.8638562543, + "USD": 1, + "SGD": 1.3682619212, + "GBP": 0.7664996545, + "CNY": 6.8816516932, + "AUD": 1.3863165169 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-29", + "to_USD": { + "CAD": 1.3013130615, + "INR": 72.4913614375, + "EUR": 0.8638562543, + "USD": 1, + "SGD": 1.3682619212, + "GBP": 0.7664996545, + "CNY": 6.8816516932, + "AUD": 1.3863165169 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-09-30", + "to_USD": { + "CAD": 1.3013130615, + "INR": 72.4913614375, + "EUR": 0.8638562543, + "USD": 1, + "SGD": 1.3682619212, + "GBP": 0.7664996545, + "CNY": 6.8816516932, + "AUD": 1.3863165169 + } + }, + { + "type": "exchange_rates", + "erid": "er-2018-10-01", + "to_USD": { + "CAD": 1.2809753576, + "INR": 72.9118559366, + "EUR": 0.8616232983, + "USD": 1, + "SGD": 1.3702395313, + "GBP": 0.7675168017, + "CNY": 6.868860934, + "AUD": 1.3846286404 + } + } +] diff --git a/modules/eventing/assets/attachments/examples/high_risk/merchants.json b/modules/eventing/assets/attachments/examples/high_risk/merchants.json new file mode 100644 index 000000000..2b2cd18b0 --- /dev/null +++ b/modules/eventing/assets/attachments/examples/high_risk/merchants.json @@ -0,0 +1,65013 @@ +[ +{ + "type": "merchant", + "merchantid": "merchant-501233450539197794-0", + "name": "FlightAware Inc", + "city": { + "name": "Bentonville", + "code": "IN", + "state": "Indiana", + "county": "Fayette", + "display": "Bentonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6044372234677422456-1", + "name": "USSearch Incorporated", + "city": { + "name": "Rincon", + "code": "GA", + "state": "Georgia", + "county": "Effingham", + "display": "Rincon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8325060299420976708-2", + "name": "Energy Points, Inc", + "city": { + "name": "Moscow", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Covington Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2339563716805116249-3", + "name": "CB Insights Inc", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "West Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7373105480197164748-4", + "name": "Solar Census Company", + "city": { + "name": "Pe Ell", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Peell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2217592893536642650-5", + "name": "WeMakeItSafer Inc", + "city": { + "name": "Jacksboro", + "code": "TX", + "state": "Texas", + "county": "Jack", + "display": "Jacksboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2627038740284806767-6", + "name": "Credit Sesame Inc", + "city": { + "name": "Sioux City", + "code": "IA", + "state": "Iowa", + "county": "Woodbury", + "display": "Blvd Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2914295034816259174-7", + "name": "Weight Watchers Incorporated", + "city": { + "name": "Arrowsmith", + "code": "IL", + "state": "Illinois", + "county": "Mclean", + "display": "Arrowsmith" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3398579248012586914-8", + "name": "PYA Analytics Incorporated", + "city": { + "name": "Sesser", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Goode" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-167566062957544642-9", + "name": "MapQuest Incorporated", + "city": { + "name": "Simpson", + "code": "IL", + "state": "Illinois", + "county": "Johnson", + "display": "Robbs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5558237345453186302-10", + "name": "SigFig Inc", + "city": { + "name": "Coloma", + "code": "CA", + "state": "California", + "county": "El Dorado", + "display": "Coloma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8683452355129068124-11", + "name": "Construction Monitor Corp", + "city": { + "name": "Nashville", + "code": "NC", + "state": "North Carolina", + "county": "Nash", + "display": "Momeyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7561811714888168464-12", + "name": "Arrive Labs Corporation", + "city": { + "name": "Chavies", + "code": "KY", + "state": "Kentucky", + "county": "Perry", + "display": "Chavies" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7338728586234333996-13", + "name": "Synthicity Incorporated", + "city": { + "name": "Pansey", + "code": "AL", + "state": "Alabama", + "county": "Houston", + "display": "Pansey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4756106358532488297-14", + "name": "eInstitutional Company", + "city": { + "name": "Moroni", + "code": "UT", + "state": "Utah", + "county": "Sanpete", + "display": "Moroni" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1061380815263676471-15", + "name": "SAS LLC", + "city": { + "name": "Paicines", + "code": "CA", + "state": "California", + "county": "San Benito", + "display": "Panoche" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2671030200101705776-16", + "name": "GetRaised LLC", + "city": { + "name": "Shoals", + "code": "WV", + "state": "West Virginia", + "county": "Wayne", + "display": "Shoals" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1198006251912892506-17", + "name": "IBM Corp", + "city": { + "name": "Cedar", + "code": "MN", + "state": "Minnesota", + "county": "Anoka", + "display": "Oak Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2587000937929698613-18", + "name": "Palantir Technologies Corporation", + "city": { + "name": "Kellerman", + "code": "AL", + "state": "Alabama", + "county": "Tuscaloosa", + "display": "Searles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7481608503761597087-19", + "name": "Google Maps Incorporated", + "city": { + "name": "Wilbraham", + "code": "MA", + "state": "Massachusetts", + "county": "Hampden", + "display": "Wilbraham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7663837986485606015-20", + "name": "Roadify Transit Inc", + "city": { + "name": "Athens", + "code": "IL", + "state": "Illinois", + "county": "Menard", + "display": "Athens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8559453321117178323-21", + "name": "CONNECT-DOT Corporation", + "city": { + "name": "Wedderburn", + "code": "OR", + "state": "Oregon", + "county": "Curry", + "display": "Wedderburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2682844416202521633-22", + "name": "Mozio Inc", + "city": { + "name": "Bath", + "code": "NY", + "state": "New York", + "county": "Steuben", + "display": "Bath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9021104375654741729-23", + "name": "SAS Incorporated", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Arsenal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-759605945513541974-24", + "name": "FindTheBest.com Incorporated", + "city": { + "name": "Wilmington", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Custer Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6651829488660799814-25", + "name": "SmartProcure LLC", + "city": { + "name": "Bretz", + "code": "WV", + "state": "West Virginia", + "county": "Preston", + "display": "Bretz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6215632031706852400-26", + "name": "The Vanguard Group Corporation", + "city": { + "name": "Franklin", + "code": "NC", + "state": "North Carolina", + "county": "Macon", + "display": "Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7945398411639602224-27", + "name": "Inrix Traffic Company", + "city": { + "name": "Bronx", + "code": "NY", + "state": "New York", + "county": "Bronx", + "display": "Esplanade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2803285039048912676-28", + "name": "StreetCred Software, Corporation", + "city": { + "name": "Monrovia", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Monrovia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6604365855503062775-29", + "name": "Aunt Bertha, Company", + "city": { + "name": "Fort Lauderdale", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Lauderhill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3242614188194728891-30", + "name": "HelloWallet Inc", + "city": { + "name": "Grampian", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Grampian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1627381309359808899-31", + "name": "Liberty Mutual Insurance Cos Corporation", + "city": { + "name": "New Paris", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "New Paris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5311927246208705713-32", + "name": "AtSite Corp", + "city": { + "name": "Lumber Bridge", + "code": "NC", + "state": "North Carolina", + "county": "Robeson", + "display": "Lumber Bridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2629911606854649819-33", + "name": "Code for America Company", + "city": { + "name": "Saint Peter", + "code": "IL", + "state": "Illinois", + "county": "Fayette", + "display": "St Peter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2037591971392316788-34", + "name": "Citigroup Corp", + "city": { + "name": "Barton", + "code": "VT", + "state": "Vermont", + "county": "Orleans", + "display": "West Glover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2718877847597668777-35", + "name": "PlaceILive.com LLC", + "city": { + "name": "Rawl", + "code": "WV", + "state": "West Virginia", + "county": "Mingo", + "display": "Rawl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7478610059307147871-36", + "name": "VisualDoD, Corp", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Nys Dept Of Tax \u0026 Finance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4975249678507640420-37", + "name": "SpaceCurve Corp", + "city": { + "name": "Kirkland", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Totem Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1363585710475529225-38", + "name": "Kroll Bond Ratings Agency Incorporated", + "city": { + "name": "Viola", + "code": "AR", + "state": "Arkansas", + "county": "Fulton", + "display": "Viola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4745905187492708501-39", + "name": "Construction Monitor LLC", + "city": { + "name": "Climax Springs", + "code": "MO", + "state": "Missouri", + "county": "Camden", + "display": "Climax Sprgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7506934391669544280-40", + "name": "TrialTrove Incorporated", + "city": { + "name": "Rentz", + "code": "GA", + "state": "Georgia", + "county": "Laurens", + "display": "Rentz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3755969145755718156-41", + "name": "CoreLogic Corp", + "city": { + "name": "San Juan Bautista", + "code": "CA", + "state": "California", + "county": "San Benito", + "display": "San Juan Bautista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3321710981400855005-42", + "name": "AtSite Company", + "city": { + "name": "Zurich", + "code": "MT", + "state": "Montana", + "county": "Blaine", + "display": "Zurich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7953274849279451463-43", + "name": "Forrester Research Inc", + "city": { + "name": "West Union", + "code": "IA", + "state": "Iowa", + "county": "Fayette", + "display": "West Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4400124260933614083-44", + "name": "Recargo LLC", + "city": { + "name": "Abilene", + "code": "TX", + "state": "Texas", + "county": "Taylor", + "display": "Abilene" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-330151684706709734-45", + "name": "PayScale, LLC", + "city": { + "name": "Orient", + "code": "IA", + "state": "Iowa", + "county": "Adair", + "display": "Zion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3909624772458770597-46", + "name": "Lawdragon LLC", + "city": { + "name": "Alexandria", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Weil" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8997481548049309375-47", + "name": "Azavea Corporation", + "city": { + "name": "Loleta", + "code": "CA", + "state": "California", + "county": "Humboldt", + "display": "Loleta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5418224491453948590-48", + "name": "SigFig Company", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Wilkes Barre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5857858779299113932-49", + "name": "Docket Alarm, LLC", + "city": { + "name": "El Segundo", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "El Segundo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5001980330882093199-50", + "name": "Uber Company", + "city": { + "name": "Great Neck", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Harbor Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9076578640078988002-51", + "name": "Progressive Insurance Group Incorporated", + "city": { + "name": "Xenia", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Sugarcreek Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9178255268999664835-52", + "name": "Mozio Incorporated", + "city": { + "name": "Jamaica", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Rochdale Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7446022752824825204-53", + "name": "Epsilon LLC", + "city": { + "name": "Mcarthur", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Mcarthur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4932993544835283753-54", + "name": "McGraw Hill Financial Inc", + "city": { + "name": "Amery", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Amery" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-642003253032433474-55", + "name": "Berkery Noyes MandASoft LLC", + "city": { + "name": "Viborg", + "code": "SD", + "state": "South Dakota", + "county": "Turner", + "display": "Swan Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-546268158124317116-56", + "name": "OSIsoft Company", + "city": { + "name": "Edgefield", + "code": "SC", + "state": "South Carolina", + "county": "Edgefield", + "display": "Cleora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5701769618658388108-57", + "name": "Compendia Bioscience Life Technologies Company", + "city": { + "name": "Plover", + "code": "WI", + "state": "Wisconsin", + "county": "Portage", + "display": "Buena Vista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7584801650961219166-58", + "name": "MetLife Corp", + "city": { + "name": "Good Hart", + "code": "MI", + "state": "Michigan", + "county": "Emmet", + "display": "Harbor Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5192917599516086534-59", + "name": "Teradata Inc", + "city": { + "name": "Sarah Ann", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Sarah Ann" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8993831421611415990-60", + "name": "Rezolve Group Corporation", + "city": { + "name": "Allenhurst", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Loch Arbour" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3752781218885968701-61", + "name": "Connotate Corp", + "city": { + "name": "Melrose", + "code": "NM", + "state": "New Mexico", + "county": "Curry", + "display": "Melrose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-371208508841907247-62", + "name": "Rank and Filed LLC", + "city": { + "name": "Sebastian", + "code": "FL", + "state": "Florida", + "county": "Brevard", + "display": "Micco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9002761601099372112-63", + "name": "Lending Club Incorporated", + "city": { + "name": "Water Mill", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Wtr Mill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1638829746864917218-64", + "name": "PolicyMap Incorporated", + "city": { + "name": "Sopchoppy", + "code": "FL", + "state": "Florida", + "county": "Wakulla", + "display": "Sopchoppy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7796777083842162182-65", + "name": "Unigo Corp", + "city": { + "name": "Newburg", + "code": "WI", + "state": "Wisconsin", + "county": "Washington", + "display": "Newburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-29372123613087746-66", + "name": "Outline Corp", + "city": { + "name": "Sextons Creek", + "code": "KY", + "state": "Kentucky", + "county": "Clay", + "display": "Sextons Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6187840044538043239-67", + "name": "Quandl LLC", + "city": { + "name": "Kirkwood", + "code": "IL", + "state": "Illinois", + "county": "Warren", + "display": "Tompkins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4588799179103092032-68", + "name": "Credit Karma Corporation", + "city": { + "name": "Aberdeen", + "code": "MS", + "state": "Mississippi", + "county": "Monroe", + "display": "Centralgrove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2004642140807173105-69", + "name": "Canon Corporation", + "city": { + "name": "Blachly", + "code": "OR", + "state": "Oregon", + "county": "Lane", + "display": "Triangle Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1186510747668689874-70", + "name": "MicroBilt Corporation", + "city": { + "name": "Holdingford", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Holdingford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2386043087176739176-71", + "name": "Geofeedia Incorporated", + "city": { + "name": "North Richland Hills", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Fort Worth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5683174242247563523-72", + "name": "Onvia Company", + "city": { + "name": "Laguna", + "code": "NM", + "state": "New Mexico", + "county": "Cibola", + "display": "Mesita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3753392688546409181-73", + "name": "HERE Inc", + "city": { + "name": "New Prague", + "code": "MN", + "state": "Minnesota", + "county": "Scott", + "display": "New Prague" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1444501184389758573-74", + "name": "Personal Democracy Media Company", + "city": { + "name": "Zuni", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Black Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9117043256905423229-75", + "name": "Ceiba Solutions Company", + "city": { + "name": "Danboro", + "code": "PA", + "state": "Pennsylvania", + "county": "Bucks", + "display": "Danboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1529447803721624558-76", + "name": "Scale Unlimited Corporation", + "city": { + "name": "Colp", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Old Camp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5712992115651289762-77", + "name": "SpaceCurve Corporation", + "city": { + "name": "Verndale", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Wing River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7167106058699817943-78", + "name": "CB Insights Corp", + "city": { + "name": "South Ozone Park", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "South Ozone Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8364267861508686372-79", + "name": "SolarList Corp", + "city": { + "name": "Georgetown", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Georgetown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4628132784885150210-80", + "name": "Avalara Incorporated", + "city": { + "name": "Elkader", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Osborne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7465719782626729327-81", + "name": "PlanetEcosystems Company", + "city": { + "name": "Mannsville", + "code": "KY", + "state": "Kentucky", + "county": "Taylor", + "display": "Mannsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8590975497400104807-82", + "name": "SeeClickFix Corp", + "city": { + "name": "Pima", + "code": "AZ", + "state": "Arizona", + "county": "Graham", + "display": "Eden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8110853471461374637-83", + "name": "Panjiva Corporation", + "city": { + "name": "Mount Pleasant", + "code": "AR", + "state": "Arkansas", + "county": "Izard", + "display": "Mount Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2506834319279501248-84", + "name": "InnoCentive Incorporated", + "city": { + "name": "Falcon Heights", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "Falcon Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-329480657186062760-85", + "name": "KidAdmit, LLC", + "city": { + "name": "Long Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "East Long Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5736490461555293534-86", + "name": "Panjiva Corporation", + "city": { + "name": "Avoca", + "code": "NY", + "state": "New York", + "county": "Steuben", + "display": "Avoca" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4642525602086184656-87", + "name": "Zonability Incorporated", + "city": { + "name": "Geneva", + "code": "AL", + "state": "Alabama", + "county": "Geneva", + "display": "Eunola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8141978658923475747-88", + "name": "Biovia Corp", + "city": { + "name": "Nuremberg", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Fern Glen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-930977177771307407-89", + "name": "Retroficiency Company", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Nevada Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4431047122332405830-90", + "name": "LOVELAND Technologies Inc", + "city": { + "name": "Angola", + "code": "IN", + "state": "Indiana", + "county": "Steuben", + "display": "Angola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3450989031171849556-91", + "name": "Morgan Stanley Inc", + "city": { + "name": "Waverly", + "code": "GA", + "state": "Georgia", + "county": "Camden", + "display": "Spring Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2800962264139767963-92", + "name": "ZocDoc LLC", + "city": { + "name": "Rugby", + "code": "ND", + "state": "North Dakota", + "county": "Pierce", + "display": "Silva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6313591874627005077-93", + "name": "Geoscape Corp", + "city": { + "name": "Spring Lake", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Spring Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1965282774241794518-94", + "name": "Everyday Health Incorporated", + "city": { + "name": "Lewisville", + "code": "NC", + "state": "North Carolina", + "county": "Forsyth", + "display": "West Bend" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2856324619161861976-95", + "name": "Amida Technology Solutions Company", + "city": { + "name": "Water Mill", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Watermill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-262877386996496551-96", + "name": "Boundless Corporation", + "city": { + "name": "Trenton", + "code": "IL", + "state": "Illinois", + "county": "Clinton", + "display": "Sugar Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2132755572425097180-97", + "name": "LOGIXDATA, LLC", + "city": { + "name": "Whittier", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Pico Rivera" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4629305236432754029-98", + "name": "Wheaton World Wide Moving Corporation", + "city": { + "name": "Omaha", + "code": "NE", + "state": "Nebraska", + "county": "Douglas", + "display": "Bar Code" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4500698545012642604-99", + "name": "gRadiant Research Inc", + "city": { + "name": "Durants Neck", + "code": "NC", + "state": "North Carolina", + "county": "Perquimans", + "display": "Hertford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7107949635499134066-100", + "name": "Mapbox Corp", + "city": { + "name": "Posen", + "code": "MI", + "state": "Michigan", + "county": "Presque Isle", + "display": "Posen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-162748198233786728-101", + "name": "Oversight Systems Company", + "city": { + "name": "Scooba", + "code": "MS", + "state": "Mississippi", + "county": "Kemper", + "display": "Electric Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4108443080415677944-102", + "name": "ideas42 Company", + "city": { + "name": "Osseo", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Osseo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2762871534793283085-103", + "name": "IVES Group LLC", + "city": { + "name": "Luzerne", + "code": "IA", + "state": "Iowa", + "county": "Benton", + "display": "Luzerne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1717316735216544452-104", + "name": "Rank and Filed Inc", + "city": { + "name": "Saint Paul", + "code": "MN", + "state": "Minnesota", + "county": "Ramsey", + "display": "Minn Mining Boxes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-540413947656020526-105", + "name": "Center for Responsive Politics Inc", + "city": { + "name": "Blue Creek", + "code": "OH", + "state": "Ohio", + "county": "Adams", + "display": "Blue Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2245863337273937304-106", + "name": "Azavea Inc", + "city": { + "name": "New Virginia", + "code": "IA", + "state": "Iowa", + "county": "Warren", + "display": "Jamison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2166251624916999313-107", + "name": "IFI CLAIMS Patent Services Inc", + "city": { + "name": "Howell", + "code": "MI", + "state": "Michigan", + "county": "Livingston", + "display": "Howell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6943106624917850135-108", + "name": "Revelstone Corp", + "city": { + "name": "Andover", + "code": "NJ", + "state": "New Jersey", + "county": "Sussex", + "display": "Byram Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3424131883437816551-109", + "name": "Patently-O Inc", + "city": { + "name": "Park City", + "code": "UT", + "state": "Utah", + "county": "Summit", + "display": "Kimball Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6179772165467236447-110", + "name": "48 Factoring Corporation", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "So Pole" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6167316338759183977-111", + "name": "TagniFi Corporation", + "city": { + "name": "Ottawa", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Ottawa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8724673710750471494-112", + "name": "Graebel Van Lines Company", + "city": { + "name": "North Pownal", + "code": "VT", + "state": "Vermont", + "county": "Bennington", + "display": "N Pownal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3775576383156376750-113", + "name": "48 Factoring Corp", + "city": { + "name": "Greensburg", + "code": "IN", + "state": "Indiana", + "county": "Decatur", + "display": "Burney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3417054809625618671-114", + "name": "Munetrix Company", + "city": { + "name": "Sturtevant", + "code": "WI", + "state": "Wisconsin", + "county": "Racine", + "display": "Sturtevant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2824488195325811791-115", + "name": "Foursquare LLC", + "city": { + "name": "Bledsoe", + "code": "KY", + "state": "Kentucky", + "county": "Harlan", + "display": "Bledsoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3496311696429180675-116", + "name": "SpotHero.com Incorporated", + "city": { + "name": "Olympia", + "code": "WA", + "state": "Washington", + "county": "Thurston", + "display": "Washington State Department" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5347020836194397207-117", + "name": "BetterLesson LLC", + "city": { + "name": "Wedderburn", + "code": "OR", + "state": "Oregon", + "county": "Curry", + "display": "Wedderburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4286177495908355721-118", + "name": "Ayasdi LLC", + "city": { + "name": "Rosebush", + "code": "MI", + "state": "Michigan", + "county": "Isabella", + "display": "Rosebush" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5875212041318087154-119", + "name": "IBM Corp", + "city": { + "name": "Springfield", + "code": "IL", + "state": "Illinois", + "county": "Sangamon", + "display": "Jerome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7519322344649248496-120", + "name": "KidAdmit, Corporation", + "city": { + "name": "Fort Leonard Wood", + "code": "MO", + "state": "Missouri", + "county": "Pulaski", + "display": "Ft Leonard Wd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1987095690814515857-121", + "name": "IFI CLAIMS Patent Services Company", + "city": { + "name": "Mesa", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Mesa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2543754520120754471-122", + "name": "Seabourne Corporation", + "city": { + "name": "Schoolcraft", + "code": "MI", + "state": "Michigan", + "county": "Kalamazoo", + "display": "Schoolcraft" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9004954358869665939-123", + "name": "HealthPocket, LLC", + "city": { + "name": "Buffalo", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "Snyder Square" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5167835839957148740-124", + "name": "iMedicare Corporation", + "city": { + "name": "Osprey", + "code": "FL", + "state": "Florida", + "county": "Sarasota", + "display": "Osprey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8922316068806433238-125", + "name": "Jurispect LLC", + "city": { + "name": "Santa Fe", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Jaconita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6612358853391904586-126", + "name": "Dabo Health Inc", + "city": { + "name": "Bernalillo", + "code": "NM", + "state": "New Mexico", + "county": "Sandoval", + "display": "Bernalillo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1618200316448249157-127", + "name": "Captricity Corp", + "city": { + "name": "D Lo", + "code": "MS", + "state": "Mississippi", + "county": "Simpson", + "display": "D Lo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-770565711872751150-128", + "name": "nGAP orporated Corporation", + "city": { + "name": "Fort Lauderdale", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Everglades Br" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-703460223791086499-129", + "name": "LoopNet Company", + "city": { + "name": "Franklin", + "code": "NE", + "state": "Nebraska", + "county": "Franklin", + "display": "Macon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8436827725763183950-130", + "name": "Fujitsu Incorporated", + "city": { + "name": "Marshes Siding", + "code": "KY", + "state": "Kentucky", + "county": "Mccreary", + "display": "Marshes Sdng" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-536448273514821351-131", + "name": "HealthPocket, Company", + "city": { + "name": "Richfield Springs", + "code": "NY", + "state": "New York", + "county": "Otsego", + "display": "Richfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8617221661803175936-132", + "name": "NerdWallet Corporation", + "city": { + "name": "Puposky", + "code": "MN", + "state": "Minnesota", + "county": "Beltrami", + "display": "Durand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8511128607726460490-133", + "name": "Eat Shop Sleep Corp", + "city": { + "name": "Kake", + "code": "AK", + "state": "Alaska", + "county": "Petersburg", + "display": "Kake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7778259490808892664-134", + "name": "Merrill Inc", + "city": { + "name": "Romeo", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Bruce Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4543470065267051573-135", + "name": "McKinsey Inc", + "city": { + "name": "Scranton", + "code": "ND", + "state": "North Dakota", + "county": "Bowman", + "display": "Gascoyne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7813030023457107098-136", + "name": "Aidin Company", + "city": { + "name": "Compton", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Rancho Dominguez" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-987824140718201109-137", + "name": "Merrill Lynch Inc", + "city": { + "name": "Shelby", + "code": "IN", + "state": "Indiana", + "county": "Lake", + "display": "Shelby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5221019905968225720-138", + "name": "Impact Forecasting LLC", + "city": { + "name": "Williamsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Blair", + "display": "Williamsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7495381662146248767-139", + "name": "Ayasdi Incorporated", + "city": { + "name": "Hanover", + "code": "NM", + "state": "New Mexico", + "county": "Grant", + "display": "San Lorenzo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3828145240742315934-140", + "name": "Trulia Company", + "city": { + "name": "Cedar Creek", + "code": "NE", + "state": "Nebraska", + "county": "Cass", + "display": "Cedar Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4542131346235756591-141", + "name": "PYA Analytics Inc", + "city": { + "name": "Wyalusing", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Wyalusing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4187283006391173278-142", + "name": "Verdafero LLC", + "city": { + "name": "Lake Charles", + "code": "LA", + "state": "Louisiana", + "county": "Calcasieu", + "display": "Mcneese State University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-165923034791834870-143", + "name": "Sage Bionetworks Inc", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Richmond Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3676231951168577912-144", + "name": "TagniFi LLC", + "city": { + "name": "Long Eddy", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Long Eddy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4790775879297943507-145", + "name": "MuckRock.com LLC", + "city": { + "name": "Pleasureville", + "code": "KY", + "state": "Kentucky", + "county": "Henry", + "display": "Franklinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7062297409829153142-146", + "name": "Dow Jones \u0026 Co Corporation", + "city": { + "name": "Atlanta", + "code": "GA", + "state": "Georgia", + "county": "Fulton", + "display": "Mellon Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5557744209938964115-147", + "name": "Zebu Compliance Solutions Corp", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Ohio Dept Of Taxation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3515563636407614750-148", + "name": "Recargo Inc", + "city": { + "name": "Windsor Heights", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Windsor Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2858433378704809922-149", + "name": "CityScan LLC", + "city": { + "name": "Alma", + "code": "NE", + "state": "Nebraska", + "county": "Harlan", + "display": "Prairie Dog" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6758113234174622620-150", + "name": "PYA Analytics Incorporated", + "city": { + "name": "Mount Carmel", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Connersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4621739702096724847-151", + "name": "Evidera Corp", + "city": { + "name": "Sisters", + "code": "OR", + "state": "Oregon", + "county": "Deschutes", + "display": "Blk Btte Rnch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3824964290141066839-152", + "name": "SmartAsset Corp", + "city": { + "name": "Limekiln", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Limekiln" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5914861886476804932-153", + "name": "Ceiba Solutions Corp", + "city": { + "name": "Haltom City", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "N Richland Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9146925156135650264-154", + "name": "iMedicare Corporation", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Mtn Green" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6133171455148761250-155", + "name": "Moody's Corporation", + "city": { + "name": "Springfield", + "code": "IL", + "state": "Illinois", + "county": "Sangamon", + "display": "Jerome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5635747801292324080-156", + "name": "Panjiva Corp", + "city": { + "name": "Essexville", + "code": "MI", + "state": "Michigan", + "county": "Bay", + "display": "Essexville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5783259052728179751-157", + "name": "PricewaterhouseCoopers Corp", + "city": { + "name": "Sloatsburg", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "Sloatsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8376531019740317461-158", + "name": "SmartAsset Corp", + "city": { + "name": "Rampart", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Rampart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5091555987131380700-159", + "name": "Locavore LLC", + "city": { + "name": "Rochester", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Oakland Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3661049067042185258-160", + "name": "Fidelity Investments Corporation", + "city": { + "name": "Shawnee", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "Merriam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7744082604563041062-161", + "name": "Wheaton World Wide Moving Inc", + "city": { + "name": "Hillsdale", + "code": "KS", + "state": "Kansas", + "county": "Miami", + "display": "Hillsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7917971092306404604-162", + "name": "Trintech Inc", + "city": { + "name": "Othello", + "code": "WA", + "state": "Washington", + "county": "Adams", + "display": "Othello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6279036500422337798-163", + "name": "Ranku Company", + "city": { + "name": "Freistatt", + "code": "MO", + "state": "Missouri", + "county": "Lawrence", + "display": "Freistatt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3388353400684496262-164", + "name": "LegiNation, Incorporated", + "city": { + "name": "Pleasanton", + "code": "KS", + "state": "Kansas", + "county": "Linn", + "display": "Pleasanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8091719383208301671-165", + "name": "Alarm.com Corporation", + "city": { + "name": "Trevett", + "code": "ME", + "state": "Maine", + "county": "Lincoln", + "display": "Trevett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8571763284599030303-166", + "name": "OnDeck Incorporated", + "city": { + "name": "Highland Park", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "New Brunswick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-441635372438993368-167", + "name": "Civis Analytics Corporation", + "city": { + "name": "Harper", + "code": "OR", + "state": "Oregon", + "county": "Malheur", + "display": "Harper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5245262261256331691-168", + "name": "iRecycle Incorporated", + "city": { + "name": "Gretna", + "code": "LA", + "state": "Louisiana", + "county": "Jefferson", + "display": "Terrytown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1424611249613435660-169", + "name": "Alarm.com Company", + "city": { + "name": "North Myrtle Beach", + "code": "SC", + "state": "South Carolina", + "county": "Horry", + "display": "North Myrtle Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8887381068688991622-170", + "name": "Science Exchange Incorporated", + "city": { + "name": "Alamo", + "code": "GA", + "state": "Georgia", + "county": "Wheeler", + "display": "Alamo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3668407063166904152-171", + "name": "Weather Decision Technologies Company", + "city": { + "name": "Eagle", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Eagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3143771170135834941-172", + "name": "Housefax Corp", + "city": { + "name": "Klamath", + "code": "CA", + "state": "California", + "county": "Del Norte", + "display": "Klamath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4106284396928400709-173", + "name": "Expert Health Data Programming, Company", + "city": { + "name": "Blain", + "code": "PA", + "state": "Pennsylvania", + "county": "Perry", + "display": "Blain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3206660118895023421-174", + "name": "Biovia Company", + "city": { + "name": "Washington", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Washington Dt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-883706182269288354-175", + "name": "Walk Score Inc", + "city": { + "name": "Mayville", + "code": "MI", + "state": "Michigan", + "county": "Tuscola", + "display": "Mayville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1379718715816540355-176", + "name": "Vimo Corporation", + "city": { + "name": "Greenville", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Smithfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2177477502781941350-177", + "name": "CrowdANALYTIX Company", + "city": { + "name": "Stillwater", + "code": "MN", + "state": "Minnesota", + "county": "Washington", + "display": "Grant Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7051896623926270928-178", + "name": "CostQuest Corporation", + "city": { + "name": "Vesta", + "code": "VA", + "state": "Virginia", + "county": "Patrick", + "display": "Vesta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5846570952474056546-179", + "name": "Practice Fusion Inc", + "city": { + "name": "Bronx", + "code": "NY", + "state": "New York", + "county": "Bronx", + "display": "Williamsbridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7632481418740499373-180", + "name": "Retroficiency Corp", + "city": { + "name": "Auburn", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Bowman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8569288831021278758-181", + "name": "PossibilityU Incorporated", + "city": { + "name": "Columbus Junction", + "code": "IA", + "state": "Iowa", + "county": "Louisa", + "display": "Columbus Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4847131419117704030-182", + "name": "3 Round Stones, Corp", + "city": { + "name": "Pottsville", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Phoenix Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8476951310597241530-183", + "name": "LOGIXDATA, LLC", + "city": { + "name": "Marshfield", + "code": "MO", + "state": "Missouri", + "county": "Webster", + "display": "Marshfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1941060081797122476-184", + "name": "Business and Legal Resources Corporation", + "city": { + "name": "Marengo", + "code": "IA", + "state": "Iowa", + "county": "Iowa", + "display": "Genoa Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3081965838106123659-185", + "name": "Center for Responsive Politics LLC", + "city": { + "name": "Allenwood", + "code": "PA", + "state": "Pennsylvania", + "county": "Union", + "display": "Gregg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8878152361262399559-186", + "name": "Tendril Inc", + "city": { + "name": "Du Quoin", + "code": "IL", + "state": "Illinois", + "county": "Perry", + "display": "Du Quoin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5927009572858680208-187", + "name": "Weather Decision Technologies Incorporated", + "city": { + "name": "Amherst", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "Cushman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2149417799085489013-188", + "name": "Weight Watchers Corporation", + "city": { + "name": "Wingdale", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Wingdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6004008708656253743-189", + "name": "Personal Democracy Media Inc", + "city": { + "name": "Monroeville", + "code": "OH", + "state": "Ohio", + "county": "Huron", + "display": "Ridgefield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7586201750749346681-190", + "name": "H3 Biomedicine Corp", + "city": { + "name": "Tinnie", + "code": "NM", + "state": "New Mexico", + "county": "Lincoln", + "display": "Tinnie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-638482882135362843-191", + "name": "Embark Corporation", + "city": { + "name": "Swanton", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Maquam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6613185076334702367-192", + "name": "Think Computer Corp", + "city": { + "name": "Belgrade", + "code": "NE", + "state": "Nebraska", + "county": "Boone", + "display": "Belgrade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3621295718102703795-193", + "name": "EMC Incorporated", + "city": { + "name": "Gig Harbor", + "code": "WA", + "state": "Washington", + "county": "Pierce", + "display": "Victor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7587442529370418981-194", + "name": "Innography Incorporated", + "city": { + "name": "Paramus", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Paramus" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1778653071074049664-195", + "name": "BlackRock Corp", + "city": { + "name": "Fort Lauderdale", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Bonaventure" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7799203298284729342-196", + "name": "Way Better Patents LLC", + "city": { + "name": "White Sulphur Springs", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "White Sulphur Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-849142697317989489-197", + "name": "Farmers Inc", + "city": { + "name": "Smartt", + "code": "TN", + "state": "Tennessee", + "county": "Warren", + "display": "Smartt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1426774087956781760-198", + "name": "BlackRock Inc", + "city": { + "name": "Oxford", + "code": "ME", + "state": "Maine", + "county": "Oxford", + "display": "Oxford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2071104450853766658-199", + "name": "Berkery Noyes MandASoft Inc", + "city": { + "name": "Alexandria", + "code": "VA", + "state": "Virginia", + "county": "Alexandria City", + "display": "Dod" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9178781258127405767-200", + "name": "StreetEasy LLC", + "city": { + "name": "Plano", + "code": "TX", + "state": "Texas", + "county": "Collin", + "display": "Parker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1181579482718331838-201", + "name": "College Abacus, an ECMC initiative Corporation", + "city": { + "name": "Elgin", + "code": "TX", + "state": "Texas", + "county": "Bastrop", + "display": "Elgin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7541252924241332912-202", + "name": "FindTheBest.com Incorporated", + "city": { + "name": "Clinton Corners", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Clinton Crn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6520533587378202877-203", + "name": "Mercaris Corp", + "city": { + "name": "Arenzville", + "code": "IL", + "state": "Illinois", + "county": "Cass", + "display": "Arenzville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-316247834821120826-204", + "name": "Votizen Inc", + "city": { + "name": "Woods Cross", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "West Bountiful" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3868665265513893187-205", + "name": "Weather Decision Technologies Corp", + "city": { + "name": "Point Marion", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Point Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4728886771254185217-206", + "name": "JJ Keller Corporation", + "city": { + "name": "Scammon", + "code": "KS", + "state": "Kansas", + "county": "Cherokee", + "display": "Scammon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6362276183361172075-207", + "name": "Xignite Corporation", + "city": { + "name": "Atlantic Beach", + "code": "FL", + "state": "Florida", + "county": "Duval", + "display": "Jacksonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6391372909720997418-208", + "name": "STILLWATER SUPERCOMPUTING INC Corporation", + "city": { + "name": "San Ardo", + "code": "CA", + "state": "California", + "county": "Monterey", + "display": "San Ardo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4911635539947549177-209", + "name": "Mozio Corp", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Univ Of Miami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1729960082164518080-210", + "name": "Solar Census Corporation", + "city": { + "name": "West Rockport", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "West Rockport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5725035204175229003-211", + "name": "Quertle Inc", + "city": { + "name": "Pauls Valley", + "code": "OK", + "state": "Oklahoma", + "county": "Garvin", + "display": "Pauls Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3506754790132148294-212", + "name": "The DocGraph Journal Incorporated", + "city": { + "name": "Tremonton", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Elwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-186871433559237857-213", + "name": "Inrix Traffic LLC", + "city": { + "name": "Lebanon", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Bolton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6539002243337672857-214", + "name": "Stevens Worldwide Van Lines Corporation", + "city": { + "name": "Georgetown", + "code": "LA", + "state": "Louisiana", + "county": "Grant", + "display": "Mudville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3018261413007955370-215", + "name": "GreatSchools Company", + "city": { + "name": "Decatur", + "code": "IL", + "state": "Illinois", + "county": "Macon", + "display": "Long Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4024174484415072725-216", + "name": "Zebu Compliance Solutions Corp", + "city": { + "name": "Sweet Water", + "code": "AL", + "state": "Alabama", + "county": "Marengo", + "display": "Sweet Water" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8028815005489571747-217", + "name": "Intermap Technologies Corporation", + "city": { + "name": "Dundas", + "code": "MN", + "state": "Minnesota", + "county": "Rice", + "display": "Dundas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1940187917623811174-218", + "name": "Sage Bionetworks Incorporated", + "city": { + "name": "Letcher", + "code": "SD", + "state": "South Dakota", + "county": "Sanborn", + "display": "Letcher" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1990483423942727863-219", + "name": "DataLogix Corp", + "city": { + "name": "Mesa", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Mesa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8912864906962859578-220", + "name": "Consumer Reports Corporation", + "city": { + "name": "Needville", + "code": "TX", + "state": "Texas", + "county": "Fort Bend", + "display": "Needville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3654784452703969748-221", + "name": "3 Round Stones, Corp", + "city": { + "name": "Long Grove", + "code": "IA", + "state": "Iowa", + "county": "Scott", + "display": "Wildwood Camp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-588020994197119961-222", + "name": "Legal Science Partners Inc", + "city": { + "name": "Fresno", + "code": "OH", + "state": "Ohio", + "county": "Coshocton", + "display": "New Bedford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2432923324136795944-223", + "name": "McGraw Hill Financial Incorporated", + "city": { + "name": "Castle Rock", + "code": "CO", + "state": "Colorado", + "county": "Douglas", + "display": "Castle Pines" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3723469953046556180-224", + "name": "PublicEngines Corp", + "city": { + "name": "Guildhall", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Ferdinand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8941705303156473931-225", + "name": "Deloitte Incorporated", + "city": { + "name": "Bisbee", + "code": "AZ", + "state": "Arizona", + "county": "Cochise", + "display": "Bisbee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7444465196638686575-226", + "name": "BetterLesson Inc", + "city": { + "name": "Willow Street", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Willow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1742633543905152800-227", + "name": "Asset4 Corporation", + "city": { + "name": "Corona", + "code": "SD", + "state": "South Dakota", + "county": "Roberts", + "display": "Linden Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1535639556352868980-228", + "name": "Relationship Science LLC", + "city": { + "name": "Mount Rainier", + "code": "MD", + "state": "Maryland", + "county": "Prince Georges", + "display": "Mount Rainier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5157964201415583289-229", + "name": "Alarm.com Company", + "city": { + "name": "Melba", + "code": "ID", + "state": "Idaho", + "county": "Canyon", + "display": "Stoddard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3343592717783364660-230", + "name": "Level One Technologies Incorporated", + "city": { + "name": "Mount Washington", + "code": "KY", + "state": "Kentucky", + "county": "Bullitt", + "display": "Mt Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8872633733247291586-231", + "name": "FarmLogs Incorporated", + "city": { + "name": "Waite Park", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Waite Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4062817593834499404-232", + "name": "Standard and Poor's Company", + "city": { + "name": "Jenera", + "code": "OH", + "state": "Ohio", + "county": "Hancock", + "display": "Jenera" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3163547476099533123-233", + "name": "Synthicity LLC", + "city": { + "name": "Clifton", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Clifton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2108700476726221742-234", + "name": "Biovia Incorporated", + "city": { + "name": "Gaylord", + "code": "MI", + "state": "Michigan", + "county": "Otsego", + "display": "Gaylord" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-671717805387848551-235", + "name": "Simple Energy Inc", + "city": { + "name": "Trenton", + "code": "NJ", + "state": "New Jersey", + "county": "Mercer", + "display": "Nj Income Tax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8603686942267592332-236", + "name": "Merrill Corp", + "city": { + "name": "Arnold", + "code": "CA", + "state": "California", + "county": "Calaveras", + "display": "Arnold" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2935226858963760426-237", + "name": "WebFilings LLC", + "city": { + "name": "Garland City", + "code": "AR", + "state": "Arkansas", + "county": "Miller", + "display": "Garland City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5997071472542062978-238", + "name": "CareSet Systems LLC", + "city": { + "name": "Saint Joseph", + "code": "MI", + "state": "Michigan", + "county": "Berrien", + "display": "Saint Joseph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9082786615459757234-239", + "name": "Morgan Stanley Company", + "city": { + "name": "Felton", + "code": "DE", + "state": "Delaware", + "county": "Kent", + "display": "Felton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4710895058627345041-240", + "name": "Xatori Corp", + "city": { + "name": "Kasson", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "Canisteo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5055700485549117703-241", + "name": "Teradata Company", + "city": { + "name": "Ragland", + "code": "WV", + "state": "West Virginia", + "county": "Mingo", + "display": "Ragland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1065638939343935032-242", + "name": "First Fuel Software Corporation", + "city": { + "name": "Angleton", + "code": "TX", + "state": "Texas", + "county": "Brazoria", + "display": "Angleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8047584628231195285-243", + "name": "Robinson + Yu Corporation", + "city": { + "name": "Indian Springs", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Indian Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4032821220863870596-244", + "name": "AutoGrid Systems LLC", + "city": { + "name": "Fort Worth", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Kenneth Copeland Ministries" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1450424072144671877-245", + "name": "Weather Channel LLC", + "city": { + "name": "Brewster", + "code": "KS", + "state": "Kansas", + "county": "Thomas", + "display": "Brewster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6039161625972230315-246", + "name": "BillGuard Incorporated", + "city": { + "name": "Franklin", + "code": "TX", + "state": "Texas", + "county": "Robertson", + "display": "Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2651179195384190746-247", + "name": "Deloitte Incorporated", + "city": { + "name": "Amity", + "code": "AR", + "state": "Arkansas", + "county": "Clark", + "display": "Caney Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5137738304259907070-248", + "name": "Adobe Digital Government Incorporated", + "city": { + "name": "Snyder", + "code": "OK", + "state": "Oklahoma", + "county": "Kiowa", + "display": "Snyder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8063246301045201982-249", + "name": "Innography Corporation", + "city": { + "name": "Underwood", + "code": "IN", + "state": "Indiana", + "county": "Scott", + "display": "Underwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6050441218909099379-250", + "name": "Panjiva Inc", + "city": { + "name": "Lanham", + "code": "MD", + "state": "Maryland", + "county": "Prince Georges", + "display": "Glenarden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1031912478290035631-251", + "name": "FindTheBest.com Corporation", + "city": { + "name": "Earlville", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Earlville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6328721528522119779-252", + "name": "Gallup Corporation", + "city": { + "name": "Underwood", + "code": "IN", + "state": "Indiana", + "county": "Scott", + "display": "Underwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1891486577198993660-253", + "name": "Intelius Corp", + "city": { + "name": "Holdenville", + "code": "OK", + "state": "Oklahoma", + "county": "Hughes", + "display": "Spaulding" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6090646486468956113-254", + "name": "Google Public Data Explorer Company", + "city": { + "name": "Cumberland Center", + "code": "ME", + "state": "Maine", + "county": "Cumberland", + "display": "Cumberlnd Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-143623526596140021-255", + "name": "Fuzion Apps, Corporation", + "city": { + "name": "Oak Brook", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Oak Brook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5980613952045615783-256", + "name": "Canon Corp", + "city": { + "name": "Bedford", + "code": "IA", + "state": "Iowa", + "county": "Taylor", + "display": "Bedford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4350154138754397173-257", + "name": "Zoner Corporation", + "city": { + "name": "North Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "No Las Vegas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-419326049483177866-258", + "name": "Ayasdi Incorporated", + "city": { + "name": "Du Bois", + "code": "IL", + "state": "Illinois", + "county": "Washington", + "display": "Dubois" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8239657596927683099-259", + "name": "Chemical Abstracts Service Corporation", + "city": { + "name": "New Zion", + "code": "SC", + "state": "South Carolina", + "county": "Clarendon", + "display": "Workman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9152172905232833510-260", + "name": "CONNECT-DOT Inc", + "city": { + "name": "Hampton", + "code": "IA", + "state": "Iowa", + "county": "Franklin", + "display": "Hansell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6765791362370345742-261", + "name": "PlaceILive.com Company", + "city": { + "name": "Youngsville", + "code": "NM", + "state": "New Mexico", + "county": "Rio Arriba", + "display": "Rito De Las Sillas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-373482154931353961-262", + "name": "Cappex Corporation", + "city": { + "name": "Gunnison", + "code": "CO", + "state": "Colorado", + "county": "Gunnison", + "display": "Gunnison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1076203676453709800-263", + "name": "Smart Utility Systems Company", + "city": { + "name": "Fergus Falls", + "code": "MN", + "state": "Minnesota", + "county": "Otter Tail", + "display": "Carlisle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-339338390203261411-264", + "name": "Lumesis, Corp", + "city": { + "name": "Manchester Township", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Manchester Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1924937025472416168-265", + "name": "CostQuest Corporation", + "city": { + "name": "Medina", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Crystal Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1487222292651998961-266", + "name": "Aunt Bertha, Company", + "city": { + "name": "Loysville", + "code": "PA", + "state": "Pennsylvania", + "county": "Perry", + "display": "Cisna Run" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-305467554885386262-267", + "name": "Code for America Inc", + "city": { + "name": "Copalis Beach", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Copalis Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3018890113844909317-268", + "name": "Charles Schwab Inc", + "city": { + "name": "Dushore", + "code": "PA", + "state": "Pennsylvania", + "county": "Sullivan", + "display": "Wilmot Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6388696145512958340-269", + "name": "IPHIX Company", + "city": { + "name": "Amherst", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "Cushman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2064823862527724577-270", + "name": "Lumesis, LLC", + "city": { + "name": "Constantia", + "code": "NY", + "state": "New York", + "county": "Oswego", + "display": "Gayville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7546950961941713201-271", + "name": "Solar Census Company", + "city": { + "name": "Fort Lauderdale", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Bonaventure" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6504388772820151230-272", + "name": "IVES Group Corp", + "city": { + "name": "West Frankfort", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "West Frankfort" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3856319486584935627-273", + "name": "BlackRock Company", + "city": { + "name": "Bridgman", + "code": "MI", + "state": "Michigan", + "county": "Berrien", + "display": "Bridgman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6763844342841203265-274", + "name": "Mint Company", + "city": { + "name": "Parks", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Parks Comm Po" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1463081730094629646-275", + "name": "Mapbox Company", + "city": { + "name": "Murray", + "code": "KY", + "state": "Kentucky", + "county": "Calloway", + "display": "Shiloh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5300879317106849809-276", + "name": "CB Insights LLC", + "city": { + "name": "Enumclaw", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Enumclaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7883124229164394707-277", + "name": "Ez-XBRL Incorporated", + "city": { + "name": "Eastland", + "code": "TX", + "state": "Texas", + "county": "Eastland", + "display": "Eastland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2534851758208302676-278", + "name": "PEV4me.com LLC", + "city": { + "name": "Keytesville", + "code": "MO", + "state": "Missouri", + "county": "Chariton", + "display": "Keytesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-698440172913459824-279", + "name": "Science Exchange Inc", + "city": { + "name": "Sutter Creek", + "code": "CA", + "state": "California", + "county": "Amador", + "display": "Sutter Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4853222851708833043-280", + "name": "Geofeedia Company", + "city": { + "name": "Ringoes", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Ringoes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-274919748838153186-281", + "name": "realtor.com Corp", + "city": { + "name": "Bunceton", + "code": "MO", + "state": "Missouri", + "county": "Cooper", + "display": "Lone Elm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4648040778263289995-282", + "name": "Telenav LLC", + "city": { + "name": "Murphy", + "code": "ID", + "state": "Idaho", + "county": "Owyhee", + "display": "Silver City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9100209240926073616-283", + "name": "The Govtech Fund Corporation", + "city": { + "name": "North Port", + "code": "FL", + "state": "Florida", + "county": "Sarasota", + "display": "Venice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2690996887471179664-284", + "name": "Tableau Software Inc", + "city": { + "name": "Meeker", + "code": "CO", + "state": "Colorado", + "county": "Rio Blanco", + "display": "Meeker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5392189476209274765-285", + "name": "Impact Forecasting Inc", + "city": { + "name": "Winside", + "code": "NE", + "state": "Nebraska", + "county": "Wayne", + "display": "Winside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4574331249992958816-286", + "name": "Equilar LLC", + "city": { + "name": "Guernsey", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Guernsey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-123230338340416147-287", + "name": "Dow Jones \u0026 Co Company", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Jp Morgan Chase" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-95151118882587873-288", + "name": "CitySourced Corporation", + "city": { + "name": "Stanfield", + "code": "NC", + "state": "North Carolina", + "county": "Stanly", + "display": "Stanfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4592009160050073480-289", + "name": "NextBus Incorporated", + "city": { + "name": "Wewahitchka", + "code": "FL", + "state": "Florida", + "county": "Calhoun", + "display": "Kinard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3600446801163092451-290", + "name": "Pave Corp", + "city": { + "name": "Clinton", + "code": "AR", + "state": "Arkansas", + "county": "Van Buren", + "display": "Alread" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5087497083411427513-291", + "name": "Urban Airship Incorporated", + "city": { + "name": "West Warren", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "W Warren" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4167447588096603650-292", + "name": "LOVELAND Technologies Incorporated", + "city": { + "name": "Agoura Hills", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Saratoga Hls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5202407218730496080-293", + "name": "Calcbench, Inc", + "city": { + "name": "Clarence", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "Clarence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3142213622679312257-294", + "name": "WebMD Incorporated", + "city": { + "name": "Chartley", + "code": "MA", + "state": "Massachusetts", + "county": "Bristol", + "display": "Chartley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5520765340442643335-295", + "name": "WebMD Company", + "city": { + "name": "Hillsdale", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Hillsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3082728764448107304-296", + "name": "Amida Technology Solutions Incorporated", + "city": { + "name": "Logan", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Hanaford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1125817037992232421-297", + "name": "Iodine LLC", + "city": { + "name": "Ogden", + "code": "IL", + "state": "Illinois", + "county": "Champaign", + "display": "Ogden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5354894888320892660-298", + "name": "Xignite Corporation", + "city": { + "name": "Minneapolis", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Brooklyn Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5183724500759976993-299", + "name": "PEV4me.com Company", + "city": { + "name": "Windom", + "code": "MN", + "state": "Minnesota", + "county": "Cottonwood", + "display": "Wilder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1202122511747129770-300", + "name": "Legal Science Partners Corporation", + "city": { + "name": "Minter", + "code": "AL", + "state": "Alabama", + "county": "Dallas", + "display": "Farmersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5853948748050377045-301", + "name": "Kaiser Permanante LLC", + "city": { + "name": "Alexandria", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Alex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3159876493191452517-302", + "name": "Relationship Science Incorporated", + "city": { + "name": "Maquoketa", + "code": "IA", + "state": "Iowa", + "county": "Jackson", + "display": "Ironhills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7964800302216494054-303", + "name": "Appallicious Incorporated", + "city": { + "name": "Salyersville", + "code": "KY", + "state": "Kentucky", + "county": "Magoffin", + "display": "Edna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1995801944020849817-304", + "name": "Caspio LLC", + "city": { + "name": "Saint Charles", + "code": "VA", + "state": "Virginia", + "county": "Lee", + "display": "Saint Charles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8895696322766040159-305", + "name": "SeeClickFix LLC", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Hedwig Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-398657075785733387-306", + "name": "WattzOn Inc", + "city": { + "name": "Forest Knolls", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Forest Knolls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-844324573089889621-307", + "name": "Urban Airship Incorporated", + "city": { + "name": "Oakland", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Oakland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7672126355472583553-308", + "name": "MuckRock.com Incorporated", + "city": { + "name": "Tarlton", + "code": "OH", + "state": "Ohio", + "county": "Pickaway", + "display": "Tarlton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6404791073543070037-309", + "name": "TransUnion Corp", + "city": { + "name": "Ward Cove", + "code": "AK", + "state": "Alaska", + "county": "Ketchikan Gateway", + "display": "Ward Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3959440303024394176-310", + "name": "Civis Analytics Inc", + "city": { + "name": "North Stratford", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Columbia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3656259066175733051-311", + "name": "Sterling Infosystems LLC", + "city": { + "name": "Manito", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Parkland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6831873299668633197-312", + "name": "HDScores, Inc", + "city": { + "name": "Mount Pleasant Mills", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Mt Pleasant M" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-989983806312576166-313", + "name": "iMedicare Corp", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Miners Mill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6970438418946164558-314", + "name": "SAP Incorporated", + "city": { + "name": "Duluth", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "West Duluth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7599625631098173040-315", + "name": "indoo.rs Company", + "city": { + "name": "Middleburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Meiser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8021106522218279249-316", + "name": "Biovia Corp", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Uc Los Angeles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7561059790609621572-317", + "name": "Castle Biosciences Corp", + "city": { + "name": "Danbury", + "code": "NC", + "state": "North Carolina", + "county": "Stokes", + "display": "Hartman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-600884337279308295-318", + "name": "How's My Offer? Corp", + "city": { + "name": "Loveland", + "code": "OK", + "state": "Oklahoma", + "county": "Tillman", + "display": "Loveland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3276694253600442433-319", + "name": "IFI CLAIMS Patent Services Incorporated", + "city": { + "name": "South Byron", + "code": "NY", + "state": "New York", + "county": "Genesee", + "display": "South Byron" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7665315063100803403-320", + "name": "Aunt Bertha, Corp", + "city": { + "name": "Kingston Mines", + "code": "IL", + "state": "Illinois", + "county": "Peoria", + "display": "Kingston Mine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2895618481728201120-321", + "name": "OpenPlans Company", + "city": { + "name": "Summersville", + "code": "MO", + "state": "Missouri", + "county": "Texas", + "display": "Summersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-195404228825061948-322", + "name": "HealthMap Company", + "city": { + "name": "Swanzey", + "code": "NH", + "state": "New Hampshire", + "county": "Cheshire", + "display": "East Swanzey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2289167175813465582-323", + "name": "The Schork Report Inc", + "city": { + "name": "Saint Ann", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Saint Anne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6064735769205352043-324", + "name": "iRecycle Corp", + "city": { + "name": "Andalusia", + "code": "AL", + "state": "Alabama", + "county": "Covington", + "display": "Dixie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6739391682417389115-325", + "name": "Bloomberg Corp", + "city": { + "name": "Mc Clure", + "code": "PA", + "state": "Pennsylvania", + "county": "Mifflin", + "display": "Mc Clure" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1358063509405722993-326", + "name": "OTC Markets Corp", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Usps Headquarters" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7655334840122236665-327", + "name": "Roadify Transit LLC", + "city": { + "name": "Bloomville", + "code": "OH", + "state": "Ohio", + "county": "Seneca", + "display": "Bloomville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-446773997873020087-328", + "name": "TagniFi Corporation", + "city": { + "name": "Nimitz", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Nimitz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6288030244356933319-329", + "name": "Exversion Corporation", + "city": { + "name": "Carolina", + "code": "RI", + "state": "Rhode Island", + "county": "Washington", + "display": "Carolina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4894894472276827153-330", + "name": "StreetEasy Inc", + "city": { + "name": "Bradenton", + "code": "FL", + "state": "Florida", + "county": "Manatee", + "display": "West Bradenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3692155382777412043-331", + "name": "H3 Biomedicine Inc", + "city": { + "name": "Ragland", + "code": "WV", + "state": "West Virginia", + "county": "Mingo", + "display": "Ragland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3287533544818406828-332", + "name": "Municode Corp", + "city": { + "name": "Martin", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Martin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9174399813486188490-333", + "name": "Galorath orporated Inc", + "city": { + "name": "Springfield", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Mallet Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1878213314771951625-334", + "name": "ideas42 Company", + "city": { + "name": "San Jose", + "code": "CA", + "state": "California", + "county": "Santa Clara", + "display": "California Water Service" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8651783835683763908-335", + "name": "AccuWeather Inc", + "city": { + "name": "Blackey", + "code": "KY", + "state": "Kentucky", + "county": "Letcher", + "display": "Carcassonne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-911041418059682518-336", + "name": "Business Monitor International Incorporated", + "city": { + "name": "Gans", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Lake Lynn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7417344509807136667-337", + "name": "TopCoder Corporation", + "city": { + "name": "Wykoff", + "code": "MN", + "state": "Minnesota", + "county": "Fillmore", + "display": "Fillmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2513950478940504141-338", + "name": "Ecodesk Corporation", + "city": { + "name": "Northrop", + "code": "MN", + "state": "Minnesota", + "county": "Martin", + "display": "Northrop" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5162191550340126255-339", + "name": "Arpin Van Lines Inc", + "city": { + "name": "Fort Washington", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Ft Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-412631229574334884-340", + "name": "Knoema LLC", + "city": { + "name": "Thompson", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Thompson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-240253208077373131-341", + "name": "NextBus Corp", + "city": { + "name": "Carrollton", + "code": "GA", + "state": "Georgia", + "county": "Carroll", + "display": "University Of West Georgia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6841460398775331918-342", + "name": "LoseIt.com Inc", + "city": { + "name": "Wellington", + "code": "NV", + "state": "Nevada", + "county": "Lyon", + "display": "Sweetwater" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1930604905261301277-343", + "name": "Junar, Company", + "city": { + "name": "Newburgh", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Town Branch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8959274842763453275-344", + "name": "OpenCounter LLC", + "city": { + "name": "Fergus Falls", + "code": "MN", + "state": "Minnesota", + "county": "Otter Tail", + "display": "Fergus Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7954642727981767676-345", + "name": "Everyday Health Company", + "city": { + "name": "Gold Run", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Gold Run" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4863364479249380039-346", + "name": "TrustedID Corporation", + "city": { + "name": "Gold Run", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Gold Run" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-913617835051721852-347", + "name": "MetLife Corp", + "city": { + "name": "Monroe", + "code": "LA", + "state": "Louisiana", + "county": "Ouachita", + "display": "Corey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6342472296581271663-348", + "name": "Ernst \u0026 Young LLP Corp", + "city": { + "name": "Statesville", + "code": "NC", + "state": "North Carolina", + "county": "Iredell", + "display": "East Monbo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-917397039138294116-349", + "name": "InfoCommerce Group LLC", + "city": { + "name": "Saint Michaels", + "code": "MD", + "state": "Maryland", + "county": "Talbot", + "display": "St Michaels" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-566437476537931951-350", + "name": "Locavore Inc", + "city": { + "name": "Lillian", + "code": "AL", + "state": "Alabama", + "county": "Baldwin", + "display": "Lillian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4259713634827492871-351", + "name": "SnapSense Company", + "city": { + "name": "West Townsend", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Townsend" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3869558988175159103-352", + "name": "Acxiom Corporation", + "city": { + "name": "Sebastopol", + "code": "CA", + "state": "California", + "county": "Sonoma", + "display": "Sebastopol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-937520129219539601-353", + "name": "AccuWeather Incorporated", + "city": { + "name": "Ragland", + "code": "WV", + "state": "West Virginia", + "county": "Mingo", + "display": "Ragland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1705244602646873047-354", + "name": "Galorath orporated Company", + "city": { + "name": "Church Hill", + "code": "MD", + "state": "Maryland", + "county": "Queen Annes", + "display": "Church Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4392585001227892398-355", + "name": "S\u0026P Capital IQ Corporation", + "city": { + "name": "Williamstown", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Williamstn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5921186109377877703-356", + "name": "SmartAsset Corp", + "city": { + "name": "Saint Paul", + "code": "MN", + "state": "Minnesota", + "county": "Ramsey", + "display": "Minn Mining Boxes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-227005928903190855-357", + "name": "Deloitte Corporation", + "city": { + "name": "Butler", + "code": "KY", + "state": "Kentucky", + "county": "Pendleton", + "display": "Butler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3936058630028273644-358", + "name": "Legal Science Partners Corp", + "city": { + "name": "San Francisco", + "code": "CA", + "state": "California", + "county": "San Francisco", + "display": "Presidio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4928300414955774167-359", + "name": "State Farm Insurance LLC", + "city": { + "name": "Bronson", + "code": "TX", + "state": "Texas", + "county": "Sabine", + "display": "Bronson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-781851796045831926-360", + "name": "FindTheBest.com Inc", + "city": { + "name": "Montgomery", + "code": "IN", + "state": "Indiana", + "county": "Daviess", + "display": "Glendale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1778488515740208396-361", + "name": "LoopNet Inc", + "city": { + "name": "Boneville", + "code": "GA", + "state": "Georgia", + "county": "Mcduffie", + "display": "Boneville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4381844509993944595-362", + "name": "Careset.com Incorporated", + "city": { + "name": "Island Pond", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Brighton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9165582639352812835-363", + "name": "Ensco Corporation", + "city": { + "name": "Hastings", + "code": "NE", + "state": "Nebraska", + "county": "Adams", + "display": "Good Samaritan Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2537293899114894363-364", + "name": "People Power Incorporated", + "city": { + "name": "Water Valley", + "code": "MS", + "state": "Mississippi", + "county": "Yalobusha", + "display": "Pine Flat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-810085237449119906-365", + "name": "HealthPocket, Incorporated", + "city": { + "name": "Spring Grove", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Spring Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8637183468696051069-366", + "name": "IFI CLAIMS Patent Services Corp", + "city": { + "name": "Benezett", + "code": "PA", + "state": "Pennsylvania", + "county": "Elk", + "display": "Benezette" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5013660325818858638-367", + "name": "Whitby Group Incorporated", + "city": { + "name": "Noxen", + "code": "PA", + "state": "Pennsylvania", + "county": "Wyoming", + "display": "Forkston Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-562303512889164750-368", + "name": "OptumInsight Company", + "city": { + "name": "Corona", + "code": "SD", + "state": "South Dakota", + "county": "Roberts", + "display": "Linden Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1886546759492251557-369", + "name": "SmartProcure LLC", + "city": { + "name": "Robbinsville", + "code": "NC", + "state": "North Carolina", + "county": "Graham", + "display": "Robbinsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8273339943528607578-370", + "name": "KLD Research Corporation", + "city": { + "name": "Highgate Springs", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Highgate Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2381730300682964299-371", + "name": "LexisNexis Corporation", + "city": { + "name": "Glenn", + "code": "CA", + "state": "California", + "county": "Glenn", + "display": "Bayliss" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3617743577597190969-372", + "name": "StreamLink Software Corporation", + "city": { + "name": "Stow", + "code": "NY", + "state": "New York", + "county": "Chautauqua", + "display": "Stow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4583674916524746322-373", + "name": "PolicyMap Company", + "city": { + "name": "Pe Ell", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Peell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3513357595734652350-374", + "name": "SeeClickFix Corp", + "city": { + "name": "Milroy", + "code": "MN", + "state": "Minnesota", + "county": "Redwood", + "display": "Milroy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-31940324183656834-375", + "name": "Recargo Company", + "city": { + "name": "Millen", + "code": "GA", + "state": "Georgia", + "county": "Jenkins", + "display": "Perkins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8386924009739527252-376", + "name": "IVES Group Corporation", + "city": { + "name": "Oakwood", + "code": "GA", + "state": "Georgia", + "county": "Hall", + "display": "Oakwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5833039510932796607-377", + "name": "Spikes Cavell Analytic Corporation", + "city": { + "name": "Greeley", + "code": "CO", + "state": "Colorado", + "county": "Weld", + "display": "Garden City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1697505059388823357-378", + "name": "PlotWatt Corp", + "city": { + "name": "Irvona", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Irvona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-581108433358985130-379", + "name": "Patently-O LLC", + "city": { + "name": "Marion", + "code": "IN", + "state": "Indiana", + "county": "Grant", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5312635300700880965-380", + "name": "Golden Helix Incorporated", + "city": { + "name": "San Antonio", + "code": "TX", + "state": "Texas", + "county": "Bexar", + "display": "Castle Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-134861696344271609-381", + "name": "Environmental Data Resources Company", + "city": { + "name": "Pottsboro", + "code": "TX", + "state": "Texas", + "county": "Grayson", + "display": "Pottsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4049932744247958618-382", + "name": "Energy Solutions Forum Inc", + "city": { + "name": "Nevada", + "code": "MO", + "state": "Missouri", + "county": "Vernon", + "display": "Camp Clark" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5611208887917687453-383", + "name": "College Board LLC", + "city": { + "name": "Sterling", + "code": "CT", + "state": "Connecticut", + "county": "Windham", + "display": "North Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8141457049896373682-384", + "name": "StreetCred Software, Corp", + "city": { + "name": "Eldorado", + "code": "IL", + "state": "Illinois", + "county": "Saline", + "display": "College Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7583365135608686301-385", + "name": "Galorath orporated Corporation", + "city": { + "name": "Chesterton", + "code": "IN", + "state": "Indiana", + "county": "Porter", + "display": "Burns Harbor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-21687229319098602-386", + "name": "TowerData Corp", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Dept Navy Hq Marines Arl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3783787528565557411-387", + "name": "EMC Incorporated", + "city": { + "name": "Banner", + "code": "WY", + "state": "Wyoming", + "county": "Sheridan", + "display": "Story" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8918549918982006586-388", + "name": "Patently-O Corp", + "city": { + "name": "New Zion", + "code": "SC", + "state": "South Carolina", + "county": "Clarendon", + "display": "Workman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4598599790522816231-389", + "name": "Quertle Company", + "city": { + "name": "Stevenson", + "code": "WA", + "state": "Washington", + "county": "Skamania", + "display": "Skamania" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7939021581943497365-390", + "name": "AllState Insurance Group Company", + "city": { + "name": "Menahga", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Menahga" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5069899315699097532-391", + "name": "Microsoft Windows Azure Marketplace LLC", + "city": { + "name": "Syracuse", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Carousel Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2461051935814907845-392", + "name": "Garmin Corporation", + "city": { + "name": "Dairy", + "code": "OR", + "state": "Oregon", + "county": "Klamath", + "display": "Dairy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7005092122978121351-393", + "name": "New Media Parents Company", + "city": { + "name": "Fort Bayard", + "code": "NM", + "state": "New Mexico", + "county": "Grant", + "display": "Silver City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2058326045714273943-394", + "name": "Fitch Corporation", + "city": { + "name": "Mocksville", + "code": "NC", + "state": "North Carolina", + "county": "Davie", + "display": "Mocksville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8003821886561498988-395", + "name": "PlaceILive.com Corporation", + "city": { + "name": "New Canaan", + "code": "CT", + "state": "Connecticut", + "county": "Fairfield", + "display": "New Canaan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4019988103159845167-396", + "name": "Business and Legal Resources Corporation", + "city": { + "name": "Gotha", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Gotha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7502312205477814235-397", + "name": "CityScan Corporation", + "city": { + "name": "Brewster", + "code": "KS", + "state": "Kansas", + "county": "Thomas", + "display": "Brewster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8716296179758456060-398", + "name": "PlotWatt Company", + "city": { + "name": "Fannettsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Franklin", + "display": "Boggstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6462944876161564937-399", + "name": "Ayasdi Corp", + "city": { + "name": "Alto", + "code": "TX", + "state": "Texas", + "county": "Cherokee", + "display": "Redlawn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4836017905699157242-400", + "name": "TrustedID Corporation", + "city": { + "name": "Mahanoy City", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Morea Colliery" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4681528331957980499-401", + "name": "Vital Axiom | Niinja Company", + "city": { + "name": "Richland", + "code": "MO", + "state": "Missouri", + "county": "Pulaski", + "display": "Swedeborg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2336143992438837439-402", + "name": "InCadence Corp", + "city": { + "name": "Hawthorne", + "code": "NV", + "state": "Nevada", + "county": "Mineral", + "display": "Babbitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7783719818434014614-403", + "name": "Seabourne Inc", + "city": { + "name": "Purdon", + "code": "TX", + "state": "Texas", + "county": "Navarro", + "display": "Pursley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8905080030529859910-404", + "name": "HopStop Inc", + "city": { + "name": "Seaside Heights", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Seaside Hgts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8378785375711555084-405", + "name": "Mint Company", + "city": { + "name": "Fence Lake", + "code": "NM", + "state": "New Mexico", + "county": "Cibola", + "display": "Trechado" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6795085064837535968-406", + "name": "ProgrammableWeb Corp", + "city": { + "name": "Hertel", + "code": "WI", + "state": "Wisconsin", + "county": "Burnett", + "display": "Hertel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-89864496253521873-407", + "name": "Boundless Corporation", + "city": { + "name": "Van Vleck", + "code": "TX", + "state": "Texas", + "county": "Matagorda", + "display": "Van Vleck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8511947156952660657-408", + "name": "Marinexplore, Incorporated", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "Macys Finance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3380463478881091391-409", + "name": "American Red Ball Movers Incorporated", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Milton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1533494356224271537-410", + "name": "SAS Corp", + "city": { + "name": "Fort Gratiot", + "code": "MI", + "state": "Michigan", + "county": "Saint Clair", + "display": "Lakeport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5474918243671586608-411", + "name": "The Advisory Board Company Incorporated", + "city": { + "name": "Loogootee", + "code": "IN", + "state": "Indiana", + "county": "Martin", + "display": "Whitfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5908299193934579825-412", + "name": "Castle Biosciences Corporation", + "city": { + "name": "New Raymer", + "code": "CO", + "state": "Colorado", + "county": "Weld", + "display": "Raymer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1348003752550340537-413", + "name": "optiGov LLC", + "city": { + "name": "Kirkland", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Totem Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5484690787937695867-414", + "name": "TrustedID LLC", + "city": { + "name": "New Boston", + "code": "NH", + "state": "New Hampshire", + "county": "Hillsborough", + "display": "New Boston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8447180039926570891-415", + "name": "Owler Incorporated", + "city": { + "name": "Short Creek", + "code": "WV", + "state": "West Virginia", + "county": "Brooke", + "display": "Short Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9217536463656330381-416", + "name": "SpaceCurve Inc", + "city": { + "name": "Stanwood", + "code": "WA", + "state": "Washington", + "county": "Snohomish", + "display": "Camano Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6862365833165734560-417", + "name": "Ranku Incorporated", + "city": { + "name": "Vanlue", + "code": "OH", + "state": "Ohio", + "county": "Hancock", + "display": "Vanlue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3762724418158293461-418", + "name": "Trulia Corporation", + "city": { + "name": "Mount Blanchard", + "code": "OH", + "state": "Ohio", + "county": "Hancock", + "display": "Mount Blanchard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3655015297049830863-419", + "name": "Relationship Science LLC", + "city": { + "name": "Mount Pleasant Mills", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Mt Pleasant M" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3629201712398504509-420", + "name": "Citigroup LLC", + "city": { + "name": "Port Wentworth", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Savannah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5360372200248054638-421", + "name": "Enigma.io Company", + "city": { + "name": "Bath", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Arrowsic" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1831332341079205594-422", + "name": "FlightStats Incorporated", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Etna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1919470613402099668-423", + "name": "PlaceILive.com Company", + "city": { + "name": "Elizabethtown", + "code": "KY", + "state": "Kentucky", + "county": "Hardin", + "display": "E Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1227801424792353335-424", + "name": "Mozio Corporation", + "city": { + "name": "Letcher", + "code": "SD", + "state": "South Dakota", + "county": "Sanborn", + "display": "Letcher" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2856735946593628957-425", + "name": "PlanetEcosystems Corp", + "city": { + "name": "Primghar", + "code": "IA", + "state": "Iowa", + "county": "Obrien", + "display": "Primghar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-808322683170920307-426", + "name": "AllState Insurance Group Company", + "city": { + "name": "Paicines", + "code": "CA", + "state": "California", + "county": "San Benito", + "display": "Panoche" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4446410830653105343-427", + "name": "Orlin Research Inc", + "city": { + "name": "North Stratford", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Stratford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5355453274022285390-428", + "name": "Buildingeye Incorporated", + "city": { + "name": "Saint Joseph", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "St Joseph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7170864639415572449-429", + "name": "Impaq International Incorporated", + "city": { + "name": "Davis Junction", + "code": "IL", + "state": "Illinois", + "county": "Ogle", + "display": "Davis Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3048933536061876559-430", + "name": "Keychain Logistics Corporation", + "city": { + "name": "Kenosha", + "code": "WI", + "state": "Wisconsin", + "county": "Kenosha", + "display": "Kenosha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3930959855133543959-431", + "name": "Compared Care Inc", + "city": { + "name": "Tiplersville", + "code": "MS", + "state": "Mississippi", + "county": "Tippah", + "display": "Anvil" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8705316315551818230-432", + "name": "Capital Cube Corporation", + "city": { + "name": "Hebron", + "code": "IN", + "state": "Indiana", + "county": "Porter", + "display": "Hebron" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-991248064319050351-433", + "name": "Equilar LLC", + "city": { + "name": "Concan", + "code": "TX", + "state": "Texas", + "county": "Uvalde", + "display": "Concan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6080218069244308021-434", + "name": "Nationwide Mutual Insurance Company Corp", + "city": { + "name": "Steedman", + "code": "MO", + "state": "Missouri", + "county": "Callaway", + "display": "Steedman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3299079747863480990-435", + "name": "The Vanguard Group Company", + "city": { + "name": "Newport", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5489008359006366158-436", + "name": "Urban Airship Corporation", + "city": { + "name": "Mitchell", + "code": "IN", + "state": "Indiana", + "county": "Lawrence", + "display": "Stonington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7335721904940732241-437", + "name": "Vizzuality Inc", + "city": { + "name": "Siler", + "code": "KY", + "state": "Kentucky", + "county": "Whitley", + "display": "Siler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5734625818453613566-438", + "name": "LOGIXDATA, Corp", + "city": { + "name": "Sautee Nacoochee", + "code": "GA", + "state": "Georgia", + "county": "White", + "display": "Sautee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-686692431187256245-439", + "name": "Computer Packages LLC", + "city": { + "name": "Ranchos De Taos", + "code": "NM", + "state": "New Mexico", + "county": "Taos", + "display": "Ranches Of Taos" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1892985531246781971-440", + "name": "Accenture Incorporated", + "city": { + "name": "Raleigh", + "code": "ND", + "state": "North Dakota", + "county": "Grant", + "display": "Saint Gertrude" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7203846571005902486-441", + "name": "PIXIA Incorporated", + "city": { + "name": "Gardner", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "Gardner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1003500486688927778-442", + "name": "ClearStory Data Inc", + "city": { + "name": "Jumping Branch", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Streeter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6664583635953877661-443", + "name": "ClearHealthCosts Incorporated", + "city": { + "name": "Lee", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "W Becket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-893240076866561807-444", + "name": "Capital Cube LLC", + "city": { + "name": "Oklahoma City", + "code": "OK", + "state": "Oklahoma", + "county": "Oklahoma", + "display": "Warr Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3167416407760581016-445", + "name": "GreatSchools Inc", + "city": { + "name": "Millwood", + "code": "KY", + "state": "Kentucky", + "county": "Grayson", + "display": "Millwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3401677587103630497-446", + "name": "AccuWeather Incorporated", + "city": { + "name": "Manor", + "code": "TX", + "state": "Texas", + "county": "Travis", + "display": "Daffan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4419783522080382239-447", + "name": "Credit Karma Inc", + "city": { + "name": "Morning View", + "code": "KY", + "state": "Kentucky", + "county": "Kenton", + "display": "Visalia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6592722377958709879-448", + "name": "EMC LLC", + "city": { + "name": "Tignall", + "code": "GA", + "state": "Georgia", + "county": "Wilkes", + "display": "Tignall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7908210036433338918-449", + "name": "Earthquake Alert Company", + "city": { + "name": "Elkton", + "code": "KY", + "state": "Kentucky", + "county": "Todd", + "display": "Allegre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2737230973607229150-450", + "name": "Govini Incorporated", + "city": { + "name": "Compton", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Crystal City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5118360855497133131-451", + "name": "WaterSmart Software Inc", + "city": { + "name": "Clinton", + "code": "AR", + "state": "Arkansas", + "county": "Van Buren", + "display": "Alread" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-80561911520741681-452", + "name": "Foursquare Company", + "city": { + "name": "Westchester", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Westchester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1019444509950672475-453", + "name": "Lilly Open Innovation Drug Discovery Corp", + "city": { + "name": "Winona", + "code": "MN", + "state": "Minnesota", + "county": "Winona", + "display": "Goodview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1122189545433913988-454", + "name": "Lawdragon Inc", + "city": { + "name": "Shady Dale", + "code": "GA", + "state": "Georgia", + "county": "Jasper", + "display": "Farrar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8062498651678583044-455", + "name": "Golden Helix LLC", + "city": { + "name": "Sierra Madre", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Sierra Madre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6305664063070580346-456", + "name": "Optensity Incorporated", + "city": { + "name": "Pine Bluff", + "code": "AR", + "state": "Arkansas", + "county": "Jefferson", + "display": "Pine Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8090990551413737931-457", + "name": "Morningstar, Corporation", + "city": { + "name": "Akron", + "code": "OH", + "state": "Ohio", + "county": "Summit", + "display": "Fairlawn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2471594197341838774-458", + "name": "MedWatcher Incorporated", + "city": { + "name": "Englewood", + "code": "CO", + "state": "Colorado", + "county": "Arapahoe", + "display": "Cherry Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6839999289365011635-459", + "name": "Harris LLC", + "city": { + "name": "Central", + "code": "UT", + "state": "Utah", + "county": "Washington", + "display": "Central" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7866457299860357722-460", + "name": "USSearch LLC", + "city": { + "name": "Walthall", + "code": "MS", + "state": "Mississippi", + "county": "Webster", + "display": "Walthall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9107990143980685378-461", + "name": "PublicEngines Inc", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Cinclantflt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1641451396657386536-462", + "name": "NuCivic LLC", + "city": { + "name": "Eddyville", + "code": "KY", + "state": "Kentucky", + "county": "Lyon", + "display": "Confederate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5440797801951523568-463", + "name": "Compared Care Corporation", + "city": { + "name": "Sopchoppy", + "code": "FL", + "state": "Florida", + "county": "Wakulla", + "display": "Sopchoppy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8281509370686532591-464", + "name": "SigFig LLC", + "city": { + "name": "Richfield", + "code": "UT", + "state": "Utah", + "county": "Sevier", + "display": "Venice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6403037881200224379-465", + "name": "Aunt Bertha, Company", + "city": { + "name": "Virgie", + "code": "KY", + "state": "Kentucky", + "county": "Pike", + "display": "Virgie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1000668831263546934-466", + "name": "How's My Offer? Incorporated", + "city": { + "name": "Montgomery", + "code": "IN", + "state": "Indiana", + "county": "Daviess", + "display": "Glendale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4170249231884621804-467", + "name": "Simple Energy LLC", + "city": { + "name": "Boulder Junction", + "code": "WI", + "state": "Wisconsin", + "county": "Vilas", + "display": "Boulder Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7904470648680643678-468", + "name": "InnoCentive Incorporated", + "city": { + "name": "Mchenry", + "code": "ND", + "state": "North Dakota", + "county": "Foster", + "display": "Mchenry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1347911751834419288-469", + "name": "Evidera Incorporated", + "city": { + "name": "Castleton On Hudson", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "South Schodack" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9183087780609549446-470", + "name": "ASC Partners Inc", + "city": { + "name": "Melrose", + "code": "IA", + "state": "Iowa", + "county": "Monroe", + "display": "Melrose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8617365732827510403-471", + "name": "Ranku LLC", + "city": { + "name": "Marriottsville", + "code": "MD", + "state": "Maryland", + "county": "Carroll", + "display": "Marriottsvl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6063802749952245734-472", + "name": "Stamen Design Incorporated", + "city": { + "name": "Mount Hope", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Mount Hope" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4274869410588483877-473", + "name": "New Media Parents Inc", + "city": { + "name": "Mathis", + "code": "TX", + "state": "Texas", + "county": "San Patricio", + "display": "San Patricio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2185715640713388810-474", + "name": "Revelstone Company", + "city": { + "name": "Columbus", + "code": "GA", + "state": "Georgia", + "county": "Muscogee", + "display": "Col" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8110264865956577076-475", + "name": "ReciPal Company", + "city": { + "name": "Montrose", + "code": "WV", + "state": "West Virginia", + "county": "Randolph", + "display": "Montrose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6438449580283910185-476", + "name": "PayScale, Corporation", + "city": { + "name": "Julian", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Julian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2521661407710088565-477", + "name": "The Advisory Board Company Incorporated", + "city": { + "name": "Kearneysville", + "code": "WV", + "state": "West Virginia", + "county": "Jefferson", + "display": "Kearneysville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7532318092269251268-478", + "name": "Expert Health Data Programming, Corporation", + "city": { + "name": "Dallesport", + "code": "WA", + "state": "Washington", + "county": "Klickitat", + "display": "Dallesport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4799025746754655914-479", + "name": "Zillow Incorporated", + "city": { + "name": "D Lo", + "code": "MS", + "state": "Mississippi", + "county": "Simpson", + "display": "D Lo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4013404936997874821-480", + "name": "TransparaGov LLC", + "city": { + "name": "Pleasanton", + "code": "NE", + "state": "Nebraska", + "county": "Buffalo", + "display": "Pleasanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8542628153359453112-481", + "name": "FlightStats Company", + "city": { + "name": "Gwynedd", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Gwynedd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1179431259022982093-482", + "name": "Geofeedia Company", + "city": { + "name": "Loysville", + "code": "PA", + "state": "Pennsylvania", + "county": "Perry", + "display": "Cisna Run" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-244542271991689175-483", + "name": "Wheaton World Wide Moving Company", + "city": { + "name": "Hurricane", + "code": "UT", + "state": "Utah", + "county": "Washington", + "display": "Apple Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1885502088404364996-484", + "name": "SpotHero.com Inc", + "city": { + "name": "Calhoun", + "code": "IL", + "state": "Illinois", + "county": "Richland", + "display": "Berryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2653632975946054600-485", + "name": "Xatori LLC", + "city": { + "name": "Richland", + "code": "MO", + "state": "Missouri", + "county": "Pulaski", + "display": "Swedeborg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1005815126560828537-486", + "name": "SAS Corporation", + "city": { + "name": "Graford", + "code": "TX", + "state": "Texas", + "county": "Palo Pinto", + "display": "Graford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3205425310476723178-487", + "name": "Microsoft Windows Azure Marketplace Incorporated", + "city": { + "name": "Maben", + "code": "MS", + "state": "Mississippi", + "county": "Webster", + "display": "Maben" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4097395666535827928-488", + "name": "Weather Underground Corp", + "city": { + "name": "Dundas", + "code": "MN", + "state": "Minnesota", + "county": "Rice", + "display": "Dundas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8825573996938639328-489", + "name": "Captricity Corporation", + "city": { + "name": "Mission", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Palmview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4962555196608980398-490", + "name": "Be Informed Corp", + "city": { + "name": "Media", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Rose Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1218189284928264212-491", + "name": "HDScores, Corporation", + "city": { + "name": "Jonesboro", + "code": "TX", + "state": "Texas", + "county": "Coryell", + "display": "Pancake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3349255933307435035-492", + "name": "Liquid Robotics Inc", + "city": { + "name": "Troup", + "code": "TX", + "state": "Texas", + "county": "Smith", + "display": "Griffin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6440065979852191674-493", + "name": "GitHub Inc", + "city": { + "name": "Gove", + "code": "KS", + "state": "Kansas", + "county": "Gove", + "display": "Gove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5155499976762881082-494", + "name": "Urban Airship Company", + "city": { + "name": "Elgin", + "code": "TN", + "state": "Tennessee", + "county": "Scott", + "display": "Elgin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2824058363589001216-495", + "name": "xDayta Corporation", + "city": { + "name": "Amery", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Little Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2368779992174633226-496", + "name": "Lawdragon LLC", + "city": { + "name": "Littleton", + "code": "CO", + "state": "Colorado", + "county": "Jefferson", + "display": "Columbine Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-469125272753807649-497", + "name": "OpenPlans Incorporated", + "city": { + "name": "Suitland", + "code": "MD", + "state": "Maryland", + "county": "Prince Georges", + "display": "Morningside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4653294426759667228-498", + "name": "TransparaGov Company", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "W Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2484891591938510787-499", + "name": "Owler Corp", + "city": { + "name": "Gorham", + "code": "KS", + "state": "Kansas", + "county": "Russell", + "display": "Gorham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6398385050683532789-500", + "name": "Informatica LLC", + "city": { + "name": "Milford", + "code": "NH", + "state": "New Hampshire", + "county": "Hillsborough", + "display": "Milford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4989777508941880842-501", + "name": "Socrata Corp", + "city": { + "name": "Comptche", + "code": "CA", + "state": "California", + "county": "Mendocino", + "display": "Keene Summit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5506165855709215118-502", + "name": "JJ Keller Inc", + "city": { + "name": "Mehoopany", + "code": "PA", + "state": "Pennsylvania", + "county": "Wyoming", + "display": "Forkston Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8395307332568674012-503", + "name": "Junyo Corp", + "city": { + "name": "Greensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Allegheny Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4192872523069364121-504", + "name": "DataLogix Company", + "city": { + "name": "Hackberry", + "code": "AZ", + "state": "Arizona", + "county": "Mohave", + "display": "Kingman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6184151192408979914-505", + "name": "BuildFax LLC", + "city": { + "name": "Marshall", + "code": "MO", + "state": "Missouri", + "county": "Saline", + "display": "Marshall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2176848069556997697-506", + "name": "Whitby Group Corporation", + "city": { + "name": "Norcross", + "code": "GA", + "state": "Georgia", + "county": "Gwinnett", + "display": "Berkeley Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2862130043584674114-507", + "name": "SigFig Corp", + "city": { + "name": "Oldsmar", + "code": "FL", + "state": "Florida", + "county": "Pinellas", + "display": "Oldsmar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8973782367926742561-508", + "name": "gRadiant Research Incorporated", + "city": { + "name": "Bainbridge", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "West Bainbridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3230643506834036853-509", + "name": "SimpleTuition Inc", + "city": { + "name": "Great Barrington", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Great Barrington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5295309033840342182-510", + "name": "CareSet Systems Corporation", + "city": { + "name": "Biola", + "code": "CA", + "state": "California", + "county": "Fresno", + "display": "Biola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1053296570953788448-511", + "name": "AtSite Corp", + "city": { + "name": "Bergland", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Bergland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-668047053950713910-512", + "name": "OSIsoft Inc", + "city": { + "name": "South Royalton", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "South Royalton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4753498494262132346-513", + "name": "Simple Energy Inc", + "city": { + "name": "Oriskany", + "code": "VA", + "state": "Virginia", + "county": "Botetourt", + "display": "Oriskany" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7293779256526614555-514", + "name": "FarmLogs Corp", + "city": { + "name": "Center Line", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Center Line" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2702329486547839989-515", + "name": "Practice Fusion Corp", + "city": { + "name": "Cicero", + "code": "IN", + "state": "Indiana", + "county": "Hamilton", + "display": "Westfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5223116759840775688-516", + "name": "Outline Inc", + "city": { + "name": "Jackson", + "code": "MS", + "state": "Mississippi", + "county": "Hinds", + "display": "Jksn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-830655353406542023-517", + "name": "Robinson + Yu Company", + "city": { + "name": "Huntington", + "code": "IN", + "state": "Indiana", + "county": "Huntington", + "display": "Bowerstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-401461486626652735-518", + "name": "Fidelity Investments Inc", + "city": { + "name": "Dallas", + "code": "NC", + "state": "North Carolina", + "county": "Gaston", + "display": "Dallas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8121419157077688002-519", + "name": "Civis Analytics LLC", + "city": { + "name": "West Lebanon", + "code": "PA", + "state": "Pennsylvania", + "county": "Indiana", + "display": "West Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1939131025727250053-520", + "name": "Cambridge Semantics Incorporated", + "city": { + "name": "Webster", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Webster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4259633302032335168-521", + "name": "Whitby Group LLC", + "city": { + "name": "Two Rivers", + "code": "WI", + "state": "Wisconsin", + "county": "Manitowoc", + "display": "Two Rivers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5868393688719002235-522", + "name": "Maponics Incorporated", + "city": { + "name": "South Ozone Park", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "South Ozone Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4325612623554565783-523", + "name": "BetterLesson Corporation", + "city": { + "name": "Mountainburg", + "code": "AR", + "state": "Arkansas", + "county": "Crawford", + "display": "Mountainburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6824086522203587541-524", + "name": "T. Rowe Price LLC", + "city": { + "name": "Glidden", + "code": "IA", + "state": "Iowa", + "county": "Carroll", + "display": "Glidden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6368891681623110292-525", + "name": "J.P. Morgan Chase LLC", + "city": { + "name": "New Berlin", + "code": "IL", + "state": "Illinois", + "county": "Sangamon", + "display": "Bates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7787059955110062838-526", + "name": "Computer Packages LLC", + "city": { + "name": "Toms River", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "S Toms River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5666418438558396127-527", + "name": "OpenCounter LLC", + "city": { + "name": "Mckinney", + "code": "TX", + "state": "Texas", + "county": "Collin", + "display": "Mc Kinney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6291715584328432193-528", + "name": "American Red Ball Movers LLC", + "city": { + "name": "Aurora", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "At \u0026 T" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1291063490137028874-529", + "name": "Collective IP Inc", + "city": { + "name": "Cumberland Gap", + "code": "TN", + "state": "Tennessee", + "county": "Claiborne", + "display": "Cumberland Gp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-870145803842496430-530", + "name": "MicroBilt Company", + "city": { + "name": "Fort Necessity", + "code": "LA", + "state": "Louisiana", + "county": "Franklin", + "display": "Fort Necessity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5573655011999427817-531", + "name": "SimpleTuition Corp", + "city": { + "name": "Pontiac", + "code": "IL", + "state": "Illinois", + "county": "Livingston", + "display": "Owego" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6448156504048960045-532", + "name": "Redfin Inc", + "city": { + "name": "Appalachia", + "code": "VA", + "state": "Virginia", + "county": "Wise", + "display": "Appalachia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5248838388608619951-533", + "name": "Avvo Corporation", + "city": { + "name": "Mansura", + "code": "LA", + "state": "Louisiana", + "county": "Avoyelles", + "display": "Mansura Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2304368807578969956-534", + "name": "Yelp LLC", + "city": { + "name": "Caret", + "code": "VA", + "state": "Virginia", + "county": "Essex", + "display": "Supply" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1032148614684895181-535", + "name": "OpenCounter LLC", + "city": { + "name": "Matoaka", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Matoaka" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2507434779863340641-536", + "name": "Forrester Research Corporation", + "city": { + "name": "Memphis", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "International Paper Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4201697187091653991-537", + "name": "The Advisory Board Company Corporation", + "city": { + "name": "Gagetown", + "code": "MI", + "state": "Michigan", + "county": "Tuscola", + "display": "Gagetown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4684234707454482339-538", + "name": "U.S. News Schools Corp", + "city": { + "name": "Green Pond", + "code": "SC", + "state": "South Carolina", + "county": "Colleton", + "display": "Green Pond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7530827783885254488-539", + "name": "Lumesis, LLC", + "city": { + "name": "Jupiter", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Tequesta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5825045616801022426-540", + "name": "NERA Economic Consulting Incorporated", + "city": { + "name": "Fort Hood", + "code": "TX", + "state": "Texas", + "county": "Bell", + "display": "Chaffee Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2377858688803942796-541", + "name": "Calcbench, Corporation", + "city": { + "name": "Roundhill", + "code": "KY", + "state": "Kentucky", + "county": "Edmonson", + "display": "Region" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5226245147244245092-542", + "name": "NERA Economic Consulting Corp", + "city": { + "name": "Murphysboro", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Somerset" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9210834233313497095-543", + "name": "McGraw Hill Financial LLC", + "city": { + "name": "Snowville", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Snowville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5692069373356884969-544", + "name": "PlotWatt Corp", + "city": { + "name": "Zanesville", + "code": "OH", + "state": "Ohio", + "county": "Muskingum", + "display": "S Zanesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7789263414434692225-545", + "name": "TopCoder Inc", + "city": { + "name": "East Mc Keesport", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "East Mckeesport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5030232121274902178-546", + "name": "Govini LLC", + "city": { + "name": "Goliad", + "code": "TX", + "state": "Texas", + "county": "Goliad", + "display": "Goliad" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1003100390747661282-547", + "name": "Rapid Cycle Solutions Corp", + "city": { + "name": "Woods Hole", + "code": "MA", + "state": "Massachusetts", + "county": "Barnstable", + "display": "Woods Hole" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5254898320139687212-548", + "name": "Ernst \u0026 Young LLP LLC", + "city": { + "name": "Culberson", + "code": "NC", + "state": "North Carolina", + "county": "Cherokee", + "display": "Culberson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6590811045856628992-549", + "name": "NonprofitMetrics Company", + "city": { + "name": "De Kalb Junction", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "De Kalb Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-370681472488967694-550", + "name": "Department of Better Technology Company", + "city": { + "name": "Fort Calhoun", + "code": "NE", + "state": "Nebraska", + "county": "Washington", + "display": "Fort Calhoun" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4247573480626149250-551", + "name": "Think Computer Company", + "city": { + "name": "Webbville", + "code": "KY", + "state": "Kentucky", + "county": "Lawrence", + "display": "Webbville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1890843576913635513-552", + "name": "Sterling Infosystems Company", + "city": { + "name": "Low Moor", + "code": "VA", + "state": "Virginia", + "county": "Alleghany", + "display": "Lowmoor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1523553131696818954-553", + "name": "Aunt Bertha, Inc", + "city": { + "name": "Onaga", + "code": "KS", + "state": "Kansas", + "county": "Pottawatomie", + "display": "Onaga" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2941522550730565066-554", + "name": "BaleFire Global Incorporated", + "city": { + "name": "Eldridge", + "code": "AL", + "state": "Alabama", + "county": "Walker", + "display": "Eldridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3438244721420293074-555", + "name": "Moody's Inc", + "city": { + "name": "Staples", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Poplar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7703456546377493661-556", + "name": "MedWatcher Company", + "city": { + "name": "Porter Corners", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Porter Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5958054604904906969-557", + "name": "Code-N Corp", + "city": { + "name": "Ames", + "code": "NE", + "state": "Nebraska", + "county": "Dodge", + "display": "Ames" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4614335782559041675-558", + "name": "HealthPocket, Inc", + "city": { + "name": "Tacoma", + "code": "WA", + "state": "Washington", + "county": "Pierce", + "display": "World Vision Brm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-279167319541762584-559", + "name": "KidAdmit, Corporation", + "city": { + "name": "Port Crane", + "code": "NY", + "state": "New York", + "county": "Broome", + "display": "Sanitaria Spg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6736233365594314229-560", + "name": "SeeClickFix Corp", + "city": { + "name": "New Edinburg", + "code": "AR", + "state": "Arkansas", + "county": "Cleveland", + "display": "New Edinburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-666996702952198293-561", + "name": "Progressive Insurance Group Corp", + "city": { + "name": "Union Springs", + "code": "NY", + "state": "New York", + "county": "Cayuga", + "display": "Springport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4691245958912838229-562", + "name": "Vitals Inc", + "city": { + "name": "Marlborough", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Marlborough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1349979013076213649-563", + "name": "Department of Better Technology Corporation", + "city": { + "name": "Tonasket", + "code": "WA", + "state": "Washington", + "county": "Okanogan", + "display": "Aeneas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6225059812484523484-564", + "name": "IMS Health Company", + "city": { + "name": "New Virginia", + "code": "IA", + "state": "Iowa", + "county": "Warren", + "display": "Jamison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4606043731397422217-565", + "name": "Credit Karma Incorporated", + "city": { + "name": "Grand Chain", + "code": "IL", + "state": "Illinois", + "county": "Pulaski", + "display": "Grand Chain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9186345901819071942-566", + "name": "ConnectEDU Corp", + "city": { + "name": "Willow Street", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Willow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1284074949319642297-567", + "name": "Climate LLC", + "city": { + "name": "Port Orange", + "code": "FL", + "state": "Florida", + "county": "Volusia", + "display": "Allandale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6260354254715692349-568", + "name": "Legal Science Partners Corporation", + "city": { + "name": "Dunbar", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Dunbar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5207979882583414250-569", + "name": "Navico Corporation", + "city": { + "name": "Morrilton", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Lanty" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2582362532578283982-570", + "name": "CAN Capital Inc", + "city": { + "name": "Oak Grove", + "code": "LA", + "state": "Louisiana", + "county": "West Carroll", + "display": "Chickasaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7464553959151143052-571", + "name": "SpotCrime Incorporated", + "city": { + "name": "Winnsboro", + "code": "SC", + "state": "South Carolina", + "county": "Fairfield", + "display": "Winnsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2660571426562162190-572", + "name": "Brightscope Incorporated", + "city": { + "name": "Davis Junction", + "code": "IL", + "state": "Illinois", + "county": "Ogle", + "display": "Davis Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3494013458171546323-573", + "name": "PEV4me.com Corp", + "city": { + "name": "White Plains", + "code": "KY", + "state": "Kentucky", + "county": "Hopkins", + "display": "White Plains" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6949352000225615228-574", + "name": "Ernst \u0026 Young LLP Company", + "city": { + "name": "Summit", + "code": "MS", + "state": "Mississippi", + "county": "Pike", + "display": "Summit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5103160581967500179-575", + "name": "GetRaised Corporation", + "city": { + "name": "Wedowee", + "code": "AL", + "state": "Alabama", + "county": "Randolph", + "display": "Malone" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8822795913292991854-576", + "name": "SmartProcure Incorporated", + "city": { + "name": "Glenwood", + "code": "NC", + "state": "North Carolina", + "county": "Mcdowell", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3429961494119371688-577", + "name": "WebMD Incorporated", + "city": { + "name": "Voorhees", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Echelon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-380240274124921430-578", + "name": "Next Step Living Incorporated", + "city": { + "name": "Harmony", + "code": "ME", + "state": "Maine", + "county": "Somerset", + "display": "Harmony" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1274226541914476368-579", + "name": "AreaVibes Company", + "city": { + "name": "Madison", + "code": "VA", + "state": "Virginia", + "county": "Madison", + "display": "Banco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4374714792928941633-580", + "name": "CitySourced Company", + "city": { + "name": "Rancho Cucamonga", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Cucamonga" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5664852042327595159-581", + "name": "Barchart Incorporated", + "city": { + "name": "Monticello", + "code": "NM", + "state": "New Mexico", + "county": "Sierra", + "display": "Monticello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4374328396248656504-582", + "name": "Next Step Living Corporation", + "city": { + "name": "Northbrook", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Northbrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5099549556990649503-583", + "name": "Be Informed Company", + "city": { + "name": "Brooksville", + "code": "MS", + "state": "Mississippi", + "county": "Noxubee", + "display": "Cliftonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3058878658028380533-584", + "name": "nGAP orporated Corp", + "city": { + "name": "Pungoteague", + "code": "VA", + "state": "Virginia", + "county": "Accomack", + "display": "Pungoteague" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4453087998381076999-585", + "name": "Headlight Inc", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Wilmington Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6227322861960617195-586", + "name": "Relationship Science Incorporated", + "city": { + "name": "Gilman", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Gilman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7609634268176424685-587", + "name": "Open Data Nation Inc", + "city": { + "name": "New Castle", + "code": "PA", + "state": "Pennsylvania", + "county": "Lawrence", + "display": "Castle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1387562082921125328-588", + "name": "PYA Analytics Inc", + "city": { + "name": "Millington", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "Kerrville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9121163751201800243-589", + "name": "Center for Responsive Politics Company", + "city": { + "name": "Elko New Market", + "code": "MN", + "state": "Minnesota", + "county": "Scott", + "display": "Elko" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1558267707881136306-590", + "name": "GoodGuide LLC", + "city": { + "name": "Shell Knob", + "code": "MO", + "state": "Missouri", + "county": "Barry", + "display": "Shell Knob" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8551026195547362653-591", + "name": "IW Financial Inc", + "city": { + "name": "Bagley", + "code": "MN", + "state": "Minnesota", + "county": "Clearwater", + "display": "Zerkel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1370121737375003654-592", + "name": "FarmLogs LLC", + "city": { + "name": "Lake Norden", + "code": "SD", + "state": "South Dakota", + "county": "Hamlin", + "display": "Alsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4142361316285954407-593", + "name": "Liquid Robotics LLC", + "city": { + "name": "Greenwood", + "code": "SC", + "state": "South Carolina", + "county": "Greenwood", + "display": "Gwd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1763817614772448406-594", + "name": "PEV4me.com Company", + "city": { + "name": "Ottawa", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Ottawa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3903351654723513735-595", + "name": "BizVizz Company", + "city": { + "name": "De Soto", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "De Soto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3259882957086041627-596", + "name": "TrueCar Company", + "city": { + "name": "Gilbert", + "code": "IA", + "state": "Iowa", + "county": "Story", + "display": "Gilbert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4781123455122255113-597", + "name": "LoopNet Incorporated", + "city": { + "name": "Bellevue", + "code": "MI", + "state": "Michigan", + "county": "Eaton", + "display": "Bellevue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2557291848548610982-598", + "name": "Arrive Labs Corporation", + "city": { + "name": "Syracuse", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Dewitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5485932319895683851-599", + "name": "Knoema Inc", + "city": { + "name": "Brush Creek", + "code": "TN", + "state": "Tennessee", + "county": "Smith", + "display": "Brush Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4261125668207107397-600", + "name": "Climate Corporation", + "city": { + "name": "Cleveland", + "code": "TX", + "state": "Texas", + "county": "Liberty", + "display": "Evergreen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8176614586963378837-601", + "name": "Bekins Corporation", + "city": { + "name": "Frederick", + "code": "SD", + "state": "South Dakota", + "county": "Brown", + "display": "Elm Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5263089924171301039-602", + "name": "iRecycle LLC", + "city": { + "name": "Deposit", + "code": "NY", + "state": "New York", + "county": "Broome", + "display": "North Sanford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6767424804005589394-603", + "name": "Estately LLC", + "city": { + "name": "Cuddebackville", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Cuddebackvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3528828574961638088-604", + "name": "Ecodesk LLC", + "city": { + "name": "Mountain Home", + "code": "ID", + "state": "Idaho", + "county": "Elmore", + "display": "Pine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4652870221100758925-605", + "name": "Credit Sesame Company", + "city": { + "name": "Vail", + "code": "CO", + "state": "Colorado", + "county": "Eagle", + "display": "Vail" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1001172419658562712-606", + "name": "Lumesis, Inc", + "city": { + "name": "Bedford", + "code": "IN", + "state": "Indiana", + "county": "Lawrence", + "display": "Peerless" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7407954097840616519-607", + "name": "StreetEasy Company", + "city": { + "name": "Swanton", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Maquam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2986343076357446094-608", + "name": "Iodine Company", + "city": { + "name": "Cushing", + "code": "OK", + "state": "Oklahoma", + "county": "Payne", + "display": "Schlegal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6334534306635501214-609", + "name": "eInstitutional Corporation", + "city": { + "name": "Garrett", + "code": "IN", + "state": "Indiana", + "county": "De Kalb", + "display": "Dutch Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5291488343298707516-610", + "name": "GitHub Incorporated", + "city": { + "name": "Takotna", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Mc Grath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4383095021890699097-611", + "name": "OptumInsight Corp", + "city": { + "name": "Columbia", + "code": "LA", + "state": "Louisiana", + "county": "Caldwell", + "display": "Eastside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1713077810009954595-612", + "name": "Google Maps Incorporated", + "city": { + "name": "Hastings", + "code": "NE", + "state": "Nebraska", + "county": "Adams", + "display": "Ingleside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4400725594205274021-613", + "name": "Cyte Corporation", + "city": { + "name": "Pottersdale", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Pottersdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4974532187960681235-614", + "name": "The Bridgespan Group Corp", + "city": { + "name": "Muncy", + "code": "PA", + "state": "Pennsylvania", + "county": "Lycoming", + "display": "East Muncy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3594426681076234844-615", + "name": "Cambridge Semantics Corporation", + "city": { + "name": "Clear Creek", + "code": "WV", + "state": "West Virginia", + "county": "Raleigh", + "display": "Clear Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6195313912370370069-616", + "name": "Noveda Technologies Corporation", + "city": { + "name": "Victoria", + "code": "TX", + "state": "Texas", + "county": "Victoria", + "display": "Cologne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3278317857144910585-617", + "name": "SolarList Corporation", + "city": { + "name": "Charles Town", + "code": "WV", + "state": "West Virginia", + "county": "Jefferson", + "display": "Charles Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-505998406873014952-618", + "name": "Dabo Health Incorporated", + "city": { + "name": "Rotonda West", + "code": "FL", + "state": "Florida", + "county": "Charlotte", + "display": "Placida" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8137069720126143543-619", + "name": "SpaceCurve Corporation", + "city": { + "name": "Gold Run", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Gold Run" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3108083169746910262-620", + "name": "VitalChek Corporation", + "city": { + "name": "Glenwood", + "code": "NC", + "state": "North Carolina", + "county": "Mcdowell", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3462742284048348632-621", + "name": "Jurispect Corporation", + "city": { + "name": "New London", + "code": "CT", + "state": "Connecticut", + "county": "New London", + "display": "Us Coast Guard Acad" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1629090985921912283-622", + "name": "REI Systems Corporation", + "city": { + "name": "Gill", + "code": "MA", + "state": "Massachusetts", + "county": "Franklin", + "display": "Gill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8195072292326437315-623", + "name": "Roadify Transit Incorporated", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Crafton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-302431697846476833-624", + "name": "STILLWATER SUPERCOMPUTING INC LLC", + "city": { + "name": "Forreston", + "code": "IL", + "state": "Illinois", + "county": "Ogle", + "display": "Forreston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6137653642174503310-625", + "name": "AutoGrid Systems LLC", + "city": { + "name": "Toluca Lake", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "N Hollywood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8619792132951705634-626", + "name": "Boston Consulting Group Incorporated", + "city": { + "name": "Foxboro", + "code": "MA", + "state": "Massachusetts", + "county": "Norfolk", + "display": "Foxboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7097893465283981946-627", + "name": "S\u0026P Capital IQ LLC", + "city": { + "name": "San Benito", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Laureles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5807503204565632091-628", + "name": "Be Informed Incorporated", + "city": { + "name": "Danboro", + "code": "PA", + "state": "Pennsylvania", + "county": "Bucks", + "display": "Danboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-894494986937481606-629", + "name": "Microsoft Windows Azure Marketplace Inc", + "city": { + "name": "Monroe", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "S Bloomng Grv" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-209684227956325370-630", + "name": "WebMD Company", + "city": { + "name": "Roselle Park", + "code": "NJ", + "state": "New Jersey", + "county": "Union", + "display": "Roselle Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6871627712247884748-631", + "name": "MuckRock.com Company", + "city": { + "name": "Scranton", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Dickson City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3540212452975936931-632", + "name": "Stamen Design Corporation", + "city": { + "name": "Castle Rock", + "code": "CO", + "state": "Colorado", + "county": "Douglas", + "display": "Castle Pines" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5146907401748638884-633", + "name": "Adaptive Corp", + "city": { + "name": "Milo", + "code": "ME", + "state": "Maine", + "county": "Piscataquis", + "display": "Orneville Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7264392983534980318-634", + "name": "United Mayflower Corp", + "city": { + "name": "Burley", + "code": "ID", + "state": "Idaho", + "county": "Cassia", + "display": "Starrhs Ferry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-523055419181938275-635", + "name": "AccuWeather Corporation", + "city": { + "name": "Joyce", + "code": "WA", + "state": "Washington", + "county": "Clallam", + "display": "Joyce" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-148199605492635218-636", + "name": "LOGIXDATA, Incorporated", + "city": { + "name": "Jasper", + "code": "AR", + "state": "Arkansas", + "county": "Newton", + "display": "Jasper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3860969914772255092-637", + "name": "Copyright Clearance Center Inc", + "city": { + "name": "Salyersville", + "code": "KY", + "state": "Kentucky", + "county": "Magoffin", + "display": "Maggard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5411444006673763321-638", + "name": "Marlin \u0026 Associates Company", + "city": { + "name": "Macfarlan", + "code": "WV", + "state": "West Virginia", + "county": "Ritchie", + "display": "Macfarlan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5980218927686995302-639", + "name": "Weather Underground Incorporated", + "city": { + "name": "Romeo", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Bruce Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3802816266012714959-640", + "name": "Everyday Health Incorporated", + "city": { + "name": "Victoria", + "code": "MS", + "state": "Mississippi", + "county": "Marshall", + "display": "Victoria" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3231481246127484798-641", + "name": "Business and Legal Resources Incorporated", + "city": { + "name": "Decatur", + "code": "AR", + "state": "Arkansas", + "county": "Benton", + "display": "Decatur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6071620159778852694-642", + "name": "WebFilings Corp", + "city": { + "name": "Ekalaka", + "code": "MT", + "state": "Montana", + "county": "Carter", + "display": "Ekalaka" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1165393244832972559-643", + "name": "Stormpulse LLC", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Obetz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2412317971863000599-644", + "name": "Civinomics Company", + "city": { + "name": "Lyons Falls", + "code": "NY", + "state": "New York", + "county": "Lewis", + "display": "Lyonsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8670942543419449648-645", + "name": "Zonability Inc", + "city": { + "name": "Bimble", + "code": "KY", + "state": "Kentucky", + "county": "Knox", + "display": "Bimble" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3105097294192765617-646", + "name": "Enervee Corporation", + "city": { + "name": "Ludowici", + "code": "GA", + "state": "Georgia", + "county": "Long", + "display": "Ludowici" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6858010906439498044-647", + "name": "PlanetEcosystems LLC", + "city": { + "name": "Spanish Fork", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Cover Bridge Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3203604709731745906-648", + "name": "Lending Club Corporation", + "city": { + "name": "Commerce", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Commerce" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2898706358343246275-649", + "name": "Epsilon LLC", + "city": { + "name": "Warrenton", + "code": "OR", + "state": "Oregon", + "county": "Clatsop", + "display": "Warrenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4075384266421166530-650", + "name": "Atlas Van Lines Inc", + "city": { + "name": "Sumter", + "code": "SC", + "state": "South Carolina", + "county": "Sumter", + "display": "Bon Air" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1148026295651379462-651", + "name": "Climate Company", + "city": { + "name": "Carnelian Bay", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Carnelian Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1048899689444343772-652", + "name": "Equal Speed Corp", + "city": { + "name": "Postville", + "code": "IA", + "state": "Iowa", + "county": "Allamakee", + "display": "Postville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3590137426462601444-653", + "name": "POPVOX Inc", + "city": { + "name": "Summit", + "code": "MS", + "state": "Mississippi", + "county": "Pike", + "display": "Summit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1928466960985915738-654", + "name": "Adobe Digital Government Inc", + "city": { + "name": "Everetts", + "code": "NC", + "state": "North Carolina", + "county": "Martin", + "display": "Everetts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7404581364285144620-655", + "name": "Credit Karma Corporation", + "city": { + "name": "Durand", + "code": "IL", + "state": "Illinois", + "county": "Winnebago", + "display": "Durand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6930008060702568951-656", + "name": "CB Insights LLC", + "city": { + "name": "Dairy", + "code": "OR", + "state": "Oregon", + "county": "Klamath", + "display": "Dairy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7981950915852700735-657", + "name": "OnDeck Company", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Wilkes University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8047955103690178795-658", + "name": "Computer Packages LLC", + "city": { + "name": "Palisade", + "code": "MN", + "state": "Minnesota", + "county": "Aitkin", + "display": "Palisade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7965745375182332691-659", + "name": "Allianz Inc", + "city": { + "name": "Yellow Jacket", + "code": "CO", + "state": "Colorado", + "county": "Montezuma", + "display": "Yellow Jacket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-976022592451791343-660", + "name": "MarketSense LLC", + "city": { + "name": "Byers", + "code": "TX", + "state": "Texas", + "county": "Clay", + "display": "Byers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7687244731868633363-661", + "name": "WebFilings Incorporated", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Ny Agr And Mkts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8078563001916720895-662", + "name": "PublicEngines Incorporated", + "city": { + "name": "Pacific Beach", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Aloha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2607661525045405813-663", + "name": "The Bridgespan Group Inc", + "city": { + "name": "Pansey", + "code": "AL", + "state": "Alabama", + "county": "Houston", + "display": "Pansey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6897689335730620508-664", + "name": "Allied Van Lines Corp", + "city": { + "name": "New Boston", + "code": "NH", + "state": "New Hampshire", + "county": "Hillsborough", + "display": "New Boston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4832108611505503213-665", + "name": "CliniCast LLC", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Federal Maritime Commission" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1692417640776580915-666", + "name": "Maponics Company", + "city": { + "name": "Rockwood", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Gibraltar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6799280394127361673-667", + "name": "Junyo Company", + "city": { + "name": "Minden", + "code": "NV", + "state": "Nevada", + "county": "Douglas", + "display": "Minden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7386097394012241821-668", + "name": "Orlin Research LLC", + "city": { + "name": "Manitowish Waters", + "code": "WI", + "state": "Wisconsin", + "county": "Vilas", + "display": "Manitowsh Wtr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7261364281194389892-669", + "name": "DemystData LLC", + "city": { + "name": "Shageluk", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Shageluk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2320068191729822011-670", + "name": "Gallup Corporation", + "city": { + "name": "Snoqualmie Pass", + "code": "WA", + "state": "Washington", + "county": "Kittitas", + "display": "Snoqualmie Ps" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3859929845262546822-671", + "name": "Ceiba Solutions Inc", + "city": { + "name": "Paintsville", + "code": "KY", + "state": "Kentucky", + "county": "Johnson", + "display": "Offutt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6456334418417695035-672", + "name": "Sterling Infosystems LLC", + "city": { + "name": "Cooperstown", + "code": "ND", + "state": "North Dakota", + "county": "Griggs", + "display": "Cooperstwn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2616073116915868642-673", + "name": "Unigo Inc", + "city": { + "name": "Radersburg", + "code": "MT", + "state": "Montana", + "county": "Broadwater", + "display": "Radersburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1917353567924460398-674", + "name": "Energy Points, Corporation", + "city": { + "name": "Bradford", + "code": "IL", + "state": "Illinois", + "county": "Stark", + "display": "Broadmoor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-938014020061461313-675", + "name": "Lumesis, Company", + "city": { + "name": "New Bloomfield", + "code": "MO", + "state": "Missouri", + "county": "Callaway", + "display": "Dixie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8580272290133548631-676", + "name": "Mango Transit Company", + "city": { + "name": "Silver City", + "code": "MS", + "state": "Mississippi", + "county": "Humphreys", + "display": "Silver City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8914983155361653232-677", + "name": "Rivet Software Incorporated", + "city": { + "name": "Georgetown", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Sun City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8657062307171523400-678", + "name": "The Schork Report Corp", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Mehlville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3225939159916079947-679", + "name": "Revaluate Corporation", + "city": { + "name": "Burlison", + "code": "TN", + "state": "Tennessee", + "county": "Tipton", + "display": "Randolph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7440552193277120244-680", + "name": "IPHIX Company", + "city": { + "name": "Bridgeton", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Hazelwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8606891835602597912-681", + "name": "mHealthCoach Corporation", + "city": { + "name": "Lancaster", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Eden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7708662406873414892-682", + "name": "3 Round Stones, Corp", + "city": { + "name": "Apache Junction", + "code": "AZ", + "state": "Arizona", + "county": "Pinal", + "display": "Apache Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8730964111289599797-683", + "name": "CONNECT-DOT Corporation", + "city": { + "name": "Senatobia", + "code": "MS", + "state": "Mississippi", + "county": "Tate", + "display": "Northwest Junior College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8578189289776938118-684", + "name": "Food+Tech Connect Company", + "city": { + "name": "Narvon", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Fetterville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8116592522581624106-685", + "name": "Ontodia, Inc", + "city": { + "name": "Washington", + "code": "VA", + "state": "Virginia", + "county": "Rappahannock", + "display": "Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1636623687168754015-686", + "name": "CB Insights Company", + "city": { + "name": "Long Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Bixby Knolls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3044718035883400185-687", + "name": "Intelius Incorporated", + "city": { + "name": "Anthony", + "code": "TX", + "state": "Texas", + "county": "El Paso", + "display": "Vinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-361817661336957558-688", + "name": "Environmental Data Resources LLC", + "city": { + "name": "Cascade", + "code": "CO", + "state": "Colorado", + "county": "El Paso", + "display": "Cascade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7073666366303708376-689", + "name": "Urban Airship Corporation", + "city": { + "name": "Fort Gibson", + "code": "OK", + "state": "Oklahoma", + "county": "Muskogee", + "display": "Fort Gibson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2711199841828004991-690", + "name": "Evidera Corporation", + "city": { + "name": "Tamiment", + "code": "PA", + "state": "Pennsylvania", + "county": "Pike", + "display": "Bushkill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1781708564748661827-691", + "name": "Teradata Incorporated", + "city": { + "name": "Lyerly", + "code": "GA", + "state": "Georgia", + "county": "Chattooga", + "display": "Lyerly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6358891860145861193-692", + "name": "Bloomberg Corporation", + "city": { + "name": "Deltona", + "code": "FL", + "state": "Florida", + "county": "Volusia", + "display": "Deltona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4235452588200194615-693", + "name": "Fastcase Incorporated", + "city": { + "name": "Canajoharie", + "code": "NY", + "state": "New York", + "county": "Montgomery", + "display": "Browns Hollow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6564467392249882308-694", + "name": "Navico Company", + "city": { + "name": "Ruidoso", + "code": "NM", + "state": "New Mexico", + "county": "Lincoln", + "display": "Ruidoso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5233635263217606371-695", + "name": "Liquid Robotics Corporation", + "city": { + "name": "Onia", + "code": "AR", + "state": "Arkansas", + "county": "Stone", + "display": "Onia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7419646171363040441-696", + "name": "Barchart Corp", + "city": { + "name": "Stanley", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Stanley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7045185900456319079-697", + "name": "Construction Monitor Company", + "city": { + "name": "Ripplemead", + "code": "VA", + "state": "Virginia", + "county": "Giles", + "display": "Kimballton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7928229137311800429-698", + "name": "USSearch Company", + "city": { + "name": "Franklinton", + "code": "NC", + "state": "North Carolina", + "county": "Franklin", + "display": "Franklinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6326072740473945728-699", + "name": "Synthicity Incorporated", + "city": { + "name": "Alexandria", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Timber Trails" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8509276642805942684-700", + "name": "WebMD Incorporated", + "city": { + "name": "Claxton", + "code": "GA", + "state": "Georgia", + "county": "Evans", + "display": "Claxton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-289549826396873448-701", + "name": "Captricity Incorporated", + "city": { + "name": "Deltona", + "code": "FL", + "state": "Florida", + "county": "Volusia", + "display": "Deltona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4774577947951879067-702", + "name": "IBM Incorporated", + "city": { + "name": "Mc Caskill", + "code": "AR", + "state": "Arkansas", + "county": "Hempstead", + "display": "Mc Caskill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2137572658117710210-703", + "name": "Arpin Van Lines Inc", + "city": { + "name": "Oak Ridge", + "code": "NJ", + "state": "New Jersey", + "county": "Passaic", + "display": "Jefferson Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3703674963914802493-704", + "name": "Navico Corp", + "city": { + "name": "Spokane", + "code": "WA", + "state": "Washington", + "county": "Spokane", + "display": "Shadle Garland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1652535331114406707-705", + "name": "Genability Incorporated", + "city": { + "name": "Ligonier", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Ligonier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6540762530271009181-706", + "name": "Energy Points, Company", + "city": { + "name": "Roaring Spring", + "code": "PA", + "state": "Pennsylvania", + "county": "Blair", + "display": "Bakers Summit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6952189763170010659-707", + "name": "SpeSo Health Corporation", + "city": { + "name": "Madison", + "code": "WI", + "state": "Wisconsin", + "county": "Dane", + "display": "Wi Lottery" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4590258347695984988-708", + "name": "Standard and Poor's Corporation", + "city": { + "name": "Prim", + "code": "AR", + "state": "Arkansas", + "county": "Cleburne", + "display": "Woodrow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4452239025586357310-709", + "name": "Quid Corporation", + "city": { + "name": "Saint Francisville", + "code": "IL", + "state": "Illinois", + "county": "Lawrence", + "display": "St Francisvle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7372422427404936148-710", + "name": "Dow Jones \u0026 Co LLC", + "city": { + "name": "Township Of Washington", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Twp Washinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6454169806354564272-711", + "name": "SolarList LLC", + "city": { + "name": "Piney Fork", + "code": "OH", + "state": "Ohio", + "county": "Jefferson", + "display": "Piney Fork" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1615352566432714451-712", + "name": "Everyday Health Corp", + "city": { + "name": "Gillett", + "code": "WI", + "state": "Wisconsin", + "county": "Oconto", + "display": "Pulcifer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3739729741050063101-713", + "name": "Lucid Corporation", + "city": { + "name": "Atmore", + "code": "AL", + "state": "Alabama", + "county": "Escambia", + "display": "Atmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7241037380437243789-714", + "name": "optiGov Corporation", + "city": { + "name": "Connoquenessing", + "code": "PA", + "state": "Pennsylvania", + "county": "Butler", + "display": "Connoqunsg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7093305068918747677-715", + "name": "Scale Unlimited Company", + "city": { + "name": "Monroe", + "code": "OH", + "state": "Ohio", + "county": "Butler", + "display": "Liberty Tnsp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8962076853876527498-716", + "name": "WebFilings Corp", + "city": { + "name": "Hernando", + "code": "MS", + "state": "Mississippi", + "county": "Desoto", + "display": "Hernando" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2406636911875015244-717", + "name": "Inrix Traffic Inc", + "city": { + "name": "Bishopville", + "code": "SC", + "state": "South Carolina", + "county": "Lee", + "display": "Ashland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4431462863432276937-718", + "name": "Palantir Technologies Incorporated", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Warrior Run" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2222293246071673875-719", + "name": "Apextech Incorporated", + "city": { + "name": "Riga", + "code": "MI", + "state": "Michigan", + "county": "Lenawee", + "display": "Riga" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5635710330843672443-720", + "name": "BillGuard Corporation", + "city": { + "name": "Saint Bernard", + "code": "LA", + "state": "Louisiana", + "county": "Saint Bernard", + "display": "Reggio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1748931615111218122-721", + "name": "North American Van Lines Inc", + "city": { + "name": "Bellflower", + "code": "MO", + "state": "Missouri", + "county": "Montgomery", + "display": "Gamma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5014536024359879575-722", + "name": "Forrester Research LLC", + "city": { + "name": "Sutter Creek", + "code": "CA", + "state": "California", + "county": "Amador", + "display": "Sutter Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3167609444749407025-723", + "name": "MarketSense Company", + "city": { + "name": "Dairy", + "code": "OR", + "state": "Oregon", + "county": "Klamath", + "display": "Dairy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3408133935317075878-724", + "name": "Spikes Cavell Analytic Corp", + "city": { + "name": "Tinnie", + "code": "NM", + "state": "New Mexico", + "county": "Lincoln", + "display": "Tinnie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9095593187791691720-725", + "name": "Mozio Company", + "city": { + "name": "Chicago Heights", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Ford Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6453386329510832785-726", + "name": "DemystData Corporation", + "city": { + "name": "White River Junction", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "White Riv Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1396827314031475030-727", + "name": "StockSmart LLC", + "city": { + "name": "Prophetstown", + "code": "IL", + "state": "Illinois", + "county": "Whiteside", + "display": "Leon Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8860933429015790167-728", + "name": "Xcential Incorporated", + "city": { + "name": "Carrollton", + "code": "GA", + "state": "Georgia", + "county": "Carroll", + "display": "University Of West Georgia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3364602253572559461-729", + "name": "NERA Economic Consulting Corporation", + "city": { + "name": "Roanoke", + "code": "TX", + "state": "Texas", + "county": "Denton", + "display": "Westlake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3406171332754260272-730", + "name": "Wolfram Research LLC", + "city": { + "name": "Boneville", + "code": "GA", + "state": "Georgia", + "county": "Mcduffie", + "display": "Boneville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1677622154291286280-731", + "name": "Graematter, Incorporated", + "city": { + "name": "Franklin", + "code": "NC", + "state": "North Carolina", + "county": "Macon", + "display": "East Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-876236360926317405-732", + "name": "ClearStory Data Inc", + "city": { + "name": "Burt", + "code": "MI", + "state": "Michigan", + "county": "Saginaw", + "display": "Burt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4641251619130247916-733", + "name": "Bing Corp", + "city": { + "name": "Guildhall", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Ferdinand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5946764130612440817-734", + "name": "Science Exchange Corp", + "city": { + "name": "Burley", + "code": "ID", + "state": "Idaho", + "county": "Cassia", + "display": "Starrhs Ferry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2179804373836210972-735", + "name": "FlightView Corporation", + "city": { + "name": "Logan", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Logan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2424523462499946595-736", + "name": "Aquicore LLC", + "city": { + "name": "Sharpsburg", + "code": "MD", + "state": "Maryland", + "county": "Washington", + "display": "Sharpsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8565952397236643983-737", + "name": "Cyte Corp", + "city": { + "name": "Fort Lauderdale", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Bonaventure" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7058914361434647158-738", + "name": "GoodGuide Incorporated", + "city": { + "name": "Tompkinsville", + "code": "KY", + "state": "Kentucky", + "county": "Monroe", + "display": "Flippin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4066002009293193468-739", + "name": "Vizzuality LLC", + "city": { + "name": "Climax", + "code": "CO", + "state": "Colorado", + "county": "Lake", + "display": "Leadville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8810284882171047158-740", + "name": "Careset.com Corp", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Bunker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2566621777808571308-741", + "name": "Fitch Incorporated", + "city": { + "name": "Wingdale", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Wingdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4598459511885023151-742", + "name": "Lawdragon LLC", + "city": { + "name": "Mayfield", + "code": "MI", + "state": "Michigan", + "county": "Grand Traverse", + "display": "Mayfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9145595656997155760-743", + "name": "Foursquare Corporation", + "city": { + "name": "Wappapello", + "code": "MO", + "state": "Missouri", + "county": "Wayne", + "display": "Wappapello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5239815963754034618-744", + "name": "Energy Solutions Forum Corporation", + "city": { + "name": "North Grafton", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "North Grafton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-522252663171280688-745", + "name": "Rivet Software Inc", + "city": { + "name": "Grand Chain", + "code": "IL", + "state": "Illinois", + "county": "Pulaski", + "display": "Grand Chain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5227688594184413990-746", + "name": "College Abacus, an ECMC initiative Corporation", + "city": { + "name": "Jenison", + "code": "MI", + "state": "Michigan", + "county": "Ottawa", + "display": "Georgetown Tp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8544141415799958394-747", + "name": "WebFilings Incorporated", + "city": { + "name": "Faulkton", + "code": "SD", + "state": "South Dakota", + "county": "Faulk", + "display": "Burkmere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4028261764851343717-748", + "name": "Intelius Inc", + "city": { + "name": "Saint Paul", + "code": "MN", + "state": "Minnesota", + "county": "Ramsey", + "display": "Vadnais Hts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2980404400137058885-749", + "name": "GovTribe Inc", + "city": { + "name": "Walcott", + "code": "WY", + "state": "Wyoming", + "county": "Carbon", + "display": "Walcott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7472659088677896611-750", + "name": "Moody's Inc", + "city": { + "name": "North Tonawanda", + "code": "NY", + "state": "New York", + "county": "Niagara", + "display": "No Tonawanda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7743907885374522730-751", + "name": "Intermap Technologies Incorporated", + "city": { + "name": "Bethlehem", + "code": "KY", + "state": "Kentucky", + "county": "Henry", + "display": "Bethlehem" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3271936969201621591-752", + "name": "xDayta Incorporated", + "city": { + "name": "Sherman Oaks", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Us Purchasing Exchange" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2420972178072028011-753", + "name": "Geoscape Company", + "city": { + "name": "Thiells", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "Thiells" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-153598718867192127-754", + "name": "Experian Incorporated", + "city": { + "name": "Burnham", + "code": "PA", + "state": "Pennsylvania", + "county": "Mifflin", + "display": "Burnham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2847710128828607295-755", + "name": "Marinexplore, LLC", + "city": { + "name": "Rugby", + "code": "TN", + "state": "Tennessee", + "county": "Morgan", + "display": "Elgin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6313873762568078971-756", + "name": "PeerJ LLC", + "city": { + "name": "Columbus Junction", + "code": "IA", + "state": "Iowa", + "county": "Louisa", + "display": "Columbus Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1104912452871584628-757", + "name": "Wheaton World Wide Moving Company", + "city": { + "name": "Hallettsville", + "code": "TX", + "state": "Texas", + "county": "Lavaca", + "display": "Hallettsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6363798759592540597-758", + "name": "RAND LLC", + "city": { + "name": "Asbury Park", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Wanamassa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-730585934477701038-759", + "name": "The Govtech Fund LLC", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Alder Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7866467501101235200-760", + "name": "Wolfram Research Incorporated", + "city": { + "name": "Kalamazoo", + "code": "MI", + "state": "Michigan", + "county": "Kalamazoo", + "display": "Parchment" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7741146577576071328-761", + "name": "Govini Corp", + "city": { + "name": "Windom", + "code": "MN", + "state": "Minnesota", + "county": "Cottonwood", + "display": "Wilder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7802801472849929626-762", + "name": "The Advisory Board Company Inc", + "city": { + "name": "North Waterboro", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "N Waterboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5969817432109258462-763", + "name": "Science Exchange Incorporated", + "city": { + "name": "Talbott", + "code": "TN", + "state": "Tennessee", + "county": "Hamblen", + "display": "Talbott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8416882255818503945-764", + "name": "Geofeedia Inc", + "city": { + "name": "Richfield", + "code": "UT", + "state": "Utah", + "county": "Sevier", + "display": "Venice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1733941135387415742-765", + "name": "Plus-U Inc", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Thunderbolt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1266307322707407676-766", + "name": "PlanetEcosystems LLC", + "city": { + "name": "Sharon", + "code": "KS", + "state": "Kansas", + "county": "Barber", + "display": "Sharon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6741652963406013946-767", + "name": "J.P. Morgan Chase Inc", + "city": { + "name": "West Des Moines", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "W Des Moines" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3024070142400423528-768", + "name": "Google Maps Inc", + "city": { + "name": "Leesburg", + "code": "OH", + "state": "Ohio", + "county": "Highland", + "display": "Highland County" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5627190705484135544-769", + "name": "SpotHero.com Inc", + "city": { + "name": "Miramar Beach", + "code": "FL", + "state": "Florida", + "county": "Walton", + "display": "Miramar Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7664470755433137725-770", + "name": "OptumInsight Incorporated", + "city": { + "name": "Kanawha Head", + "code": "WV", + "state": "West Virginia", + "county": "Upshur", + "display": "Kanawha Head" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8424258947539160596-771", + "name": "Chubb Company", + "city": { + "name": "Lynchburg", + "code": "VA", + "state": "Virginia", + "county": "Lynchburg City", + "display": "Fort Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2341546156309765046-772", + "name": "Azavea Company", + "city": { + "name": "Cole Camp", + "code": "MO", + "state": "Missouri", + "county": "Benton", + "display": "Mount Hulda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2715561235097461928-773", + "name": "Noveda Technologies Corporation", + "city": { + "name": "North Myrtle Beach", + "code": "SC", + "state": "South Carolina", + "county": "Horry", + "display": "North Myrtle Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4217704417904455416-774", + "name": "StockSmart Company", + "city": { + "name": "Marble Falls", + "code": "AR", + "state": "Arkansas", + "county": "Newton", + "display": "Dogpatch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7200839331279191289-775", + "name": "H3 Biomedicine Corporation", + "city": { + "name": "Jonesville", + "code": "NC", + "state": "North Carolina", + "county": "Yadkin", + "display": "Jonesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1918173784153616048-776", + "name": "Ernst \u0026 Young LLP Corporation", + "city": { + "name": "Bellwood", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Bellwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3631038918054158669-777", + "name": "College Abacus, an ECMC initiative LLC", + "city": { + "name": "Port Orchard", + "code": "WA", + "state": "Washington", + "county": "Kitsap", + "display": "Waterman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4835256354221490868-778", + "name": "Weather Channel Incorporated", + "city": { + "name": "Eddyville", + "code": "KY", + "state": "Kentucky", + "county": "Lyon", + "display": "Confederate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5336277454034406272-779", + "name": "Credit Karma Company", + "city": { + "name": "Knoxville", + "code": "TN", + "state": "Tennessee", + "county": "Knox", + "display": "Lonsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5417969333177334547-780", + "name": "Palantir Technologies LLC", + "city": { + "name": "Corral", + "code": "ID", + "state": "Idaho", + "county": "Camas", + "display": "Corral" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5144550845621037084-781", + "name": "Forrester Research Corporation", + "city": { + "name": "Mount Pleasant", + "code": "MS", + "state": "Mississippi", + "county": "Marshall", + "display": "Holly Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9196412727204014287-782", + "name": "Credit Karma Company", + "city": { + "name": "Hawesville", + "code": "KY", + "state": "Kentucky", + "county": "Hancock", + "display": "Arrington Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8213733991439134579-783", + "name": "Equifax Inc", + "city": { + "name": "Lackawaxen", + "code": "PA", + "state": "Pennsylvania", + "county": "Pike", + "display": "Lackawaxen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-989091601292141376-784", + "name": "Remi Corporation", + "city": { + "name": "Peru", + "code": "IA", + "state": "Iowa", + "county": "Madison", + "display": "East Peru" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1011461110648362546-785", + "name": "Revaluate Corp", + "city": { + "name": "Windthorst", + "code": "TX", + "state": "Texas", + "county": "Archer", + "display": "Antelope" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-725235948094613350-786", + "name": "Business and Legal Resources Inc", + "city": { + "name": "Antwerp", + "code": "OH", + "state": "Ohio", + "county": "Paulding", + "display": "Antwerp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9011952765587463604-787", + "name": "The DocGraph Journal Corp", + "city": { + "name": "Kingdom City", + "code": "MO", + "state": "Missouri", + "county": "Callaway", + "display": "Kingdom City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5181346669559793201-788", + "name": "Aquicore Inc", + "city": { + "name": "Monroe", + "code": "GA", + "state": "Georgia", + "county": "Walton", + "display": "Between" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1397257520451221062-789", + "name": "Castle Biosciences Corp", + "city": { + "name": "Cumberland Foreside", + "code": "ME", + "state": "Maine", + "county": "Cumberland", + "display": "Cumb Foreside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-57437767531503963-790", + "name": "Maponics Company", + "city": { + "name": "Inverness", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Inverness" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5234566061663810061-791", + "name": "Recargo Company", + "city": { + "name": "Menlo", + "code": "IA", + "state": "Iowa", + "county": "Guthrie", + "display": "Glendon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4883180688227366407-792", + "name": "TuvaLabs Corporation", + "city": { + "name": "Laporte", + "code": "MN", + "state": "Minnesota", + "county": "Hubbard", + "display": "Guthrie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4471552887527204086-793", + "name": "PossibilityU Incorporated", + "city": { + "name": "Hodge", + "code": "LA", + "state": "Louisiana", + "county": "Jackson", + "display": "Hodge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6903445559935402770-794", + "name": "Govzilla, Company", + "city": { + "name": "Bloomsbury", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Bloomsbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1198539739509155552-795", + "name": "Kyruus Corporation", + "city": { + "name": "Waelder", + "code": "TX", + "state": "Texas", + "county": "Gonzales", + "display": "Waelder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6108316656062704112-796", + "name": "CitySourced Incorporated", + "city": { + "name": "Quinn", + "code": "SD", + "state": "South Dakota", + "county": "Pennington", + "display": "Cottonwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6006281059711840-797", + "name": "Solar Census Corporation", + "city": { + "name": "Raleigh", + "code": "NC", + "state": "North Carolina", + "county": "Wake", + "display": "North Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-656218400201611567-798", + "name": "Quid Incorporated", + "city": { + "name": "Newbury", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Plum Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-417178332336346535-799", + "name": "Computer Packages Inc", + "city": { + "name": "Goshen", + "code": "OH", + "state": "Ohio", + "county": "Clermont", + "display": "Edenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6776125662575650986-800", + "name": "VisualDoD, Corporation", + "city": { + "name": "Larkspur", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Larkspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5311473140964487594-801", + "name": "Locavore Inc", + "city": { + "name": "Philadelphia", + "code": "PA", + "state": "Pennsylvania", + "county": "Philadelphia", + "display": "Lawndale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2579969089363039556-802", + "name": "Acxiom Corp", + "city": { + "name": "Medina", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Crystal Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1513010014529422306-803", + "name": "Avvo Incorporated", + "city": { + "name": "West Nottingham", + "code": "NH", + "state": "New Hampshire", + "county": "Rockingham", + "display": "W Nottingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4360352506346374904-804", + "name": "Robinson + Yu Corp", + "city": { + "name": "Palestine", + "code": "AR", + "state": "Arkansas", + "county": "Saint Francis", + "display": "Palestine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5620368036922258373-805", + "name": "CostQuest Corp", + "city": { + "name": "West Kingston", + "code": "RI", + "state": "Rhode Island", + "county": "Washington", + "display": "South Kingstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5731495313057977443-806", + "name": "Foursquare Corp", + "city": { + "name": "Donovan", + "code": "IL", + "state": "Illinois", + "county": "Iroquois", + "display": "Donovan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4224250376210029763-807", + "name": "NuCivic Company", + "city": { + "name": "Sheridan", + "code": "IN", + "state": "Indiana", + "county": "Hamilton", + "display": "Sheridan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6639369403309398831-808", + "name": "Apextech Corp", + "city": { + "name": "Westhampton", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "W Hampton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5866761042508268179-809", + "name": "SpeSo Health Inc", + "city": { + "name": "Beaumont", + "code": "TX", + "state": "Texas", + "county": "Jefferson", + "display": "Beaumont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-408621718937186936-810", + "name": "US Green Data Company", + "city": { + "name": "Stanley", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Stanley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6771010612534797755-811", + "name": "TrialX Incorporated", + "city": { + "name": "Osage", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Snellman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-421120806850004545-812", + "name": "Aquicore Inc", + "city": { + "name": "Magnolia", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Magnolia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8732655783294756819-813", + "name": "Geofeedia Incorporated", + "city": { + "name": "Buffalo", + "code": "MN", + "state": "Minnesota", + "county": "Wright", + "display": "Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8768690139785603795-814", + "name": "StreetEasy LLC", + "city": { + "name": "Tunnel City", + "code": "WI", + "state": "Wisconsin", + "county": "Monroe", + "display": "Tunnel City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8720399953782432166-815", + "name": "US Green Data Company", + "city": { + "name": "Owego", + "code": "NY", + "state": "New York", + "county": "Tioga", + "display": "Gaskill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1164781545271382468-816", + "name": "AccuWeather Company", + "city": { + "name": "Valley Springs", + "code": "SD", + "state": "South Dakota", + "county": "Minnehaha", + "display": "Valley Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5657072217290054479-817", + "name": "CGI LLC", + "city": { + "name": "Sayville", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Fire Island Pines" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1901711820317166826-818", + "name": "Inovalon Incorporated", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Reading" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1648383213707488192-819", + "name": "Personal, Corp", + "city": { + "name": "Jonesboro", + "code": "TX", + "state": "Texas", + "county": "Coryell", + "display": "Pancake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7609203895733566797-820", + "name": "College Board Corporation", + "city": { + "name": "Fairchance", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Fairchance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7337147371223228967-821", + "name": "PlanetEcosystems Inc", + "city": { + "name": "Midvale", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "Midvale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4114822593344319666-822", + "name": "Trintech Incorporated", + "city": { + "name": "Hannawa Falls", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "Hannawa Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1795393323381471473-823", + "name": "Noesis LLC", + "city": { + "name": "Sandy Hook", + "code": "KY", + "state": "Kentucky", + "county": "Elliott", + "display": "Sandy Hook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-885416649314750177-824", + "name": "Personalis Company", + "city": { + "name": "New Virginia", + "code": "IA", + "state": "Iowa", + "county": "Warren", + "display": "Jamison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7275782107723109785-825", + "name": "Onvia Incorporated", + "city": { + "name": "Ardmore", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Ardmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7475351775635600461-826", + "name": "Outline Company", + "city": { + "name": "Grand Junction", + "code": "TN", + "state": "Tennessee", + "county": "Hardeman", + "display": "Grand Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6248512681360448474-827", + "name": "Mozio LLC", + "city": { + "name": "Mc Bee", + "code": "SC", + "state": "South Carolina", + "county": "Chesterfield", + "display": "Mc Bee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1201301641590034026-828", + "name": "Personal, LLC", + "city": { + "name": "Pleasant Dale", + "code": "NE", + "state": "Nebraska", + "county": "Seward", + "display": "Pleasant Dale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5985671112361434400-829", + "name": "Appallicious Inc", + "city": { + "name": "Cambridge", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Weller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4455516101494762439-830", + "name": "Fujitsu Corp", + "city": { + "name": "Hastings", + "code": "NE", + "state": "Nebraska", + "county": "Adams", + "display": "Good Samaritan Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6507015154915423371-831", + "name": "CGI Corp", + "city": { + "name": "Villanueva", + "code": "NM", + "state": "New Mexico", + "county": "San Miguel", + "display": "El Cerrito" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1927707954253463397-832", + "name": "Porch Company", + "city": { + "name": "West Hatfield", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "W Hatfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8550044656243078378-833", + "name": "BillGuard Incorporated", + "city": { + "name": "Ladysmith", + "code": "VA", + "state": "Virginia", + "county": "Caroline", + "display": "Ladysmith" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8967734870416752339-834", + "name": "Sophic Systems Alliance Incorporated", + "city": { + "name": "Lackawaxen", + "code": "PA", + "state": "Pennsylvania", + "county": "Pike", + "display": "Lackawaxen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4596948466447648609-835", + "name": "5PSolutions Company", + "city": { + "name": "Booneville", + "code": "KY", + "state": "Kentucky", + "county": "Owsley", + "display": "Pebworth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4802478583944035264-836", + "name": "The Vanguard Group Incorporated", + "city": { + "name": "Kenedy", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Kenedy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7677299547891902014-837", + "name": "Bekins Corp", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "North College Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7293450769474637299-838", + "name": "Pave Inc", + "city": { + "name": "Garland", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Garland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5201436513270688220-839", + "name": "Harris Corp", + "city": { + "name": "West Union", + "code": "IA", + "state": "Iowa", + "county": "Fayette", + "display": "West Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7207919293008501984-840", + "name": "Remi Incorporated", + "city": { + "name": "Two Rivers", + "code": "WI", + "state": "Wisconsin", + "county": "Manitowoc", + "display": "Two Rivers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3633595166864571813-841", + "name": "DataLogix Inc", + "city": { + "name": "Simonton", + "code": "TX", + "state": "Texas", + "county": "Fort Bend", + "display": "Simonton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7723773646781237055-842", + "name": "Mapbox Corporation", + "city": { + "name": "Arlington", + "code": "GA", + "state": "Georgia", + "county": "Calhoun", + "display": "Arlington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-728782896719268922-843", + "name": "Zillow Corp", + "city": { + "name": "Geneseo", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Hanna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3022719585295866798-844", + "name": "Votizen Inc", + "city": { + "name": "Warren", + "code": "AR", + "state": "Arkansas", + "county": "Bradley", + "display": "Mckinney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7227314679524352432-845", + "name": "ReciPal Corp", + "city": { + "name": "Portland", + "code": "IN", + "state": "Indiana", + "county": "Jay", + "display": "Liber" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5795682365198726733-846", + "name": "DataMade Company", + "city": { + "name": "Westmoreland City", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Westmoreland City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2978603780062741075-847", + "name": "Lumesis, Company", + "city": { + "name": "Crump", + "code": "TN", + "state": "Tennessee", + "county": "Hardin", + "display": "Crump" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7141607535019049124-848", + "name": "Asset4 Inc", + "city": { + "name": "Belva", + "code": "WV", + "state": "West Virginia", + "county": "Nicholas", + "display": "Belva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6705487842624670528-849", + "name": "LoopNet Company", + "city": { + "name": "Rodney", + "code": "MI", + "state": "Michigan", + "county": "Mecosta", + "display": "Rodney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-25922284872549571-850", + "name": "Numedii Company", + "city": { + "name": "Greenwich", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Greenwich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2502991782927606186-851", + "name": "State Farm Insurance Incorporated", + "city": { + "name": "Ville Platte", + "code": "LA", + "state": "Louisiana", + "county": "Evangeline", + "display": "Ville Platte" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5068902038093736319-852", + "name": "Patently-O Corp", + "city": { + "name": "Cobalt", + "code": "CT", + "state": "Connecticut", + "county": "Middlesex", + "display": "Cobalt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-635382410230718986-853", + "name": "optiGov Corp", + "city": { + "name": "Pine Mountain Club", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Pine Mountain Club" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7957477522266763827-854", + "name": "Weather Underground Company", + "city": { + "name": "Brainard", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Brainard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3933300334237950700-855", + "name": "Cerner LLC", + "city": { + "name": "Boonton", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Powerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4543893389548507403-856", + "name": "CitySourced Corporation", + "city": { + "name": "Salt Lake City", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "Holladay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1605095832840255352-857", + "name": "Docket Alarm, Corp", + "city": { + "name": "Mc Cool Junction", + "code": "NE", + "state": "Nebraska", + "county": "York", + "display": "Mc Cool Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1158583593340027376-858", + "name": "Estately Inc", + "city": { + "name": "Keene", + "code": "VA", + "state": "Virginia", + "county": "Albemarle", + "display": "Keene" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1496773396566729032-859", + "name": "College Board Company", + "city": { + "name": "New Paris", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "New Paris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8230610447774493355-860", + "name": "Quandl LLC", + "city": { + "name": "Diamond", + "code": "OH", + "state": "Ohio", + "county": "Portage", + "display": "Diamond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-460017116549135549-861", + "name": "Simple Energy LLC", + "city": { + "name": "Big Wells", + "code": "TX", + "state": "Texas", + "county": "Dimmit", + "display": "Big Wells" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2218487124190612428-862", + "name": "Suddath Corp", + "city": { + "name": "Mannsville", + "code": "OK", + "state": "Oklahoma", + "county": "Johnston", + "display": "Mannsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8361513412454442989-863", + "name": "PricewaterhouseCoopers Corp", + "city": { + "name": "Hanamaulu", + "code": "HI", + "state": "Hawaii", + "county": "Kauai", + "display": "Lihue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1648105298459503936-864", + "name": "GuideStar Corporation", + "city": { + "name": "Badger", + "code": "MN", + "state": "Minnesota", + "county": "Roseau", + "display": "Badger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3089629956784394774-865", + "name": "Zebu Compliance Solutions Corp", + "city": { + "name": "Mc Cool Junction", + "code": "NE", + "state": "Nebraska", + "county": "York", + "display": "Mc Cool Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4739018649933307744-866", + "name": "Farmers Incorporated", + "city": { + "name": "Labadie", + "code": "MO", + "state": "Missouri", + "county": "Franklin", + "display": "Labadie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1785096373892735982-867", + "name": "GoodGuide Inc", + "city": { + "name": "Waseca", + "code": "MN", + "state": "Minnesota", + "county": "Waseca", + "display": "Otisco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3549283271121496513-868", + "name": "Noesis LLC", + "city": { + "name": "Voorheesville", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Voorheesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-886461266559235790-869", + "name": "Politify Company", + "city": { + "name": "Loyall", + "code": "KY", + "state": "Kentucky", + "county": "Harlan", + "display": "Loyall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6837625088282102107-870", + "name": "Nautilytics Corporation", + "city": { + "name": "Auburn", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Bowman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8850187747945078131-871", + "name": "LexisNexis Inc", + "city": { + "name": "Inverness", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Inverness" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3419207508896614455-872", + "name": "Govzilla, Inc", + "city": { + "name": "Billings", + "code": "MT", + "state": "Montana", + "county": "Yellowstone", + "display": "Lockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8903029501216635624-873", + "name": "Personal Democracy Media Company", + "city": { + "name": "Glen", + "code": "WV", + "state": "West Virginia", + "county": "Clay", + "display": "Glen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4035513847303812009-874", + "name": "Marlin Alter and Associates Corporation", + "city": { + "name": "Cedarville", + "code": "WV", + "state": "West Virginia", + "county": "Gilmer", + "display": "Cedarville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3632029888865499432-875", + "name": "Careset.com Corp", + "city": { + "name": "Peel", + "code": "AR", + "state": "Arkansas", + "county": "Marion", + "display": "Peel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2228020363751763798-876", + "name": "Equifax Corp", + "city": { + "name": "Clayton", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Murray Isle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4403268217309149507-877", + "name": "NerdWallet Corporation", + "city": { + "name": "Milo", + "code": "ME", + "state": "Maine", + "county": "Piscataquis", + "display": "Orneville Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5252273850331632750-878", + "name": "SocialEffort Corporation", + "city": { + "name": "Carrollton", + "code": "KY", + "state": "Kentucky", + "county": "Carroll", + "display": "English" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1101669683414428984-879", + "name": "PEV4me.com LLC", + "city": { + "name": "East Wenatchee", + "code": "WA", + "state": "Washington", + "county": "Douglas", + "display": "East Wenatchee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2159020854884377768-880", + "name": "Propeller Health Incorporated", + "city": { + "name": "Edgefield", + "code": "SC", + "state": "South Carolina", + "county": "Edgefield", + "display": "Cleora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7644729130951826223-881", + "name": "Personalis Corporation", + "city": { + "name": "Forestburgh", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Forestburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1211378923600055652-882", + "name": "LoseIt.com Corporation", + "city": { + "name": "Geyser", + "code": "MT", + "state": "Montana", + "county": "Judith Basin", + "display": "Geyser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7693846488679425255-883", + "name": "Dun \u0026 Bradstreet Inc", + "city": { + "name": "Watsontown", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Watsonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1177008292825348990-884", + "name": "SlashDB Corp", + "city": { + "name": "Free Union", + "code": "VA", + "state": "Virginia", + "county": "Albemarle", + "display": "Mission Home" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8018159161864332283-885", + "name": "Noveda Technologies Corp", + "city": { + "name": "De Kalb", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Hodgson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5065481156017796511-886", + "name": "AllState Insurance Group Corporation", + "city": { + "name": "Jber", + "code": "AK", + "state": "Alaska", + "county": "Anchorage", + "display": "Elmendorf AFB" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-515193461453869068-887", + "name": "PayScale, LLC", + "city": { + "name": "Faucett", + "code": "MO", + "state": "Missouri", + "county": "Buchanan", + "display": "Faucett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1781547176336383940-888", + "name": "Lenddo Incorporated", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Alder Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5625647668834990180-889", + "name": "Captricity Inc", + "city": { + "name": "Griffithville", + "code": "AR", + "state": "Arkansas", + "county": "White", + "display": "Griffithville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6960965880921038137-890", + "name": "Cambridge Information Group Corp", + "city": { + "name": "Montauk", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Montauk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8399992964400115642-891", + "name": "Moody's Company", + "city": { + "name": "Saint Joseph", + "code": "MI", + "state": "Michigan", + "county": "Berrien", + "display": "Saint Joseph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2299984899545611854-892", + "name": "Center for Responsive Politics Corporation", + "city": { + "name": "Iron", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Iron Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6884445830647222888-893", + "name": "IMS Health LLC", + "city": { + "name": "Crawfordsville", + "code": "IN", + "state": "Indiana", + "county": "Montgomery", + "display": "Rr Donnelley \u0026 Sons" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9011007803218778395-894", + "name": "Construction Monitor Incorporated", + "city": { + "name": "Marsland", + "code": "NE", + "state": "Nebraska", + "county": "Dawes", + "display": "Marsland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7798044955402730936-895", + "name": "LOVELAND Technologies LLC", + "city": { + "name": "Seahurst", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Burien" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6826726376205217203-896", + "name": "Apextech Corp", + "city": { + "name": "Monroeville", + "code": "OH", + "state": "Ohio", + "county": "Huron", + "display": "Ridgefield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4934085943919154734-897", + "name": "American Red Ball Movers Corp", + "city": { + "name": "Mc Coy", + "code": "CO", + "state": "Colorado", + "county": "Eagle", + "display": "Mc Coy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4016723412169243643-898", + "name": "Navico LLC", + "city": { + "name": "Compton", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Crystal City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2787625745127829994-899", + "name": "LegiNation, Corporation", + "city": { + "name": "Appleton", + "code": "WI", + "state": "Wisconsin", + "county": "Outagamie", + "display": "Thrivent Finan For Lutherans" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7882850783692691942-900", + "name": "FlightView Inc", + "city": { + "name": "Glenwood Springs", + "code": "CO", + "state": "Colorado", + "county": "Garfield", + "display": "Glenwood Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6714559807984413624-901", + "name": "Eat Shop Sleep LLC", + "city": { + "name": "Lake Ariel", + "code": "PA", + "state": "Pennsylvania", + "county": "Wayne", + "display": "Cobbs Lake Preserve" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6296891050994684013-902", + "name": "Kyruus Incorporated", + "city": { + "name": "Herndon", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Mandata" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8887929759950233110-903", + "name": "Spokeo LLC", + "city": { + "name": "Bullville", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Bullville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7300439094265252843-904", + "name": "Mint LLC", + "city": { + "name": "White Lake", + "code": "SD", + "state": "South Dakota", + "county": "Aurora", + "display": "White Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-885285558658549833-905", + "name": "College Board Corp", + "city": { + "name": "Pingree", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Pingree" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5652416951801762261-906", + "name": "indoo.rs Corporation", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "Claycomo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3081517138191691412-907", + "name": "Sterling Infosystems LLC", + "city": { + "name": "Mount Sherman", + "code": "KY", + "state": "Kentucky", + "county": "Larue", + "display": "Mount Sherman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1238705552073634004-908", + "name": "Urban Airship LLC", + "city": { + "name": "Jefferson", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Jefferson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1236801949665755239-909", + "name": "Marlin \u0026 Associates Incorporated", + "city": { + "name": "Burns", + "code": "WY", + "state": "Wyoming", + "county": "Laramie", + "display": "Burns" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4304394023081670218-910", + "name": "Vitals Company", + "city": { + "name": "Zanesville", + "code": "OH", + "state": "Ohio", + "county": "Muskingum", + "display": "S Zanesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6522720780889015448-911", + "name": "Estately Corp", + "city": { + "name": "Grand Isle", + "code": "LA", + "state": "Louisiana", + "county": "Jefferson", + "display": "Grand Isle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-513761080567661341-912", + "name": "Asset4 LLC", + "city": { + "name": "Ogden", + "code": "UT", + "state": "Utah", + "county": "Weber", + "display": "Marriott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3370172836567483244-913", + "name": "BlackRock Corporation", + "city": { + "name": "Newport", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7515500033080574415-914", + "name": "Eat Shop Sleep LLC", + "city": { + "name": "Mount Vernon", + "code": "KY", + "state": "Kentucky", + "county": "Rockcastle", + "display": "Climax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-11013762499155963-915", + "name": "FindTheBest.com Incorporated", + "city": { + "name": "Kimball", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Kimball" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5925125769550832374-916", + "name": "Lawdragon LLC", + "city": { + "name": "Oneonta", + "code": "AL", + "state": "Alabama", + "county": "Blount", + "display": "Hoods Crossroads" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1839062950728166537-917", + "name": "Arpin Van Lines Inc", + "city": { + "name": "Freeman", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Freeman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1305365863739554455-918", + "name": "Quid Inc", + "city": { + "name": "Danbury", + "code": "NC", + "state": "North Carolina", + "county": "Stokes", + "display": "Hartman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7196465988538318282-919", + "name": "Lumesis, Corp", + "city": { + "name": "Bonita", + "code": "LA", + "state": "Louisiana", + "county": "Morehouse", + "display": "Bonita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6188175299415767880-920", + "name": "Weight Watchers Inc", + "city": { + "name": "Gilberts", + "code": "IL", + "state": "Illinois", + "county": "Kane", + "display": "Gilberts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3470358164401273840-921", + "name": "mHealthCoach Corp", + "city": { + "name": "Cedar Bluff", + "code": "VA", + "state": "Virginia", + "county": "Tazewell", + "display": "Cedar Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8791037189493419781-922", + "name": "The Govtech Fund Incorporated", + "city": { + "name": "North Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "No Las Vegas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1710952803417356653-923", + "name": "NuCivic Inc", + "city": { + "name": "Prescott", + "code": "WA", + "state": "Washington", + "county": "Walla Walla", + "display": "Prescott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1306037691401929398-924", + "name": "Numedii Incorporated", + "city": { + "name": "Fredericksburg", + "code": "VA", + "state": "Virginia", + "county": "Spotsylvania", + "display": "Fredericksburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2952659399289169695-925", + "name": "Recargo LLC", + "city": { + "name": "North Canton", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Lake Slagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3348135437461096103-926", + "name": "DataMarket Company", + "city": { + "name": "Muskegon", + "code": "MI", + "state": "Michigan", + "county": "Muskegon", + "display": "Muskegon Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3321574345248987997-927", + "name": "Import.io Corp", + "city": { + "name": "Middlebourne", + "code": "WV", + "state": "West Virginia", + "county": "Tyler", + "display": "Wick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2019697830016078220-928", + "name": "Knowledge Agency LLC", + "city": { + "name": "Mc Cutchenville", + "code": "OH", + "state": "Ohio", + "county": "Wyandot", + "display": "Mc Cutchenville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7283220397995781483-929", + "name": "Connotate Corp", + "city": { + "name": "Bartlesville", + "code": "OK", + "state": "Oklahoma", + "county": "Washington", + "display": "Phillips 66" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2165581297503622689-930", + "name": "Walk Score LLC", + "city": { + "name": "Freeman", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Freeman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-599503381038156270-931", + "name": "Rapid Cycle Solutions LLC", + "city": { + "name": "Watertown", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Watertown Financial" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5244663419860933732-932", + "name": "PatientsLikeMe Inc", + "city": { + "name": "Athens", + "code": "IL", + "state": "Illinois", + "county": "Menard", + "display": "Athens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4412873106353383392-933", + "name": "SmartAsset Corporation", + "city": { + "name": "Natalia", + "code": "TX", + "state": "Texas", + "county": "Medina", + "display": "Natalia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6325613029649755596-934", + "name": "InCadence Corp", + "city": { + "name": "Geneva", + "code": "AL", + "state": "Alabama", + "county": "Geneva", + "display": "Eunola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3580324437722401834-935", + "name": "WebFilings Company", + "city": { + "name": "Irvine", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Uc Irvine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3112951053140079440-936", + "name": "SmartProcure Company", + "city": { + "name": "Hamilton", + "code": "OH", + "state": "Ohio", + "county": "Butler", + "display": "City View Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2034136836290341723-937", + "name": "Housefax Corporation", + "city": { + "name": "Fort Leonard Wood", + "code": "MO", + "state": "Missouri", + "county": "Pulaski", + "display": "Ft Leonard Wd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7720154557637912740-938", + "name": "Accenture Inc", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Catholic Univ" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8899340986004661669-939", + "name": "Rivet Software Company", + "city": { + "name": "Verona", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "Verona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7273007355911622741-940", + "name": "Peterson's LLC", + "city": { + "name": "Humptulips", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Humptulips" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6280482151345304250-941", + "name": "Enigma.io Corp", + "city": { + "name": "De Soto", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "De Soto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6512216429189690248-942", + "name": "OTC Markets LLC", + "city": { + "name": "Florence", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Florence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8334304760504560413-943", + "name": "KPMG Incorporated", + "city": { + "name": "Hardwick", + "code": "GA", + "state": "Georgia", + "county": "Baldwin", + "display": "Hardwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7300693013344482951-944", + "name": "Kaiser Permanante Corp", + "city": { + "name": "Mount Lookout", + "code": "WV", + "state": "West Virginia", + "county": "Nicholas", + "display": "Mount Lookout" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5314239153142678804-945", + "name": "Healthgrades Incorporated", + "city": { + "name": "Water Mill", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Wtr Mill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1567997735621003219-946", + "name": "Seabourne Inc", + "city": { + "name": "Tivoli", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Tivoli" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2193033966455347174-947", + "name": "MicroBilt Inc", + "city": { + "name": "South Bend", + "code": "WA", + "state": "Washington", + "county": "Pacific", + "display": "Nemah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-227692134638958374-948", + "name": "Ernst \u0026 Young LLP LLC", + "city": { + "name": "Prophetstown", + "code": "IL", + "state": "Illinois", + "county": "Whiteside", + "display": "Prophetstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3972110615821493071-949", + "name": "OTC Markets Corporation", + "city": { + "name": "Holdrege", + "code": "NE", + "state": "Nebraska", + "county": "Phelps", + "display": "Sheridan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4656283287104535425-950", + "name": "iRecycle LLC", + "city": { + "name": "White Heath", + "code": "IL", + "state": "Illinois", + "county": "Piatt", + "display": "White Heath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3773488551482993283-951", + "name": "LoseIt.com Corp", + "city": { + "name": "Paintsville", + "code": "KY", + "state": "Kentucky", + "county": "Johnson", + "display": "Paintsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4126061186846913615-952", + "name": "PEV4me.com Corp", + "city": { + "name": "Rushford", + "code": "MN", + "state": "Minnesota", + "county": "Fillmore", + "display": "Bratsberg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2915182086813675639-953", + "name": "Funding Circle Corp", + "city": { + "name": "Ayr", + "code": "NE", + "state": "Nebraska", + "county": "Adams", + "display": "Ayr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-273263606341302306-954", + "name": "indoo.rs Corporation", + "city": { + "name": "Fort Worth", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Sansom Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8142321188849074657-955", + "name": "SeeClickFix Company", + "city": { + "name": "Salyersville", + "code": "KY", + "state": "Kentucky", + "county": "Magoffin", + "display": "Maggard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8900221480746128917-956", + "name": "Locavore Corp", + "city": { + "name": "Garrett", + "code": "IN", + "state": "Indiana", + "county": "De Kalb", + "display": "Keyser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4853637501029258723-957", + "name": "LexisNexis Inc", + "city": { + "name": "Allendale", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Allendale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2915552482475296907-958", + "name": "TagniFi Company", + "city": { + "name": "Monticello", + "code": "KY", + "state": "Kentucky", + "county": "Wayne", + "display": "Delta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5527352398361310986-959", + "name": "mHealthCoach LLC", + "city": { + "name": "Narrows", + "code": "VA", + "state": "Virginia", + "county": "Giles", + "display": "Narrows" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7674999531768300888-960", + "name": "Retroficiency Incorporated", + "city": { + "name": "Refton", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Refton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3814282771153445501-961", + "name": "SAP Incorporated", + "city": { + "name": "West Point", + "code": "MS", + "state": "Mississippi", + "county": "Clay", + "display": "Abbott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8899930000778913100-962", + "name": "Archimedes Incorporated", + "city": { + "name": "Fallsburg", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Fallsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8893427221521046744-963", + "name": "TagniFi Corp", + "city": { + "name": "Tivoli", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Tivoli" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-96433267406040264-964", + "name": "Patently-O Inc", + "city": { + "name": "Media", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Rose Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8869549816467812813-965", + "name": "Foursquare Inc", + "city": { + "name": "Camden", + "code": "SC", + "state": "South Carolina", + "county": "Kershaw", + "display": "Kirkland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5277015432818723258-966", + "name": "Cambridge Semantics Corp", + "city": { + "name": "Paicines", + "code": "CA", + "state": "California", + "county": "San Benito", + "display": "San Benito" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2519931863814428132-967", + "name": "Tendril Company", + "city": { + "name": "North Street", + "code": "MI", + "state": "Michigan", + "county": "Saint Clair", + "display": "Clyde" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1318367632851549441-968", + "name": "Graematter, Inc", + "city": { + "name": "Hatch", + "code": "NM", + "state": "New Mexico", + "county": "Dona Ana", + "display": "Rodey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2694237227921611212-969", + "name": "FlightAware LLC", + "city": { + "name": "Feasterville Trevose", + "code": "PA", + "state": "Pennsylvania", + "county": "Bucks", + "display": "Oakford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7467625139416622266-970", + "name": "InnoCentive LLC", + "city": { + "name": "Huntsville", + "code": "MO", + "state": "Missouri", + "county": "Randolph", + "display": "Huntsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2623728443361602654-971", + "name": "Spokeo LLC", + "city": { + "name": "Nimrod", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Nimrod" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7327592846631631908-972", + "name": "Equifax Inc", + "city": { + "name": "Newington", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Newington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7109300009718090087-973", + "name": "The DocGraph Journal Inc", + "city": { + "name": "Seattle", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Diagnos Techs Inc Mrs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1308867412526560682-974", + "name": "Liquid Robotics LLC", + "city": { + "name": "New Orleans", + "code": "LA", + "state": "Louisiana", + "county": "Orleans", + "display": "University Of New Orleans" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5440052709930906827-975", + "name": "Xcential Incorporated", + "city": { + "name": "Floydada", + "code": "TX", + "state": "Texas", + "county": "Floyd", + "display": "Floydada" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5818000834446044753-976", + "name": "AutoGrid Systems Company", + "city": { + "name": "Milford Center", + "code": "OH", + "state": "Ohio", + "county": "Union", + "display": "Milford Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7993270344746440601-977", + "name": "SimpleTuition Corporation", + "city": { + "name": "Spanish Fork", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Cover Bridge Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1674247181549017100-978", + "name": "MetLife Incorporated", + "city": { + "name": "Wilmington", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Custer Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7242566314863271134-979", + "name": "Relationship Science LLC", + "city": { + "name": "Unalakleet", + "code": "AK", + "state": "Alaska", + "county": "Nome", + "display": "Unalakleet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3681527339933325505-980", + "name": "5PSolutions Corp", + "city": { + "name": "Sunbury", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Augustaville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6642368765562709634-981", + "name": "Bing Corporation", + "city": { + "name": "Page", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Lake Powell Mart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6796150872971690848-982", + "name": "MuckRock.com Corporation", + "city": { + "name": "Ramsey", + "code": "IL", + "state": "Illinois", + "county": "Fayette", + "display": "Bayle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2770203625244951442-983", + "name": "Genability LLC", + "city": { + "name": "Dahlonega", + "code": "GA", + "state": "Georgia", + "county": "Lumpkin", + "display": "North Georgia College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6900483483283279297-984", + "name": "Junar, Incorporated", + "city": { + "name": "SLC", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "Slc" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3893467375356592134-985", + "name": "Robinson + Yu Corporation", + "city": { + "name": "Lapeer", + "code": "MI", + "state": "Michigan", + "county": "Lapeer", + "display": "Lake Nepessing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8548975259543650387-986", + "name": "HealthMap Inc", + "city": { + "name": "Winona", + "code": "MN", + "state": "Minnesota", + "county": "Winona", + "display": "Wilson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-620595605847754742-987", + "name": "Simple Energy Company", + "city": { + "name": "Grand Mound", + "code": "IA", + "state": "Iowa", + "county": "Clinton", + "display": "Grand Mound" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8814650694585338974-988", + "name": "Merrill Corp", + "city": { + "name": "Beach Haven", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Harvey Cedars Boro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3892406254638218692-989", + "name": "Walk Score Company", + "city": { + "name": "Carthage", + "code": "IL", + "state": "Illinois", + "county": "Hancock", + "display": "Mccall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1040877729128214977-990", + "name": "FlightStats LLC", + "city": { + "name": "Granite Falls", + "code": "NC", + "state": "North Carolina", + "county": "Caldwell", + "display": "Granite Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-881320594813891271-991", + "name": "Morgan Stanley Inc", + "city": { + "name": "Hasty", + "code": "CO", + "state": "Colorado", + "county": "Bent", + "display": "Hasty" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6166783816237373526-992", + "name": "Cloudmade Corp", + "city": { + "name": "Catawissa", + "code": "PA", + "state": "Pennsylvania", + "county": "Columbia", + "display": "Catawissa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4249164200304205041-993", + "name": "POPVOX Corp", + "city": { + "name": "Bardstown", + "code": "KY", + "state": "Kentucky", + "county": "Nelson", + "display": "Bardstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7297119676978691257-994", + "name": "Propeller Health Inc", + "city": { + "name": "Whitestone", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Flushing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8189837715053737745-995", + "name": "Adobe Digital Government Inc", + "city": { + "name": "Garland City", + "code": "AR", + "state": "Arkansas", + "county": "Miller", + "display": "Garland City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-31991279131700126-996", + "name": "Bridgewater Corporation", + "city": { + "name": "Jumping Branch", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Streeter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4731829942812618173-997", + "name": "StreetEasy LLC", + "city": { + "name": "Brazil", + "code": "IN", + "state": "Indiana", + "county": "Clay", + "display": "Hoosierville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5831102281549117758-998", + "name": "Center for Responsive Politics LLC", + "city": { + "name": "Mechanicville", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Malta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2031097331815513126-999", + "name": "Predilytics Incorporated", + "city": { + "name": "Marion", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7377958001675530303-1000", + "name": "TrialTrove Company", + "city": { + "name": "Blakesburg", + "code": "IA", + "state": "Iowa", + "county": "Wapello", + "display": "Munterville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2493353340745488436-1001", + "name": "Healthgrades LLC", + "city": { + "name": "Buffalo", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "University Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1878094983705335907-1002", + "name": "Kroll Bond Ratings Agency Corp", + "city": { + "name": "New Hyde Park", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Hillside Manor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-687649228099113225-1003", + "name": "Food+Tech Connect LLC", + "city": { + "name": "Xenia", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Sugarcreek Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-686181139968619051-1004", + "name": "Locavore LLC", + "city": { + "name": "Crested Butte", + "code": "CO", + "state": "Colorado", + "county": "Gunnison", + "display": "Cement Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4426289520483379215-1005", + "name": "Berkshire Hathaway Company", + "city": { + "name": "North Richland Hills", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Fort Worth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4855820520886898177-1006", + "name": "SmartProcure Company", + "city": { + "name": "Mount Freedom", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Mount Freedom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7368955052603064649-1007", + "name": "indoo.rs Company", + "city": { + "name": "Westport", + "code": "SD", + "state": "South Dakota", + "county": "Brown", + "display": "Westport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5842638837747203769-1008", + "name": "OpportunitySpace, LLC", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "North College Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9157109808431615590-1009", + "name": "ASC Partners Incorporated", + "city": { + "name": "Boise", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Intermountain Gas Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2191326183785330677-1010", + "name": "SnapSense LLC", + "city": { + "name": "Haltom City", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "N Richland Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3526406646607909592-1011", + "name": "Porch Company", + "city": { + "name": "West Portsmouth", + "code": "OH", + "state": "Ohio", + "county": "Scioto", + "display": "Portsmouth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8209623211080338184-1012", + "name": "Mapbox Incorporated", + "city": { + "name": "Parowan", + "code": "UT", + "state": "Utah", + "county": "Iron", + "display": "Parowan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8056810507064755208-1013", + "name": "BlackRock Inc", + "city": { + "name": "Jericho", + "code": "VT", + "state": "Vermont", + "county": "Chittenden", + "display": "Jericho Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7148192476497697997-1014", + "name": "Merrill Incorporated", + "city": { + "name": "Milroy", + "code": "MN", + "state": "Minnesota", + "county": "Redwood", + "display": "Milroy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7698244462939305658-1015", + "name": "Buildingeye Corporation", + "city": { + "name": "Royal Palm Beach", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "West Palm Bch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-866989859833528275-1016", + "name": "indoo.rs LLC", + "city": { + "name": "Gouldsboro", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "S Gouldsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9160784492833185947-1017", + "name": "CliniCast Corporation", + "city": { + "name": "Garrett", + "code": "IN", + "state": "Indiana", + "county": "De Kalb", + "display": "Dutch Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7861563959399470704-1018", + "name": "MicroBilt Corp", + "city": { + "name": "Tyronza", + "code": "AR", + "state": "Arkansas", + "county": "Poinsett", + "display": "Tyronza" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1032875996780651411-1019", + "name": "Earth Networks Incorporated", + "city": { + "name": "Truckee", + "code": "CA", + "state": "California", + "county": "Nevada", + "display": "Prosser Lakeview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-577102122230692185-1020", + "name": "Cloudspyre Company", + "city": { + "name": "Hemphill", + "code": "TX", + "state": "Texas", + "county": "Sabine", + "display": "East Mayfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-982396958282248026-1021", + "name": "Knoema Company", + "city": { + "name": "Millington", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "Kerrville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3775431968163699184-1022", + "name": "BetterLesson Incorporated", + "city": { + "name": "Lake Nebagamon", + "code": "WI", + "state": "Wisconsin", + "county": "Douglas", + "display": "Lake Nebagamon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3319764459615841402-1023", + "name": "ProgrammableWeb Corp", + "city": { + "name": "Hershey", + "code": "NE", + "state": "Nebraska", + "county": "Lincoln", + "display": "Hershey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7483182354159444224-1024", + "name": "Environmental Data Resources Incorporated", + "city": { + "name": "Malta", + "code": "ID", + "state": "Idaho", + "county": "Cassia", + "display": "Malta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2163213464577242930-1025", + "name": "Morningstar, Incorporated", + "city": { + "name": "Pilot Mountain", + "code": "NC", + "state": "North Carolina", + "county": "Surry", + "display": "Pilot Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7323950966577758448-1026", + "name": "Forrester Research Corp", + "city": { + "name": "Middleville", + "code": "NY", + "state": "New York", + "county": "Herkimer", + "display": "Fairfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5460533399752966318-1027", + "name": "Synthicity Inc", + "city": { + "name": "Texarkana", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Red River Army Depot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4320319665907679177-1028", + "name": "Fitch Incorporated", + "city": { + "name": "Greenup", + "code": "KY", + "state": "Kentucky", + "county": "Greenup", + "display": "Lloyd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4146550734421980987-1029", + "name": "Abt Associates LLC", + "city": { + "name": "Jamesport", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Jamesport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1542334526260159428-1030", + "name": "Healthgrades LLC", + "city": { + "name": "Offerle", + "code": "KS", + "state": "Kansas", + "county": "Edwards", + "display": "Offerle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8350218206574583838-1031", + "name": "xDayta Inc", + "city": { + "name": "Brigham City", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Perry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2531561633721340867-1032", + "name": "FarmLogs LLC", + "city": { + "name": "Yakima", + "code": "WA", + "state": "Washington", + "county": "Yakima", + "display": "Tampico" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7650574574314946545-1033", + "name": "Citigroup Incorporated", + "city": { + "name": "Oxford", + "code": "NE", + "state": "Nebraska", + "county": "Furnas", + "display": "Reuben" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6841194590407591807-1034", + "name": "TagniFi Incorporated", + "city": { + "name": "Joes", + "code": "CO", + "state": "Colorado", + "county": "Yuma", + "display": "Joes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3339663105135812978-1035", + "name": "Bekins Corporation", + "city": { + "name": "Piermont", + "code": "NH", + "state": "New Hampshire", + "county": "Grafton", + "display": "Piermont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2056670301583501721-1036", + "name": "ASC Partners Incorporated", + "city": { + "name": "New Haven", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "New Haven" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6085113677086536578-1037", + "name": "Headlight LLC", + "city": { + "name": "Bondurant", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Bondurant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8157164574692405041-1038", + "name": "Wolfram Research Company", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Alder Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5593291853297810972-1039", + "name": "Charles Schwab Inc", + "city": { + "name": "Death Valley", + "code": "CA", + "state": "California", + "county": "Inyo", + "display": "Death Valley Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1977349163680789267-1040", + "name": "SAP Corp", + "city": { + "name": "Kellerman", + "code": "AL", + "state": "Alabama", + "county": "Tuscaloosa", + "display": "Searles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3652904448901338127-1041", + "name": "Charles River Associates Inc", + "city": { + "name": "Williamstown", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Williamstn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5636008941527517312-1042", + "name": "HealthPocket, LLC", + "city": { + "name": "Anderson Island", + "code": "WA", + "state": "Washington", + "county": "Pierce", + "display": "Anderson Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6800202799954210987-1043", + "name": "Collective IP Incorporated", + "city": { + "name": "Benoit", + "code": "WI", + "state": "Wisconsin", + "county": "Bayfield", + "display": "Mason" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3020618262960841561-1044", + "name": "KPMG Company", + "city": { + "name": "Confluence", + "code": "PA", + "state": "Pennsylvania", + "county": "Somerset", + "display": "Listonburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-203443852889972478-1045", + "name": "Outline Company", + "city": { + "name": "Hampton", + "code": "IA", + "state": "Iowa", + "county": "Franklin", + "display": "Hansell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3631199818945667169-1046", + "name": "RAND Incorporated", + "city": { + "name": "Penn Yan", + "code": "NY", + "state": "New York", + "county": "Yates", + "display": "Penn Yan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7065460442057022437-1047", + "name": "StreetEasy Corporation", + "city": { + "name": "Oshkosh", + "code": "NE", + "state": "Nebraska", + "county": "Garden", + "display": "Penn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4013834279075561883-1048", + "name": "Kaiser Permanante Corporation", + "city": { + "name": "Coal City", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Daggett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4971918070162503190-1049", + "name": "Ez-XBRL Corporation", + "city": { + "name": "New Cumberland", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Nw Cumb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8311338236534895246-1050", + "name": "Zurich Insurance LLC", + "city": { + "name": "Lancaster", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Eden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4543622933258796349-1051", + "name": "Simple Energy Corp", + "city": { + "name": "Frazee", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Frazee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3564998021934155878-1052", + "name": "Kaiser Permanante Corporation", + "city": { + "name": "Hagatna", + "code": "GU", + "state": "Guam", + "county": "Guam", + "display": "Agana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6548258246278403090-1053", + "name": "North American Van Lines Corporation", + "city": { + "name": "Thurman", + "code": "IA", + "state": "Iowa", + "county": "Fremont", + "display": "Bartlett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7816093362882738785-1054", + "name": "Knowledge Agency LLC", + "city": { + "name": "Beaumont", + "code": "KY", + "state": "Kentucky", + "county": "Metcalfe", + "display": "Beaumont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8541331535091297298-1055", + "name": "T. Rowe Price Incorporated", + "city": { + "name": "Smiths Grove", + "code": "KY", + "state": "Kentucky", + "county": "Warren", + "display": "Smiths Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4494486465198322799-1056", + "name": "Appallicious Corporation", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "Triborough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-208768941612829988-1057", + "name": "IFI CLAIMS Patent Services Company", + "city": { + "name": "Los Alamos", + "code": "NM", + "state": "New Mexico", + "county": "Los Alamos", + "display": "Bandelier National Monument" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6621512119733687545-1058", + "name": "LexisNexis Company", + "city": { + "name": "Charlemont", + "code": "MA", + "state": "Massachusetts", + "county": "Franklin", + "display": "West Hawley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5337404472445820825-1059", + "name": "Morningstar, Incorporated", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Wilkes University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4976791997513996067-1060", + "name": "Civic Impulse Incorporated", + "city": { + "name": "Voorhees", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Kirkwd Vrhes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4689060277500521369-1061", + "name": "Predilytics Inc", + "city": { + "name": "Fairchance", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Fairchance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-203180639991824528-1062", + "name": "Fuzion Apps, LLC", + "city": { + "name": "Garden Valley", + "code": "ID", + "state": "Idaho", + "county": "Boise", + "display": "Garden Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2111460869681061175-1063", + "name": "NextBus Incorporated", + "city": { + "name": "Williamsburg", + "code": "MI", + "state": "Michigan", + "county": "Grand Traverse", + "display": "Williamsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6364827484858509902-1064", + "name": "College Board Incorporated", + "city": { + "name": "Paramus", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Paramus" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5541982245608056673-1065", + "name": "LoopNet Company", + "city": { + "name": "Walthall", + "code": "MS", + "state": "Mississippi", + "county": "Webster", + "display": "Walthall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8031325334928935577-1066", + "name": "CoreLogic LLC", + "city": { + "name": "Banner Elk", + "code": "NC", + "state": "North Carolina", + "county": "Avery", + "display": "Elk Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3265159012623985092-1067", + "name": "Zurich Insurance Corporation", + "city": { + "name": "Lone Tree", + "code": "CO", + "state": "Colorado", + "county": "Douglas", + "display": "Lone Tree" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8811209540725221628-1068", + "name": "karmadata LLC", + "city": { + "name": "West Topsham", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "East Orange" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5112613338779482124-1069", + "name": "Garmin Corp", + "city": { + "name": "Pavo", + "code": "GA", + "state": "Georgia", + "county": "Thomas", + "display": "Pavo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5131124766588782952-1070", + "name": "Weather Decision Technologies Corp", + "city": { + "name": "Philadelphia", + "code": "MS", + "state": "Mississippi", + "county": "Neshoba", + "display": "Choctaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5206439478102799406-1071", + "name": "Fidelity Investments Company", + "city": { + "name": "Piedmont", + "code": "SC", + "state": "South Carolina", + "county": "Greenville", + "display": "Piedmont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1568655386250090712-1072", + "name": "Amazon Web Services Corp", + "city": { + "name": "Orange", + "code": "MA", + "state": "Massachusetts", + "county": "Franklin", + "display": "Blissville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-24509331264796096-1073", + "name": "Junar, Corporation", + "city": { + "name": "Elkader", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Clayton Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8336102421136652454-1074", + "name": "Trintech Corp", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Commerce" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6724786162922057868-1075", + "name": "Onvia Incorporated", + "city": { + "name": "Chapmanville", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Chapmanville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2293352039863049154-1076", + "name": "SAP Incorporated", + "city": { + "name": "Chatom", + "code": "AL", + "state": "Alabama", + "county": "Washington", + "display": "Chatom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3018511751917659766-1077", + "name": "GreatSchools Corporation", + "city": { + "name": "Bloomville", + "code": "OH", + "state": "Ohio", + "county": "Seneca", + "display": "Bloomville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8049180129762351638-1078", + "name": "Aquicore Company", + "city": { + "name": "Reidsville", + "code": "NC", + "state": "North Carolina", + "county": "Rockingham", + "display": "Monroeton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5821953793903148701-1079", + "name": "ASC Partners Company", + "city": { + "name": "Schodack Landing", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Schodack Lndg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6145812935306729718-1080", + "name": "Mapbox Inc", + "city": { + "name": "Eagle Bridge", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "White Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4202191017964360241-1081", + "name": "WattzOn Incorporated", + "city": { + "name": "Mcdaniel", + "code": "MD", + "state": "Maryland", + "county": "Talbot", + "display": "Mcdaniel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1484362048814813771-1082", + "name": "Peterson's Corp", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Xerox" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1068850311953820727-1083", + "name": "FutureAdvisor Company", + "city": { + "name": "Twilight", + "code": "WV", + "state": "West Virginia", + "county": "Boone", + "display": "Twilight" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1837085233502125058-1084", + "name": "HDScores, Inc", + "city": { + "name": "Bishopville", + "code": "SC", + "state": "South Carolina", + "county": "Lee", + "display": "Ashland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2970073639417935613-1085", + "name": "Knoema Inc", + "city": { + "name": "Falls", + "code": "PA", + "state": "Pennsylvania", + "county": "Wyoming", + "display": "Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7830817467687560859-1086", + "name": "State Farm Insurance Company", + "city": { + "name": "Monmouth Junction", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "Monmouth Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6206458759475426456-1087", + "name": "Amida Technology Solutions Corporation", + "city": { + "name": "Knoxville", + "code": "TN", + "state": "Tennessee", + "county": "Knox", + "display": "Lonsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6606207698454827902-1088", + "name": "Overture Technologies Corp", + "city": { + "name": "Grandview", + "code": "IN", + "state": "Indiana", + "county": "Spencer", + "display": "Newtonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-92645153844815171-1089", + "name": "Simple Energy Inc", + "city": { + "name": "Brush Creek", + "code": "TN", + "state": "Tennessee", + "county": "Smith", + "display": "Brush Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6654602235858267406-1090", + "name": "Chemical Abstracts Service Company", + "city": { + "name": "New Augusta", + "code": "MS", + "state": "Mississippi", + "county": "Perry", + "display": "Wingate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9221796198634757998-1091", + "name": "Moody's LLC", + "city": { + "name": "Reinholds", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Vinemont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6657674809496537260-1092", + "name": "NonprofitMetrics Incorporated", + "city": { + "name": "Four Lakes", + "code": "WA", + "state": "Washington", + "county": "Spokane", + "display": "Four Lakes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-153374026816631710-1093", + "name": "BaleFire Global Corporation", + "city": { + "name": "Kincheloe", + "code": "MI", + "state": "Michigan", + "county": "Chippewa", + "display": "Sault S Marie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4380950075233817089-1094", + "name": "IMS Health LLC", + "city": { + "name": "Harlingen", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Avondale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7931175086771856082-1095", + "name": "Weather Decision Technologies Inc", + "city": { + "name": "Thompson", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Thompson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5673032653922028091-1096", + "name": "gRadiant Research Inc", + "city": { + "name": "Kane", + "code": "IL", + "state": "Illinois", + "county": "Greene", + "display": "Old Kane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7497142883454927133-1097", + "name": "Trulia Inc", + "city": { + "name": "Malad City", + "code": "ID", + "state": "Idaho", + "county": "Oneida", + "display": "Daniels" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4183784549742771599-1098", + "name": "Docket Alarm, Corp", + "city": { + "name": "New Cumberland", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "N Cumberld" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8523167729090861858-1099", + "name": "Panjiva Incorporated", + "city": { + "name": "Bancroft", + "code": "ID", + "state": "Idaho", + "county": "Caribou", + "display": "Chesterfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-925872822137016918-1100", + "name": "ProPublica Incorporated", + "city": { + "name": "Nordheim", + "code": "TX", + "state": "Texas", + "county": "De Witt", + "display": "Nordheim" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3114484604713401658-1101", + "name": "Abt Associates LLC", + "city": { + "name": "Hiawatha", + "code": "KS", + "state": "Kansas", + "county": "Brown", + "display": "Hamlin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6721491203371992242-1102", + "name": "TopCoder Company", + "city": { + "name": "Bellevue", + "code": "MI", + "state": "Michigan", + "county": "Eaton", + "display": "Bellevue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4714242887731957635-1103", + "name": "eScholar Company", + "city": { + "name": "San Pablo", + "code": "CA", + "state": "California", + "county": "Contra Costa", + "display": "Richmond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7112166964364161772-1104", + "name": "FarmLogs Corp", + "city": { + "name": "Staunton", + "code": "VA", + "state": "Virginia", + "county": "Staunton City", + "display": "Staunton Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1319305694895125907-1105", + "name": "The DocGraph Journal Corp", + "city": { + "name": "Coal Township", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Excelsior" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-241909480135285955-1106", + "name": "Roadify Transit Company", + "city": { + "name": "Watervliet", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Maplewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3828332978661038054-1107", + "name": "HDScores, Inc", + "city": { + "name": "Yellow Spring", + "code": "WV", + "state": "West Virginia", + "county": "Hampshire", + "display": "Lehew" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1940719892710581569-1108", + "name": "Citigroup Corporation", + "city": { + "name": "North Canton", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Lake Slagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9065134515749655510-1109", + "name": "Zonability Inc", + "city": { + "name": "Andover", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Internal Revenue Service" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2382845873265981320-1110", + "name": "Garmin Company", + "city": { + "name": "Clare", + "code": "IA", + "state": "Iowa", + "county": "Webster", + "display": "Clare" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-472947312200267112-1111", + "name": "Boston Consulting Group LLC", + "city": { + "name": "Pohnpei", + "code": "FM", + "state": "Federated States of Micronesia", + "county": "Federated States Of Micro", + "display": "Pohnpei" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7672858467026725480-1112", + "name": "HealthMap Corp", + "city": { + "name": "Minerva", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Pekin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4020288340758326525-1113", + "name": "Orlin Research LLC", + "city": { + "name": "Canaan", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Canaan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1811561140056335479-1114", + "name": "FindTheBest.com Inc", + "city": { + "name": "Eagleville", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Eagleville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9120219648776877502-1115", + "name": "Rivet Software Incorporated", + "city": { + "name": "Griffithville", + "code": "AR", + "state": "Arkansas", + "county": "White", + "display": "Griffithville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4882415291252301517-1116", + "name": "PayScale, Incorporated", + "city": { + "name": "Moundville", + "code": "AL", + "state": "Alabama", + "county": "Hale", + "display": "Havana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1001034047234745644-1117", + "name": "IW Financial Corp", + "city": { + "name": "Marthaville", + "code": "LA", + "state": "Louisiana", + "county": "Natchitoches", + "display": "Ajax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7033380284812068652-1118", + "name": "Construction Monitor Inc", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Creekside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1938982042973824917-1119", + "name": "MetLife LLC", + "city": { + "name": "Pacific Beach", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Aloha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5935656948831849085-1120", + "name": "U.S. News Schools Company", + "city": { + "name": "Mahanoy City", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Morea Colliery" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5633098278568570735-1121", + "name": "J.P. Morgan Chase Inc", + "city": { + "name": "Novinger", + "code": "MO", + "state": "Missouri", + "county": "Adair", + "display": "Stahl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-731312645694865169-1122", + "name": "Allianz Company", + "city": { + "name": "Holland", + "code": "TX", + "state": "Texas", + "county": "Bell", + "display": "Vilas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4892085788225506489-1123", + "name": "Chubb Corporation", + "city": { + "name": "Houtzdale", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Ginter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6155652896986507537-1124", + "name": "Datamyne Corp", + "city": { + "name": "West Wardsboro", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "Stratton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2001692751046115982-1125", + "name": "TrustedID Company", + "city": { + "name": "Mounds", + "code": "IL", + "state": "Illinois", + "county": "Pulaski", + "display": "Mounds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-423105889613620578-1126", + "name": "Environmental Data Resources Company", + "city": { + "name": "Ontario", + "code": "NY", + "state": "New York", + "county": "Wayne", + "display": "Ontario" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6909868992139203350-1127", + "name": "Maponics Corp", + "city": { + "name": "Huntley", + "code": "WY", + "state": "Wyoming", + "county": "Goshen", + "display": "Huntley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3200748485036130960-1128", + "name": "Spikes Cavell Analytic Inc", + "city": { + "name": "Indianola", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Baird" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1212162144323113842-1129", + "name": "PatientsLikeMe Inc", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Richmond Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8502512828210716217-1130", + "name": "Equifax Company", + "city": { + "name": "Northbrook", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Northbrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2840019999038025631-1131", + "name": "Graebel Van Lines Inc", + "city": { + "name": "Newland", + "code": "NC", + "state": "North Carolina", + "county": "Avery", + "display": "Stamey Branch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6426297717023538110-1132", + "name": "Estately Corporation", + "city": { + "name": "Woods Cross", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "West Bountiful" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2580712499044548323-1133", + "name": "Equifax Corporation", + "city": { + "name": "West Jordan", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "West Valley City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4612756829220513104-1134", + "name": "Environmental Data Resources Corp", + "city": { + "name": "Franklinton", + "code": "NC", + "state": "North Carolina", + "county": "Franklin", + "display": "Franklinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7310359268935231539-1135", + "name": "Canon LLC", + "city": { + "name": "Yadkinville", + "code": "NC", + "state": "North Carolina", + "county": "Yadkin", + "display": "Footsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-67043564359168861-1136", + "name": "Relationship Science Company", + "city": { + "name": "Bellemont", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Flagstaff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5007503141156804164-1137", + "name": "USSearch Inc", + "city": { + "name": "Graceville", + "code": "FL", + "state": "Florida", + "county": "Jackson", + "display": "Graceville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7251662185973215361-1138", + "name": "Intelius Corporation", + "city": { + "name": "Arrow Rock", + "code": "MO", + "state": "Missouri", + "county": "Saline", + "display": "Arrow Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8874149553478097845-1139", + "name": "Enigma.io LLC", + "city": { + "name": "Mc Intire", + "code": "IA", + "state": "Iowa", + "county": "Mitchell", + "display": "Mc Intire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5544710637697766277-1140", + "name": "GoodGuide Company", + "city": { + "name": "West Lebanon", + "code": "NH", + "state": "New Hampshire", + "county": "Grafton", + "display": "West Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-709241009802263317-1141", + "name": "Zebu Compliance Solutions Corp", + "city": { + "name": "Karnes City", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Karnes City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9086858669604500345-1142", + "name": "Abt Associates Corp", + "city": { + "name": "Blue Mound", + "code": "IL", + "state": "Illinois", + "county": "Macon", + "display": "Blue Mound" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2690353728724673132-1143", + "name": "The DocGraph Journal Incorporated", + "city": { + "name": "Yorktown", + "code": "VA", + "state": "Virginia", + "county": "York", + "display": "Nav Wpns Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1645313735960068920-1144", + "name": "Aureus Sciences Corporation", + "city": { + "name": "Eddyville", + "code": "KY", + "state": "Kentucky", + "county": "Lyon", + "display": "Confederate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7385637114424186352-1145", + "name": "Code for America Incorporated", + "city": { + "name": "Fresno", + "code": "OH", + "state": "Ohio", + "county": "Coshocton", + "display": "New Bedford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7521501937549480354-1146", + "name": "Social Health Insights Incorporated", + "city": { + "name": "Oxford", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Oxford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-19105281905989297-1147", + "name": "IBM LLC", + "city": { + "name": "Crumpton", + "code": "MD", + "state": "Maryland", + "county": "Queen Annes", + "display": "Crumpton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4908163202341785132-1148", + "name": "realtor.com Inc", + "city": { + "name": "Colorado Springs", + "code": "CO", + "state": "Colorado", + "county": "El Paso", + "display": "Cheyenne Mtn AFB" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-12552941242092778-1149", + "name": "Suddath Corporation", + "city": { + "name": "Drums", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Drums" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7531582785827265062-1150", + "name": "OnDeck Corporation", + "city": { + "name": "Holland", + "code": "TX", + "state": "Texas", + "county": "Bell", + "display": "Vilas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-434017135132014255-1151", + "name": "Stevens Worldwide Van Lines Corp", + "city": { + "name": "Forestport", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Forestport Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8192137570717875619-1152", + "name": "IMS Health Inc", + "city": { + "name": "Marietta", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Marietta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8137913882617911504-1153", + "name": "DataLogix Corporation", + "city": { + "name": "Wewahitchka", + "code": "FL", + "state": "Florida", + "county": "Calhoun", + "display": "Kinard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1021462805714470695-1154", + "name": "Politify Incorporated", + "city": { + "name": "Yorkshire", + "code": "OH", + "state": "Ohio", + "county": "Darke", + "display": "Yorkshire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6600964856791854846-1155", + "name": "Personal Democracy Media Corporation", + "city": { + "name": "Fargo", + "code": "ND", + "state": "North Dakota", + "county": "Cass", + "display": "Reiles Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8812308039343317011-1156", + "name": "Reed Elsevier Incorporated", + "city": { + "name": "Hawthorne", + "code": "NV", + "state": "Nevada", + "county": "Mineral", + "display": "Babbitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4870963286725653088-1157", + "name": "Harris Corp", + "city": { + "name": "New Raymer", + "code": "CO", + "state": "Colorado", + "county": "Weld", + "display": "Raymer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6613309035613251195-1158", + "name": "Alarm.com LLC", + "city": { + "name": "Darden", + "code": "TN", + "state": "Tennessee", + "county": "Henderson", + "display": "Darden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1215614037387627718-1159", + "name": "Avalara Corporation", + "city": { + "name": "Terry", + "code": "MS", + "state": "Mississippi", + "county": "Hinds", + "display": "Terry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1412611281400282484-1160", + "name": "Thinknum Corp", + "city": { + "name": "Emerson", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Emerson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7900391028516178146-1161", + "name": "Iodine Corp", + "city": { + "name": "Hightstown", + "code": "NJ", + "state": "New Jersey", + "county": "Mercer", + "display": "Hightstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6636941984584733480-1162", + "name": "Adaptive Corporation", + "city": { + "name": "Switchback", + "code": "WV", + "state": "West Virginia", + "county": "Mcdowell", + "display": "Switchback" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4772934432398856168-1163", + "name": "WeMakeItSafer Inc", + "city": { + "name": "Grinnell", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Newburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9074435641484475235-1164", + "name": "SpaceCurve Corporation", + "city": { + "name": "Jericho", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Uhc Berdon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-756718882237209497-1165", + "name": "Nautilytics Corporation", + "city": { + "name": "Providence", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Friar Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-528831433651332778-1166", + "name": "MuckRock.com Company", + "city": { + "name": "Gregory", + "code": "SD", + "state": "South Dakota", + "county": "Gregory", + "display": "Carlock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3278978332861979644-1167", + "name": "Wheaton World Wide Moving Incorporated", + "city": { + "name": "Stockholm", + "code": "SD", + "state": "South Dakota", + "county": "Grant", + "display": "Stockholm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-877315375733958199-1168", + "name": "Standard and Poor's Corp", + "city": { + "name": "Utica", + "code": "NE", + "state": "Nebraska", + "county": "Seward", + "display": "Utica" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2230466217549357178-1169", + "name": "Mozio Corp", + "city": { + "name": "Chicago Heights", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Ford Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8873483403050213731-1170", + "name": "Seabourne Incorporated", + "city": { + "name": "Camarillo", + "code": "CA", + "state": "California", + "county": "Ventura", + "display": "Santa Rosa Va" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3533749048293616083-1171", + "name": "Government Transaction Services Inc", + "city": { + "name": "Rangeley", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "Sandy Rvr Plt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3698697428350720245-1172", + "name": "Lending Club Company", + "city": { + "name": "Lodi", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Lodi" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1000677720796418992-1173", + "name": "TrustedID LLC", + "city": { + "name": "Bainbridge", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "West Bainbridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6421532958299159319-1174", + "name": "Socrata Inc", + "city": { + "name": "Syracuse", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Carousel Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3873433166015149814-1175", + "name": "PlaceILive.com Company", + "city": { + "name": "Scranton", + "code": "ND", + "state": "North Dakota", + "county": "Bowman", + "display": "Gascoyne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7954260493099166606-1176", + "name": "CoreLogic Company", + "city": { + "name": "Moxee", + "code": "WA", + "state": "Washington", + "county": "Yakima", + "display": "Moxee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2942074799632507943-1177", + "name": "Recargo Corp", + "city": { + "name": "Torrance", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Torrance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5894220724841586197-1178", + "name": "WebFilings LLC", + "city": { + "name": "Magdalena", + "code": "NM", + "state": "New Mexico", + "county": "Socorro", + "display": "Magdalena" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3843649879513229843-1179", + "name": "Propeller Health Corp", + "city": { + "name": "Fort Wainwright", + "code": "AK", + "state": "Alaska", + "county": "Fairbanks North Star", + "display": "Ft Wainwright" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1208214885384795355-1180", + "name": "TrustedID Incorporated", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis City", + "display": "Courtesy Reply Mail Firms" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9088573044441112812-1181", + "name": "Enervee Company", + "city": { + "name": "Jersey Shore", + "code": "PA", + "state": "Pennsylvania", + "county": "Lycoming", + "display": "Larrys Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5072647400414534092-1182", + "name": "BizVizz Inc", + "city": { + "name": "Hartleton", + "code": "PA", + "state": "Pennsylvania", + "county": "Union", + "display": "Hartleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2739591397900210104-1183", + "name": "FlightAware Corporation", + "city": { + "name": "South Royalton", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "South Royalton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9082155453979254764-1184", + "name": "Google Maps Corp", + "city": { + "name": "Williamstown", + "code": "WV", + "state": "West Virginia", + "county": "Wood", + "display": "Williamstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7657579183656945223-1185", + "name": "Arpin Van Lines Inc", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Adv Comm Inter Govt Relation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6073711884533248856-1186", + "name": "Altova Company", + "city": { + "name": "Riegelwood", + "code": "NC", + "state": "North Carolina", + "county": "Columbus", + "display": "Acme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4881659449667311788-1187", + "name": "Zillow Company", + "city": { + "name": "Walcott", + "code": "WY", + "state": "Wyoming", + "county": "Carbon", + "display": "Walcott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2892812806530261452-1188", + "name": "S\u0026P Capital IQ LLC", + "city": { + "name": "Ligonier", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Ligonier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5892222240357040148-1189", + "name": "Appallicious Corp", + "city": { + "name": "Sumas", + "code": "WA", + "state": "Washington", + "county": "Whatcom", + "display": "Clearbrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3417050814319960266-1190", + "name": "Garmin Inc", + "city": { + "name": "Enumclaw", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Enumclaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8594714561320075952-1191", + "name": "WaterSmart Software Inc", + "city": { + "name": "Hamburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Edenburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6745935324478352307-1192", + "name": "Practice Fusion Corp", + "city": { + "name": "Mount Vernon", + "code": "KY", + "state": "Kentucky", + "county": "Rockcastle", + "display": "Climax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8340637733540361977-1193", + "name": "Lilly Open Innovation Drug Discovery Corp", + "city": { + "name": "Springfield", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "Orchard Lane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6784892608094781191-1194", + "name": "IVES Group Inc", + "city": { + "name": "Southfield", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Southfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7796645780771406211-1195", + "name": "CoreLogic Incorporated", + "city": { + "name": "Braceville", + "code": "IL", + "state": "Illinois", + "county": "Grundy", + "display": "Godley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3029628293557626350-1196", + "name": "Personal, Corp", + "city": { + "name": "Tremont", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Zerbe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4957445761961331428-1197", + "name": "iMedicare LLC", + "city": { + "name": "Electric City", + "code": "WA", + "state": "Washington", + "county": "Grant", + "display": "Electric City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5473076801847519554-1198", + "name": "Collective IP Corp", + "city": { + "name": "Scottdale", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Scottdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4557234454769454793-1199", + "name": "Oliver Wyman Corporation", + "city": { + "name": "Bayport", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Bayport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6457110019065774024-1200", + "name": "CrowdANALYTIX Inc", + "city": { + "name": "Birmingham", + "code": "AL", + "state": "Alabama", + "county": "Jefferson", + "display": "Cahaba Hts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5647325315032446698-1201", + "name": "Graebel Van Lines Company", + "city": { + "name": "Saint Leo", + "code": "FL", + "state": "Florida", + "county": "Pasco", + "display": "Saint Leo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4318828525196647742-1202", + "name": "Equilar Incorporated", + "city": { + "name": "Lake Clear", + "code": "NY", + "state": "New York", + "county": "Franklin", + "display": "Upper St Reg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4566643891350953160-1203", + "name": "Junar, Corporation", + "city": { + "name": "Petersburg", + "code": "WV", + "state": "West Virginia", + "county": "Grant", + "display": "Petersburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6925424220801744873-1204", + "name": "Arrive Labs Corporation", + "city": { + "name": "Jefferson", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Jefferson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1461198425351530150-1205", + "name": "OnDeck Incorporated", + "city": { + "name": "Westville", + "code": "SC", + "state": "South Carolina", + "county": "Kershaw", + "display": "Westville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4668603671589750207-1206", + "name": "ProgrammableWeb Inc", + "city": { + "name": "Middle Point", + "code": "OH", + "state": "Ohio", + "county": "Van Wert", + "display": "Middle Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8809187231290629877-1207", + "name": "Dow Jones \u0026 Co Corp", + "city": { + "name": "Liberty", + "code": "TX", + "state": "Texas", + "county": "Liberty", + "display": "Moss Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4073913370807186279-1208", + "name": "R R Donnelley Company", + "city": { + "name": "Mckinney", + "code": "TX", + "state": "Texas", + "county": "Collin", + "display": "Mc Kinney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3467912548041208351-1209", + "name": "Remi Corp", + "city": { + "name": "Mackinac Island", + "code": "MI", + "state": "Michigan", + "county": "Mackinac", + "display": "Mackinac Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6859503082797291383-1210", + "name": "USSearch Incorporated", + "city": { + "name": "Masonic Home", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Masonic Home" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7149119653631570528-1211", + "name": "AreaVibes Incorporated", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Nys Tax Processing Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5866138048871057182-1212", + "name": "Granicus Company", + "city": { + "name": "Angola", + "code": "IN", + "state": "Indiana", + "county": "Steuben", + "display": "Angola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1392970032882530145-1213", + "name": "Compliance and Risks Corporation", + "city": { + "name": "Harpswell", + "code": "ME", + "state": "Maine", + "county": "Cumberland", + "display": "South Harpswell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6771390010727447541-1214", + "name": "Poncho App Inc", + "city": { + "name": "Corona Del Mar", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Corona Dl Mar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-186115592639377320-1215", + "name": "Cloudmade Inc", + "city": { + "name": "Pleasant Ridge", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Pleasant Rdg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1737084578504854227-1216", + "name": "Accela Inc", + "city": { + "name": "Elkader", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Mederville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5810679218075794205-1217", + "name": "Parsons Brinckerhoff LLC", + "city": { + "name": "Kayenta", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Black Mesa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4904486519077315581-1218", + "name": "Urban Mapping, Company", + "city": { + "name": "Gypsum", + "code": "OH", + "state": "Ohio", + "county": "Ottawa", + "display": "Gypsum" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-732909964824197774-1219", + "name": "Gallup Company", + "city": { + "name": "Redwood", + "code": "VA", + "state": "Virginia", + "county": "Franklin", + "display": "Redwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6822908827298521697-1220", + "name": "Marinexplore, Incorporated", + "city": { + "name": "Saint Bernard", + "code": "LA", + "state": "Louisiana", + "county": "Saint Bernard", + "display": "Reggio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4886535994339519185-1221", + "name": "Ernst \u0026 Young LLP LLC", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Mtn Green" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5909463814165818777-1222", + "name": "Practice Fusion Incorporated", + "city": { + "name": "Spangler", + "code": "PA", + "state": "Pennsylvania", + "county": "Cambria", + "display": "Spangler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6398098165847865044-1223", + "name": "SpotHero.com LLC", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "West Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7818347765918097320-1224", + "name": "Lending Club Inc", + "city": { + "name": "Long Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "East Long Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1867551380647168719-1225", + "name": "FindTheBest.com Company", + "city": { + "name": "Winston Salem", + "code": "NC", + "state": "North Carolina", + "county": "Forsyth", + "display": "Ardmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1354945883733857766-1226", + "name": "VisualDoD, LLC", + "city": { + "name": "Winthrop Harbor", + "code": "IL", + "state": "Illinois", + "county": "Lake", + "display": "Winthrop Hbr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5609889418470768148-1227", + "name": "Chemical Abstracts Service Corp", + "city": { + "name": "Indianapolis", + "code": "IN", + "state": "Indiana", + "county": "Marion", + "display": "Cumberland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6166181411057100347-1228", + "name": "Urban Airship Corporation", + "city": { + "name": "Coalgate", + "code": "OK", + "state": "Oklahoma", + "county": "Coal", + "display": "Phillips" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7469748512072958204-1229", + "name": "SocialEffort Incorporated", + "city": { + "name": "Stephentown", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Stephentown Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3252394919724459204-1230", + "name": "Onvia LLC", + "city": { + "name": "Castor", + "code": "LA", + "state": "Louisiana", + "county": "Bienville", + "display": "Roy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6854478643425791986-1231", + "name": "iFactor Consulting LLC", + "city": { + "name": "Hydetown", + "code": "PA", + "state": "Pennsylvania", + "county": "Crawford", + "display": "Hydetown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7067021397838106794-1232", + "name": "Retroficiency LLC", + "city": { + "name": "Mount Carmel", + "code": "IL", + "state": "Illinois", + "county": "Wabash", + "display": "Maud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2685439770505515950-1233", + "name": "Amazon Web Services Inc", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Worthngtn Hls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7251310948847862279-1234", + "name": "BillGuard Corp", + "city": { + "name": "Mound", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Shorewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6209843430664353487-1235", + "name": "MicroBilt Corp", + "city": { + "name": "Pulaski", + "code": "WI", + "state": "Wisconsin", + "county": "Brown", + "display": "Pulaski" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1039248335667233226-1236", + "name": "Orlin Research Incorporated", + "city": { + "name": "Grandview", + "code": "IN", + "state": "Indiana", + "county": "Spencer", + "display": "Newtonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-43754757156582510-1237", + "name": "USSearch Corp", + "city": { + "name": "Hi Hat", + "code": "KY", + "state": "Kentucky", + "county": "Floyd", + "display": "Hi Hat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8981508418491254011-1238", + "name": "FirstPoint, Incorporated", + "city": { + "name": "Bolivia", + "code": "NC", + "state": "North Carolina", + "county": "Brunswick", + "display": "Bolivia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2891003171389796955-1239", + "name": "GetRaised LLC", + "city": { + "name": "Retsil", + "code": "WA", + "state": "Washington", + "county": "Kitsap", + "display": "Retsil" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5646368466189309592-1240", + "name": "GoodGuide Corp", + "city": { + "name": "Green", + "code": "KS", + "state": "Kansas", + "county": "Clay", + "display": "Green" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1889402167586546675-1241", + "name": "SolarList Incorporated", + "city": { + "name": "Hartsburg", + "code": "MO", + "state": "Missouri", + "county": "Boone", + "display": "Wilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3935710304177491303-1242", + "name": "Dun \u0026 Bradstreet LLC", + "city": { + "name": "Williamsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Blair", + "display": "Williamsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8645490517459002672-1243", + "name": "Jurispect Inc", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Wilkes Barre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-26606651514557410-1244", + "name": "SocialEffort Company", + "city": { + "name": "Cataract", + "code": "WI", + "state": "Wisconsin", + "county": "Monroe", + "display": "Cataract" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-927782600915074395-1245", + "name": "Kroll Bond Ratings Agency Inc", + "city": { + "name": "Bagley", + "code": "MN", + "state": "Minnesota", + "county": "Clearwater", + "display": "Zerkel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3252216067035836871-1246", + "name": "PlanetEcosystems Incorporated", + "city": { + "name": "North Evans", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "North Evans" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-58572451421529771-1247", + "name": "Sophic Systems Alliance Corporation", + "city": { + "name": "Piney Fork", + "code": "OH", + "state": "Ohio", + "county": "Jefferson", + "display": "Piney Fork" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3450701776215534863-1248", + "name": "Factset Inc", + "city": { + "name": "Dumont", + "code": "MN", + "state": "Minnesota", + "county": "Traverse", + "display": "Dumont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7518929810041509229-1249", + "name": "Nautilytics Company", + "city": { + "name": "Harvey", + "code": "ND", + "state": "North Dakota", + "county": "Wells", + "display": "Hamberg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5287386219890901192-1250", + "name": "Healthline Corp", + "city": { + "name": "Ruston", + "code": "LA", + "state": "Louisiana", + "county": "Lincoln", + "display": "Vernon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5498672680931205925-1251", + "name": "Overture Technologies Incorporated", + "city": { + "name": "Sioux Center", + "code": "IA", + "state": "Iowa", + "county": "Sioux", + "display": "Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6750769705758523544-1252", + "name": "Practice Fusion Inc", + "city": { + "name": "Lebanon", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Bolton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1476867291086812048-1253", + "name": "CostQuest Company", + "city": { + "name": "Cape Canaveral", + "code": "FL", + "state": "Florida", + "county": "Brevard", + "display": "Cpe Canaveral" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4881033680351815700-1254", + "name": "Lucid Corp", + "city": { + "name": "Wheatland", + "code": "ND", + "state": "North Dakota", + "county": "Cass", + "display": "Wheatland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5917608095681824334-1255", + "name": "Revaluate Corporation", + "city": { + "name": "Verona", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Verona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2342656062524663857-1256", + "name": "iFactor Consulting Corp", + "city": { + "name": "Seahurst", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Burien" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5555433949760931565-1257", + "name": "Nielsen Incorporated", + "city": { + "name": "Ogdensburg", + "code": "WI", + "state": "Wisconsin", + "county": "Waupaca", + "display": "Ogdensburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6196612218578930684-1258", + "name": "Fuzion Apps, Incorporated", + "city": { + "name": "Irvona", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Irvona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1004159824199934239-1259", + "name": "Ranku Corp", + "city": { + "name": "Enumclaw", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Enumclaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6125093932421155468-1260", + "name": "Housefax Corp", + "city": { + "name": "Davis", + "code": "WV", + "state": "West Virginia", + "county": "Tucker", + "display": "Davis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1457068671875373478-1261", + "name": "Socrata Incorporated", + "city": { + "name": "North Charleston", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Chas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7164634124635241612-1262", + "name": "Google Public Data Explorer Company", + "city": { + "name": "Farnhamville", + "code": "IA", + "state": "Iowa", + "county": "Calhoun", + "display": "Farnhamville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3910794232320357506-1263", + "name": "OpenCounter Company", + "city": { + "name": "Rossville", + "code": "TN", + "state": "Tennessee", + "county": "Fayette", + "display": "Rossville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-728167190170906280-1264", + "name": "Housefax Company", + "city": { + "name": "Bradley", + "code": "CA", + "state": "California", + "county": "Monterey", + "display": "Bradley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-476950116041222663-1265", + "name": "Vimo LLC", + "city": { + "name": "Washington Boro", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Washington Boro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2565633263143229678-1266", + "name": "Google Maps Company", + "city": { + "name": "Pacific Beach", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Aloha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5591214601228123784-1267", + "name": "LoopNet Company", + "city": { + "name": "Lynn", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "East Lynn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1859700169480223164-1268", + "name": "Quandl Company", + "city": { + "name": "Stockport", + "code": "OH", + "state": "Ohio", + "county": "Morgan", + "display": "Pennsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6803512300120789173-1269", + "name": "Merrill Corporation", + "city": { + "name": "Netarts", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Netarts Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4003696100443752668-1270", + "name": "Sterling Infosystems Company", + "city": { + "name": "Telford", + "code": "TN", + "state": "Tennessee", + "county": "Washington", + "display": "Telford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8665881003629301112-1271", + "name": "Appallicious Corp", + "city": { + "name": "Meyersville", + "code": "TX", + "state": "Texas", + "county": "De Witt", + "display": "Meyersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8044410085695937249-1272", + "name": "College Board Incorporated", + "city": { + "name": "Mallard", + "code": "IA", + "state": "Iowa", + "county": "Palo Alto", + "display": "Mallard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8939947278224791014-1273", + "name": "Factual Corporation", + "city": { + "name": "Little Rock", + "code": "IA", + "state": "Iowa", + "county": "Lyon", + "display": "Little Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4174793371860748955-1274", + "name": "Navico Corp", + "city": { + "name": "Foresthill", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Todd Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6565505474623142278-1275", + "name": "Govini Corporation", + "city": { + "name": "Fort Worth", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Kenneth Copeland Ministries" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7098630165343947977-1276", + "name": "Xatori LLC", + "city": { + "name": "Putney", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "E Dummerston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6933470076075508602-1277", + "name": "Zoner LLC", + "city": { + "name": "Dorchester Center", + "code": "MA", + "state": "Massachusetts", + "county": "Suffolk", + "display": "Dorchester Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1738622232021850003-1278", + "name": "Recargo Corporation", + "city": { + "name": "Merit", + "code": "TX", + "state": "Texas", + "county": "Hunt", + "display": "Merit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3812155728836948456-1279", + "name": "Relationship Science Corporation", + "city": { + "name": "Ashburnham", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Ashburnham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6252985536703137783-1280", + "name": "Boston Consulting Group Corporation", + "city": { + "name": "Hernando", + "code": "MS", + "state": "Mississippi", + "county": "Desoto", + "display": "Hernando" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-802299108235054401-1281", + "name": "Be Informed LLC", + "city": { + "name": "Wewahitchka", + "code": "FL", + "state": "Florida", + "county": "Calhoun", + "display": "Kinard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4683671131752676713-1282", + "name": "The Vanguard Group Company", + "city": { + "name": "Port Clinton", + "code": "OH", + "state": "Ohio", + "county": "Ottawa", + "display": "Pt Clinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8536504122349810356-1283", + "name": "Charles Schwab Inc", + "city": { + "name": "Marshall", + "code": "IN", + "state": "Indiana", + "county": "Parke", + "display": "Howard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4185144460247541412-1284", + "name": "GovTribe Corporation", + "city": { + "name": "Karlsruhe", + "code": "ND", + "state": "North Dakota", + "county": "Mchenry", + "display": "Karlsruhe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6133241067925831796-1285", + "name": "Altova Inc", + "city": { + "name": "Lahoma", + "code": "OK", + "state": "Oklahoma", + "county": "Garfield", + "display": "Lahoma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4146570165734796573-1286", + "name": "Teradata Company", + "city": { + "name": "New Franklin", + "code": "MO", + "state": "Missouri", + "county": "Howard", + "display": "New Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3245429086435724843-1287", + "name": "Ceiba Solutions Incorporated", + "city": { + "name": "MAFB", + "code": "ND", + "state": "North Dakota", + "county": "Ward", + "display": "Mafb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-373271243985588602-1288", + "name": "PIXIA Incorporated", + "city": { + "name": "Oakwood", + "code": "GA", + "state": "Georgia", + "county": "Hall", + "display": "Oakwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6391757899720754799-1289", + "name": "Microsoft Windows Azure Marketplace Corp", + "city": { + "name": "Georgetown", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Georgetown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1470914953313715178-1290", + "name": "Government Transaction Services LLC", + "city": { + "name": "Roseland", + "code": "FL", + "state": "Florida", + "county": "Indian River", + "display": "Roseland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4589411485168066650-1291", + "name": "Berkery Noyes MandASoft Corp", + "city": { + "name": "Rincon", + "code": "GA", + "state": "Georgia", + "county": "Effingham", + "display": "Rincon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5286285988175165727-1292", + "name": "PlaceILive.com Inc", + "city": { + "name": "Pittstown", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Pittstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1040998313997192612-1293", + "name": "Fuzion Apps, LLC", + "city": { + "name": "Roy", + "code": "UT", + "state": "Utah", + "county": "Weber", + "display": "Roy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3009825560469178757-1294", + "name": "Department of Better Technology LLC", + "city": { + "name": "Henderson", + "code": "AR", + "state": "Arkansas", + "county": "Baxter", + "display": "Henderson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4723049539003435198-1295", + "name": "Moody's Inc", + "city": { + "name": "Mayfield", + "code": "MI", + "state": "Michigan", + "county": "Grand Traverse", + "display": "Mayfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1255680169419955780-1296", + "name": "Sophic Systems Alliance Inc", + "city": { + "name": "Peel", + "code": "AR", + "state": "Arkansas", + "county": "Marion", + "display": "Peel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-611493464268025959-1297", + "name": "iFactor Consulting Corporation", + "city": { + "name": "Larkspur", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Larkspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6154359251130929133-1298", + "name": "DataMarket LLC", + "city": { + "name": "Badger", + "code": "CA", + "state": "California", + "county": "Tulare", + "display": "Miramonte" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6306995098638428957-1299", + "name": "Stevens Worldwide Van Lines Corporation", + "city": { + "name": "Millington", + "code": "MD", + "state": "Maryland", + "county": "Kent", + "display": "Millington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8594644796776317287-1300", + "name": "Avvo Corp", + "city": { + "name": "San Francisco", + "code": "CA", + "state": "California", + "county": "San Francisco", + "display": "Uc San Francisco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8326772823207179735-1301", + "name": "Propeller Health Inc", + "city": { + "name": "Jonesville", + "code": "LA", + "state": "Louisiana", + "county": "Catahoula", + "display": "Manifest" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1657287907662841778-1302", + "name": "realtor.com LLC", + "city": { + "name": "Clinton Corners", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Clinton Crn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5737727157384372607-1303", + "name": "North American Van Lines Corp", + "city": { + "name": "Watertown", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Wtown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1000790370410843661-1304", + "name": "Code for America Company", + "city": { + "name": "Seminole", + "code": "AL", + "state": "Alabama", + "county": "Baldwin", + "display": "Robertsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6937453378281318392-1305", + "name": "iMedicare Corp", + "city": { + "name": "Castor", + "code": "LA", + "state": "Louisiana", + "county": "Bienville", + "display": "Roy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8151763775108192797-1306", + "name": "Geoscape LLC", + "city": { + "name": "Collinsville", + "code": "AL", + "state": "Alabama", + "county": "De Kalb", + "display": "Collinsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8935997412765440927-1307", + "name": "Impaq International Inc", + "city": { + "name": "Manton", + "code": "CA", + "state": "California", + "county": "Tehama", + "display": "Manton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4508733109399453392-1308", + "name": "HealthMap LLC", + "city": { + "name": "Echo", + "code": "UT", + "state": "Utah", + "county": "Summit", + "display": "Echo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5428906331796169892-1309", + "name": "Apextech Inc", + "city": { + "name": "Summitville", + "code": "OH", + "state": "Ohio", + "county": "Columbiana", + "display": "Summitville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2719101028363560582-1310", + "name": "Plus-U Inc", + "city": { + "name": "West Milton", + "code": "PA", + "state": "Pennsylvania", + "county": "Union", + "display": "Lewisburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3377532726691755840-1311", + "name": "Allied Van Lines LLC", + "city": { + "name": "Moosic", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Scranton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8591367330895586193-1312", + "name": "Govzilla, Corporation", + "city": { + "name": "Forest Knolls", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Forest Knolls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-548920835639829848-1313", + "name": "YourMapper Incorporated", + "city": { + "name": "Montgomery", + "code": "AL", + "state": "Alabama", + "county": "Montgomery", + "display": "Maxwell Afb Gunter Annex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1611122744689441508-1314", + "name": "HealthMap Inc", + "city": { + "name": "Lexington", + "code": "NC", + "state": "North Carolina", + "county": "Davidson", + "display": "Lex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7016791748015600340-1315", + "name": "xDayta Corporation", + "city": { + "name": "Port Haywood", + "code": "VA", + "state": "Virginia", + "county": "Mathews", + "display": "Peary" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1818415603160825641-1316", + "name": "Equilar LLC", + "city": { + "name": "Bassett", + "code": "NE", + "state": "Nebraska", + "county": "Rock", + "display": "Rose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3904959679002859803-1317", + "name": "Robinson + Yu LLC", + "city": { + "name": "Eureka", + "code": "KS", + "state": "Kansas", + "county": "Greenwood", + "display": "Reece" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3664832120697581838-1318", + "name": "Stamen Design Incorporated", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Commercial National Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-242395787493867852-1319", + "name": "TopCoder Company", + "city": { + "name": "Windsor", + "code": "OH", + "state": "Ohio", + "county": "Ashtabula", + "display": "Windsor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-967267725031621866-1320", + "name": "OpenGov LLC", + "city": { + "name": "Garrison", + "code": "ND", + "state": "North Dakota", + "county": "Mclean", + "display": "White Sheild" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8423351816462759858-1321", + "name": "Govzilla, Incorporated", + "city": { + "name": "Fredonia", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Pipe Spring National Monumen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8858313994804781107-1322", + "name": "Simple Energy Corporation", + "city": { + "name": "Newport", + "code": "VA", + "state": "Virginia", + "county": "Giles", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2295949590270851158-1323", + "name": "Healthline Corporation", + "city": { + "name": "Jacob", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Neunert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5374795006375433277-1324", + "name": "TrialTrove Corp", + "city": { + "name": "Wallingford", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Nether Providence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6460737378073047685-1325", + "name": "Aidin LLC", + "city": { + "name": "Cambridge", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Weller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8830599137710403571-1326", + "name": "Ayasdi Inc", + "city": { + "name": "Brigham City", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Perry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-64632574898497884-1327", + "name": "Adaptive Corp", + "city": { + "name": "Santa Elena", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "La Gloria" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5266676331517298008-1328", + "name": "TrialTrove Incorporated", + "city": { + "name": "Badin", + "code": "NC", + "state": "North Carolina", + "county": "Stanly", + "display": "Badin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6848149104322516630-1329", + "name": "Bing LLC", + "city": { + "name": "Clermont", + "code": "KY", + "state": "Kentucky", + "county": "Bullitt", + "display": "Clermont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8209202154438861827-1330", + "name": "PublicEngines LLC", + "city": { + "name": "Postville", + "code": "IA", + "state": "Iowa", + "county": "Allamakee", + "display": "Postville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4344821411906376395-1331", + "name": "Collective IP Company", + "city": { + "name": "Gibson", + "code": "PA", + "state": "Pennsylvania", + "county": "Susquehanna", + "display": "Gibson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3630973581834087525-1332", + "name": "Enervee LLC", + "city": { + "name": "Cazenovia", + "code": "WI", + "state": "Wisconsin", + "county": "Richland", + "display": "Cazenovia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4519067991908913368-1333", + "name": "Factual LLC", + "city": { + "name": "Max Meadows", + "code": "VA", + "state": "Virginia", + "county": "Wythe", + "display": "Fort Chiswell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4533488582174557333-1334", + "name": "Social Health Insights LLC", + "city": { + "name": "Port Huron", + "code": "MI", + "state": "Michigan", + "county": "Saint Clair", + "display": "Port Huron" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2278786642745335407-1335", + "name": "Rand McNally Company", + "city": { + "name": "Rome", + "code": "OH", + "state": "Ohio", + "county": "Ashtabula", + "display": "Roaming Shores" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2128899498997616490-1336", + "name": "SigFig LLC", + "city": { + "name": "Athens", + "code": "WI", + "state": "Wisconsin", + "county": "Marathon", + "display": "Milan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3906963118713443282-1337", + "name": "CityScan LLC", + "city": { + "name": "Hanover", + "code": "MA", + "state": "Massachusetts", + "county": "Plymouth", + "display": "West Hanover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8872934641099578659-1338", + "name": "Xatori Company", + "city": { + "name": "Stephentown", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Stephentown Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1864866340640116854-1339", + "name": "Sterling Infosystems Company", + "city": { + "name": "Harmon", + "code": "IL", + "state": "Illinois", + "county": "Lee", + "display": "Harmon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6659964822841469656-1340", + "name": "FindTheBest.com Inc", + "city": { + "name": "East Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "East Pittsburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5414503095933566521-1341", + "name": "Allianz Corporation", + "city": { + "name": "Georgetown", + "code": "CA", + "state": "California", + "county": "El Dorado", + "display": "Wentworth Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6847258230260561554-1342", + "name": "Whitby Group Corp", + "city": { + "name": "Maple Plain", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Minnetrista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-124759825235513475-1343", + "name": "Zebu Compliance Solutions Corp", + "city": { + "name": "Muskogee", + "code": "OK", + "state": "Oklahoma", + "county": "Muskogee", + "display": "Beland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5347381201045416235-1344", + "name": "IBM LLC", + "city": { + "name": "Plover", + "code": "WI", + "state": "Wisconsin", + "county": "Portage", + "display": "Buena Vista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5640397597697326324-1345", + "name": "Optensity Incorporated", + "city": { + "name": "Santa Fe", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "New Mexico State Capitol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3701473032263723162-1346", + "name": "Innography Inc", + "city": { + "name": "MAFB", + "code": "ND", + "state": "North Dakota", + "county": "Ward", + "display": "Mafb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1729340848062026956-1347", + "name": "ProgrammableWeb LLC", + "city": { + "name": "Moscow", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Covington Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1170246703018333392-1348", + "name": "OnDeck Corporation", + "city": { + "name": "Pungoteague", + "code": "VA", + "state": "Virginia", + "county": "Accomack", + "display": "Pungoteague" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-43484192854241387-1349", + "name": "OpenPlans Inc", + "city": { + "name": "Stow", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Stow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-671882528175236726-1350", + "name": "Yelp Corporation", + "city": { + "name": "Clarence", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "Clarence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2380262491035682076-1351", + "name": "Palantir Technologies Company", + "city": { + "name": "Woodrow", + "code": "CO", + "state": "Colorado", + "county": "Washington", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3351759053468931723-1352", + "name": "BillGuard LLC", + "city": { + "name": "Saint Clairsville", + "code": "OH", + "state": "Ohio", + "county": "Belmont", + "display": "St Clairsvle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5732633815679594704-1353", + "name": "Ensco Corporation", + "city": { + "name": "Alma", + "code": "NE", + "state": "Nebraska", + "county": "Harlan", + "display": "Prairie Dog" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6942987647630446413-1354", + "name": "PolicyMap Company", + "city": { + "name": "South Kortright", + "code": "NY", + "state": "New York", + "county": "Delaware", + "display": "South Kortright" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7061917253844444294-1355", + "name": "GreatSchools LLC", + "city": { + "name": "La Grange", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "Rutersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1690549467280666116-1356", + "name": "Galorath orporated LLC", + "city": { + "name": "Andover", + "code": "OH", + "state": "Ohio", + "county": "Ashtabula", + "display": "Cherry Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7214886911641353635-1357", + "name": "Clean Power Finance Corp", + "city": { + "name": "Posen", + "code": "MI", + "state": "Michigan", + "county": "Presque Isle", + "display": "Posen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-216410393787107645-1358", + "name": "Thomson Reuters Incorporated", + "city": { + "name": "Moundville", + "code": "MO", + "state": "Missouri", + "county": "Vernon", + "display": "Moundville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4536304563160609842-1359", + "name": "Appallicious Inc", + "city": { + "name": "Danbury", + "code": "CT", + "state": "Connecticut", + "county": "Fairfield", + "display": "Danbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9206550852652208007-1360", + "name": "Food+Tech Connect Corporation", + "city": { + "name": "Loveland", + "code": "OH", + "state": "Ohio", + "county": "Clermont", + "display": "Murdock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2656054127728525617-1361", + "name": "GitHub Corporation", + "city": { + "name": "Columbia", + "code": "LA", + "state": "Louisiana", + "county": "Caldwell", + "display": "Eastside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3258971508395032668-1362", + "name": "SmartAsset Company", + "city": { + "name": "Lemon Cove", + "code": "CA", + "state": "California", + "county": "Tulare", + "display": "Lemon Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1861241232780773983-1363", + "name": "PossibilityU LLC", + "city": { + "name": "Sunol", + "code": "CA", + "state": "California", + "county": "Alameda", + "display": "Sunol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5072516175687983702-1364", + "name": "MedWatcher LLC", + "city": { + "name": "Frankfort", + "code": "SD", + "state": "South Dakota", + "county": "Spink", + "display": "Spink Colony" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8988587117643156451-1365", + "name": "Smartronix Company", + "city": { + "name": "Fernandina Beach", + "code": "FL", + "state": "Florida", + "county": "Nassau", + "display": "Amelia City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5826952762860510342-1366", + "name": "US Green Data LLC", + "city": { + "name": "Gilson", + "code": "IL", + "state": "Illinois", + "county": "Knox", + "display": "Gilson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5680690013461033483-1367", + "name": "Abt Associates Inc", + "city": { + "name": "Alexandria", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Alex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3595462703118584074-1368", + "name": "Liquid Robotics LLC", + "city": { + "name": "Milan", + "code": "TN", + "state": "Tennessee", + "county": "Gibson", + "display": "Milan Army Ammunition Plant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8182977132603541671-1369", + "name": "iRecycle Corporation", + "city": { + "name": "Van", + "code": "TX", + "state": "Texas", + "county": "Van Zandt", + "display": "Van" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2368640716446897233-1370", + "name": "Equifax LLC", + "city": { + "name": "Nallen", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Russelville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3914356547158244216-1371", + "name": "Epsilon LLC", + "city": { + "name": "Noxen", + "code": "PA", + "state": "Pennsylvania", + "county": "Wyoming", + "display": "Forkston Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4866216197063585188-1372", + "name": "WebFilings Company", + "city": { + "name": "Tinley Park", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Tinley Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7471345388899752210-1373", + "name": "Food+Tech Connect Corporation", + "city": { + "name": "Newburg", + "code": "WI", + "state": "Wisconsin", + "county": "Washington", + "display": "Newburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1290762731677787192-1374", + "name": "SeeClickFix Inc", + "city": { + "name": "Paintsville", + "code": "KY", + "state": "Kentucky", + "county": "Johnson", + "display": "Offutt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1318655786930704062-1375", + "name": "Dun \u0026 Bradstreet Corp", + "city": { + "name": "Hartford", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Central" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2471275496890099111-1376", + "name": "Quid Corporation", + "city": { + "name": "Pelham", + "code": "AL", + "state": "Alabama", + "county": "Shelby", + "display": "Indian Springs Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2522101083554900979-1377", + "name": "Kyruus Company", + "city": { + "name": "American Falls", + "code": "ID", + "state": "Idaho", + "county": "Power", + "display": "Heglar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2309747595901914187-1378", + "name": "Lenddo LLC", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Bureau Labor Statistics" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8093973887695790151-1379", + "name": "Glassy Media Company", + "city": { + "name": "Boonville", + "code": "MO", + "state": "Missouri", + "county": "Cooper", + "display": "Billingsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6871696664391160244-1380", + "name": "Yelp Corp", + "city": { + "name": "Winslow", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Tolani Lakes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6752280048279589453-1381", + "name": "TowerData Corp", + "city": { + "name": "Falcon Heights", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "Falcon Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2119192816424072799-1382", + "name": "REI Systems Company", + "city": { + "name": "North Port", + "code": "FL", + "state": "Florida", + "county": "Sarasota", + "display": "Venice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6724147866005901214-1383", + "name": "TransparaGov Incorporated", + "city": { + "name": "Pleasanton", + "code": "NE", + "state": "Nebraska", + "county": "Buffalo", + "display": "Rusco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7353598695793809203-1384", + "name": "Credit Karma Inc", + "city": { + "name": "Cromwell", + "code": "MN", + "state": "Minnesota", + "county": "Carlton", + "display": "Cromwell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4906512043911696728-1385", + "name": "Liberty Mutual Insurance Cos Incorporated", + "city": { + "name": "Indianapolis", + "code": "IN", + "state": "Indiana", + "county": "Marion", + "display": "In Univ Purdue Indianapolis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8335896058156057471-1386", + "name": "SocialEffort Inc", + "city": { + "name": "Lake Norden", + "code": "SD", + "state": "South Dakota", + "county": "Hamlin", + "display": "Alsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6736003834916118446-1387", + "name": "BuildFax Corp", + "city": { + "name": "Cross City", + "code": "FL", + "state": "Florida", + "county": "Dixie", + "display": "Cross City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8095275691201054826-1388", + "name": "Kaiser Permanante Incorporated", + "city": { + "name": "Oden", + "code": "AR", + "state": "Arkansas", + "county": "Montgomery", + "display": "Pine Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5833099620155982566-1389", + "name": "Lending Club Incorporated", + "city": { + "name": "Grimes", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Herrold" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7726018966101336873-1390", + "name": "Revaluate Corp", + "city": { + "name": "Seabrook", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Seabrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5387118939457911986-1391", + "name": "nGAP orporated LLC", + "city": { + "name": "Saint Marie", + "code": "MT", + "state": "Montana", + "county": "Valley", + "display": "Saint Marie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-269738456476465405-1392", + "name": "SmartAsset LLC", + "city": { + "name": "NSL", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "Nsl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4833239606484787125-1393", + "name": "Zillow Corp", + "city": { + "name": "Columbia City", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Collins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2891167517250963771-1394", + "name": "Quid Company", + "city": { + "name": "Mc Leansboro", + "code": "IL", + "state": "Illinois", + "county": "Hamilton", + "display": "South Crouch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5121749601617108312-1395", + "name": "InfoCommerce Group Incorporated", + "city": { + "name": "Karnes City", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Karnes City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1859198245871584525-1396", + "name": "Castle Biosciences Inc", + "city": { + "name": "Cushing", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8274114860989525826-1397", + "name": "LOVELAND Technologies Incorporated", + "city": { + "name": "North Evans", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "North Evans" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6535292673416125401-1398", + "name": "Chemical Abstracts Service LLC", + "city": { + "name": "Sparks Glencoe", + "code": "MD", + "state": "Maryland", + "county": "Baltimore", + "display": "Sparks Glencoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-402809262316508577-1399", + "name": "VitalChek Incorporated", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Cinclantflt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-864282357668987080-1400", + "name": "WattzOn Corporation", + "city": { + "name": "Key Largo", + "code": "FL", + "state": "Florida", + "county": "Monroe", + "display": "Ocean Reef Club" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1936432533009990744-1401", + "name": "Fujitsu Company", + "city": { + "name": "Sharon", + "code": "SC", + "state": "South Carolina", + "county": "York", + "display": "Sharon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4901431483932579562-1402", + "name": "IMS Health Corp", + "city": { + "name": "New Johnsonville", + "code": "TN", + "state": "Tennessee", + "county": "Humphreys", + "display": "New Johnsonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7782340632832167257-1403", + "name": "OnStar Company", + "city": { + "name": "Manheim", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Mastersonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2088293413783572767-1404", + "name": "WaterSmart Software Incorporated", + "city": { + "name": "Colonial Beach", + "code": "VA", + "state": "Virginia", + "county": "Westmoreland", + "display": "Colonial Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1526989145207753327-1405", + "name": "McKinsey Inc", + "city": { + "name": "Sisseton", + "code": "SD", + "state": "South Dakota", + "county": "Roberts", + "display": "Agency Vlg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7515335467021667958-1406", + "name": "MicroBilt Corporation", + "city": { + "name": "Amboy", + "code": "WA", + "state": "Washington", + "county": "Clark", + "display": "Chelatchie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7428912489127003362-1407", + "name": "OpenPlans Incorporated", + "city": { + "name": "Tishomingo", + "code": "MS", + "state": "Mississippi", + "county": "Tishomingo", + "display": "Mingo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3109604296608114443-1408", + "name": "Weather Underground Corp", + "city": { + "name": "Oxford", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Oxford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2380683085597594969-1409", + "name": "PlanetEcosystems Corporation", + "city": { + "name": "Granite", + "code": "CO", + "state": "Colorado", + "county": "Chaffee", + "display": "Twin Lakes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5253466134132823002-1410", + "name": "Bridgewater LLC", + "city": { + "name": "Merkel", + "code": "TX", + "state": "Texas", + "county": "Taylor", + "display": "Blair" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3849927903457585533-1411", + "name": "Caspio Company", + "city": { + "name": "Osage", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Snellman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8376329121340950014-1412", + "name": "Webitects LLC", + "city": { + "name": "Varna", + "code": "IL", + "state": "Illinois", + "county": "Marshall", + "display": "Varna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2750040754916684030-1413", + "name": "Solar Census Inc", + "city": { + "name": "Sachse", + "code": "TX", + "state": "Texas", + "county": "Dallas", + "display": "Garland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1785210882773969056-1414", + "name": "Alarm.com Corp", + "city": { + "name": "Hendersonville", + "code": "TN", + "state": "Tennessee", + "county": "Sumner", + "display": "Hendersonvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8362589665573382942-1415", + "name": "Citigroup Inc", + "city": { + "name": "Hoosick", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Hoosick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9039626276571357205-1416", + "name": "Keychain Logistics Corp", + "city": { + "name": "Ganado", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Cornfields" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5897177813249700366-1417", + "name": "Estately Company", + "city": { + "name": "Mapleton Depot", + "code": "PA", + "state": "Pennsylvania", + "county": "Huntingdon", + "display": "Mapleton Dep" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5030344460686700699-1418", + "name": "R R Donnelley Corp", + "city": { + "name": "Sandy", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "Sandy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2463055896895985995-1419", + "name": "SocialEffort Corporation", + "city": { + "name": "Tchula", + "code": "MS", + "state": "Mississippi", + "county": "Holmes", + "display": "Thornton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8770402387887639586-1420", + "name": "Energy Solutions Forum LLC", + "city": { + "name": "Cherry Hill", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Ellisburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4534672997422204835-1421", + "name": "Ceiba Solutions Company", + "city": { + "name": "Hot Springs National Park", + "code": "AR", + "state": "Arkansas", + "county": "Garland", + "display": "Pleasant Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3192593213012958408-1422", + "name": "McKinsey Inc", + "city": { + "name": "Santee", + "code": "SC", + "state": "South Carolina", + "county": "Orangeburg", + "display": "Parlers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2975788572303005670-1423", + "name": "SpeSo Health Corp", + "city": { + "name": "Dawson", + "code": "AL", + "state": "Alabama", + "county": "De Kalb", + "display": "Dawson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1545075195352938016-1424", + "name": "Earth Networks Corp", + "city": { + "name": "Averill", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Averill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8151708341727978777-1425", + "name": "S\u0026P Capital IQ Incorporated", + "city": { + "name": "Grimes", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Herrold" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2139389226742323942-1426", + "name": "Whitby Group Corp", + "city": { + "name": "Dayton", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Wpafb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5732736267495944284-1427", + "name": "Bridgewater Inc", + "city": { + "name": "Dunkirk", + "code": "IN", + "state": "Indiana", + "county": "Jay", + "display": "Crumley Crossing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3381092285218375173-1428", + "name": "Xatori Company", + "city": { + "name": "Corry", + "code": "PA", + "state": "Pennsylvania", + "county": "Erie", + "display": "Columbus Boro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-567224241866481081-1429", + "name": "Consumer Reports Incorporated", + "city": { + "name": "Geddes", + "code": "SD", + "state": "South Dakota", + "county": "Charles Mix", + "display": "Geddes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4352497372475532715-1430", + "name": "AtSite LLC", + "city": { + "name": "Phenix", + "code": "VA", + "state": "Virginia", + "county": "Charlotte", + "display": "Phenix" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6662446999262173518-1431", + "name": "Ceiba Solutions Inc", + "city": { + "name": "Wauregan", + "code": "CT", + "state": "Connecticut", + "county": "Windham", + "display": "Wauregan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1175636634410667563-1432", + "name": "iTriage Corporation", + "city": { + "name": "Second Mesa", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Toreva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5961514787957593443-1433", + "name": "RAND Company", + "city": { + "name": "Saint Elmo", + "code": "IL", + "state": "Illinois", + "county": "Fayette", + "display": "Saint Elmo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8193480325119482654-1434", + "name": "Smartronix Company", + "city": { + "name": "Flushing", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Linden Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1426402603479577104-1435", + "name": "SnapSense Inc", + "city": { + "name": "Manton", + "code": "CA", + "state": "California", + "county": "Tehama", + "display": "Manton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8419589263661531416-1436", + "name": "Copyright Clearance Center Corporation", + "city": { + "name": "Novinger", + "code": "MO", + "state": "Missouri", + "county": "Adair", + "display": "Stahl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8862264655947626532-1437", + "name": "PlaceILive.com Incorporated", + "city": { + "name": "Mount Pleasant", + "code": "MS", + "state": "Mississippi", + "county": "Marshall", + "display": "Holly Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5996103513508883868-1438", + "name": "Quandl Company", + "city": { + "name": "Loxahatchee", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Vlg Wellingtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1325984583570561019-1439", + "name": "OTC Markets LLC", + "city": { + "name": "Deep River", + "code": "CT", + "state": "Connecticut", + "county": "Middlesex", + "display": "Deep River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5917998221238532588-1440", + "name": "American Red Ball Movers Company", + "city": { + "name": "Biddeford Pool", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "Biddeford Pl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5957743468308258790-1441", + "name": "Compliance and Risks Inc", + "city": { + "name": "Rock Hall", + "code": "MD", + "state": "Maryland", + "county": "Kent", + "display": "Rock Hall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8262335899540057465-1442", + "name": "CostQuest Company", + "city": { + "name": "Herndon", + "code": "KY", + "state": "Kentucky", + "county": "Christian", + "display": "Herndon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-999568046768379489-1443", + "name": "Castle Biosciences LLC", + "city": { + "name": "Normal", + "code": "AL", + "state": "Alabama", + "county": "Madison", + "display": "Normal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4218589232501566043-1444", + "name": "Docket Alarm, LLC", + "city": { + "name": "Leola", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Oregon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-386402642592498182-1445", + "name": "People Power Corporation", + "city": { + "name": "Poplarville", + "code": "MS", + "state": "Mississippi", + "county": "Pearl River", + "display": "Hillsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1910256727228741922-1446", + "name": "Ontodia, Corp", + "city": { + "name": "Rickreall", + "code": "OR", + "state": "Oregon", + "county": "Polk", + "display": "Rickreall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2884355746275052981-1447", + "name": "FlightView Company", + "city": { + "name": "Lisbon", + "code": "ND", + "state": "North Dakota", + "county": "Ransom", + "display": "Lisbon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2039732227904163861-1448", + "name": "Progressive Insurance Group Company", + "city": { + "name": "Fall River Mills", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Fl River Mls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8796064497599453681-1449", + "name": "Biovia Corporation", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Fairmont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3074412970824176519-1450", + "name": "IFI CLAIMS Patent Services Corporation", + "city": { + "name": "Gardner", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "Gardner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1611925480060474331-1451", + "name": "SAS Inc", + "city": { + "name": "Paulden", + "code": "AZ", + "state": "Arizona", + "county": "Yavapai", + "display": "Paulden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4473059654519781467-1452", + "name": "Amida Technology Solutions Corp", + "city": { + "name": "Moab", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Castleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1632035318476075472-1453", + "name": "People Power Corporation", + "city": { + "name": "Cobalt", + "code": "CT", + "state": "Connecticut", + "county": "Middlesex", + "display": "Cobalt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8329291593190355393-1454", + "name": "OpenPlans LLC", + "city": { + "name": "Osage", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Snellman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3210395658502834232-1455", + "name": "SmartProcure LLC", + "city": { + "name": "New Woodstock", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Sheds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2644720826671981178-1456", + "name": "Center for Responsive Politics Incorporated", + "city": { + "name": "Middleburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Meiser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-184899818666538289-1457", + "name": "FlightView Corp", + "city": { + "name": "Ashland", + "code": "ME", + "state": "Maine", + "county": "Aroostook", + "display": "Nashville Plt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2693360611186298621-1458", + "name": "Optensity Corporation", + "city": { + "name": "Oneonta", + "code": "AL", + "state": "Alabama", + "county": "Blount", + "display": "Hoods Crossroads" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2194130540915318557-1459", + "name": "OnStar Company", + "city": { + "name": "Oak Brook", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Oak Brook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8501567406484333156-1460", + "name": "FlightAware Inc", + "city": { + "name": "Bay Port", + "code": "MI", + "state": "Michigan", + "county": "Huron", + "display": "Bay Port" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7219733045723940119-1461", + "name": "Synthicity Corporation", + "city": { + "name": "Lake Wilson", + "code": "MN", + "state": "Minnesota", + "county": "Murray", + "display": "Hadley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8794127818122781884-1462", + "name": "CostQuest Corp", + "city": { + "name": "Weslaco", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Progreso Lks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8233261243908468129-1463", + "name": "NERA Economic Consulting Corp", + "city": { + "name": "Rainsville", + "code": "AL", + "state": "Alabama", + "county": "De Kalb", + "display": "Rainsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4563244328754448304-1464", + "name": "Be Informed Incorporated", + "city": { + "name": "West Newbury", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "West Newbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7289222392324191403-1465", + "name": "iMedicare Company", + "city": { + "name": "Haltom City", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "N Richland Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8198373465094921597-1466", + "name": "Social Health Insights LLC", + "city": { + "name": "Cumberland Foreside", + "code": "ME", + "state": "Maine", + "county": "Cumberland", + "display": "Cumb Foreside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4328726062049460994-1467", + "name": "Way Better Patents Corp", + "city": { + "name": "Ogden", + "code": "UT", + "state": "Utah", + "county": "Weber", + "display": "Ms City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4195458633512547050-1468", + "name": "xDayta Corp", + "city": { + "name": "Kake", + "code": "AK", + "state": "Alaska", + "county": "Petersburg", + "display": "Kake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8583989115360762104-1469", + "name": "Berkery Noyes MandASoft Company", + "city": { + "name": "Sutherland Springs", + "code": "TX", + "state": "Texas", + "county": "Wilson", + "display": "Sutherland Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3713718890894732905-1470", + "name": "Castle Biosciences Corporation", + "city": { + "name": "Okabena", + "code": "MN", + "state": "Minnesota", + "county": "Jackson", + "display": "Okabena" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3192064374027903706-1471", + "name": "Apextech Corporation", + "city": { + "name": "Saginaw", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Brevator" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1916703856580934585-1472", + "name": "Acxiom Inc", + "city": { + "name": "Arenzville", + "code": "IL", + "state": "Illinois", + "county": "Cass", + "display": "Arenzville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1802448684716436870-1473", + "name": "PolicyMap Inc", + "city": { + "name": "West Nottingham", + "code": "NH", + "state": "New Hampshire", + "county": "Rockingham", + "display": "W Nottingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4050795192662486058-1474", + "name": "ReciPal Inc", + "city": { + "name": "Enoree", + "code": "SC", + "state": "South Carolina", + "county": "Spartanburg", + "display": "Enoree" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6412473895064264019-1475", + "name": "SimpleTuition Corp", + "city": { + "name": "Climax", + "code": "CO", + "state": "Colorado", + "county": "Lake", + "display": "Leadville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1487016767987065128-1476", + "name": "Galorath orporated Incorporated", + "city": { + "name": "Raleigh", + "code": "NC", + "state": "North Carolina", + "county": "Wake", + "display": "Duraleigh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5367813680244948468-1477", + "name": "Telenav Company", + "city": { + "name": "Lees Summit", + "code": "MO", + "state": "Missouri", + "county": "Jackson", + "display": "Unity School Of Christianity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-336761824517969319-1478", + "name": "Glassy Media LLC", + "city": { + "name": "Howe", + "code": "TX", + "state": "Texas", + "county": "Grayson", + "display": "Dorchester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-917866770690479674-1479", + "name": "ReciPal Corporation", + "city": { + "name": "Selman City", + "code": "TX", + "state": "Texas", + "county": "Rusk", + "display": "Turnertown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1364405987411205607-1480", + "name": "Credit Sesame Inc", + "city": { + "name": "Bay City", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Bay City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6631893007809815946-1481", + "name": "Allied Van Lines Corporation", + "city": { + "name": "Stewart", + "code": "TN", + "state": "Tennessee", + "county": "Houston", + "display": "Stewart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6039716978683087991-1482", + "name": "Wolfram Research LLC", + "city": { + "name": "Bogalusa", + "code": "LA", + "state": "Louisiana", + "county": "Washington", + "display": "Lees Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1906922739067287423-1483", + "name": "Caspio Inc", + "city": { + "name": "Twilight", + "code": "WV", + "state": "West Virginia", + "county": "Boone", + "display": "Twilight" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8423820105702662033-1484", + "name": "TrustedID LLC", + "city": { + "name": "Mount Auburn", + "code": "IL", + "state": "Illinois", + "county": "Christian", + "display": "Mt Auburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3395952620732859820-1485", + "name": "Copyright Clearance Center Inc", + "city": { + "name": "Philadelphia", + "code": "PA", + "state": "Pennsylvania", + "county": "Philadelphia", + "display": "Lawndale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5494773130978543503-1486", + "name": "Bing Company", + "city": { + "name": "Waverly", + "code": "VA", + "state": "Virginia", + "county": "Sussex", + "display": "Waverly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7940976349555499763-1487", + "name": "Honest Buildings Corp", + "city": { + "name": "Ordinary", + "code": "VA", + "state": "Virginia", + "county": "Gloucester", + "display": "Ordinary" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7241976843360972433-1488", + "name": "Adaptive Company", + "city": { + "name": "Bremen", + "code": "IN", + "state": "Indiana", + "county": "Marshall", + "display": "Bremen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1771932488553508575-1489", + "name": "Revelstone Inc", + "city": { + "name": "New Berlin", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Hoboken" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3673261598605663832-1490", + "name": "Kaiser Permanante Inc", + "city": { + "name": "Edgefield", + "code": "SC", + "state": "South Carolina", + "county": "Edgefield", + "display": "Pleasant Lane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3987656849337948897-1491", + "name": "TrialX Corporation", + "city": { + "name": "Signal Mountain", + "code": "TN", + "state": "Tennessee", + "county": "Hamilton", + "display": "Signal Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6128597315039639873-1492", + "name": "Code-N Inc", + "city": { + "name": "Monticello", + "code": "NM", + "state": "New Mexico", + "county": "Sierra", + "display": "Monticello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6881546493094348660-1493", + "name": "Russell Investments Inc", + "city": { + "name": "Newport", + "code": "OR", + "state": "Oregon", + "county": "Lincoln", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6468716217470906503-1494", + "name": "Mapbox LLC", + "city": { + "name": "Porter Corners", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Porter Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7646997781957401425-1495", + "name": "Nautilytics Corporation", + "city": { + "name": "Louisville", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Fairhope" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3759177455097674110-1496", + "name": "Graebel Van Lines Corp", + "city": { + "name": "Balmorhea", + "code": "TX", + "state": "Texas", + "county": "Reeves", + "display": "Balmorhea" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5202167920496406657-1497", + "name": "mHealthCoach Company", + "city": { + "name": "Aberdeen", + "code": "MS", + "state": "Mississippi", + "county": "Monroe", + "display": "Centralgrove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3979009033667309283-1498", + "name": "StreetEasy Corp", + "city": { + "name": "Saint James", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Nissequogue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8228744753735621794-1499", + "name": "Charles Schwab Corporation", + "city": { + "name": "Spencer", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Vandalia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9105949327192998418-1500", + "name": "Panjiva Company", + "city": { + "name": "Flagler", + "code": "CO", + "state": "Colorado", + "county": "Kit Carson", + "display": "Flagler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9008265092215053608-1501", + "name": "OnDeck Corp", + "city": { + "name": "Merom", + "code": "IN", + "state": "Indiana", + "county": "Sullivan", + "display": "Merom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5926000603938419512-1502", + "name": "Municode LLC", + "city": { + "name": "Comanche", + "code": "OK", + "state": "Oklahoma", + "county": "Stephens", + "display": "Comanche" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3108727898547692249-1503", + "name": "PEV4me.com Incorporated", + "city": { + "name": "New Boston", + "code": "NH", + "state": "New Hampshire", + "county": "Hillsborough", + "display": "New Boston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6576115421763316756-1504", + "name": "WebMD Corp", + "city": { + "name": "Hiltons", + "code": "VA", + "state": "Virginia", + "county": "Scott", + "display": "Hiltons" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6086000516785012659-1505", + "name": "AllState Insurance Group Corp", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Richmond Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5996695508714661082-1506", + "name": "Scale Unlimited LLC", + "city": { + "name": "Virginia City", + "code": "NV", + "state": "Nevada", + "county": "Storey", + "display": "Gold Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3138815979325931793-1507", + "name": "ZocDoc Company", + "city": { + "name": "Saint Paul", + "code": "AR", + "state": "Arkansas", + "county": "Madison", + "display": "Saint Paul" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6018441169995454071-1508", + "name": "Connotate Corp", + "city": { + "name": "Winona", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Winona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4231200234276420571-1509", + "name": "PYA Analytics Inc", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Finneytown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4553094797184110428-1510", + "name": "Careset.com Inc", + "city": { + "name": "Keyport", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Keyport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5779970423513623026-1511", + "name": "Science Exchange Incorporated", + "city": { + "name": "Dannebrog", + "code": "NE", + "state": "Nebraska", + "county": "Howard", + "display": "Nysted" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3337377836539276656-1512", + "name": "Apextech Incorporated", + "city": { + "name": "Rio Dell", + "code": "CA", + "state": "California", + "county": "Humboldt", + "display": "Rio Dell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6190387974595474301-1513", + "name": "Impact Forecasting Incorporated", + "city": { + "name": "Grand Tower", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Red Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-338016705381648207-1514", + "name": "Splunk Corporation", + "city": { + "name": "Rockwood", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Brownstown Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1393669649565974555-1515", + "name": "HelloWallet Corporation", + "city": { + "name": "San Diego", + "code": "TX", + "state": "Texas", + "county": "Duval", + "display": "Rosita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1094937028223706915-1516", + "name": "Lumesis, Corporation", + "city": { + "name": "Mercury", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Jackass Flats" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-739951027833011932-1517", + "name": "Arrive Labs Company", + "city": { + "name": "Hannibal", + "code": "NY", + "state": "New York", + "county": "Oswego", + "display": "Hannibal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6746208089948327291-1518", + "name": "DataMarket Incorporated", + "city": { + "name": "Terre Haute", + "code": "IN", + "state": "Indiana", + "county": "Vigo", + "display": "Cemar Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8126677917496140830-1519", + "name": "Connotate Company", + "city": { + "name": "Madison", + "code": "MO", + "state": "Missouri", + "county": "Monroe", + "display": "Woodlawn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7068954530771271111-1520", + "name": "Predilytics Incorporated", + "city": { + "name": "Monroe", + "code": "GA", + "state": "Georgia", + "county": "Walton", + "display": "Monroe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8198794955631780312-1521", + "name": "Ranku Inc", + "city": { + "name": "Porter Corners", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Porter Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1966999068707628954-1522", + "name": "Propeller Health Incorporated", + "city": { + "name": "Whitestone", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Flushing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4355603884507255116-1523", + "name": "Eat Shop Sleep LLC", + "city": { + "name": "Sterling", + "code": "CT", + "state": "Connecticut", + "county": "Windham", + "display": "North Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7666726646298496990-1524", + "name": "Energy Points, Corp", + "city": { + "name": "Barnegat Light", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Barnegat Light" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2195685693223152917-1525", + "name": "Webitects LLC", + "city": { + "name": "Ossipee", + "code": "NH", + "state": "New Hampshire", + "county": "Carroll", + "display": "Ossipee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7172009370973228184-1526", + "name": "Porch LLC", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Ridgemont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6730165001314166952-1527", + "name": "Funding Circle Inc", + "city": { + "name": "Richfield Springs", + "code": "NY", + "state": "New York", + "county": "Otsego", + "display": "Richfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4987111263916480130-1528", + "name": "optiGov Inc", + "city": { + "name": "North Hollywood", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Universal Cty" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4993912160948805440-1529", + "name": "Equifax Company", + "city": { + "name": "Wolcottville", + "code": "IN", + "state": "Indiana", + "county": "Lagrange", + "display": "Witmer Manor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4833586394915995734-1530", + "name": "Enigma.io Corp", + "city": { + "name": "Saint John", + "code": "WA", + "state": "Washington", + "county": "Whitman", + "display": "Saint John" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2569188419478367446-1531", + "name": "Exversion Company", + "city": { + "name": "Horseshoe Bend", + "code": "ID", + "state": "Idaho", + "county": "Boise", + "display": "Gardena" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6560194854368822570-1532", + "name": "Munetrix Company", + "city": { + "name": "Ferguson", + "code": "NC", + "state": "North Carolina", + "county": "Wilkes", + "display": "Darby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2138792621953531735-1533", + "name": "StreamLink Software Corporation", + "city": { + "name": "Guernsey", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Guernsey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2461233845414493329-1534", + "name": "Seabourne Inc", + "city": { + "name": "Warwick", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Warwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2942404699460457412-1535", + "name": "BaleFire Global LLC", + "city": { + "name": "Waseca", + "code": "MN", + "state": "Minnesota", + "county": "Waseca", + "display": "Otisco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7121611735115385371-1536", + "name": "Acxiom Company", + "city": { + "name": "Upper Tract", + "code": "WV", + "state": "West Virginia", + "county": "Pendleton", + "display": "Upper Tract" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3519301436776113915-1537", + "name": "SpotHero.com Corp", + "city": { + "name": "Zephyr Cove", + "code": "NV", + "state": "Nevada", + "county": "Douglas", + "display": "Pinewild" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7368212880384163087-1538", + "name": "Liquid Robotics Inc", + "city": { + "name": "Lebanon", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Bolton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-956916411652686910-1539", + "name": "The Schork Report Incorporated", + "city": { + "name": "Erie", + "code": "PA", + "state": "Pennsylvania", + "county": "Erie", + "display": "Erie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2798040926579184996-1540", + "name": "HERE Incorporated", + "city": { + "name": "Vienna", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Oakton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7979635144989887452-1541", + "name": "eInstitutional Company", + "city": { + "name": "Concan", + "code": "TX", + "state": "Texas", + "county": "Uvalde", + "display": "Concan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4703994199754003527-1542", + "name": "Kyruus Inc", + "city": { + "name": "Polo", + "code": "IL", + "state": "Illinois", + "county": "Ogle", + "display": "Polo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6871959739203321470-1543", + "name": "People Power Corporation", + "city": { + "name": "Spring Lake", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Spring Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8751491899838276591-1544", + "name": "OnDeck Corp", + "city": { + "name": "Browder", + "code": "KY", + "state": "Kentucky", + "county": "Muhlenberg", + "display": "Browder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2075414618416685683-1545", + "name": "FlightAware LLC", + "city": { + "name": "Carthage", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Carthage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6561005670526616017-1546", + "name": "How's My Offer? LLC", + "city": { + "name": "Reno", + "code": "NV", + "state": "Nevada", + "county": "Washoe", + "display": "Red Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4049665070044287124-1547", + "name": "Center for Responsive Politics Corp", + "city": { + "name": "Point Of Rocks", + "code": "WY", + "state": "Wyoming", + "county": "Sweetwater", + "display": "Point Of Rocks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2361137056052147998-1548", + "name": "FlightAware Company", + "city": { + "name": "Decatur", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Dunaire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4426429906614842109-1549", + "name": "Graematter, Corporation", + "city": { + "name": "Columbia City", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Collins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6445403560384450451-1550", + "name": "Junyo Incorporated", + "city": { + "name": "Pleasant Grove", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Cedar Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7025962194881752694-1551", + "name": "Healthgrades Corporation", + "city": { + "name": "Flagler", + "code": "CO", + "state": "Colorado", + "county": "Kit Carson", + "display": "Flagler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8304572275262526400-1552", + "name": "Optensity Incorporated", + "city": { + "name": "North Waterboro", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "N Waterboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8633306521588365616-1553", + "name": "Standard and Poor's Inc", + "city": { + "name": "Kemblesville", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Kemblesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8282793086421184141-1554", + "name": "OpportunitySpace, Company", + "city": { + "name": "Ransom Canyon", + "code": "TX", + "state": "Texas", + "county": "Lubbock", + "display": "Ransom Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5009442576673997519-1555", + "name": "Govini Inc", + "city": { + "name": "Scooba", + "code": "MS", + "state": "Mississippi", + "county": "Kemper", + "display": "Electric Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2036010114802390545-1556", + "name": "Dabo Health Company", + "city": { + "name": "Glover", + "code": "VT", + "state": "Vermont", + "county": "Orleans", + "display": "Barton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4020468054026807061-1557", + "name": "MetLife Corporation", + "city": { + "name": "Moscow", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Covington Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3661591503618674987-1558", + "name": "DataMarket Inc", + "city": { + "name": "North Salem", + "code": "NH", + "state": "New Hampshire", + "county": "Rockingham", + "display": "No Salem" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2630760592339751962-1559", + "name": "H3 Biomedicine Corporation", + "city": { + "name": "Austin", + "code": "TX", + "state": "Texas", + "county": "Travis", + "display": "State Comptroller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2482412493242029320-1560", + "name": "Bridgewater Company", + "city": { + "name": "Gilman", + "code": "IA", + "state": "Iowa", + "county": "Marshall", + "display": "Gilman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1814978640069239714-1561", + "name": "Enigma.io Corporation", + "city": { + "name": "Cross City", + "code": "FL", + "state": "Florida", + "county": "Dixie", + "display": "Cross City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3566998570803242102-1562", + "name": "CliniCast Incorporated", + "city": { + "name": "Jasper", + "code": "AR", + "state": "Arkansas", + "county": "Newton", + "display": "Jasper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1086004158550885017-1563", + "name": "Ez-XBRL Inc", + "city": { + "name": "Enterprise", + "code": "KS", + "state": "Kansas", + "county": "Dickinson", + "display": "Enterprise" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-74523922696423623-1564", + "name": "SlashDB Corp", + "city": { + "name": "Weston", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Stony Brook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8313299285637984350-1565", + "name": "KidAdmit, Corp", + "city": { + "name": "Mitchell", + "code": "IN", + "state": "Indiana", + "county": "Lawrence", + "display": "Stonington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2081286988476603474-1566", + "name": "Careset.com Incorporated", + "city": { + "name": "Gurnee", + "code": "IL", + "state": "Illinois", + "county": "Lake", + "display": "Gurnee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3782450500207180769-1567", + "name": "gRadiant Research Company", + "city": { + "name": "Westbrookville", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Westbrookvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6816822152157952347-1568", + "name": "SAS LLC", + "city": { + "name": "Cedarville", + "code": "WV", + "state": "West Virginia", + "county": "Gilmer", + "display": "Cedarville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7905222652969606744-1569", + "name": "Energy Points, Inc", + "city": { + "name": "Calumet", + "code": "MI", + "state": "Michigan", + "county": "Houghton", + "display": "Centennial Hts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4410797178923362981-1570", + "name": "EMC Company", + "city": { + "name": "White", + "code": "SD", + "state": "South Dakota", + "county": "Brookings", + "display": "Roland Colony" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-868430447748870631-1571", + "name": "Weather Underground LLC", + "city": { + "name": "Bowling Green", + "code": "MO", + "state": "Missouri", + "county": "Pike", + "display": "Tarrants" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6507613658080116634-1572", + "name": "Lumesis, Corporation", + "city": { + "name": "Vermillion", + "code": "SD", + "state": "South Dakota", + "county": "Clay", + "display": "Westerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3970654383659995291-1573", + "name": "Quid Company", + "city": { + "name": "Cleveland", + "code": "OH", + "state": "Ohio", + "county": "Cuyahoga", + "display": "Brooklyn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1723025508538039887-1574", + "name": "Housefax Company", + "city": { + "name": "Breckenridge", + "code": "CO", + "state": "Colorado", + "county": "Summit", + "display": "Blue River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7379233981166929509-1575", + "name": "Open Data Nation LLC", + "city": { + "name": "Hallett", + "code": "OK", + "state": "Oklahoma", + "county": "Pawnee", + "display": "Hallett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5836703088855534753-1576", + "name": "48 Factoring Incorporated", + "city": { + "name": "La Jara", + "code": "CO", + "state": "Colorado", + "county": "Conejos", + "display": "Bountiful" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8866212800369720523-1577", + "name": "Personal, Inc", + "city": { + "name": "Point Pleasant Beach", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Pt Pleas Bch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5146871061699696712-1578", + "name": "Brightscope Inc", + "city": { + "name": "Newton Junction", + "code": "NH", + "state": "New Hampshire", + "county": "Rockingham", + "display": "Newton Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6652903730571292575-1579", + "name": "Asset4 Company", + "city": { + "name": "Sloatsburg", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "Sloatsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4888591410277727256-1580", + "name": "Biovia Corp", + "city": { + "name": "Wideman", + "code": "AR", + "state": "Arkansas", + "county": "Izard", + "display": "Forty Four" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5799962976380814100-1581", + "name": "Zonability Company", + "city": { + "name": "Mason City", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Teheran" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5731127736098206701-1582", + "name": "Zurich Insurance LLC", + "city": { + "name": "Tallulah", + "code": "LA", + "state": "Louisiana", + "county": "Madison", + "display": "Tallulah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1377987299628579195-1583", + "name": "SpotCrime Company", + "city": { + "name": "Merom", + "code": "IN", + "state": "Indiana", + "county": "Sullivan", + "display": "Merom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-700124191705665985-1584", + "name": "Calcbench, Incorporated", + "city": { + "name": "Irvine", + "code": "KY", + "state": "Kentucky", + "county": "Estill", + "display": "Crystal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3778572643604528969-1585", + "name": "Mint Corp", + "city": { + "name": "Carrier Mills", + "code": "IL", + "state": "Illinois", + "county": "Saline", + "display": "Carrier Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6832922289991405834-1586", + "name": "Nielsen Corp", + "city": { + "name": "Pine Bluff", + "code": "AR", + "state": "Arkansas", + "county": "Jefferson", + "display": "Pine Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-307083464090594927-1587", + "name": "College Board Company", + "city": { + "name": "Woodson", + "code": "TX", + "state": "Texas", + "county": "Throckmorton", + "display": "Woodson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9001312884514300198-1588", + "name": "StreetEasy Incorporated", + "city": { + "name": "Monterey", + "code": "IN", + "state": "Indiana", + "county": "Pulaski", + "display": "Monterey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4427880976643394385-1589", + "name": "NerdWallet LLC", + "city": { + "name": "Dryden", + "code": "VA", + "state": "Virginia", + "county": "Lee", + "display": "Dryden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1086560598380870053-1590", + "name": "Solar Census Company", + "city": { + "name": "Surprise", + "code": "NE", + "state": "Nebraska", + "county": "Butler", + "display": "Ulysses" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6907963448640257873-1591", + "name": "Recargo Incorporated", + "city": { + "name": "Coltons Point", + "code": "MD", + "state": "Maryland", + "county": "Saint Marys", + "display": "Coltons Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7216452809669049500-1592", + "name": "SpaceCurve LLC", + "city": { + "name": "Little Birch", + "code": "WV", + "state": "West Virginia", + "county": "Braxton", + "display": "Tesla" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4679052701228906469-1593", + "name": "Kyruus Inc", + "city": { + "name": "Coal City", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Daggett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2940700700737946170-1594", + "name": "VisualDoD, Corporation", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Naval Base" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-522286086674450829-1595", + "name": "Compared Care Incorporated", + "city": { + "name": "Cherokee", + "code": "KS", + "state": "Kansas", + "county": "Crawford", + "display": "Cherokee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7672213790637608080-1596", + "name": "Revaluate Incorporated", + "city": { + "name": "Brookport", + "code": "IL", + "state": "Illinois", + "county": "Massac", + "display": "Shady Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6762150496271945994-1597", + "name": "Allied Van Lines Incorporated", + "city": { + "name": "New Castle", + "code": "PA", + "state": "Pennsylvania", + "county": "Lawrence", + "display": "Castle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3354430285268093314-1598", + "name": "Xcential Corp", + "city": { + "name": "San Simeon", + "code": "CA", + "state": "California", + "county": "San Luis Obispo", + "display": "Ragged Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8048562282536579033-1599", + "name": "Civinomics LLC", + "city": { + "name": "Browns Summit", + "code": "NC", + "state": "North Carolina", + "county": "Guilford", + "display": "Osceola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1305244759402451509-1600", + "name": "Estately Incorporated", + "city": { + "name": "El Jobean", + "code": "FL", + "state": "Florida", + "county": "Charlotte", + "display": "El Jobean" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5325390070872439169-1601", + "name": "Energy Solutions Forum Incorporated", + "city": { + "name": "Tivoli", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Tivoli" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1017502079048302803-1602", + "name": "TrialTrove LLC", + "city": { + "name": "Hyde Park", + "code": "MA", + "state": "Massachusetts", + "county": "Suffolk", + "display": "Hyde Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7145171959086902857-1603", + "name": "PeerJ Inc", + "city": { + "name": "Fort Lauderdale", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Lauderhill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1895430781215729294-1604", + "name": "Experian LLC", + "city": { + "name": "Columbia", + "code": "LA", + "state": "Louisiana", + "county": "Caldwell", + "display": "Riverton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9127942200846021585-1605", + "name": "Booz Allen Hamilton Incorporated", + "city": { + "name": "Carrollton", + "code": "KY", + "state": "Kentucky", + "county": "Carroll", + "display": "English" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1942598541626887590-1606", + "name": "TrialTrove LLC", + "city": { + "name": "Rampart", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Rampart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4627389147226274708-1607", + "name": "HealthPocket, LLC", + "city": { + "name": "West Palm Beach", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Royal Palm Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7728495886262799325-1608", + "name": "Civinomics Corp", + "city": { + "name": "Piru", + "code": "CA", + "state": "California", + "county": "Ventura", + "display": "Piru" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4431716454518616689-1609", + "name": "Civis Analytics Company", + "city": { + "name": "American Falls", + "code": "ID", + "state": "Idaho", + "county": "Power", + "display": "Heglar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8528349368262700729-1610", + "name": "xDayta Company", + "city": { + "name": "Toronto", + "code": "KS", + "state": "Kansas", + "county": "Woodson", + "display": "Toronto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5593349368603061872-1611", + "name": "GitHub Company", + "city": { + "name": "Marseilles", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Danway" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9196086867182693007-1612", + "name": "Politify Company", + "city": { + "name": "Amery", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Little Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1177272217510350925-1613", + "name": "IW Financial Company", + "city": { + "name": "Quail Valley", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Canyon Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2281690264087391808-1614", + "name": "Certara Company", + "city": { + "name": "Mapleton Depot", + "code": "PA", + "state": "Pennsylvania", + "county": "Huntingdon", + "display": "Mapleton Dep" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6983285068736347327-1615", + "name": "ClearHealthCosts Corporation", + "city": { + "name": "Marble", + "code": "MN", + "state": "Minnesota", + "county": "Itasca", + "display": "Marble" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-810141630955133953-1616", + "name": "Marlin \u0026 Associates Inc", + "city": { + "name": "South International Falls", + "code": "MN", + "state": "Minnesota", + "county": "Koochiching", + "display": "South International Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7080901118959506906-1617", + "name": "Intelius Inc", + "city": { + "name": "Wellington", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "West Palm Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5072789414577013510-1618", + "name": "StockSmart LLC", + "city": { + "name": "Bustins Island", + "code": "ME", + "state": "Maine", + "county": "Cumberland", + "display": "Bustins Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5835033533583635968-1619", + "name": "BetterLesson Corporation", + "city": { + "name": "Kennebunk", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "Kennebunk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1603478978178363966-1620", + "name": "Morningstar, Company", + "city": { + "name": "Forsyth", + "code": "GA", + "state": "Georgia", + "county": "Monroe", + "display": "Forsyth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7110395259528544549-1621", + "name": "SAP Corporation", + "city": { + "name": "Empire", + "code": "CA", + "state": "California", + "county": "Stanislaus", + "display": "Empire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7978787753840021301-1622", + "name": "PolicyMap Incorporated", + "city": { + "name": "Horseshoe Bend", + "code": "ID", + "state": "Idaho", + "county": "Boise", + "display": "Horseshoe Bend" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8742308049827462205-1623", + "name": "Synthicity Corp", + "city": { + "name": "Joyce", + "code": "WA", + "state": "Washington", + "county": "Clallam", + "display": "Joyce" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1729909731044649563-1624", + "name": "Epsilon Incorporated", + "city": { + "name": "Sugar Grove", + "code": "NC", + "state": "North Carolina", + "county": "Watauga", + "display": "Beech Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2006121226385525289-1625", + "name": "Google Public Data Explorer Corp", + "city": { + "name": "Pana", + "code": "IL", + "state": "Illinois", + "county": "Christian", + "display": "Pana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6232683837770868619-1626", + "name": "Center for Responsive Politics Inc", + "city": { + "name": "Daniel", + "code": "WY", + "state": "Wyoming", + "county": "Sublette", + "display": "Daniel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9025676753324976854-1627", + "name": "Department of Better Technology Corp", + "city": { + "name": "Albuquerque", + "code": "NM", + "state": "New Mexico", + "county": "Bernalillo", + "display": "Los Ranchos" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5473733748643851380-1628", + "name": "Iodine Company", + "city": { + "name": "Rosharon", + "code": "TX", + "state": "Texas", + "county": "Brazoria", + "display": "Sandy Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3204269297120664880-1629", + "name": "Factual Corporation", + "city": { + "name": "Brandywine", + "code": "WV", + "state": "West Virginia", + "county": "Pendleton", + "display": "Brandywine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6267670205439014897-1630", + "name": "HealthMap Incorporated", + "city": { + "name": "Grand Isle", + "code": "VT", + "state": "Vermont", + "county": "Grand Isle", + "display": "Grand Isle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5909875239136742097-1631", + "name": "SpotHero.com Corp", + "city": { + "name": "Bloomington", + "code": "IL", + "state": "Illinois", + "county": "Mclean", + "display": "Bloomington Normal Airport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8266219790435396598-1632", + "name": "Splunk Incorporated", + "city": { + "name": "Grinnell", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Newburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1626017334961202813-1633", + "name": "Personal, Incorporated", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Albany Brm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1687645842387805777-1634", + "name": "Civic Insight Corporation", + "city": { + "name": "Chugiak", + "code": "AK", + "state": "Alaska", + "county": "Anchorage", + "display": "Chugiak" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6989614201343879575-1635", + "name": "FutureAdvisor Incorporated", + "city": { + "name": "Culloden", + "code": "WV", + "state": "West Virginia", + "county": "Cabell", + "display": "Culloden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8436924375808603666-1636", + "name": "The Schork Report LLC", + "city": { + "name": "Fort Thomas", + "code": "KY", + "state": "Kentucky", + "county": "Campbell", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1841926357314730122-1637", + "name": "Kaiser Permanante Inc", + "city": { + "name": "Scottdale", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Scottdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8067285489559952361-1638", + "name": "First Fuel Software Corp", + "city": { + "name": "MOL", + "code": "OH", + "state": "Ohio", + "county": "Lake", + "display": "Mol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9096269074626885603-1639", + "name": "OpenCounter Corp", + "city": { + "name": "Estero", + "code": "FL", + "state": "Florida", + "county": "Lee", + "display": "Estero" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7828537990630662900-1640", + "name": "Harris Corporation", + "city": { + "name": "Irondale", + "code": "OH", + "state": "Ohio", + "county": "Jefferson", + "display": "Cream City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8057326616295326017-1641", + "name": "Headlight Incorporated", + "city": { + "name": "Mc Kee", + "code": "KY", + "state": "Kentucky", + "county": "Jackson", + "display": "Morrill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6431984002543116989-1642", + "name": "SAS LLC", + "city": { + "name": "Kinston", + "code": "NC", + "state": "North Carolina", + "county": "Lenoir", + "display": "Kinston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7195177524540515314-1643", + "name": "Think Computer Company", + "city": { + "name": "Duluth", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "West Duluth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2328922564053043112-1644", + "name": "Code for America Company", + "city": { + "name": "Belva", + "code": "WV", + "state": "West Virginia", + "county": "Nicholas", + "display": "Belva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5814329140545741805-1645", + "name": "Relationship Science Corporation", + "city": { + "name": "Danbury", + "code": "NC", + "state": "North Carolina", + "county": "Stokes", + "display": "Hartman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3061614769132582728-1646", + "name": "CAN Capital Inc", + "city": { + "name": "Candor", + "code": "NY", + "state": "New York", + "county": "Tioga", + "display": "Candor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8580682502761093841-1647", + "name": "Peterson's Incorporated", + "city": { + "name": "Wamego", + "code": "KS", + "state": "Kansas", + "county": "Pottawatomie", + "display": "Wamego" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1124730598236394515-1648", + "name": "Development Seed Incorporated", + "city": { + "name": "Reading", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Saint Lawrence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3440356309801124045-1649", + "name": "PeerJ Inc", + "city": { + "name": "White River Junction", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "White Riv Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3789915170961884252-1650", + "name": "Tableau Software Incorporated", + "city": { + "name": "Seabrook", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Seabrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8458542511793532956-1651", + "name": "BetterLesson Company", + "city": { + "name": "Sullivan", + "code": "NH", + "state": "New Hampshire", + "county": "Cheshire", + "display": "E Sullivan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1267688180486318517-1652", + "name": "Esri LLC", + "city": { + "name": "Oakdale", + "code": "LA", + "state": "Louisiana", + "county": "Allen", + "display": "Bond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3892899458837813471-1653", + "name": "Embark Corp", + "city": { + "name": "Mount Sterling", + "code": "WI", + "state": "Wisconsin", + "county": "Crawford", + "display": "Mt Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5378765658795320000-1654", + "name": "Citigroup Inc", + "city": { + "name": "Wyalusing", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Wyalusing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2243034287284412650-1655", + "name": "The Vanguard Group Corporation", + "city": { + "name": "Fort Myers", + "code": "FL", + "state": "Florida", + "county": "Lee", + "display": "Florida Gulf Coast Univ" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5006765686385718382-1656", + "name": "EarthObserver App Incorporated", + "city": { + "name": "Whitewater", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Cabazon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2599148972548518935-1657", + "name": "StreetCred Software, Corp", + "city": { + "name": "Quinn", + "code": "SD", + "state": "South Dakota", + "county": "Pennington", + "display": "Cottonwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5178831919341845771-1658", + "name": "Mozio Corp", + "city": { + "name": "Riceboro", + "code": "GA", + "state": "Georgia", + "county": "Liberty", + "display": "South Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6515640447869286069-1659", + "name": "Mozio Corporation", + "city": { + "name": "Finlayson", + "code": "MN", + "state": "Minnesota", + "county": "Pine", + "display": "Finlayson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4863693237842056878-1660", + "name": "MetLife LLC", + "city": { + "name": "Shoshoni", + "code": "WY", + "state": "Wyoming", + "county": "Fremont", + "display": "Shoshoni" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2299154828073462977-1661", + "name": "HERE Incorporated", + "city": { + "name": "Houston", + "code": "DE", + "state": "Delaware", + "county": "Kent", + "display": "Houston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7934731014511544746-1662", + "name": "Sterling Infosystems Incorporated", + "city": { + "name": "Ferguson", + "code": "NC", + "state": "North Carolina", + "county": "Wilkes", + "display": "Darby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3422581286677447540-1663", + "name": "Everyday Health LLC", + "city": { + "name": "Wanette", + "code": "OK", + "state": "Oklahoma", + "county": "Pottawatomie", + "display": "Wanette" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6833549279240811506-1664", + "name": "Healthline Corporation", + "city": { + "name": "Fallsburg", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Fallsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4701758385285808240-1665", + "name": "MicroBilt Incorporated", + "city": { + "name": "Leesburg", + "code": "OH", + "state": "Ohio", + "county": "Highland", + "display": "Samantha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5878407183523084298-1666", + "name": "SimpleTuition Company", + "city": { + "name": "Endicott", + "code": "NY", + "state": "New York", + "county": "Broome", + "display": "Crestview Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8185603662923635466-1667", + "name": "Cyte Corporation", + "city": { + "name": "Okeechobee", + "code": "FL", + "state": "Florida", + "county": "Okeechobee", + "display": "Basinger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5637375968620084431-1668", + "name": "Morningstar, LLC", + "city": { + "name": "Red Valley", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Teec Nos Pos" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3860395778405755753-1669", + "name": "SpeSo Health Incorporated", + "city": { + "name": "Winslow", + "code": "IN", + "state": "Indiana", + "county": "Pike", + "display": "Coe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6955065737663598861-1670", + "name": "Clean Power Finance Inc", + "city": { + "name": "Takotna", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Mc Grath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5638864791664948655-1671", + "name": "DataLogix Corp", + "city": { + "name": "Florence", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Florence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-479615293472701722-1672", + "name": "BillGuard Company", + "city": { + "name": "Wenatchee", + "code": "WA", + "state": "Washington", + "county": "Chelan", + "display": "West Wenatchee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-829497388636416837-1673", + "name": "ZocDoc Incorporated", + "city": { + "name": "Knoxville", + "code": "TN", + "state": "Tennessee", + "county": "Knox", + "display": "University Of Tenn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5569391946990121234-1674", + "name": "TransparaGov Incorporated", + "city": { + "name": "Sayville", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Fire Island Pines" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4911164760485655336-1675", + "name": "Municode Inc", + "city": { + "name": "Commerce", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Commerce" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2948596533255556025-1676", + "name": "TagniFi Corp", + "city": { + "name": "Mosinee", + "code": "WI", + "state": "Wisconsin", + "county": "Marathon", + "display": "Kronenwetter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7871507940725343855-1677", + "name": "McKinsey Company", + "city": { + "name": "Bardstown", + "code": "KY", + "state": "Kentucky", + "county": "Nelson", + "display": "Bardstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8767226267928015003-1678", + "name": "SAP Inc", + "city": { + "name": "Andover", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Internal Revenue Service" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2855134637298663180-1679", + "name": "Wolters Kluwer LLC", + "city": { + "name": "Hallett", + "code": "OK", + "state": "Oklahoma", + "county": "Pawnee", + "display": "Hallett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2496838403386185474-1680", + "name": "Energy Solutions Forum Inc", + "city": { + "name": "Jadwin", + "code": "MO", + "state": "Missouri", + "county": "Dent", + "display": "Jadwin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8875718454903106599-1681", + "name": "Ecodesk Company", + "city": { + "name": "Schodack Landing", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Schodack Lndg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8740443802091470343-1682", + "name": "Politify LLC", + "city": { + "name": "Cataract", + "code": "WI", + "state": "Wisconsin", + "county": "Monroe", + "display": "Cataract" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4742138041002187712-1683", + "name": "Ez-XBRL Corp", + "city": { + "name": "Phillipsburg", + "code": "MO", + "state": "Missouri", + "county": "Laclede", + "display": "Phillipsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6621459593654372079-1684", + "name": "Copyright Clearance Center Corporation", + "city": { + "name": "South Whitley", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Luther" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6833345471150815242-1685", + "name": "Propeller Health LLC", + "city": { + "name": "Elverson", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Loag" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7190940164563517953-1686", + "name": "Fitch Company", + "city": { + "name": "Nodaway", + "code": "IA", + "state": "Iowa", + "county": "Adams", + "display": "Guss" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6682039089725931592-1687", + "name": "CAN Capital Company", + "city": { + "name": "Carmel", + "code": "CA", + "state": "California", + "county": "Monterey", + "display": "Carmel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3998467591447310041-1688", + "name": "Spikes Cavell Analytic Corporation", + "city": { + "name": "Labadie", + "code": "MO", + "state": "Missouri", + "county": "Franklin", + "display": "Labadie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2151969056181873510-1689", + "name": "Porch Corp", + "city": { + "name": "Bradford", + "code": "IL", + "state": "Illinois", + "county": "Stark", + "display": "Broadmoor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2022759212145874521-1690", + "name": "Cloudmade Company", + "city": { + "name": "Belton", + "code": "MO", + "state": "Missouri", + "county": "Cass", + "display": "Village Of Loch Lloyd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8638341828438028731-1691", + "name": "Government Transaction Services Corp", + "city": { + "name": "Mount Carmel", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Dooleyville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8821777587975388668-1692", + "name": "VitalChek Incorporated", + "city": { + "name": "Chapmansboro", + "code": "TN", + "state": "Tennessee", + "county": "Cheatham", + "display": "Chapmansboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2410535938557772213-1693", + "name": "Oversight Systems Inc", + "city": { + "name": "Bruno", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Bruno" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7958873129989168315-1694", + "name": "Trulia Company", + "city": { + "name": "Pleasant Unity", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Pleasant Unity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5166736226651642102-1695", + "name": "OTC Markets Corporation", + "city": { + "name": "Eleroy", + "code": "IL", + "state": "Illinois", + "county": "Stephenson", + "display": "Eleroy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4331188673046753639-1696", + "name": "McGraw Hill Financial Corp", + "city": { + "name": "Conneaut Lake", + "code": "PA", + "state": "Pennsylvania", + "county": "Crawford", + "display": "Conneaut Lake Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-113320178959584548-1697", + "name": "Energy Points, Inc", + "city": { + "name": "Lockport", + "code": "KY", + "state": "Kentucky", + "county": "Henry", + "display": "Lockport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6327327401276752683-1698", + "name": "Weather Underground Inc", + "city": { + "name": "Mount Carmel", + "code": "IL", + "state": "Illinois", + "county": "Wabash", + "display": "Maud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1236839433746135612-1699", + "name": "Equilar Corporation", + "city": { + "name": "Saint Bernice", + "code": "IN", + "state": "Indiana", + "county": "Vermillion", + "display": "Saint Bernice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8316918415969863294-1700", + "name": "Appallicious Inc", + "city": { + "name": "Richland", + "code": "MO", + "state": "Missouri", + "county": "Pulaski", + "display": "Swedeborg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3705360937376381666-1701", + "name": "Berkery Noyes MandASoft Corp", + "city": { + "name": "Dutzow", + "code": "MO", + "state": "Missouri", + "county": "Warren", + "display": "Dutzow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9104626957245430095-1702", + "name": "TuvaLabs Incorporated", + "city": { + "name": "Portland", + "code": "IN", + "state": "Indiana", + "county": "Jay", + "display": "Liber" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-608260481171219678-1703", + "name": "Verdafero Incorporated", + "city": { + "name": "Crete", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Crete" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-281675740912057183-1704", + "name": "Symcat LLC", + "city": { + "name": "North Myrtle Beach", + "code": "SC", + "state": "South Carolina", + "county": "Horry", + "display": "North Myrtle Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8765959398147657308-1705", + "name": "Lilly Open Innovation Drug Discovery Corporation", + "city": { + "name": "Upper Sandusky", + "code": "OH", + "state": "Ohio", + "county": "Wyandot", + "display": "Upper Sandusky" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3662392404111842533-1706", + "name": "Aidin LLC", + "city": { + "name": "Bassett", + "code": "NE", + "state": "Nebraska", + "county": "Rock", + "display": "Rose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2030713232457923632-1707", + "name": "Uber Corp", + "city": { + "name": "Stonewall", + "code": "OK", + "state": "Oklahoma", + "county": "Pontotoc", + "display": "Harden City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2119278132112094742-1708", + "name": "Adaptive Inc", + "city": { + "name": "Olympic Valley", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Olympic Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8621785821005979612-1709", + "name": "Dun \u0026 Bradstreet Company", + "city": { + "name": "Dover Foxcroft", + "code": "ME", + "state": "Maine", + "county": "Piscataquis", + "display": "Dovr Foxcroft" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1815417663505182543-1710", + "name": "Construction Monitor Incorporated", + "city": { + "name": "Varna", + "code": "IL", + "state": "Illinois", + "county": "Marshall", + "display": "Varna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2503763831111463196-1711", + "name": "Galorath orporated Incorporated", + "city": { + "name": "Medfield", + "code": "MA", + "state": "Massachusetts", + "county": "Norfolk", + "display": "Medfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1847487330377596112-1712", + "name": "Bloomberg Corp", + "city": { + "name": "Mackinaw", + "code": "IL", + "state": "Illinois", + "county": "Tazewell", + "display": "Mackinaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6582827080446855347-1713", + "name": "BetterLesson Incorporated", + "city": { + "name": "Carolina", + "code": "RI", + "state": "Rhode Island", + "county": "Washington", + "display": "Carolina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8864610499421873330-1714", + "name": "Xatori LLC", + "city": { + "name": "Bellona", + "code": "NY", + "state": "New York", + "county": "Yates", + "display": "Bellona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9213291897124408562-1715", + "name": "Zonability LLC", + "city": { + "name": "Jonesville", + "code": "NC", + "state": "North Carolina", + "county": "Yadkin", + "display": "Jonesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1680780015366059677-1716", + "name": "Fastcase LLC", + "city": { + "name": "Holiday", + "code": "FL", + "state": "Florida", + "county": "Pasco", + "display": "Tarpon Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4319794598747380979-1717", + "name": "AutoGrid Systems Corp", + "city": { + "name": "La Pine", + "code": "OR", + "state": "Oregon", + "county": "Deschutes", + "display": "E Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4074769588563526612-1718", + "name": "KPMG Company", + "city": { + "name": "Colonial Beach", + "code": "VA", + "state": "Virginia", + "county": "Westmoreland", + "display": "Colonial Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7203666640959730242-1719", + "name": "FlightView Inc", + "city": { + "name": "Lashmeet", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Lashmeet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3152354211834770188-1720", + "name": "3 Round Stones, LLC", + "city": { + "name": "Benjamin", + "code": "TX", + "state": "Texas", + "county": "Knox", + "display": "Benjamin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1386267372931501738-1721", + "name": "McKinsey Inc", + "city": { + "name": "Hamilton", + "code": "OH", + "state": "Ohio", + "county": "Butler", + "display": "City View Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4582828188060328381-1722", + "name": "IMS Health Incorporated", + "city": { + "name": "Benjamin", + "code": "TX", + "state": "Texas", + "county": "Knox", + "display": "Benjamin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3318731611567626320-1723", + "name": "Fastcase LLC", + "city": { + "name": "Cavalier", + "code": "ND", + "state": "North Dakota", + "county": "Pembina", + "display": "Cavalier Afs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2100388220143852559-1724", + "name": "VitalChek Inc", + "city": { + "name": "Vail", + "code": "CO", + "state": "Colorado", + "county": "Eagle", + "display": "Vail" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5137215796910685547-1725", + "name": "BetterLesson Corporation", + "city": { + "name": "Weslaco", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Progreso Lks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-817914991129399955-1726", + "name": "CostQuest Corporation", + "city": { + "name": "Sheffield", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Sheffield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1882610212744930348-1727", + "name": "Informatica Corporation", + "city": { + "name": "Mora", + "code": "MN", + "state": "Minnesota", + "county": "Kanabec", + "display": "Knife Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4500600018517716623-1728", + "name": "LOVELAND Technologies Incorporated", + "city": { + "name": "Kilmichael", + "code": "MS", + "state": "Mississippi", + "county": "Montgomery", + "display": "Poplar Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7517318610031019033-1729", + "name": "Fidelity Investments Corp", + "city": { + "name": "Los Alamos", + "code": "NM", + "state": "New Mexico", + "county": "Los Alamos", + "display": "White Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1900790815291504518-1730", + "name": "Ernst \u0026 Young LLP Incorporated", + "city": { + "name": "Leesville", + "code": "SC", + "state": "South Carolina", + "county": "Lexington", + "display": "Fairview Crossroads" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4343328158181613346-1731", + "name": "Aquicore Inc", + "city": { + "name": "Low Moor", + "code": "VA", + "state": "Virginia", + "county": "Alleghany", + "display": "Lowmoor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6972762661768209709-1732", + "name": "Fastcase Corporation", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Preachers Slough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3934112455921138290-1733", + "name": "IBM Inc", + "city": { + "name": "Greensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Allegheny Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-238645701596602975-1734", + "name": "OnStar Corp", + "city": { + "name": "Whitehall", + "code": "MI", + "state": "Michigan", + "county": "Muskegon", + "display": "Sylvan Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8123455823415940668-1735", + "name": "Lucid Corp", + "city": { + "name": "Abie", + "code": "NE", + "state": "Nebraska", + "county": "Butler", + "display": "Abie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2090439125431722263-1736", + "name": "Mercaris Corp", + "city": { + "name": "Cogswell", + "code": "ND", + "state": "North Dakota", + "county": "Sargent", + "display": "Straubville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5579202302906384523-1737", + "name": "Lumesis, Company", + "city": { + "name": "Waterford Works", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Waterford Works" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6358612175184116316-1738", + "name": "Kaiser Permanante Incorporated", + "city": { + "name": "Clear Creek", + "code": "WV", + "state": "West Virginia", + "county": "Raleigh", + "display": "Clear Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6847276544261837689-1739", + "name": "Ecodesk LLC", + "city": { + "name": "Bretz", + "code": "WV", + "state": "West Virginia", + "county": "Preston", + "display": "Bretz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8772595053771683379-1740", + "name": "Mango Transit Company", + "city": { + "name": "Granville Summit", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Granville Smt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6503105565136270316-1741", + "name": "Science Exchange Incorporated", + "city": { + "name": "Monticello", + "code": "KY", + "state": "Kentucky", + "county": "Wayne", + "display": "Delta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2001024770091274287-1742", + "name": "SeeClickFix Corp", + "city": { + "name": "Othello", + "code": "WA", + "state": "Washington", + "county": "Adams", + "display": "Othello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-504351641659401208-1743", + "name": "Farmers Corp", + "city": { + "name": "Bonnieville", + "code": "KY", + "state": "Kentucky", + "county": "Hart", + "display": "Bonnieville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9194777248992681084-1744", + "name": "Ecodesk Company", + "city": { + "name": "Jacksonville", + "code": "IL", + "state": "Illinois", + "county": "Morgan", + "display": "Pisgah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4076202058884124830-1745", + "name": "Inrix Traffic Company", + "city": { + "name": "Amherst", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "Cushman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4614364098161510241-1746", + "name": "Ayasdi LLC", + "city": { + "name": "Acme", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Acme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-197426936376486673-1747", + "name": "Social Health Insights LLC", + "city": { + "name": "Winslow", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Tolani" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8829321704878765264-1748", + "name": "Qado Energy, LLC", + "city": { + "name": "Pascoag", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Pascoag" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1244967344084895833-1749", + "name": "College Board Company", + "city": { + "name": "Arnold", + "code": "CA", + "state": "California", + "county": "Calaveras", + "display": "Arnold" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3507566858196931756-1750", + "name": "Asset4 Corp", + "city": { + "name": "Jamestown", + "code": "NY", + "state": "New York", + "county": "Chautauqua", + "display": "Jamestown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5503763785007996343-1751", + "name": "ZocDoc Corp", + "city": { + "name": "Saint Helena Island", + "code": "SC", + "state": "South Carolina", + "county": "Beaufort", + "display": "St Helena Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8138176603944008112-1752", + "name": "Exversion Company", + "city": { + "name": "Ottawa", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Ottawa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7119864704640377397-1753", + "name": "Parsons Brinckerhoff Incorporated", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Wilkes University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4050316145140119735-1754", + "name": "Graematter, Corporation", + "city": { + "name": "Hannaford", + "code": "ND", + "state": "North Dakota", + "county": "Griggs", + "display": "Hannaford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8683915482835502091-1755", + "name": "ASC Partners Inc", + "city": { + "name": "Bloomfield", + "code": "KY", + "state": "Kentucky", + "county": "Nelson", + "display": "Bloomfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8322347340739718787-1756", + "name": "Enervee Corporation", + "city": { + "name": "Covington", + "code": "LA", + "state": "Louisiana", + "county": "Saint Tammany", + "display": "Riverwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3775945206919111533-1757", + "name": "Level One Technologies LLC", + "city": { + "name": "Edenville", + "code": "MI", + "state": "Michigan", + "county": "Midland", + "display": "Edenville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7526412962296811131-1758", + "name": "TagniFi Corp", + "city": { + "name": "Arcade", + "code": "NY", + "state": "New York", + "county": "Wyoming", + "display": "Arcade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7806412736464655250-1759", + "name": "IVES Group Company", + "city": { + "name": "Olympia Fields", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Olympia Flds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6889774414717355903-1760", + "name": "SocialEffort LLC", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Immig And Naturalization Ser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4888532522399921604-1761", + "name": "ConnectEDU Incorporated", + "city": { + "name": "Littleton", + "code": "IL", + "state": "Illinois", + "county": "Schuyler", + "display": "Littleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-248874117897039507-1762", + "name": "Inrix Traffic Corp", + "city": { + "name": "Riverbank", + "code": "CA", + "state": "California", + "county": "Stanislaus", + "display": "Riverbank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7711393303656236983-1763", + "name": "Liberty Mutual Insurance Cos Incorporated", + "city": { + "name": "Craftsbury Common", + "code": "VT", + "state": "Vermont", + "county": "Orleans", + "display": "Craftsbury Common" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5444881612101514371-1764", + "name": "Yahoo Corp", + "city": { + "name": "Gallman", + "code": "MS", + "state": "Mississippi", + "county": "Copiah", + "display": "Gallman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8122090068173538430-1765", + "name": "Junyo Incorporated", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "Knickerbocker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7456612900312857496-1766", + "name": "Whitby Group Corp", + "city": { + "name": "Ann Arbor", + "code": "MI", + "state": "Michigan", + "county": "Washtenaw", + "display": "Loch Alpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5503978555541790099-1767", + "name": "Russell Investments Corp", + "city": { + "name": "Madison", + "code": "WI", + "state": "Wisconsin", + "county": "Dane", + "display": "State Capitol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5235212334792799739-1768", + "name": "Garmin Corporation", + "city": { + "name": "Daphne", + "code": "AL", + "state": "Alabama", + "county": "Baldwin", + "display": "Daphne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5182168820641966958-1769", + "name": "Relationship Science Inc", + "city": { + "name": "Fort Worth", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Kenneth Copeland Ministries" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-891568211845789359-1770", + "name": "Scale Unlimited Incorporated", + "city": { + "name": "Randolph", + "code": "AL", + "state": "Alabama", + "county": "Bibb", + "display": "Randolph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4797534520301715080-1771", + "name": "KidAdmit, Inc", + "city": { + "name": "Wilbraham", + "code": "MA", + "state": "Massachusetts", + "county": "Hampden", + "display": "Wilbraham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7271689462790434417-1772", + "name": "Chemical Abstracts Service Company", + "city": { + "name": "Union Bridge", + "code": "MD", + "state": "Maryland", + "county": "Carroll", + "display": "Linwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7459754752815639500-1773", + "name": "Xatori Corporation", + "city": { + "name": "Burlingham", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Burlingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8681322495848327726-1774", + "name": "LexisNexis Incorporated", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Action" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3836768927168145357-1775", + "name": "OSIsoft Incorporated", + "city": { + "name": "Sunbury", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Augustaville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2063540456602819-1776", + "name": "GreatSchools Corp", + "city": { + "name": "Slate Spring", + "code": "MS", + "state": "Mississippi", + "county": "Calhoun", + "display": "Slate Spring" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5270800729784320551-1777", + "name": "TagniFi Incorporated", + "city": { + "name": "Kake", + "code": "AK", + "state": "Alaska", + "county": "Petersburg", + "display": "Kake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6520246297354171372-1778", + "name": "Yelp Inc", + "city": { + "name": "Columbus", + "code": "GA", + "state": "Georgia", + "county": "Muscogee", + "display": "Col" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7265330588289379659-1779", + "name": "Sage Bionetworks Inc", + "city": { + "name": "South Charleston", + "code": "OH", + "state": "Ohio", + "county": "Clark", + "display": "S Charleston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-749214027407528753-1780", + "name": "Environmental Data Resources Corp", + "city": { + "name": "Newell", + "code": "SD", + "state": "South Dakota", + "county": "Butte", + "display": "Cedar Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8870882496704439204-1781", + "name": "Persint Company", + "city": { + "name": "Mercersburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Franklin", + "display": "Markes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8678111222983415685-1782", + "name": "5PSolutions Corporation", + "city": { + "name": "Sutter Creek", + "code": "CA", + "state": "California", + "county": "Amador", + "display": "Sutter Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7378480237161014344-1783", + "name": "AccuWeather Corp", + "city": { + "name": "Pleasant Dale", + "code": "NE", + "state": "Nebraska", + "county": "Seward", + "display": "Pleasant Dale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7548750548695768799-1784", + "name": "Enervee Incorporated", + "city": { + "name": "Sargentville", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "Sargentville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3533884397973820181-1785", + "name": "Ecodesk LLC", + "city": { + "name": "Barbourville", + "code": "KY", + "state": "Kentucky", + "county": "Knox", + "display": "Bailey Switch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1732867706632895908-1786", + "name": "Nautilytics Corp", + "city": { + "name": "Minford", + "code": "OH", + "state": "Ohio", + "county": "Scioto", + "display": "Minford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3993979858616336918-1787", + "name": "Spokeo Incorporated", + "city": { + "name": "Lee Center", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "West Lee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7738921786037902547-1788", + "name": "Citigroup Incorporated", + "city": { + "name": "Gilboa", + "code": "NY", + "state": "New York", + "county": "Schoharie", + "display": "Gilboa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-808018507389081977-1789", + "name": "Amazon Web Services LLC", + "city": { + "name": "Paradise Valley", + "code": "NV", + "state": "Nevada", + "county": "Humboldt", + "display": "Paradise Vly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1332222011366648892-1790", + "name": "Avvo Company", + "city": { + "name": "Andover", + "code": "NJ", + "state": "New Jersey", + "county": "Sussex", + "display": "Byram Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5318188315996924619-1791", + "name": "Business and Legal Resources Corporation", + "city": { + "name": "Marion", + "code": "LA", + "state": "Louisiana", + "county": "Union", + "display": "Litroe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7441077515971361719-1792", + "name": "Aidin LLC", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Wilmington Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8336644281730535915-1793", + "name": "Uber Company", + "city": { + "name": "Mackinaw", + "code": "IL", + "state": "Illinois", + "county": "Tazewell", + "display": "Mackinaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6086581144190358822-1794", + "name": "48 Factoring Company", + "city": { + "name": "Happy Valley", + "code": "OR", + "state": "Oregon", + "county": "Clackamas", + "display": "Happy Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1806169218507168238-1795", + "name": "Ayasdi Inc", + "city": { + "name": "Eagle", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Eagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2543423435160774620-1796", + "name": "CoolClimate Corporation", + "city": { + "name": "Anthony", + "code": "TX", + "state": "Texas", + "county": "El Paso", + "display": "Vinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4448738728250304654-1797", + "name": "Mozio LLC", + "city": { + "name": "Eola", + "code": "TX", + "state": "Texas", + "county": "Concho", + "display": "Eola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3274947603203473003-1798", + "name": "Gallup Inc", + "city": { + "name": "Butte", + "code": "MT", + "state": "Montana", + "county": "Silver Bow", + "display": "Walkerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3786834380851203683-1799", + "name": "ReciPal Corporation", + "city": { + "name": "Bloomington", + "code": "IL", + "state": "Illinois", + "county": "Mclean", + "display": "Blm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6988694633806246131-1800", + "name": "Merrill Lynch Incorporated", + "city": { + "name": "Roanoke Rapids", + "code": "NC", + "state": "North Carolina", + "county": "Halifax", + "display": "Roanoke Rapid" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1989631411513139063-1801", + "name": "Charles Schwab Corporation", + "city": { + "name": "Mc Clellanville", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Mc Clellanville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1527009758758645695-1802", + "name": "TransUnion LLC", + "city": { + "name": "Nottingham", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Nottingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-429309384571615090-1803", + "name": "PatientsLikeMe Company", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Jackson", + "display": "Kans City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-182098596886395410-1804", + "name": "The Vanguard Group Company", + "city": { + "name": "Wheatland", + "code": "IN", + "state": "Indiana", + "county": "Knox", + "display": "Steen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9170387995348145098-1805", + "name": "Synthicity Inc", + "city": { + "name": "Barhamsville", + "code": "VA", + "state": "Virginia", + "county": "New Kent", + "display": "Barhamsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3927066637258037564-1806", + "name": "Outline Corp", + "city": { + "name": "Brookville", + "code": "PA", + "state": "Pennsylvania", + "county": "Jefferson", + "display": "Hazen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8008669730775355903-1807", + "name": "SimpleTuition Inc", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Ridgemont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-510567998893833522-1808", + "name": "IMS Health Corp", + "city": { + "name": "LS", + "code": "MO", + "state": "Missouri", + "county": "Jackson", + "display": "Ls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3562637864823751503-1809", + "name": "Cerner LLC", + "city": { + "name": "Middle Bass", + "code": "OH", + "state": "Ohio", + "county": "Ottawa", + "display": "Middle Bass" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7694906288756752821-1810", + "name": "College Abacus, an ECMC initiative Incorporated", + "city": { + "name": "Avon By The Sea", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Avon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6426661690866123596-1811", + "name": "New Media Parents LLC", + "city": { + "name": "Harwinton", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Harwinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3104749607843693068-1812", + "name": "Equal Speed Inc", + "city": { + "name": "Washington", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2016792588430280851-1813", + "name": "Department of Better Technology Incorporated", + "city": { + "name": "Cleveland", + "code": "OH", + "state": "Ohio", + "county": "Cuyahoga", + "display": "Middleburg Hts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7523355642167176009-1814", + "name": "Pave Inc", + "city": { + "name": "Swanton", + "code": "NE", + "state": "Nebraska", + "county": "Saline", + "display": "Swanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8229740343397584998-1815", + "name": "Unigo LLC", + "city": { + "name": "Castaic", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Castaic" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8416060345450436495-1816", + "name": "Housefax LLC", + "city": { + "name": "West Columbia", + "code": "SC", + "state": "South Carolina", + "county": "Lexington", + "display": "Pineridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-721906653194446760-1817", + "name": "Innography Corporation", + "city": { + "name": "Hamel", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Medina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8799388184462025285-1818", + "name": "TagniFi Corporation", + "city": { + "name": "Farwell", + "code": "NE", + "state": "Nebraska", + "county": "Howard", + "display": "Farwell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-763328963588081605-1819", + "name": "Merrill Lynch LLC", + "city": { + "name": "Smithville", + "code": "TX", + "state": "Texas", + "county": "Bastrop", + "display": "Kirtley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6143592848609078625-1820", + "name": "Fuzion Apps, Corporation", + "city": { + "name": "Waynesfield", + "code": "OH", + "state": "Ohio", + "county": "Auglaize", + "display": "Waynesfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7706155216855397501-1821", + "name": "Calcbench, Incorporated", + "city": { + "name": "Deptford", + "code": "NJ", + "state": "New Jersey", + "county": "Gloucester", + "display": "Almonesson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4444168182599285043-1822", + "name": "Docket Alarm, Corporation", + "city": { + "name": "Lillian", + "code": "AL", + "state": "Alabama", + "county": "Baldwin", + "display": "Lillian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4868136169515562062-1823", + "name": "Clean Power Finance Incorporated", + "city": { + "name": "Abilene", + "code": "TX", + "state": "Texas", + "county": "Taylor", + "display": "Abilene" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5711167146232845669-1824", + "name": "HERE Incorporated", + "city": { + "name": "Franklin", + "code": "TX", + "state": "Texas", + "county": "Robertson", + "display": "Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3014315362481431633-1825", + "name": "Calcbench, Incorporated", + "city": { + "name": "Woodbine", + "code": "GA", + "state": "Georgia", + "county": "Camden", + "display": "Woodbine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-464818536607998808-1826", + "name": "Charles River Associates Inc", + "city": { + "name": "Datil", + "code": "NM", + "state": "New Mexico", + "county": "Catron", + "display": "Datil" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1696506759083016162-1827", + "name": "Municode Corporation", + "city": { + "name": "Osseo", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Osseo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6172666659953052736-1828", + "name": "National Van Lines Inc", + "city": { + "name": "Plantation", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Broward Mall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4782768469875935138-1829", + "name": "3 Round Stones, Inc", + "city": { + "name": "Bonnyman", + "code": "KY", + "state": "Kentucky", + "county": "Perry", + "display": "Blue Diamond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1409809650158473851-1830", + "name": "YourMapper Inc", + "city": { + "name": "Romeo", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Bruce Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4632354791323644207-1831", + "name": "Municode Corporation", + "city": { + "name": "Westhampton Beach", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "W Hampton Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3849694381345658667-1832", + "name": "Booz Allen Hamilton Incorporated", + "city": { + "name": "Chavies", + "code": "KY", + "state": "Kentucky", + "county": "Perry", + "display": "Chavies" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8103340070902492344-1833", + "name": "Propeller Health Company", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Jp Morgan Chase" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1545922043532871744-1834", + "name": "Whitby Group Company", + "city": { + "name": "Swedesboro", + "code": "NJ", + "state": "New Jersey", + "county": "Gloucester", + "display": "Logan Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8976076979861963517-1835", + "name": "Quandl Company", + "city": { + "name": "Hardeeville", + "code": "SC", + "state": "South Carolina", + "county": "Jasper", + "display": "Limehouse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8077922702701209983-1836", + "name": "Amazon Web Services Incorporated", + "city": { + "name": "Scranton", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Dickson City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5878921559425082991-1837", + "name": "Wheaton World Wide Moving LLC", + "city": { + "name": "Mound", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Shorewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3941606166830027958-1838", + "name": "Russell Investments Incorporated", + "city": { + "name": "Millinocket", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Long A Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4012707885451909562-1839", + "name": "Merrill Lynch Corporation", + "city": { + "name": "Dinero", + "code": "TX", + "state": "Texas", + "county": "Live Oak", + "display": "Mount Lucas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1929869431233402615-1840", + "name": "Impact Forecasting LLC", + "city": { + "name": "Amity", + "code": "AR", + "state": "Arkansas", + "county": "Clark", + "display": "Rosboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1743360925680908102-1841", + "name": "Predilytics Inc", + "city": { + "name": "Keene", + "code": "NH", + "state": "New Hampshire", + "county": "Cheshire", + "display": "Keene" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8557238020564558887-1842", + "name": "Marlin \u0026 Associates Corporation", + "city": { + "name": "Yadkinville", + "code": "NC", + "state": "North Carolina", + "county": "Yadkin", + "display": "Footsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6407852374526558897-1843", + "name": "PossibilityU Inc", + "city": { + "name": "Kenedy", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Kenedy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3655237301516905859-1844", + "name": "United Mayflower Company", + "city": { + "name": "Carson", + "code": "NM", + "state": "New Mexico", + "county": "Taos", + "display": "Carson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2012884617988413531-1845", + "name": "OnStar Company", + "city": { + "name": "Thompson Falls", + "code": "MT", + "state": "Montana", + "county": "Sanders", + "display": "Copper King" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7538349935235154998-1846", + "name": "USSearch Corporation", + "city": { + "name": "Santa Fe", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Jaconita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-944159899208922747-1847", + "name": "Epsilon Corp", + "city": { + "name": "Pineville", + "code": "AR", + "state": "Arkansas", + "county": "Izard", + "display": "Pineville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6497618476403101202-1848", + "name": "Citigroup Corp", + "city": { + "name": "Kings Canyon National Pk", + "code": "CA", + "state": "California", + "county": "Tulare", + "display": "Kings Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8604752373465719830-1849", + "name": "Expert Health Data Programming, LLC", + "city": { + "name": "West Nyack", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "West Nyack" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4405335760754809355-1850", + "name": "REI Systems Inc", + "city": { + "name": "Puposky", + "code": "MN", + "state": "Minnesota", + "county": "Beltrami", + "display": "Durand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2666378789136499828-1851", + "name": "Rivet Software Corp", + "city": { + "name": "Atwater", + "code": "OH", + "state": "Ohio", + "county": "Portage", + "display": "Atwater" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5446163176836501718-1852", + "name": "Ceiba Solutions LLC", + "city": { + "name": "Yellow Jacket", + "code": "CO", + "state": "Colorado", + "county": "Montezuma", + "display": "Yellow Jacket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9144795307325007319-1853", + "name": "Teradata Corporation", + "city": { + "name": "Bradenton", + "code": "FL", + "state": "Florida", + "county": "Manatee", + "display": "B'ton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9038697031805628867-1854", + "name": "OTC Markets LLC", + "city": { + "name": "Walthall", + "code": "MS", + "state": "Mississippi", + "county": "Webster", + "display": "Walthall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1968362912832942364-1855", + "name": "Careset.com Incorporated", + "city": { + "name": "Wentworth", + "code": "SD", + "state": "South Dakota", + "county": "Lake", + "display": "Lake Madison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6118617986052237062-1856", + "name": "CliniCast Incorporated", + "city": { + "name": "Mississippi State", + "code": "MS", + "state": "Mississippi", + "county": "Oktibbeha", + "display": "Ms St" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1560860214356086933-1857", + "name": "Informatica Corp", + "city": { + "name": "North Canton", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Lake Slagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3815582250837815516-1858", + "name": "Informatica Corp", + "city": { + "name": "Orange", + "code": "TX", + "state": "Texas", + "county": "Orange", + "display": "West Orange" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8149168353046396568-1859", + "name": "Socrata Incorporated", + "city": { + "name": "Asbury Park", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Wanamassa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6333925905070003595-1860", + "name": "Oversight Systems Corporation", + "city": { + "name": "Zebulon", + "code": "NC", + "state": "North Carolina", + "county": "Wake", + "display": "Zebulon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-148818887783907064-1861", + "name": "PlanetEcosystems LLC", + "city": { + "name": "Liberty Corner", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Liberty Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2018122545907442435-1862", + "name": "Mint Incorporated", + "city": { + "name": "Sugar Grove", + "code": "NC", + "state": "North Carolina", + "county": "Watauga", + "display": "Sweetwater" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7811605540752032210-1863", + "name": "Quertle Corp", + "city": { + "name": "Alto", + "code": "MI", + "state": "Michigan", + "county": "Kent", + "display": "Alto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-242193190197934238-1864", + "name": "Smart Utility Systems LLC", + "city": { + "name": "Bryan", + "code": "TX", + "state": "Texas", + "county": "Brazos", + "display": "Wixon Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1920220833265438234-1865", + "name": "Reed Elsevier LLC", + "city": { + "name": "Spring Lake", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Spring Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4427521111619747928-1866", + "name": "Harris Inc", + "city": { + "name": "Saint Johns", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Switzerland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4252935998647261010-1867", + "name": "Avalara Company", + "city": { + "name": "Blackfoot", + "code": "ID", + "state": "Idaho", + "county": "Bingham", + "display": "Thomas Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8939464617913427829-1868", + "name": "Orlin Research LLC", + "city": { + "name": "Corona", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Flushing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9017080597034832094-1869", + "name": "H3 Biomedicine Incorporated", + "city": { + "name": "Piermont", + "code": "NH", + "state": "New Hampshire", + "county": "Grafton", + "display": "Piermont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7904238630633999270-1870", + "name": "Seabourne LLC", + "city": { + "name": "Rye", + "code": "TX", + "state": "Texas", + "county": "Liberty", + "display": "Rye" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6145129450379232766-1871", + "name": "Archimedes Inc", + "city": { + "name": "Lincolnshire", + "code": "IL", + "state": "Illinois", + "county": "Lake", + "display": "Lincolnshire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2021619814846964830-1872", + "name": "Vizzuality Corporation", + "city": { + "name": "Fulton", + "code": "TX", + "state": "Texas", + "county": "Aransas", + "display": "Fulton Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7519446281981748185-1873", + "name": "Innovest Systems Company", + "city": { + "name": "Gilman", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Gilman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6821334620188101837-1874", + "name": "OpenPlans Company", + "city": { + "name": "Mount Vernon", + "code": "IN", + "state": "Indiana", + "county": "Posey", + "display": "Solitude" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8996534190707022359-1875", + "name": "Funding Circle LLC", + "city": { + "name": "Iron", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Iron Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7913196440572726918-1876", + "name": "AccuWeather Corp", + "city": { + "name": "Ann Arbor", + "code": "MI", + "state": "Michigan", + "county": "Washtenaw", + "display": "Loch Alpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7794565496813080446-1877", + "name": "Clean Power Finance Company", + "city": { + "name": "Belfry", + "code": "MT", + "state": "Montana", + "county": "Carbon", + "display": "Belfry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8070199781115386429-1878", + "name": "3 Round Stones, LLC", + "city": { + "name": "Decatur", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Dunaire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5727485141094519653-1879", + "name": "TrustedID Incorporated", + "city": { + "name": "Deming", + "code": "WA", + "state": "Washington", + "county": "Whatcom", + "display": "Glacier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2739368860632676442-1880", + "name": "Booz Allen Hamilton Inc", + "city": { + "name": "Mosinee", + "code": "WI", + "state": "Wisconsin", + "county": "Marathon", + "display": "Kronenwetter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9184421633800882608-1881", + "name": "Cloudmade Inc", + "city": { + "name": "Sumter", + "code": "SC", + "state": "South Carolina", + "county": "Sumter", + "display": "Bon Air" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7764730114398271405-1882", + "name": "Paxata Incorporated", + "city": { + "name": "West Topsham", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "East Orange" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8871424513070128272-1883", + "name": "Intermap Technologies LLC", + "city": { + "name": "Aurora", + "code": "IL", + "state": "Illinois", + "county": "Kane", + "display": "Northern Il Gas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3753721986074356988-1884", + "name": "eInstitutional Incorporated", + "city": { + "name": "Lander", + "code": "WY", + "state": "Wyoming", + "county": "Fremont", + "display": "Ethete" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1298821244598452182-1885", + "name": "GoodGuide Inc", + "city": { + "name": "Anton Chico", + "code": "NM", + "state": "New Mexico", + "county": "Guadalupe", + "display": "Upper Anton Chico" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6235799152272601113-1886", + "name": "Relationship Science Company", + "city": { + "name": "Gloster", + "code": "MS", + "state": "Mississippi", + "county": "Amite", + "display": "Bewelcome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7838262849370638069-1887", + "name": "Nielsen Inc", + "city": { + "name": "Garwin", + "code": "IA", + "state": "Iowa", + "county": "Tama", + "display": "Green Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7808879521933860114-1888", + "name": "Capital Cube Inc", + "city": { + "name": "King Cove", + "code": "AK", + "state": "Alaska", + "county": "Aleutians East", + "display": "King Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3343266881131926316-1889", + "name": "Rapid Cycle Solutions Incorporated", + "city": { + "name": "Colp", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Old Camp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-395354102896256436-1890", + "name": "Aunt Bertha, Incorporated", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "Macys Finance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-919425970799073456-1891", + "name": "Xatori Incorporated", + "city": { + "name": "Bark River", + "code": "MI", + "state": "Michigan", + "county": "Delta", + "display": "Schaffer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4940616466360711718-1892", + "name": "Nautilytics LLC", + "city": { + "name": "Santa Paula", + "code": "CA", + "state": "California", + "county": "Ventura", + "display": "Santa Paula" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5803968061506676943-1893", + "name": "Be Informed Corp", + "city": { + "name": "Hanover", + "code": "MD", + "state": "Maryland", + "county": "Anne Arundel", + "display": "Hanover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6751436910689267734-1894", + "name": "SpotHero.com Corporation", + "city": { + "name": "Walsenburg", + "code": "CO", + "state": "Colorado", + "county": "Huerfano", + "display": "Farista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3129182649053011167-1895", + "name": "Level One Technologies Incorporated", + "city": { + "name": "Edneyville", + "code": "NC", + "state": "North Carolina", + "county": "Henderson", + "display": "Edneyville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3192266355516927132-1896", + "name": "Compliance and Risks Company", + "city": { + "name": "Yorktown", + "code": "VA", + "state": "Virginia", + "county": "York", + "display": "Nav Wpns Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6646940699362336159-1897", + "name": "Solar Census Incorporated", + "city": { + "name": "Rossville", + "code": "TN", + "state": "Tennessee", + "county": "Fayette", + "display": "Rossville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8607600450328727285-1898", + "name": "Peterson's Corporation", + "city": { + "name": "Acme", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Acme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-104503219600498336-1899", + "name": "Telenav Corp", + "city": { + "name": "Frankfort", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Frankfort" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3050893867898245050-1900", + "name": "HERE Corporation", + "city": { + "name": "Central", + "code": "SC", + "state": "South Carolina", + "county": "Pickens", + "display": "Central" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1876850926713248871-1901", + "name": "Onvia LLC", + "city": { + "name": "Lake Ariel", + "code": "PA", + "state": "Pennsylvania", + "county": "Wayne", + "display": "Cobbs Lake Preserve" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6854094334534866066-1902", + "name": "Spikes Cavell Analytic Incorporated", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Miami Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-802008014196009459-1903", + "name": "DemystData Corporation", + "city": { + "name": "New London", + "code": "IA", + "state": "Iowa", + "county": "Henry", + "display": "Lowell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5433974346803808148-1904", + "name": "MicroBilt Incorporated", + "city": { + "name": "Alma", + "code": "AR", + "state": "Arkansas", + "county": "Crawford", + "display": "Alma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8728772067811652277-1905", + "name": "Kaiser Permanante LLC", + "city": { + "name": "Raleigh", + "code": "NC", + "state": "North Carolina", + "county": "Wake", + "display": "North Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1853282087954308772-1906", + "name": "Navico Incorporated", + "city": { + "name": "Fargo", + "code": "ND", + "state": "North Dakota", + "county": "Cass", + "display": "Reiles Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-682878763404600020-1907", + "name": "Ontodia, Inc", + "city": { + "name": "Weston", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Silver Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4472596049605653758-1908", + "name": "SimpleTuition Corp", + "city": { + "name": "Spring Hill", + "code": "FL", + "state": "Florida", + "county": "Pasco", + "display": "Shady Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1534110277477415276-1909", + "name": "Environmental Data Resources Inc", + "city": { + "name": "Corning", + "code": "KS", + "state": "Kansas", + "county": "Nemaha", + "display": "Corning" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8243252581493135003-1910", + "name": "Galorath orporated Corp", + "city": { + "name": "Dugspur", + "code": "VA", + "state": "Virginia", + "county": "Carroll", + "display": "Dugspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-343826278248000302-1911", + "name": "Liquid Robotics Corp", + "city": { + "name": "Juneau", + "code": "AK", + "state": "Alaska", + "county": "Juneau", + "display": "State Of Alaska Brm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1370564907374010457-1912", + "name": "Workhands Incorporated", + "city": { + "name": "Leslie", + "code": "MO", + "state": "Missouri", + "county": "Franklin", + "display": "Leslie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3570804076827519193-1913", + "name": "Reed Elsevier Inc", + "city": { + "name": "Burlingham", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Burlingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3833738016273364856-1914", + "name": "Weather Decision Technologies LLC", + "city": { + "name": "Laguna Hills", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Aliso Viejo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-335970154711059135-1915", + "name": "CliniCast Corporation", + "city": { + "name": "Ocean View", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "Ocean View" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8528060938840017890-1916", + "name": "Analytica Incorporated", + "city": { + "name": "Cornwall On Hudson", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Cornwall Hud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3989048984619820758-1917", + "name": "Spikes Cavell Analytic Company", + "city": { + "name": "Butler", + "code": "TN", + "state": "Tennessee", + "county": "Johnson", + "display": "Butler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6157531712744242315-1918", + "name": "The Advisory Board Company Company", + "city": { + "name": "Lebanon", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5541234256776976213-1919", + "name": "realtor.com Inc", + "city": { + "name": "Climax", + "code": "NC", + "state": "North Carolina", + "county": "Guilford", + "display": "Climax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2774976880038862419-1920", + "name": "Harris Company", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Universal Postal Union Congr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4293511076811730795-1921", + "name": "LoopNet LLC", + "city": { + "name": "Albany", + "code": "KY", + "state": "Kentucky", + "county": "Clinton", + "display": "Snow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7126105818867941359-1922", + "name": "CB Insights Incorporated", + "city": { + "name": "Wellington", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "West Palm Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4227527220673013759-1923", + "name": "SAS Corp", + "city": { + "name": "Ocean Springs", + "code": "MS", + "state": "Mississippi", + "county": "Jackson", + "display": "Gulf Park Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5865936979894073233-1924", + "name": "EMC LLC", + "city": { + "name": "Blackey", + "code": "KY", + "state": "Kentucky", + "county": "Letcher", + "display": "Carcassonne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5534336541744482523-1925", + "name": "Revelstone Company", + "city": { + "name": "Edinburg", + "code": "ND", + "state": "North Dakota", + "county": "Walsh", + "display": "Gardar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7795318600821964449-1926", + "name": "Development Seed Inc", + "city": { + "name": "Laguna Park", + "code": "TX", + "state": "Texas", + "county": "Bosque", + "display": "Laguna Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7810305651402412676-1927", + "name": "CoolClimate LLC", + "city": { + "name": "Pawtucket", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Pawtucket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4659544945473606610-1928", + "name": "Knowledge Agency Company", + "city": { + "name": "San Simon", + "code": "AZ", + "state": "Arizona", + "county": "Cochise", + "display": "Portal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7914869840688297555-1929", + "name": "ProgrammableWeb Incorporated", + "city": { + "name": "Sloatsburg", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "Sloatsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4810246019628772601-1930", + "name": "Ranku Incorporated", + "city": { + "name": "Briceville", + "code": "TN", + "state": "Tennessee", + "county": "Anderson", + "display": "Devonia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3369996514632458230-1931", + "name": "AutoGrid Systems Corporation", + "city": { + "name": "Lockney", + "code": "TX", + "state": "Texas", + "county": "Floyd", + "display": "Lockney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8109132517373438456-1932", + "name": "Zillow Company", + "city": { + "name": "Sharon", + "code": "KS", + "state": "Kansas", + "county": "Barber", + "display": "Sharon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7815763637441632901-1933", + "name": "AllState Insurance Group Corp", + "city": { + "name": "Columbus Junction", + "code": "IA", + "state": "Iowa", + "county": "Louisa", + "display": "Cairo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6438052892008089559-1934", + "name": "Innography Company", + "city": { + "name": "Sisseton", + "code": "SD", + "state": "South Dakota", + "county": "Roberts", + "display": "Agency Vlg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7090463260047346728-1935", + "name": "Rand McNally Inc", + "city": { + "name": "Burlingame", + "code": "KS", + "state": "Kansas", + "county": "Osage", + "display": "Burlingame" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-252123505414078850-1936", + "name": "Ayasdi Incorporated", + "city": { + "name": "Silver Beach", + "code": "MA", + "state": "Massachusetts", + "county": "Barnstable", + "display": "North Falmouth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3470849913966832319-1937", + "name": "Aquicore LLC", + "city": { + "name": "Tinnie", + "code": "NM", + "state": "New Mexico", + "county": "Lincoln", + "display": "Tinnie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8164268047256896709-1938", + "name": "Oliver Wyman Corp", + "city": { + "name": "Leesburg", + "code": "VA", + "state": "Virginia", + "county": "Loudoun", + "display": "Lucketts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3419813748015297587-1939", + "name": "BaleFire Global LLC", + "city": { + "name": "Bryan", + "code": "OH", + "state": "Ohio", + "county": "Williams", + "display": "Bryan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7102189847785632750-1940", + "name": "eScholar Incorporated", + "city": { + "name": "Vancourt", + "code": "TX", + "state": "Texas", + "county": "Tom Green", + "display": "Vancourt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6922775894945317308-1941", + "name": "Weight Watchers Company", + "city": { + "name": "Barto", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Harlem" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3395121928660789852-1942", + "name": "Fitch Company", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Washing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6918063848981560325-1943", + "name": "Eat Shop Sleep Corporation", + "city": { + "name": "Rotonda West", + "code": "FL", + "state": "Florida", + "county": "Charlotte", + "display": "Placida" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4795149947427168661-1944", + "name": "CoreLogic Corp", + "city": { + "name": "Ganado", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Greasewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8506040051790221443-1945", + "name": "Reed Elsevier Inc", + "city": { + "name": "Cuyahoga Falls", + "code": "OH", + "state": "Ohio", + "county": "Summit", + "display": "Cuyahoga Fls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3196004713219587155-1946", + "name": "GenoSpace Corporation", + "city": { + "name": "Edinburgh", + "code": "IN", + "state": "Indiana", + "county": "Johnson", + "display": "Edinburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4258793625304672888-1947", + "name": "H3 Biomedicine Company", + "city": { + "name": "Bridgeton", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Upper Deerfield Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7067813553644404399-1948", + "name": "Propeller Health Corp", + "city": { + "name": "Franklin", + "code": "NC", + "state": "North Carolina", + "county": "Macon", + "display": "Cartoogechaye" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3732612624523025145-1949", + "name": "Dow Jones \u0026 Co Corp", + "city": { + "name": "Loysville", + "code": "PA", + "state": "Pennsylvania", + "county": "Perry", + "display": "Loysville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6493241432758654546-1950", + "name": "Aidin Corporation", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Peace Corps" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1481235180963086954-1951", + "name": "SnapSense Corp", + "city": { + "name": "Gilmer", + "code": "TX", + "state": "Texas", + "county": "Upshur", + "display": "Soules Chapel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2041711098425947604-1952", + "name": "MuckRock.com Incorporated", + "city": { + "name": "Manti", + "code": "UT", + "state": "Utah", + "county": "Sanpete", + "display": "Manti" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-330613273288737386-1953", + "name": "Food+Tech Connect Corp", + "city": { + "name": "Unadilla", + "code": "GA", + "state": "Georgia", + "county": "Dooly", + "display": "Unidilla" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1660236661733473233-1954", + "name": "HealthPocket, Corp", + "city": { + "name": "Levittown", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Island Trees" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2723686352222514065-1955", + "name": "Altova Corporation", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Swepco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1734132642281128513-1956", + "name": "Boundless Company", + "city": { + "name": "Central", + "code": "AZ", + "state": "Arizona", + "county": "Graham", + "display": "Central" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-460133167224795609-1957", + "name": "InCadence Incorporated", + "city": { + "name": "Lopez", + "code": "PA", + "state": "Pennsylvania", + "county": "Sullivan", + "display": "Lopez" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2708896409316756384-1958", + "name": "Sophic Systems Alliance Incorporated", + "city": { + "name": "Patchogue", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "East Patchogue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3231705486377967156-1959", + "name": "Impact Forecasting Corporation", + "city": { + "name": "Big Pine Key", + "code": "FL", + "state": "Florida", + "county": "Monroe", + "display": "Summrlnd Key" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5697027948385390166-1960", + "name": "First Fuel Software Corporation", + "city": { + "name": "Chinle", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Rough Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2109543514649725478-1961", + "name": "Xatori Company", + "city": { + "name": "Viborg", + "code": "SD", + "state": "South Dakota", + "county": "Turner", + "display": "Swan Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4060615216121381236-1962", + "name": "3 Round Stones, Corporation", + "city": { + "name": "Buras", + "code": "LA", + "state": "Louisiana", + "county": "Plaquemines", + "display": "Ostrica" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6242879513904411045-1963", + "name": "OSIsoft Company", + "city": { + "name": "Fairfield", + "code": "OH", + "state": "Ohio", + "county": "Butler", + "display": "Hamilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-405396296034009490-1964", + "name": "Inrix Traffic Inc", + "city": { + "name": "Peach Springs", + "code": "AZ", + "state": "Arizona", + "county": "Mohave", + "display": "Shipley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2504880757143138183-1965", + "name": "Cyte Corp", + "city": { + "name": "Menahga", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Midway" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1836906115563190843-1966", + "name": "WebFilings Corporation", + "city": { + "name": "Seahurst", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Seahurst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4494801725518989110-1967", + "name": "Harris LLC", + "city": { + "name": "Hendersonville", + "code": "TN", + "state": "Tennessee", + "county": "Sumner", + "display": "Hendersonvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5495738535497941091-1968", + "name": "Spokeo Corporation", + "city": { + "name": "Pine Mountain Club", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Pine Mountain Club" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2582205235883758759-1969", + "name": "Google Maps Corporation", + "city": { + "name": "Nevada", + "code": "OH", + "state": "Ohio", + "county": "Wyandot", + "display": "Nevada" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6337656054696094087-1970", + "name": "Outline Corp", + "city": { + "name": "Farmington", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-606405767475659441-1971", + "name": "PeerJ Incorporated", + "city": { + "name": "Garwin", + "code": "IA", + "state": "Iowa", + "county": "Tama", + "display": "Green Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1987627147863351947-1972", + "name": "R R Donnelley Corporation", + "city": { + "name": "Everglades City", + "code": "FL", + "state": "Florida", + "county": "Collier", + "display": "Everglades City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1452256606065716522-1973", + "name": "Booz Allen Hamilton Corp", + "city": { + "name": "Scammon", + "code": "KS", + "state": "Kansas", + "county": "Cherokee", + "display": "Scammon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2218103766859355815-1974", + "name": "Department of Better Technology Corp", + "city": { + "name": "Henderson", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Woodville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4657454045366004477-1975", + "name": "Keychain Logistics Inc", + "city": { + "name": "Mitchell", + "code": "IN", + "state": "Indiana", + "county": "Lawrence", + "display": "Stonington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-167287395938538331-1976", + "name": "Symcat Incorporated", + "city": { + "name": "Murphy", + "code": "ID", + "state": "Idaho", + "county": "Owyhee", + "display": "Silver City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1492122374628396910-1977", + "name": "ProPublica LLC", + "city": { + "name": "Yellow Jacket", + "code": "CO", + "state": "Colorado", + "county": "Montezuma", + "display": "Yellow Jacket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-379425923160492450-1978", + "name": "Open Data Nation LLC", + "city": { + "name": "Langlois", + "code": "OR", + "state": "Oregon", + "county": "Curry", + "display": "Langlois" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-946938576309571669-1979", + "name": "Energy Points, Company", + "city": { + "name": "Grafton", + "code": "ND", + "state": "North Dakota", + "county": "Walsh", + "display": "Nash" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3794958316504402038-1980", + "name": "Paxata Corp", + "city": { + "name": "Howes", + "code": "SD", + "state": "South Dakota", + "county": "Meade", + "display": "Bridger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7004900663409793446-1981", + "name": "BuildZoom Corp", + "city": { + "name": "Lebanon", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Bolton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1527949680016834648-1982", + "name": "ProgrammableWeb Company", + "city": { + "name": "Lake Wilson", + "code": "MN", + "state": "Minnesota", + "county": "Murray", + "display": "Hadley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2941602822904035030-1983", + "name": "Aureus Sciences Incorporated", + "city": { + "name": "Logan", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Logan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-79035526541092669-1984", + "name": "FlightAware Company", + "city": { + "name": "Jacksonville", + "code": "TX", + "state": "Texas", + "county": "Cherokee", + "display": "Lake Jacksonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4824649851575965229-1985", + "name": "AreaVibes Corp", + "city": { + "name": "Petersburg", + "code": "IN", + "state": "Indiana", + "county": "Pike", + "display": "Petersburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3711125117776516024-1986", + "name": "The DocGraph Journal Incorporated", + "city": { + "name": "Bradley", + "code": "CA", + "state": "California", + "county": "Monterey", + "display": "Bradley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1982775135327292298-1987", + "name": "Google Maps LLC", + "city": { + "name": "Dayton", + "code": "WY", + "state": "Wyoming", + "county": "Sheridan", + "display": "Dayton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4514031061906573551-1988", + "name": "CrowdANALYTIX Incorporated", + "city": { + "name": "Wallingford", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Nether Providence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6452416264273540282-1989", + "name": "Cappex LLC", + "city": { + "name": "Petersburg", + "code": "WV", + "state": "West Virginia", + "county": "Grant", + "display": "Arthur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1719408191367538727-1990", + "name": "Funding Circle Company", + "city": { + "name": "Dumont", + "code": "MN", + "state": "Minnesota", + "county": "Traverse", + "display": "Dumont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7343209938945914939-1991", + "name": "Intermap Technologies Inc", + "city": { + "name": "Lumberton", + "code": "MS", + "state": "Mississippi", + "county": "Lamar", + "display": "Pistol Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6141047911798560222-1992", + "name": "Smart Utility Systems Company", + "city": { + "name": "Equinunk", + "code": "PA", + "state": "Pennsylvania", + "county": "Wayne", + "display": "Equinunk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5613912164367102811-1993", + "name": "IMS Health Incorporated", + "city": { + "name": "Spencer", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Vandalia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7835230944689011190-1994", + "name": "OSIsoft Inc", + "city": { + "name": "Greensburg", + "code": "KS", + "state": "Kansas", + "county": "Kiowa", + "display": "Greensburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8782922397731193789-1995", + "name": "Fuzion Apps, Incorporated", + "city": { + "name": "Mount Pleasant", + "code": "TN", + "state": "Tennessee", + "county": "Maury", + "display": "Mount Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5088065163945239072-1996", + "name": "Calcbench, Company", + "city": { + "name": "Petoskey", + "code": "MI", + "state": "Michigan", + "county": "Emmet", + "display": "Petoskey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4421929923619305898-1997", + "name": "Optensity Inc", + "city": { + "name": "Willow City", + "code": "ND", + "state": "North Dakota", + "county": "Bottineau", + "display": "Ostby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1612020807983605623-1998", + "name": "Civic Impulse Corp", + "city": { + "name": "White River Junction", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "White Riv Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6440710542374328456-1999", + "name": "CB Insights Inc", + "city": { + "name": "East Calais", + "code": "VT", + "state": "Vermont", + "county": "Washington", + "display": "South Woodbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4747880942375773845-2000", + "name": "Fuzion Apps, Company", + "city": { + "name": "Walnut Grove", + "code": "CA", + "state": "California", + "county": "Sacramento", + "display": "Long Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2351852095028854550-2001", + "name": "CONNECT-DOT Incorporated", + "city": { + "name": "New Madrid", + "code": "MO", + "state": "Missouri", + "county": "New Madrid", + "display": "Howardville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3324027814556202649-2002", + "name": "nGAP orporated Incorporated", + "city": { + "name": "Mont Belvieu", + "code": "TX", + "state": "Texas", + "county": "Chambers", + "display": "Mont Belvieu" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3431785582141048961-2003", + "name": "Panjiva Company", + "city": { + "name": "Willington", + "code": "CT", + "state": "Connecticut", + "county": "Tolland", + "display": "East Willington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5769909221142263890-2004", + "name": "PeerJ LLC", + "city": { + "name": "Pine Grove", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Suedburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1793622318948871326-2005", + "name": "Ranku Company", + "city": { + "name": "Daisy", + "code": "GA", + "state": "Georgia", + "county": "Evans", + "display": "Daisy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7105818567816023551-2006", + "name": "Archimedes Corp", + "city": { + "name": "Southport", + "code": "NC", + "state": "North Carolina", + "county": "Brunswick", + "display": "Boiling Spring Lakes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-290574456461800381-2007", + "name": "U.S. News Schools Corp", + "city": { + "name": "Niceville", + "code": "FL", + "state": "Florida", + "county": "Okaloosa", + "display": "Choctaw Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8935187122552085290-2008", + "name": "Chemical Abstracts Service Incorporated", + "city": { + "name": "Harrison Township", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Selfridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3636871369836192053-2009", + "name": "Nationwide Mutual Insurance Company Corporation", + "city": { + "name": "Brierfield", + "code": "AL", + "state": "Alabama", + "county": "Bibb", + "display": "Brierfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-645464586503645578-2010", + "name": "TransUnion Inc", + "city": { + "name": "Peridot", + "code": "AZ", + "state": "Arizona", + "county": "Gila", + "display": "Peridot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-312681846893318873-2011", + "name": "Civic Impulse LLC", + "city": { + "name": "Santee", + "code": "SC", + "state": "South Carolina", + "county": "Orangeburg", + "display": "Parlers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6676604363485253008-2012", + "name": "Dabo Health LLC", + "city": { + "name": "Glenmont", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Bethlehem Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4799710732976401183-2013", + "name": "eScholar Company", + "city": { + "name": "Mulkeytown", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Urbain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7162175503384301768-2014", + "name": "Yelp Incorporated", + "city": { + "name": "Seattle", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "East Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6800210015248978472-2015", + "name": "Civic Insight Inc", + "city": { + "name": "Paulden", + "code": "AZ", + "state": "Arizona", + "county": "Yavapai", + "display": "Paulden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1385322290189025151-2016", + "name": "ASC Partners Company", + "city": { + "name": "Cleveland", + "code": "OH", + "state": "Ohio", + "county": "Cuyahoga", + "display": "Middleburg Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5287400658532505848-2017", + "name": "Liberty Mutual Insurance Cos LLC", + "city": { + "name": "Jumping Branch", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Streeter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1508806214901433143-2018", + "name": "Weather Decision Technologies Company", + "city": { + "name": "Wichita Falls", + "code": "TX", + "state": "Texas", + "county": "Wichita", + "display": "Cashion Community" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5608851244909914029-2019", + "name": "TuvaLabs LLC", + "city": { + "name": "Gallup", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Williams Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2678319332253149099-2020", + "name": "Berkery Noyes MandASoft Company", + "city": { + "name": "South Rockwood", + "code": "MI", + "state": "Michigan", + "county": "Monroe", + "display": "South Rockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6973132280943662372-2021", + "name": "Mozio Incorporated", + "city": { + "name": "Kasson", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "Canisteo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4253340572496448153-2022", + "name": "Recargo Inc", + "city": { + "name": "Hanover", + "code": "MA", + "state": "Massachusetts", + "county": "Plymouth", + "display": "West Hanover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2285084036942815123-2023", + "name": "CAN Capital Company", + "city": { + "name": "Chillicothe", + "code": "MO", + "state": "Missouri", + "county": "Livingston", + "display": "Chillicothe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1505715565537170571-2024", + "name": "SAP Incorporated", + "city": { + "name": "Chesterfield", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Wildwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5399439611395128033-2025", + "name": "LoseIt.com Inc", + "city": { + "name": "West Haven", + "code": "CT", + "state": "Connecticut", + "county": "New Haven", + "display": "N Haven" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2401970533730926172-2026", + "name": "Overture Technologies Corporation", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Harris Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7347742380528889847-2027", + "name": "OpenCounter LLC", + "city": { + "name": "Burgettstown", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Burgettstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6481606743659216426-2028", + "name": "How's My Offer? Corporation", + "city": { + "name": "Walnut Ridge", + "code": "AR", + "state": "Arkansas", + "county": "Lawrence", + "display": "Wms College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7686358022906118629-2029", + "name": "Splunk Corporation", + "city": { + "name": "Ruso", + "code": "ND", + "state": "North Dakota", + "county": "Mclean", + "display": "Ruso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7688121626923060957-2030", + "name": "Equal Speed Corp", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "N Kansas City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2515463950124176169-2031", + "name": "Alarm.com LLC", + "city": { + "name": "Leeper", + "code": "PA", + "state": "Pennsylvania", + "county": "Clarion", + "display": "Leeper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4720841853374531491-2032", + "name": "Chubb Company", + "city": { + "name": "Gosport", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Baker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7738228592722990311-2033", + "name": "Remi Corp", + "city": { + "name": "Fleetwood", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Ruscombmanor Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7163173846524350160-2034", + "name": "Farmers Inc", + "city": { + "name": "Renovo", + "code": "PA", + "state": "Pennsylvania", + "county": "Clinton", + "display": "West Renovo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7834239492792525590-2035", + "name": "Knoema Corporation", + "city": { + "name": "Lagrange", + "code": "IN", + "state": "Indiana", + "county": "Lagrange", + "display": "Royer Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8151687272339696268-2036", + "name": "Embark LLC", + "city": { + "name": "Hardeeville", + "code": "SC", + "state": "South Carolina", + "county": "Jasper", + "display": "Limehouse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8384076641665717946-2037", + "name": "Wheaton World Wide Moving Company", + "city": { + "name": "Reading", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Mt Penn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6379741087328523228-2038", + "name": "Cappex Company", + "city": { + "name": "Newtonia", + "code": "MO", + "state": "Missouri", + "county": "Newton", + "display": "Neosho" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4811812860857469221-2039", + "name": "RAND Corp", + "city": { + "name": "Dinero", + "code": "TX", + "state": "Texas", + "county": "Live Oak", + "display": "Mount Lucas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5759259108566467600-2040", + "name": "Politify Inc", + "city": { + "name": "Signal Mountain", + "code": "TN", + "state": "Tennessee", + "county": "Hamilton", + "display": "Signal Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5932417275024666635-2041", + "name": "Personal, Inc", + "city": { + "name": "National Mine", + "code": "MI", + "state": "Michigan", + "county": "Marquette", + "display": "National Mine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3903495922712527012-2042", + "name": "WebFilings Corporation", + "city": { + "name": "Cucumber", + "code": "WV", + "state": "West Virginia", + "county": "Mcdowell", + "display": "Cucumber" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5269986198540987501-2043", + "name": "Weight Watchers Incorporated", + "city": { + "name": "New Berlin", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Hoboken" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5043490088184938276-2044", + "name": "Zurich Insurance LLC", + "city": { + "name": "Willow Beach", + "code": "AZ", + "state": "Arizona", + "county": "Mohave", + "display": "Willow Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7069170024533001647-2045", + "name": "RedLaser Corp", + "city": { + "name": "Vallecito", + "code": "CA", + "state": "California", + "county": "Calaveras", + "display": "Vallecito" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6759816399564420571-2046", + "name": "Apextech LLC", + "city": { + "name": "Maple Plain", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Minnetrista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2907197422111599738-2047", + "name": "IW Financial Incorporated", + "city": { + "name": "Bath", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Arrowsic" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-581443189053464825-2048", + "name": "Arpin Van Lines Corporation", + "city": { + "name": "Glen Flora", + "code": "WI", + "state": "Wisconsin", + "county": "Rusk", + "display": "Cedar Rapids" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-85296336753615842-2049", + "name": "PayScale, Corp", + "city": { + "name": "Greenfield Park", + "code": "NY", + "state": "New York", + "county": "Ulster", + "display": "Greenfld Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4076280677515969794-2050", + "name": "College Abacus, an ECMC initiative Company", + "city": { + "name": "Netarts", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Netarts Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8858183921089414691-2051", + "name": "StreetCred Software, Company", + "city": { + "name": "Kent", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Lake Sawyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4658337021899126495-2052", + "name": "OTC Markets Incorporated", + "city": { + "name": "Ocean View", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "Seaville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5048170492661210777-2053", + "name": "InnoCentive Inc", + "city": { + "name": "Gypsum", + "code": "OH", + "state": "Ohio", + "county": "Ottawa", + "display": "Gypsum" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4152173852081419737-2054", + "name": "ClearHealthCosts Company", + "city": { + "name": "Franklin", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Shawville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4985465122298411536-2055", + "name": "Ayasdi LLC", + "city": { + "name": "Mexia", + "code": "TX", + "state": "Texas", + "county": "Limestone", + "display": "Prairie Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-749092099381161011-2056", + "name": "Food+Tech Connect Corp", + "city": { + "name": "Lyerly", + "code": "GA", + "state": "Georgia", + "county": "Chattooga", + "display": "Lyerly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1530303445591711854-2057", + "name": "Earthquake Alert Company", + "city": { + "name": "Swedesboro", + "code": "NJ", + "state": "New Jersey", + "county": "Gloucester", + "display": "Logan Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1543283679345603516-2058", + "name": "StreamLink Software Corporation", + "city": { + "name": "Saint John", + "code": "KS", + "state": "Kansas", + "county": "Stafford", + "display": "Saint John" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1363319798938267879-2059", + "name": "PossibilityU LLC", + "city": { + "name": "Vergennes", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Oraville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-915162908814519110-2060", + "name": "StreamLink Software LLC", + "city": { + "name": "Pacoima", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Arleta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8820866562894801250-2061", + "name": "The DocGraph Journal Inc", + "city": { + "name": "Washington", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Washington Dt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3843046666760557539-2062", + "name": "Datamyne LLC", + "city": { + "name": "Ruby", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Ruby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2900364199635165440-2063", + "name": "Fastcase Corporation", + "city": { + "name": "Fonda", + "code": "IA", + "state": "Iowa", + "county": "Pocahontas", + "display": "Industry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7440845841787011410-2064", + "name": "Vitals LLC", + "city": { + "name": "Hamtramck", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Detroit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4950362109485488078-2065", + "name": "Socrata Corporation", + "city": { + "name": "North Canton", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Lake Slagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-548690777480409802-2066", + "name": "Cerner Inc", + "city": { + "name": "Pacoima", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Arleta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-313434640860429258-2067", + "name": "Child Care Desk Incorporated", + "city": { + "name": "De Pere", + "code": "WI", + "state": "Wisconsin", + "county": "Brown", + "display": "De Pere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5622164598846258789-2068", + "name": "TagniFi Inc", + "city": { + "name": "Ridley Park", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Ridley Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2454534005486002832-2069", + "name": "OnStar LLC", + "city": { + "name": "Sugarloaf", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Sugarloaf" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8544630567445204601-2070", + "name": "Nationwide Mutual Insurance Company Inc", + "city": { + "name": "Winter Haven", + "code": "FL", + "state": "Florida", + "county": "Polk", + "display": "Cypress Gdns" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6683956610230436425-2071", + "name": "Standard and Poor's Incorporated", + "city": { + "name": "Cataract", + "code": "WI", + "state": "Wisconsin", + "county": "Monroe", + "display": "Cataract" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7104897862795832954-2072", + "name": "Booz Allen Hamilton Incorporated", + "city": { + "name": "Wyalusing", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Wyalusing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2397354474004912338-2073", + "name": "Everyday Health Corp", + "city": { + "name": "Sugarcreek", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Shanesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2204365768590400739-2074", + "name": "Weather Channel Incorporated", + "city": { + "name": "Montrose", + "code": "NY", + "state": "New York", + "county": "Westchester", + "display": "Montrose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8840063677769978859-2075", + "name": "RAND Inc", + "city": { + "name": "Crystal Bay", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Orono" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7390549655669342302-2076", + "name": "FarmLogs Inc", + "city": { + "name": "Randolph Center", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "Randolph Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6455405630576015803-2077", + "name": "Impact Forecasting Company", + "city": { + "name": "Huntington", + "code": "WV", + "state": "West Virginia", + "county": "Cabell", + "display": "Huntington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2266838356752630338-2078", + "name": "CostQuest Company", + "city": { + "name": "Riverside", + "code": "MO", + "state": "Missouri", + "county": "Platte", + "display": "Kansas City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1801161683061235599-2079", + "name": "Dun \u0026 Bradstreet Corp", + "city": { + "name": "Potts Camp", + "code": "MS", + "state": "Mississippi", + "county": "Marshall", + "display": "Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1043001980800929737-2080", + "name": "Factual Corporation", + "city": { + "name": "Whitewater", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Cabazon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7488729583810847418-2081", + "name": "WaterSmart Software LLC", + "city": { + "name": "Seahurst", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Seahurst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5183633938431551284-2082", + "name": "iRecycle Inc", + "city": { + "name": "Mongaup Valley", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Mongaup Vly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7591246096961364545-2083", + "name": "Esri Corporation", + "city": { + "name": "Harpswell", + "code": "ME", + "state": "Maine", + "county": "Cumberland", + "display": "South Harpswell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8105403003796722792-2084", + "name": "Kaiser Permanante LLC", + "city": { + "name": "Tamiment", + "code": "PA", + "state": "Pennsylvania", + "county": "Pike", + "display": "Bushkill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8717108521186707521-2085", + "name": "Fuzion Apps, Company", + "city": { + "name": "Canon City", + "code": "CO", + "state": "Colorado", + "county": "Fremont", + "display": "Canon City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5298142230479810973-2086", + "name": "Business Monitor International Corporation", + "city": { + "name": "Oshkosh", + "code": "NE", + "state": "Nebraska", + "county": "Garden", + "display": "Oshkosh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8738140618645237974-2087", + "name": "Municode Corp", + "city": { + "name": "Waverly", + "code": "VA", + "state": "Virginia", + "county": "Sussex", + "display": "Waverly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2253170442114444190-2088", + "name": "Social Health Insights Corporation", + "city": { + "name": "Selbyville", + "code": "DE", + "state": "Delaware", + "county": "Sussex", + "display": "West Fenwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6749898945251501540-2089", + "name": "Healthline Corporation", + "city": { + "name": "Newland", + "code": "NC", + "state": "North Carolina", + "county": "Avery", + "display": "Stamey Branch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8219209499164411143-2090", + "name": "nGAP orporated Company", + "city": { + "name": "Albion", + "code": "IN", + "state": "Indiana", + "county": "Noble", + "display": "Burr Oak" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6439896994385000854-2091", + "name": "Mozio Company", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Marys Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-487012445881387903-2092", + "name": "Mercaris Incorporated", + "city": { + "name": "Fairfield", + "code": "IL", + "state": "Illinois", + "county": "Wayne", + "display": "Big Mound" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6260236079274660502-2093", + "name": "Ernst \u0026 Young LLP Company", + "city": { + "name": "East Moriches", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "E Moriches" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4504822619008337188-2094", + "name": "LoseIt.com Corporation", + "city": { + "name": "Georgetown", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Sun City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6292725066800418380-2095", + "name": "AreaVibes Company", + "city": { + "name": "Coal City", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Daggett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-609206937024214121-2096", + "name": "Kaiser Permanante Corporation", + "city": { + "name": "Sag Harbor", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Sag Harbor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7694276676429465991-2097", + "name": "Epsilon Corporation", + "city": { + "name": "Chesterfield", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Wildwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1254991387032907280-2098", + "name": "Palantir Technologies Company", + "city": { + "name": "Laramie", + "code": "WY", + "state": "Wyoming", + "county": "Albany", + "display": "Laramie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7248703483432369347-2099", + "name": "Onvia Company", + "city": { + "name": "Warren", + "code": "AR", + "state": "Arkansas", + "county": "Bradley", + "display": "Mckinney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-584770182169181026-2100", + "name": "How's My Offer? Company", + "city": { + "name": "Mobile", + "code": "AL", + "state": "Alabama", + "county": "Mobile", + "display": "Chickasaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7887271609061460485-2101", + "name": "Oversight Systems Company", + "city": { + "name": "Cambridge", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Weller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9172480606693781075-2102", + "name": "Russell Investments Corp", + "city": { + "name": "Humptulips", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Humptulips" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6139406473617438545-2103", + "name": "New Media Parents Corporation", + "city": { + "name": "Hollandale", + "code": "MS", + "state": "Mississippi", + "county": "Washington", + "display": "Estill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1958940060781079996-2104", + "name": "NerdWallet Inc", + "city": { + "name": "Ecorse", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "River Rouge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3620471622835160198-2105", + "name": "Personalis LLC", + "city": { + "name": "Hampton", + "code": "IA", + "state": "Iowa", + "county": "Franklin", + "display": "Hansell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1848350956118022570-2106", + "name": "Liberty Mutual Insurance Cos Corp", + "city": { + "name": "Mount Carmel", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Mt Carmel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7186971368651599890-2107", + "name": "SpotCrime Company", + "city": { + "name": "Compton", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Rancho Dominguez" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1051620075153185487-2108", + "name": "Bloomberg Corp", + "city": { + "name": "Lincoln", + "code": "NE", + "state": "Nebraska", + "county": "Lancaster", + "display": "Prairie Home" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1209455200646271637-2109", + "name": "Maponics Corp", + "city": { + "name": "Erie", + "code": "PA", + "state": "Pennsylvania", + "county": "Erie", + "display": "Erie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5882306431085379070-2110", + "name": "Fujitsu Corp", + "city": { + "name": "Salt Lake City", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "Holladay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2917695888459741228-2111", + "name": "MuckRock.com Company", + "city": { + "name": "Houghton", + "code": "NY", + "state": "New York", + "county": "Allegany", + "display": "Houghton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1231827570170038225-2112", + "name": "MicroBilt LLC", + "city": { + "name": "Brandywine", + "code": "WV", + "state": "West Virginia", + "county": "Pendleton", + "display": "Brandywine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1813326298137610371-2113", + "name": "FlightView Inc", + "city": { + "name": "Ashburnham", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Ashburnham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2302396580074116747-2114", + "name": "Appallicious Corp", + "city": { + "name": "Springfield", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Mallet Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8046708228945971146-2115", + "name": "Import.io Incorporated", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Arsenal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8287552927504800138-2116", + "name": "Boundless Incorporated", + "city": { + "name": "Dale", + "code": "TX", + "state": "Texas", + "county": "Caldwell", + "display": "Dale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-606334940990121597-2117", + "name": "Smart Utility Systems Inc", + "city": { + "name": "Hamilton", + "code": "OH", + "state": "Ohio", + "county": "Butler", + "display": "Millville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6242060233251364075-2118", + "name": "Climate Corporation", + "city": { + "name": "Bedford", + "code": "IN", + "state": "Indiana", + "county": "Lawrence", + "display": "Englewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5583471375579098638-2119", + "name": "TransUnion Company", + "city": { + "name": "Georgetown", + "code": "CA", + "state": "California", + "county": "El Dorado", + "display": "Wentworth Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5121074501770230492-2120", + "name": "SnapSense Corporation", + "city": { + "name": "Gillett", + "code": "WI", + "state": "Wisconsin", + "county": "Oconto", + "display": "Pulcifer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5814974015686307503-2121", + "name": "Civic Insight Inc", + "city": { + "name": "Dinosaur", + "code": "CO", + "state": "Colorado", + "county": "Moffat", + "display": "Blue Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1487167683278666347-2122", + "name": "How's My Offer? Incorporated", + "city": { + "name": "Marion", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8447400800612954490-2123", + "name": "Owler Corporation", + "city": { + "name": "Ogden", + "code": "UT", + "state": "Utah", + "county": "Weber", + "display": "Warren" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2675935980021224386-2124", + "name": "StreetEasy Corporation", + "city": { + "name": "Spearsville", + "code": "LA", + "state": "Louisiana", + "county": "Union", + "display": "Lockhart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5770652485165480209-2125", + "name": "Intelius Inc", + "city": { + "name": "Brielle", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Brielle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1079349210656571523-2126", + "name": "Connotate Inc", + "city": { + "name": "Wilmot", + "code": "WI", + "state": "Wisconsin", + "county": "Kenosha", + "display": "Wilmot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5475088436743436874-2127", + "name": "ConnectEDU Company", + "city": { + "name": "Newhall", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Newhall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1613862810283166010-2128", + "name": "CONNECT-DOT LLC", + "city": { + "name": "Pingree", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Pingree" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-694748015451004292-2129", + "name": "HealthMap Corporation", + "city": { + "name": "Milan", + "code": "MI", + "state": "Michigan", + "county": "Monroe", + "display": "Milan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7173839889979805595-2130", + "name": "Progressive Insurance Group LLC", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Melbourne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4804302390107032060-2131", + "name": "Deloitte LLC", + "city": { + "name": "Machesney Park", + "code": "IL", + "state": "Illinois", + "county": "Winnebago", + "display": "Machesney Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7406930536669589785-2132", + "name": "Nationwide Mutual Insurance Company Company", + "city": { + "name": "Garland", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Garland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4521335632528212509-2133", + "name": "Azavea Inc", + "city": { + "name": "Mc Graws", + "code": "WV", + "state": "West Virginia", + "county": "Wyoming", + "display": "Mc Graws" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6296189694213196810-2134", + "name": "SpaceCurve Corp", + "city": { + "name": "New Laguna", + "code": "NM", + "state": "New Mexico", + "county": "Cibola", + "display": "Encinal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7239014012219650709-2135", + "name": "Innovest Systems Incorporated", + "city": { + "name": "Klamath", + "code": "CA", + "state": "California", + "county": "Del Norte", + "display": "Klamath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1361895963548298700-2136", + "name": "Patently-O LLC", + "city": { + "name": "Hollandale", + "code": "MS", + "state": "Mississippi", + "county": "Washington", + "display": "Murphy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2358591091964492292-2137", + "name": "OpenGov Company", + "city": { + "name": "Holiday", + "code": "FL", + "state": "Florida", + "county": "Pasco", + "display": "Tarpon Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7241509264312493766-2138", + "name": "Apextech Company", + "city": { + "name": "Crook", + "code": "CO", + "state": "Colorado", + "county": "Logan", + "display": "Crook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3008858015039876702-2139", + "name": "National Van Lines Company", + "city": { + "name": "Yorktown", + "code": "VA", + "state": "Virginia", + "county": "York", + "display": "Nav Wpns Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-857799308816515833-2140", + "name": "Compliance and Risks Incorporated", + "city": { + "name": "De Kalb", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Siloam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2717276822112529390-2141", + "name": "Wheaton World Wide Moving Company", + "city": { + "name": "Daisetta", + "code": "TX", + "state": "Texas", + "county": "Liberty", + "display": "Daisetta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3807910583766643136-2142", + "name": "Socrata Incorporated", + "city": { + "name": "Saint George", + "code": "GA", + "state": "Georgia", + "county": "Charlton", + "display": "Saint George" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3049322175534672897-2143", + "name": "PeerJ Company", + "city": { + "name": "Laverne", + "code": "OK", + "state": "Oklahoma", + "county": "Harper", + "display": "Laverne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4894711214343197823-2144", + "name": "Impaq International Corporation", + "city": { + "name": "Geneseo", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Hanna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4771888029058967585-2145", + "name": "Personalis LLC", + "city": { + "name": "Saint Paul", + "code": "MN", + "state": "Minnesota", + "county": "Ramsey", + "display": "Maplewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4662736178134280401-2146", + "name": "Epsilon Company", + "city": { + "name": "Burley", + "code": "ID", + "state": "Idaho", + "county": "Cassia", + "display": "Starrhs Ferry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9129055576896762849-2147", + "name": "Jurispect Corporation", + "city": { + "name": "Menahga", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Blueberry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3705676742802819343-2148", + "name": "Maponics Inc", + "city": { + "name": "Post Falls", + "code": "ID", + "state": "Idaho", + "county": "Kootenai", + "display": "State Line" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8586354287358409825-2149", + "name": "Patently-O Inc", + "city": { + "name": "Taberg", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Point Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2606557876956799810-2150", + "name": "Nautilytics Incorporated", + "city": { + "name": "Rudyard", + "code": "MI", + "state": "Michigan", + "county": "Chippewa", + "display": "Rudyard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6847406003551017932-2151", + "name": "xDayta Incorporated", + "city": { + "name": "Columbus", + "code": "MS", + "state": "Mississippi", + "county": "Lowndes", + "display": "Golden Triangle Regional Air" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8874339057685439512-2152", + "name": "Socrata Company", + "city": { + "name": "Swords Creek", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Dye" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8951030846322561753-2153", + "name": "Arpin Van Lines Corp", + "city": { + "name": "Belleville", + "code": "IL", + "state": "Illinois", + "county": "Saint Clair", + "display": "Shiloh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2810333199324229692-2154", + "name": "Geoscape LLC", + "city": { + "name": "Bacliff", + "code": "TX", + "state": "Texas", + "county": "Galveston", + "display": "Bacliff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1614392342681437575-2155", + "name": "McKinsey Company", + "city": { + "name": "Glenn", + "code": "CA", + "state": "California", + "county": "Glenn", + "display": "Bayliss" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1721416373754390619-2156", + "name": "KPMG Inc", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Richmond Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6219563967976598949-2157", + "name": "Graematter, Inc", + "city": { + "name": "Hankamer", + "code": "TX", + "state": "Texas", + "county": "Chambers", + "display": "Haukanier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5162200340816411064-2158", + "name": "Suddath Corporation", + "city": { + "name": "Burgettstown", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Burgettstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4588921100822081569-2159", + "name": "SpotCrime LLC", + "city": { + "name": "Aspermont", + "code": "TX", + "state": "Texas", + "county": "Stonewall", + "display": "Peacock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1682132191012891077-2160", + "name": "Compliance and Risks Corp", + "city": { + "name": "Bellevue", + "code": "MI", + "state": "Michigan", + "county": "Eaton", + "display": "Bellevue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4116753294854206779-2161", + "name": "Brightscope Incorporated", + "city": { + "name": "De Soto", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "De Soto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3544168759473650673-2162", + "name": "Vitals Inc", + "city": { + "name": "Capitol", + "code": "MT", + "state": "Montana", + "county": "Carter", + "display": "Capitol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5019412316780084025-2163", + "name": "Knowledge Agency Inc", + "city": { + "name": "Mill Neck", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Mill Neck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1472973300537298427-2164", + "name": "Fuzion Apps, Company", + "city": { + "name": "Boise", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Intermountain Gas Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4681820472754573959-2165", + "name": "IW Financial Corporation", + "city": { + "name": "Vernon", + "code": "TX", + "state": "Texas", + "county": "Wilbarger", + "display": "Vernon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1136173450756425999-2166", + "name": "American Red Ball Movers Inc", + "city": { + "name": "Gans", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Lake Lynn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4057059405950576294-2167", + "name": "Adaptive Company", + "city": { + "name": "Anthony", + "code": "TX", + "state": "Texas", + "county": "El Paso", + "display": "Vinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5767471392954883615-2168", + "name": "HDScores, Incorporated", + "city": { + "name": "Gibson", + "code": "PA", + "state": "Pennsylvania", + "county": "Susquehanna", + "display": "Gibson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6655078204350231748-2169", + "name": "WattzOn Incorporated", + "city": { + "name": "Ehrhardt", + "code": "SC", + "state": "South Carolina", + "county": "Bamberg", + "display": "Ehrhardt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2234212847800502900-2170", + "name": "Housefax LLC", + "city": { + "name": "Briceville", + "code": "TN", + "state": "Tennessee", + "county": "Anderson", + "display": "Devonia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5920408780514272032-2171", + "name": "CoolClimate Corp", + "city": { + "name": "Belt", + "code": "MT", + "state": "Montana", + "county": "Cascade", + "display": "Armington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2639121575405853684-2172", + "name": "AreaVibes Inc", + "city": { + "name": "Grand Ridge", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Grand Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7809781074542297296-2173", + "name": "IMS Health LLC", + "city": { + "name": "Patuxent River", + "code": "MD", + "state": "Maryland", + "county": "Saint Marys", + "display": "Patuxent River Naval Air Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2599584633806340814-2174", + "name": "Science Exchange Corp", + "city": { + "name": "Crestline", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Crestline" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8318750248750993337-2175", + "name": "Suddath Corp", + "city": { + "name": "Mc Caskill", + "code": "AR", + "state": "Arkansas", + "county": "Hempstead", + "display": "Mc Caskill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2239510948571909921-2176", + "name": "Smartronix Corp", + "city": { + "name": "East Bend", + "code": "NC", + "state": "North Carolina", + "county": "Yadkin", + "display": "East Bend" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-526899588813584519-2177", + "name": "Brightscope Corporation", + "city": { + "name": "Topeka", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Goofy Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7715563802459315812-2178", + "name": "Castle Biosciences Corporation", + "city": { + "name": "Mapleton Depot", + "code": "PA", + "state": "Pennsylvania", + "county": "Huntingdon", + "display": "Mapleton Dep" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7593164603022618652-2179", + "name": "FarmLogs Corporation", + "city": { + "name": "Brady Lake", + "code": "OH", + "state": "Ohio", + "county": "Portage", + "display": "Brady Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-673082796208013409-2180", + "name": "Merrill Lynch LLC", + "city": { + "name": "New Augusta", + "code": "MS", + "state": "Mississippi", + "county": "Perry", + "display": "Wingate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1627584486470054925-2181", + "name": "Castle Biosciences Company", + "city": { + "name": "Kent", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Lake Sawyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2707011509237769539-2182", + "name": "Capital Cube Incorporated", + "city": { + "name": "Warminster", + "code": "PA", + "state": "Pennsylvania", + "county": "Bucks", + "display": "Warwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1149282295228408288-2183", + "name": "Fastcase Inc", + "city": { + "name": "Muskogee", + "code": "OK", + "state": "Oklahoma", + "county": "Muskogee", + "display": "Bacone" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1665441801623172425-2184", + "name": "Junyo Corp", + "city": { + "name": "Savage", + "code": "MD", + "state": "Maryland", + "county": "Howard", + "display": "Savage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8384554879878010241-2185", + "name": "College Board Corporation", + "city": { + "name": "Andover", + "code": "NJ", + "state": "New Jersey", + "county": "Sussex", + "display": "Byram Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8342604073328554658-2186", + "name": "TrueCar Company", + "city": { + "name": "Pottsboro", + "code": "TX", + "state": "Texas", + "county": "Grayson", + "display": "Pottsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7859938382164523590-2187", + "name": "College Abacus, an ECMC initiative Corporation", + "city": { + "name": "Baytown", + "code": "TX", + "state": "Texas", + "county": "Chambers", + "display": "Beach City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1236871826471331263-2188", + "name": "Sterling Infosystems Inc", + "city": { + "name": "Newark", + "code": "NJ", + "state": "New Jersey", + "county": "Essex", + "display": "Bank Of New York" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3651330856593916345-2189", + "name": "LOGIXDATA, Company", + "city": { + "name": "Lighthouse Point", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Lighthouse Pt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5255782712929361173-2190", + "name": "Lumesis, Corp", + "city": { + "name": "Rosedale", + "code": "IN", + "state": "Indiana", + "county": "Parke", + "display": "Diamond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7499123441191329186-2191", + "name": "Thomson Reuters LLC", + "city": { + "name": "Cape May Point", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "Cape May Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-993962283946896746-2192", + "name": "StockSmart Incorporated", + "city": { + "name": "Ruso", + "code": "ND", + "state": "North Dakota", + "county": "Mclean", + "display": "Ruso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1177196185012379547-2193", + "name": "Azavea Corp", + "city": { + "name": "Yakima", + "code": "WA", + "state": "Washington", + "county": "Yakima", + "display": "Yakima Firing Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5372377318059509512-2194", + "name": "Funding Circle Inc", + "city": { + "name": "Beatty", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Rhyolite" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8166031882320479475-2195", + "name": "Credit Sesame Company", + "city": { + "name": "Cynthiana", + "code": "KY", + "state": "Kentucky", + "county": "Harrison", + "display": "Leesburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1903235136445899702-2196", + "name": "Tableau Software LLC", + "city": { + "name": "Watertown", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Watertown Financial" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5369096662950307860-2197", + "name": "Vizzuality Company", + "city": { + "name": "Wildwood", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "N Wildwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8130549795287863742-2198", + "name": "TopCoder Corp", + "city": { + "name": "Frankfort", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Frankfort" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3186700242799990125-2199", + "name": "Solar Census Corp", + "city": { + "name": "Rockport", + "code": "TX", + "state": "Texas", + "county": "Aransas", + "display": "Lamar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4666270752359439683-2200", + "name": "Chemical Abstracts Service Company", + "city": { + "name": "Huron", + "code": "OH", + "state": "Ohio", + "county": "Erie", + "display": "Ceylon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7396039181341331740-2201", + "name": "Owler Corp", + "city": { + "name": "Nedrow", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Onondaga Nation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4827834374781232154-2202", + "name": "Synthicity Company", + "city": { + "name": "Monroe Bridge", + "code": "MA", + "state": "Massachusetts", + "county": "Franklin", + "display": "Monroe Bridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8826084494570046835-2203", + "name": "Liquid Robotics Company", + "city": { + "name": "Moroni", + "code": "UT", + "state": "Utah", + "county": "Sanpete", + "display": "Moroni" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8781897929720521966-2204", + "name": "CostQuest Corporation", + "city": { + "name": "Park City", + "code": "UT", + "state": "Utah", + "county": "Summit", + "display": "Kimball Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5294610035743540018-2205", + "name": "HopStop Corporation", + "city": { + "name": "Oxford", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Oxford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6572228553603785230-2206", + "name": "Wolters Kluwer Corp", + "city": { + "name": "Clifton", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Clifton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4666441081636130062-2207", + "name": "Pave LLC", + "city": { + "name": "Larkspur", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Larkspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1554808835250929007-2208", + "name": "SpaceCurve Corporation", + "city": { + "name": "Mcdonough", + "code": "GA", + "state": "Georgia", + "county": "Henry", + "display": "Mcdonough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7491580963417833057-2209", + "name": "Govini Corp", + "city": { + "name": "Jamaica", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Rochdale Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6487146177977535558-2210", + "name": "POPVOX Corp", + "city": { + "name": "Crystal Bay", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Crystal Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2167353433088528175-2211", + "name": "Weight Watchers Corporation", + "city": { + "name": "Presho", + "code": "SD", + "state": "South Dakota", + "county": "Lyman", + "display": "Edna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4121824596765139610-2212", + "name": "Innography Inc", + "city": { + "name": "Macomb", + "code": "MO", + "state": "Missouri", + "county": "Wright", + "display": "Macomb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7357555504394876776-2213", + "name": "Whitby Group LLC", + "city": { + "name": "New Cumberland", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Fair Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7081699755521429708-2214", + "name": "Business Monitor International Corporation", + "city": { + "name": "Gravity", + "code": "IA", + "state": "Iowa", + "county": "Taylor", + "display": "Gravity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1688281404092970387-2215", + "name": "Clean Power Finance Corp", + "city": { + "name": "South Wellfleet", + "code": "MA", + "state": "Massachusetts", + "county": "Barnstable", + "display": "South Wellfleet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4027797767803600240-2216", + "name": "PublicEngines Corporation", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Ohio Dept Of Taxation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2022873476888900264-2217", + "name": "Adobe Digital Government Inc", + "city": { + "name": "Beltrami", + "code": "MN", + "state": "Minnesota", + "county": "Polk", + "display": "Beltrami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7506980057619363063-2218", + "name": "CONNECT-DOT Incorporated", + "city": { + "name": "Magnolia", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Magnolia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5177528499611283052-2219", + "name": "PatientsLikeMe Company", + "city": { + "name": "Buckland", + "code": "OH", + "state": "Ohio", + "county": "Auglaize", + "display": "Buckland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4482417483793510071-2220", + "name": "TagniFi Company", + "city": { + "name": "Greensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Allegheny Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1015147204438335999-2221", + "name": "Fuzion Apps, Inc", + "city": { + "name": "Live Oak", + "code": "FL", + "state": "Florida", + "county": "Suwannee", + "display": "Dowling Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6655786505517351698-2222", + "name": "Allied Van Lines Corporation", + "city": { + "name": "Jameson", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Jameson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6273564917955955655-2223", + "name": "Government Transaction Services Inc", + "city": { + "name": "Mason City", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Teheran" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7320900050245336014-2224", + "name": "HealthPocket, Incorporated", + "city": { + "name": "Amboy", + "code": "WA", + "state": "Washington", + "county": "Clark", + "display": "Chelatchie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7221220992850806056-2225", + "name": "The Bridgespan Group Company", + "city": { + "name": "Knoxville", + "code": "TN", + "state": "Tennessee", + "county": "Knox", + "display": "Lonsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3453069554306348318-2226", + "name": "ideas42 Corporation", + "city": { + "name": "Hilltop", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Hilltop" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5661425785381140695-2227", + "name": "Acxiom Inc", + "city": { + "name": "Oak Brook", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Hinsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2426870419319267256-2228", + "name": "Predilytics Company", + "city": { + "name": "Lake City", + "code": "AR", + "state": "Arkansas", + "county": "Craighead", + "display": "Lake City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4197624786978202456-2229", + "name": "karmadata LLC", + "city": { + "name": "Starkville", + "code": "MS", + "state": "Mississippi", + "county": "Oktibbeha", + "display": "Osborn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9119855540333542342-2230", + "name": "WaterSmart Software Incorporated", + "city": { + "name": "Hendersonville", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Hendersonvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4276528932795608009-2231", + "name": "Marinexplore, LLC", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Crafton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7838717097907005231-2232", + "name": "Avalara Incorporated", + "city": { + "name": "Prescott", + "code": "WA", + "state": "Washington", + "county": "Walla Walla", + "display": "Prescott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5231894117746015879-2233", + "name": "Zurich Insurance Company", + "city": { + "name": "Ganado", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Cornfields" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9164015919421640144-2234", + "name": "GetRaised LLC", + "city": { + "name": "Plummer", + "code": "MN", + "state": "Minnesota", + "county": "Red Lake", + "display": "Plummer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5452734478182482604-2235", + "name": "SimpleTuition LLC", + "city": { + "name": "Peridot", + "code": "AZ", + "state": "Arizona", + "county": "Gila", + "display": "Peridot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-678219064604851481-2236", + "name": "Vimo Corp", + "city": { + "name": "Ellisville", + "code": "MS", + "state": "Mississippi", + "county": "Jones", + "display": "Maybell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-478447605392886855-2237", + "name": "Glassy Media Incorporated", + "city": { + "name": "Cushing", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7900085649478666846-2238", + "name": "Asset4 Inc", + "city": { + "name": "Amargosa Valley", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Amargosa Vly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6518118050226284575-2239", + "name": "PublicEngines Corporation", + "city": { + "name": "Beatty", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Rhyolite" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2856707121880296057-2240", + "name": "Ensco Corp", + "city": { + "name": "Gleason", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Parrish" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3426534568069790806-2241", + "name": "Compliance and Risks Inc", + "city": { + "name": "Madison", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Madison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5084418135986587940-2242", + "name": "LegiStorm Corporation", + "city": { + "name": "Westfield", + "code": "PA", + "state": "Pennsylvania", + "county": "Tioga", + "display": "Westfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4609553735423176449-2243", + "name": "TransUnion Incorporated", + "city": { + "name": "Great Barrington", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Great Barrington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8106997193166281027-2244", + "name": "Legal Science Partners Corporation", + "city": { + "name": "New Franklin", + "code": "MO", + "state": "Missouri", + "county": "Howard", + "display": "New Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4088523055452750436-2245", + "name": "Arrive Labs Inc", + "city": { + "name": "Arthur", + "code": "IA", + "state": "Iowa", + "county": "Ida", + "display": "Arthur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3078902504245455877-2246", + "name": "OpportunitySpace, LLC", + "city": { + "name": "Middle Bass", + "code": "OH", + "state": "Ohio", + "county": "Ottawa", + "display": "Middle Bass" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4973527744345314681-2247", + "name": "Rivet Software Corporation", + "city": { + "name": "Mc Clellanville", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Mc Clellanville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-726583491091425922-2248", + "name": "Environmental Data Resources Incorporated", + "city": { + "name": "Corning", + "code": "OH", + "state": "Ohio", + "county": "Perry", + "display": "Corning" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2549311649894299406-2249", + "name": "Parsons Brinckerhoff Corp", + "city": { + "name": "Middletown", + "code": "CA", + "state": "California", + "county": "Lake", + "display": "Loch Lomond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5603229755638098794-2250", + "name": "Galorath orporated LLC", + "city": { + "name": "Susanville", + "code": "CA", + "state": "California", + "county": "Lassen", + "display": "Spaulding" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9140252942832768854-2251", + "name": "Ez-XBRL Company", + "city": { + "name": "Watsontown", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Watsonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-988391840956501686-2252", + "name": "TrialX Inc", + "city": { + "name": "Mcgregor", + "code": "MN", + "state": "Minnesota", + "county": "Aitkin", + "display": "Spalding" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6105786169104056884-2253", + "name": "Marinexplore, Incorporated", + "city": { + "name": "Chambersburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Franklin", + "display": "Sunbeam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1521451157369608485-2254", + "name": "Exversion Company", + "city": { + "name": "Kings Mountain", + "code": "KY", + "state": "Kentucky", + "county": "Lincoln", + "display": "Kings Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8306785525773385719-2255", + "name": "Thinknum Inc", + "city": { + "name": "Alto", + "code": "GA", + "state": "Georgia", + "county": "Habersham", + "display": "Alto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3709843457453519541-2256", + "name": "MicroBilt Corporation", + "city": { + "name": "Flatwoods", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Flatwoods" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8291327847212627761-2257", + "name": "Weight Watchers Company", + "city": { + "name": "Refton", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Refton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2756636270049988911-2258", + "name": "Calcbench, Corporation", + "city": { + "name": "Menlo", + "code": "WA", + "state": "Washington", + "county": "Pacific", + "display": "Menlo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4252662740806996599-2259", + "name": "Cloudmade LLC", + "city": { + "name": "Elverson", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Pine Swamp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7402153294358043111-2260", + "name": "VitalChek Company", + "city": { + "name": "Gilbert", + "code": "IA", + "state": "Iowa", + "county": "Story", + "display": "Gilbert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8986783350234989281-2261", + "name": "Pave Corporation", + "city": { + "name": "Crownpoint", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Lake Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6197725840354715086-2262", + "name": "Galorath orporated Incorporated", + "city": { + "name": "Brooklyn", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Holiday Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8846474296031307181-2263", + "name": "The Vanguard Group LLC", + "city": { + "name": "Paden", + "code": "OK", + "state": "Oklahoma", + "county": "Okfuskee", + "display": "Paden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-247240898058944024-2264", + "name": "KLD Research Company", + "city": { + "name": "Maynard", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Maynard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5897813093745221891-2265", + "name": "Weather Channel Inc", + "city": { + "name": "Osage", + "code": "IA", + "state": "Iowa", + "county": "Mitchell", + "display": "New Haven" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1345692989858970316-2266", + "name": "iRecycle Company", + "city": { + "name": "Murphysboro", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Somerset" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2487956279101883080-2267", + "name": "Porch Incorporated", + "city": { + "name": "Montpelier Station", + "code": "VA", + "state": "Virginia", + "county": "Orange", + "display": "Montpelier Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1062516662112410594-2268", + "name": "Wolters Kluwer LLC", + "city": { + "name": "Peru", + "code": "IN", + "state": "Indiana", + "county": "Miami", + "display": "Peru" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3798444585719376910-2269", + "name": "DataMade Corporation", + "city": { + "name": "Port Jefferson", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Prt Jefferson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2883270546334133296-2270", + "name": "VisualDoD, LLC", + "city": { + "name": "Nuremberg", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Fern Glen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6943480078370460055-2271", + "name": "Accela LLC", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Shademore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3629684178855773726-2272", + "name": "Politify Inc", + "city": { + "name": "Glen", + "code": "WV", + "state": "West Virginia", + "county": "Clay", + "display": "Glen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5388917917883940755-2273", + "name": "IW Financial LLC", + "city": { + "name": "Soldotna", + "code": "AK", + "state": "Alaska", + "county": "Kenai Peninsula", + "display": "Soldotna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5607563005502873860-2274", + "name": "Personal, Incorporated", + "city": { + "name": "Roca", + "code": "NE", + "state": "Nebraska", + "county": "Lancaster", + "display": "Saltillo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1727738275791230382-2275", + "name": "Honest Buildings Inc", + "city": { + "name": "Nimitz", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Nimitz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3356076389523804600-2276", + "name": "Lumesis, Company", + "city": { + "name": "Sikeston", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Sikeston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7088345622322544185-2277", + "name": "MapQuest Inc", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "K C" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5722409494336178129-2278", + "name": "Alarm.com LLC", + "city": { + "name": "Midland", + "code": "SD", + "state": "South Dakota", + "county": "Haakon", + "display": "England Ranch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5013297286137977665-2279", + "name": "Impaq International Company", + "city": { + "name": "Marion", + "code": "LA", + "state": "Louisiana", + "county": "Union", + "display": "Litroe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-920984617889488428-2280", + "name": "Teradata Inc", + "city": { + "name": "Fort Worth", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Federal Aviation Administrat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-184463285485716280-2281", + "name": "Ranku Company", + "city": { + "name": "South Amboy", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "South Amboy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6805746756234959771-2282", + "name": "OnStar Company", + "city": { + "name": "Hiawatha", + "code": "KS", + "state": "Kansas", + "county": "Brown", + "display": "Hamlin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2379813169246745569-2283", + "name": "HealthMap Corporation", + "city": { + "name": "South Hero", + "code": "VT", + "state": "Vermont", + "county": "Grand Isle", + "display": "Keeler Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2966982441168569226-2284", + "name": "Archimedes Company", + "city": { + "name": "Fort Mc Kavett", + "code": "TX", + "state": "Texas", + "county": "Menard", + "display": "Fort Mc Kavett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3549393722814065837-2285", + "name": "SnapSense Corporation", + "city": { + "name": "Phillipsburg", + "code": "KS", + "state": "Kansas", + "county": "Phillips", + "display": "Stuttgart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3996280646581169383-2286", + "name": "Compared Care Corp", + "city": { + "name": "Chewelah", + "code": "WA", + "state": "Washington", + "county": "Stevens", + "display": "Chewelah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9024432671794358780-2287", + "name": "VisualDoD, Incorporated", + "city": { + "name": "Rotonda West", + "code": "FL", + "state": "Florida", + "county": "Charlotte", + "display": "Placida" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6722605839021366207-2288", + "name": "MicroBilt Corporation", + "city": { + "name": "Chittenango", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Chittenango" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2734397367293067162-2289", + "name": "Datamyne Corp", + "city": { + "name": "Carson City", + "code": "NV", + "state": "Nevada", + "county": "Carson City", + "display": "Carson City Mall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7727273337241565830-2290", + "name": "PatientsLikeMe Company", + "city": { + "name": "Charlemont", + "code": "MA", + "state": "Massachusetts", + "county": "Franklin", + "display": "West Hawley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1863218560640223842-2291", + "name": "MuckRock.com Inc", + "city": { + "name": "Sinton", + "code": "TX", + "state": "Texas", + "county": "San Patricio", + "display": "Papalote" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2299345703006730227-2292", + "name": "CAN Capital Corp", + "city": { + "name": "Hartville", + "code": "MO", + "state": "Missouri", + "county": "Wright", + "display": "Hartville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1169086778186301766-2293", + "name": "Development Seed Corp", + "city": { + "name": "Franklin Springs", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Franklin Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4395240381419939186-2294", + "name": "Social Health Insights Company", + "city": { + "name": "Sumter", + "code": "SC", + "state": "South Carolina", + "county": "Sumter", + "display": "Bon Air" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2781848901938685670-2295", + "name": "Innovest Systems Corp", + "city": { + "name": "Woodville", + "code": "WI", + "state": "Wisconsin", + "county": "Saint Croix", + "display": "Woodville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3315271669988032101-2296", + "name": "Predilytics Corporation", + "city": { + "name": "Mound Bayou", + "code": "MS", + "state": "Mississippi", + "county": "Bolivar", + "display": "Mound Bayou" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7781632797565382822-2297", + "name": "Zonability Inc", + "city": { + "name": "Bloomsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Columbia", + "display": "Fernville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6250598328313271276-2298", + "name": "Trulia LLC", + "city": { + "name": "Lubbock", + "code": "TX", + "state": "Texas", + "county": "Lubbock", + "display": "City Of Lubbock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2130058147858464100-2299", + "name": "Retroficiency LLC", + "city": { + "name": "West Concord", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "West Concord" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1262434432150373818-2300", + "name": "SocialEffort Incorporated", + "city": { + "name": "Smithville", + "code": "TX", + "state": "Texas", + "county": "Bastrop", + "display": "Kirtley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7204272285904857053-2301", + "name": "FindTheBest.com Corp", + "city": { + "name": "Abie", + "code": "NE", + "state": "Nebraska", + "county": "Butler", + "display": "Abie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1881268800904753573-2302", + "name": "MuckRock.com LLC", + "city": { + "name": "Charleston", + "code": "WV", + "state": "West Virginia", + "county": "Kanawha", + "display": "Big Chimney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8314339532601656740-2303", + "name": "Careset.com Incorporated", + "city": { + "name": "Morrilton", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Morrilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6895893653310455985-2304", + "name": "Social Explorer LLC", + "city": { + "name": "Bellemont", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Flagstaff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5182673525448134558-2305", + "name": "Civinomics Company", + "city": { + "name": "Radersburg", + "code": "MT", + "state": "Montana", + "county": "Broadwater", + "display": "Radersburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2865850651439322343-2306", + "name": "FirstPoint, Corporation", + "city": { + "name": "Lake View", + "code": "SC", + "state": "South Carolina", + "county": "Dillon", + "display": "Lake View" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5033294592361540098-2307", + "name": "Weight Watchers Inc", + "city": { + "name": "Hawthorne", + "code": "NV", + "state": "Nevada", + "county": "Mineral", + "display": "Whiskey Flats" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2673352962799828358-2308", + "name": "Capital Cube LLC", + "city": { + "name": "Milton", + "code": "VT", + "state": "Vermont", + "county": "Chittenden", + "display": "Georgia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7775004742811916719-2309", + "name": "Zurich Insurance Corporation", + "city": { + "name": "Round Mountain", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Round Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7613953784517032040-2310", + "name": "Vimo Corporation", + "city": { + "name": "Perrysville", + "code": "OH", + "state": "Ohio", + "county": "Ashland", + "display": "Perrysville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1684001831312566679-2311", + "name": "HelloWallet LLC", + "city": { + "name": "Norwood", + "code": "MA", + "state": "Massachusetts", + "county": "Norfolk", + "display": "Norwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2259210375981972673-2312", + "name": "Headlight Corp", + "city": { + "name": "Tell City", + "code": "IN", + "state": "Indiana", + "county": "Perry", + "display": "Burglen Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-976959192103904155-2313", + "name": "CitySourced Corporation", + "city": { + "name": "Arden", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Arden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3116379706284959537-2314", + "name": "Appallicious Incorporated", + "city": { + "name": "Shell Knob", + "code": "MO", + "state": "Missouri", + "county": "Barry", + "display": "Shell Knob" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3977233903757474748-2315", + "name": "BillGuard Inc", + "city": { + "name": "Zurich", + "code": "MT", + "state": "Montana", + "county": "Blaine", + "display": "Zurich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-502206886498369761-2316", + "name": "Experian Inc", + "city": { + "name": "Port Sulphur", + "code": "LA", + "state": "Louisiana", + "county": "Plaquemines", + "display": "Potash" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3600139390072272275-2317", + "name": "Govzilla, Company", + "city": { + "name": "Waban", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Newton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7675871878400096913-2318", + "name": "FirstPoint, Corporation", + "city": { + "name": "Jacksonville", + "code": "TX", + "state": "Texas", + "county": "Cherokee", + "display": "Cove Spring" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7700403307772903149-2319", + "name": "CoreLogic Company", + "city": { + "name": "South Chatham", + "code": "MA", + "state": "Massachusetts", + "county": "Barnstable", + "display": "South Chatham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6350367509969826305-2320", + "name": "OnDeck Incorporated", + "city": { + "name": "Minneapolis", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Medicine Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4179552783409863263-2321", + "name": "Intermap Technologies Incorporated", + "city": { + "name": "Del Valle", + "code": "TX", + "state": "Texas", + "county": "Travis", + "display": "Del Valle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2788934321292278470-2322", + "name": "Amazon Web Services Corporation", + "city": { + "name": "Zuni", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Ramah Community" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3348465524356751299-2323", + "name": "Nautilytics LLC", + "city": { + "name": "Rockland", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "Rockland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4282922753957625870-2324", + "name": "Wolfram Research Corp", + "city": { + "name": "Saint George", + "code": "UT", + "state": "Utah", + "county": "Washington", + "display": "Harrisburg Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2170606538896837919-2325", + "name": "LOVELAND Technologies Corp", + "city": { + "name": "Roscoe", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Roscoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7173642653547829073-2326", + "name": "FindTheBest.com Inc", + "city": { + "name": "Boston", + "code": "MA", + "state": "Massachusetts", + "county": "Suffolk", + "display": "Boston University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1929143766071761731-2327", + "name": "Expert Health Data Programming, Incorporated", + "city": { + "name": "Alpine", + "code": "TX", + "state": "Texas", + "county": "Brewster", + "display": "Alpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4183825788829710802-2328", + "name": "Child Care Desk Incorporated", + "city": { + "name": "Lott", + "code": "TX", + "state": "Texas", + "county": "Falls", + "display": "Westphalia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3483207327762723308-2329", + "name": "optiGov Incorporated", + "city": { + "name": "South Pittsburg", + "code": "TN", + "state": "Tennessee", + "county": "Marion", + "display": "S Pittsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9140808501998789966-2330", + "name": "Zonability Incorporated", + "city": { + "name": "Voorhees", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Kirkwd Vrhes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4252231474875498267-2331", + "name": "Geofeedia Inc", + "city": { + "name": "King And Queen Court House", + "code": "VA", + "state": "Virginia", + "county": "King And Queen", + "display": "King And Qn C H" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1546612943807682890-2332", + "name": "Equifax Company", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Nevada Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6601819006335782471-2333", + "name": "DataMarket LLC", + "city": { + "name": "Pocahontas", + "code": "IL", + "state": "Illinois", + "county": "Bond", + "display": "Jamestown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6410189274557663118-2334", + "name": "CostQuest Inc", + "city": { + "name": "Great Barrington", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Berkshire Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6601998192391808988-2335", + "name": "Tendril Incorporated", + "city": { + "name": "Elk Rapids", + "code": "MI", + "state": "Michigan", + "county": "Antrim", + "display": "Elk Rapids" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-289873661232427529-2336", + "name": "SpotCrime Corporation", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Finneytown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7696467059169105806-2337", + "name": "SeeClickFix Company", + "city": { + "name": "Abie", + "code": "NE", + "state": "Nebraska", + "county": "Butler", + "display": "Abie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7823358263160327346-2338", + "name": "CoreLogic Corp", + "city": { + "name": "Ocean City", + "code": "MD", + "state": "Maryland", + "county": "Worcester", + "display": "Ocean City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1976216391799689967-2339", + "name": "PowerAdvocate Corp", + "city": { + "name": "Reno", + "code": "NV", + "state": "Nevada", + "county": "Washoe", + "display": "V C Highlands" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-183313294356447800-2340", + "name": "SAP Inc", + "city": { + "name": "South Hackensack", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "S Hackensack" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6920260436052042418-2341", + "name": "Business Monitor International LLC", + "city": { + "name": "Woodland Hills", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Woodland Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2818471892946876756-2342", + "name": "Civic Impulse Corporation", + "city": { + "name": "Stennis Space Center", + "code": "MS", + "state": "Mississippi", + "county": "Hancock", + "display": "Stennis Sp Ct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5927168719517622674-2343", + "name": "The Govtech Fund Incorporated", + "city": { + "name": "Bradenton", + "code": "FL", + "state": "Florida", + "county": "Manatee", + "display": "West Bradenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2875582102759326388-2344", + "name": "Earth Networks Incorporated", + "city": { + "name": "Keosauqua", + "code": "IA", + "state": "Iowa", + "county": "Van Buren", + "display": "Keosauqua" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-641831769309013936-2345", + "name": "Credit Karma Corp", + "city": { + "name": "Brenham", + "code": "TX", + "state": "Texas", + "county": "Washington", + "display": "Gay Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-632091648129642767-2346", + "name": "HERE Corporation", + "city": { + "name": "Summerland Key", + "code": "FL", + "state": "Florida", + "county": "Monroe", + "display": "Sugarloaf Key" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3841440931962304150-2347", + "name": "PayScale, Company", + "city": { + "name": "Bledsoe", + "code": "KY", + "state": "Kentucky", + "county": "Harlan", + "display": "Bledsoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3630056347972829891-2348", + "name": "Charles River Associates LLC", + "city": { + "name": "Collinsville", + "code": "AL", + "state": "Alabama", + "county": "De Kalb", + "display": "Collinsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9102345932609803205-2349", + "name": "Garmin Company", + "city": { + "name": "South Britain", + "code": "CT", + "state": "Connecticut", + "county": "New Haven", + "display": "South Britain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-721867595458817769-2350", + "name": "United Mayflower Incorporated", + "city": { + "name": "New Castle", + "code": "IN", + "state": "Indiana", + "county": "Henry", + "display": "Messick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2321056499113111634-2351", + "name": "Abt Associates LLC", + "city": { + "name": "Totz", + "code": "KY", + "state": "Kentucky", + "county": "Harlan", + "display": "Totz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5093839963311371231-2352", + "name": "Ez-XBRL Corp", + "city": { + "name": "Glendale Heights", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Glendale Hts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7377728418565475820-2353", + "name": "MarketSense Incorporated", + "city": { + "name": "Verona", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Verona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6756695190783840003-2354", + "name": "Rank and Filed Company", + "city": { + "name": "Nuevo", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Nuevo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5403583235347697882-2355", + "name": "Smartronix Inc", + "city": { + "name": "Alamogordo", + "code": "NM", + "state": "New Mexico", + "county": "Otero", + "display": "Alamogordo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6451047454414195206-2356", + "name": "Aureus Sciences Corp", + "city": { + "name": "Camden", + "code": "MI", + "state": "Michigan", + "county": "Hillsdale", + "display": "Camden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3845864223757206392-2357", + "name": "Honest Buildings LLC", + "city": { + "name": "Topsfield", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Topsfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3201729827391866874-2358", + "name": "Cerner Corp", + "city": { + "name": "Franklin", + "code": "IN", + "state": "Indiana", + "county": "Johnson", + "display": "Bengal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5165910344174597659-2359", + "name": "AutoGrid Systems Corporation", + "city": { + "name": "Sayner", + "code": "WI", + "state": "Wisconsin", + "county": "Vilas", + "display": "Plum Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4515876761619178057-2360", + "name": "Energy Points, Inc", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Ohio Dept Of Taxation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8585571722081219895-2361", + "name": "Computer Packages Corporation", + "city": { + "name": "Witmer", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Witmer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7189873088562917649-2362", + "name": "iMedicare Inc", + "city": { + "name": "West Columbia", + "code": "SC", + "state": "South Carolina", + "county": "Lexington", + "display": "Pineridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1837047026987242384-2363", + "name": "Code-N Inc", + "city": { + "name": "Florien", + "code": "LA", + "state": "Louisiana", + "county": "Sabine", + "display": "Mount Carmel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8839441062033981405-2364", + "name": "The Bridgespan Group Corporation", + "city": { + "name": "Bay City", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Bay City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6808932404070328520-2365", + "name": "CoreLogic Corporation", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "West Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7903584289777732650-2366", + "name": "Roadify Transit Corporation", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Nevada Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4620091927943591711-2367", + "name": "How's My Offer? Company", + "city": { + "name": "Boonton", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Powerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7461502632609628328-2368", + "name": "Analytica Corporation", + "city": { + "name": "Roy", + "code": "UT", + "state": "Utah", + "county": "Weber", + "display": "Roy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-927014449268746202-2369", + "name": "McKinsey LLC", + "city": { + "name": "North Palm Beach", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "West Palm Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6988037411800581204-2370", + "name": "Enervee Corp", + "city": { + "name": "Round Rock", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Three Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8902759910364025303-2371", + "name": "Altova Corporation", + "city": { + "name": "Beersheba Springs", + "code": "TN", + "state": "Tennessee", + "county": "Grundy", + "display": "Beersheba Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6979768637036461489-2372", + "name": "MetLife Inc", + "city": { + "name": "Peterson", + "code": "MN", + "state": "Minnesota", + "county": "Fillmore", + "display": "Rushford Vlg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-543863082324692308-2373", + "name": "Urban Airship LLC", + "city": { + "name": "Bainbridge Island", + "code": "WA", + "state": "Washington", + "county": "Kitsap", + "display": "Bainbridge Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2533105141029214426-2374", + "name": "Remi Inc", + "city": { + "name": "Penn Yan", + "code": "NY", + "state": "New York", + "county": "Yates", + "display": "Penn Yan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6684335792117637658-2375", + "name": "EarthObserver App Corporation", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Worthngtn Hls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8479621741594034471-2376", + "name": "Zebu Compliance Solutions Corporation", + "city": { + "name": "Shattuck", + "code": "OK", + "state": "Oklahoma", + "county": "Ellis", + "display": "Shattuck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2340320242890048897-2377", + "name": "Allied Van Lines Corp", + "city": { + "name": "Wappapello", + "code": "MO", + "state": "Missouri", + "county": "Wayne", + "display": "Wappapello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3514899375033950308-2378", + "name": "MarketSense Company", + "city": { + "name": "Offutt A F B", + "code": "NE", + "state": "Nebraska", + "county": "Sarpy", + "display": "Offutt A F B" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2189353252456636473-2379", + "name": "Inovalon Company", + "city": { + "name": "West Palm Beach", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Royal Palm Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7170875189947538198-2380", + "name": "Aquicore Corporation", + "city": { + "name": "Fishers", + "code": "NY", + "state": "New York", + "county": "Ontario", + "display": "Fishers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3131031923672929905-2381", + "name": "Brightscope Company", + "city": { + "name": "Colorado Springs", + "code": "CO", + "state": "Colorado", + "county": "El Paso", + "display": "Cheyenne Mtn AFB" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3209283271532664174-2382", + "name": "PlotWatt LLC", + "city": { + "name": "Saint Croix Falls", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Saint Croix Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2902519503844421531-2383", + "name": "ClearHealthCosts Corp", + "city": { + "name": "Hallettsville", + "code": "TX", + "state": "Texas", + "county": "Lavaca", + "display": "Hallettsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4490089925538918165-2384", + "name": "gRadiant Research Company", + "city": { + "name": "Sharon", + "code": "SC", + "state": "South Carolina", + "county": "York", + "display": "Sharon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-243903618107286739-2385", + "name": "Urban Mapping, Incorporated", + "city": { + "name": "San Benito", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Yescas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7231341263013519716-2386", + "name": "MapQuest LLC", + "city": { + "name": "Cleveland", + "code": "TX", + "state": "Texas", + "county": "Liberty", + "display": "Evergreen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1538888943819829092-2387", + "name": "Abt Associates Corp", + "city": { + "name": "North Little Rock", + "code": "AR", + "state": "Arkansas", + "county": "Pulaski", + "display": "Veterans Administration Faci" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7405105116471584396-2388", + "name": "Inovalon Company", + "city": { + "name": "Dalzell", + "code": "SC", + "state": "South Carolina", + "county": "Sumter", + "display": "Dalzell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8450635608278765101-2389", + "name": "NerdWallet Corporation", + "city": { + "name": "Hamersville", + "code": "OH", + "state": "Ohio", + "county": "Brown", + "display": "Hamersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3935183703835838449-2390", + "name": "Altova Inc", + "city": { + "name": "Jarales", + "code": "NM", + "state": "New Mexico", + "county": "Valencia", + "display": "Jarales" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6839859431513719670-2391", + "name": "Exversion Corporation", + "city": { + "name": "De Kalb", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Siloam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6367047841469662539-2392", + "name": "xDayta Corporation", + "city": { + "name": "Oxly", + "code": "MO", + "state": "Missouri", + "county": "Ripley", + "display": "Oxly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-538351812575737580-2393", + "name": "PatientsLikeMe Company", + "city": { + "name": "Nottingham", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Nottingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7663447049206285403-2394", + "name": "PublicEngines Corporation", + "city": { + "name": "Gravity", + "code": "IA", + "state": "Iowa", + "county": "Taylor", + "display": "Gravity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-160229612456410880-2395", + "name": "Ceiba Solutions LLC", + "city": { + "name": "Newark", + "code": "NJ", + "state": "New Jersey", + "county": "Essex", + "display": "Bank Of New York" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5521825780872643317-2396", + "name": "Estately Corporation", + "city": { + "name": "Fredericksburg", + "code": "IA", + "state": "Iowa", + "county": "Chickasaw", + "display": "Fredericksbrg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5195490012192620136-2397", + "name": "karmadata Inc", + "city": { + "name": "La Follette", + "code": "TN", + "state": "Tennessee", + "county": "Campbell", + "display": "La Follette" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8863187081801827884-2398", + "name": "TrialX Corp", + "city": { + "name": "Thompson", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Thompson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4759558055398146114-2399", + "name": "Credit Sesame Incorporated", + "city": { + "name": "Antigo", + "code": "WI", + "state": "Wisconsin", + "county": "Langlade", + "display": "Antigo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5110008006535246093-2400", + "name": "USSearch Incorporated", + "city": { + "name": "Burley", + "code": "ID", + "state": "Idaho", + "county": "Cassia", + "display": "Starrhs Ferry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-768322834199517768-2401", + "name": "Noveda Technologies LLC", + "city": { + "name": "Bisbee", + "code": "AZ", + "state": "Arizona", + "county": "Cochise", + "display": "Bisbee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5207732838666488214-2402", + "name": "Yahoo Company", + "city": { + "name": "Brady Lake", + "code": "OH", + "state": "Ohio", + "county": "Portage", + "display": "Brady Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1828633478245391277-2403", + "name": "BlackRock Inc", + "city": { + "name": "Roodhouse", + "code": "IL", + "state": "Illinois", + "county": "Greene", + "display": "Athensville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5880643695927231626-2404", + "name": "Acxiom Corp", + "city": { + "name": "Jersey Shore", + "code": "PA", + "state": "Pennsylvania", + "county": "Lycoming", + "display": "Larryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2316847997679724154-2405", + "name": "LegiStorm Incorporated", + "city": { + "name": "Park City", + "code": "UT", + "state": "Utah", + "county": "Summit", + "display": "Kimball Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1111285928148149906-2406", + "name": "Uber Inc", + "city": { + "name": "Port Hadlock", + "code": "WA", + "state": "Washington", + "county": "Jefferson", + "display": "Irondale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8064918295075231657-2407", + "name": "Clean Power Finance Inc", + "city": { + "name": "Fritch", + "code": "TX", + "state": "Texas", + "county": "Hutchinson", + "display": "Fritch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3184655658622232642-2408", + "name": "Factset LLC", + "city": { + "name": "North Stratford", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Stratford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3106446640060316449-2409", + "name": "Factual Corporation", + "city": { + "name": "Matthews", + "code": "NC", + "state": "North Carolina", + "county": "Union", + "display": "Wesley Chapel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1912347182006588092-2410", + "name": "Mapbox LLC", + "city": { + "name": "Beaverton", + "code": "AL", + "state": "Alabama", + "county": "Lamar", + "display": "Beaverton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8537173980448559614-2411", + "name": "RAND Corp", + "city": { + "name": "Fresno", + "code": "CA", + "state": "California", + "county": "Fresno", + "display": "Frs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2956468813594129082-2412", + "name": "Merrill Lynch Company", + "city": { + "name": "Casstown", + "code": "OH", + "state": "Ohio", + "county": "Miami", + "display": "Casstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6589137473992638541-2413", + "name": "Rand McNally Corporation", + "city": { + "name": "Jeffersonville", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Jeffersonvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-109132180842884287-2414", + "name": "IBM Corporation", + "city": { + "name": "Port Hadlock", + "code": "WA", + "state": "Washington", + "county": "Jefferson", + "display": "Irondale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9220953947500833988-2415", + "name": "Moody's Corporation", + "city": { + "name": "Kersey", + "code": "CO", + "state": "Colorado", + "county": "Weld", + "display": "Kersey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4666953757410170738-2416", + "name": "Geofeedia LLC", + "city": { + "name": "North Waterboro", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "N Waterboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3411643295080060840-2417", + "name": "Fujitsu Corp", + "city": { + "name": "Beverly", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Beverly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6068408907336458017-2418", + "name": "Graebel Van Lines Inc", + "city": { + "name": "Winona", + "code": "MS", + "state": "Mississippi", + "county": "Montgomery", + "display": "Eskridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-173665530849239015-2419", + "name": "Think Computer Incorporated", + "city": { + "name": "Whiting", + "code": "VT", + "state": "Vermont", + "county": "Addison", + "display": "Whiting" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3774270468046446740-2420", + "name": "AccuWeather LLC", + "city": { + "name": "Emporium", + "code": "PA", + "state": "Pennsylvania", + "county": "Cameron", + "display": "Emporium" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8356643709806183804-2421", + "name": "nGAP orporated Company", + "city": { + "name": "Holcomb", + "code": "MS", + "state": "Mississippi", + "county": "Grenada", + "display": "Oxberry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5401416659282926719-2422", + "name": "National Van Lines Corporation", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "W Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3550262407460250353-2423", + "name": "MedWatcher Corp", + "city": { + "name": "Sopchoppy", + "code": "FL", + "state": "Florida", + "county": "Wakulla", + "display": "Sopchoppy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5645345175126263986-2424", + "name": "Ecodesk Incorporated", + "city": { + "name": "Port Edwards", + "code": "WI", + "state": "Wisconsin", + "county": "Wood", + "display": "Port Edwards" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1532751571405366987-2425", + "name": "Spokeo Inc", + "city": { + "name": "Red Level", + "code": "AL", + "state": "Alabama", + "county": "Covington", + "display": "Red Level" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-910907678208424806-2426", + "name": "VitalChek Incorporated", + "city": { + "name": "North Tonawanda", + "code": "NY", + "state": "New York", + "county": "Niagara", + "display": "No Tonawanda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5207396030113692353-2427", + "name": "Acxiom Inc", + "city": { + "name": "Palm Bay", + "code": "FL", + "state": "Florida", + "county": "Brevard", + "display": "Palm Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6511720776727404002-2428", + "name": "Poncho App LLC", + "city": { + "name": "Clarkdale", + "code": "AZ", + "state": "Arizona", + "county": "Yavapai", + "display": "Clarkdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4780331807768375710-2429", + "name": "Govini Corp", + "city": { + "name": "Montpelier Station", + "code": "VA", + "state": "Virginia", + "county": "Orange", + "display": "Mntpelier Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5927352356102898365-2430", + "name": "Think Computer Corporation", + "city": { + "name": "Pataskala", + "code": "OH", + "state": "Ohio", + "county": "Licking", + "display": "Pataskala" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4856361341511539555-2431", + "name": "HealthPocket, Company", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Lyndon B Johnson Space Cen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2585066989912175390-2432", + "name": "FlightStats Company", + "city": { + "name": "Belmar", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "West Belmar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1902604342756639751-2433", + "name": "Charles Schwab Inc", + "city": { + "name": "Belle Vernon", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "North Belle Vernon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-22853112935367777-2434", + "name": "Iodine Corp", + "city": { + "name": "Forked River", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Lacey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8127488277190973187-2435", + "name": "Vital Axiom | Niinja Corporation", + "city": { + "name": "Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "Industry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6513869493125166171-2436", + "name": "Garmin Company", + "city": { + "name": "Elkton", + "code": "VA", + "state": "Virginia", + "county": "Rockingham", + "display": "Elkton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2130417011012761538-2437", + "name": "US Green Data Company", + "city": { + "name": "Pocopson", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Pocopson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8447937768024131748-2438", + "name": "Garmin Inc", + "city": { + "name": "Mayo", + "code": "SC", + "state": "South Carolina", + "county": "Spartanburg", + "display": "Mayo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3591188708943784154-2439", + "name": "Boston Consulting Group Corporation", + "city": { + "name": "Dugspur", + "code": "VA", + "state": "Virginia", + "county": "Carroll", + "display": "Dugspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2147563453566009616-2440", + "name": "BuildZoom Inc", + "city": { + "name": "Wisconsin Rapids", + "code": "WI", + "state": "Wisconsin", + "county": "Wood", + "display": "Wisconsin Rapids" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6670278064183390255-2441", + "name": "Locavore Incorporated", + "city": { + "name": "Clearfield", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "Sunset" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7936129466604869335-2442", + "name": "CitySourced Company", + "city": { + "name": "Starkville", + "code": "MS", + "state": "Mississippi", + "county": "Oktibbeha", + "display": "Osborn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-872707947479110157-2443", + "name": "IBM Company", + "city": { + "name": "Happy Valley", + "code": "OR", + "state": "Oregon", + "county": "Clackamas", + "display": "Happy Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1872995988071843875-2444", + "name": "ASC Partners LLC", + "city": { + "name": "Cedar", + "code": "MN", + "state": "Minnesota", + "county": "Anoka", + "display": "Oak Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4208250965177035790-2445", + "name": "Optensity Inc", + "city": { + "name": "Alto", + "code": "MI", + "state": "Michigan", + "county": "Kent", + "display": "Alto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2199758004732777220-2446", + "name": "Government Transaction Services LLC", + "city": { + "name": "Galway", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Hagedorns Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8147264219931153831-2447", + "name": "Socrata Corp", + "city": { + "name": "Nonantum", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Nonantum" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1899218606604799883-2448", + "name": "TowerData LLC", + "city": { + "name": "Bellemont", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Flagstaff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1866761303667342910-2449", + "name": "Lawdragon Corporation", + "city": { + "name": "Woods Hole", + "code": "MA", + "state": "Massachusetts", + "county": "Barnstable", + "display": "Woods Hole" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5229756804247918396-2450", + "name": "Zonability Inc", + "city": { + "name": "Erie", + "code": "PA", + "state": "Pennsylvania", + "county": "Erie", + "display": "Belle Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-181437030807688537-2451", + "name": "BizVizz Inc", + "city": { + "name": "West Terre Haute", + "code": "IN", + "state": "Indiana", + "county": "Vigo", + "display": "Shirkleville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9160964811958995475-2452", + "name": "FutureAdvisor Inc", + "city": { + "name": "Baltic", + "code": "CT", + "state": "Connecticut", + "county": "New London", + "display": "Sprague" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1092843662764877941-2453", + "name": "Lawdragon Incorporated", + "city": { + "name": "Rachel", + "code": "WV", + "state": "West Virginia", + "county": "Marion", + "display": "Rachel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6456712982887383096-2454", + "name": "Peterson's Company", + "city": { + "name": "Valley Cottage", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "Valley Cottage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8191775831018068405-2455", + "name": "FlightAware LLC", + "city": { + "name": "Attica", + "code": "OH", + "state": "Ohio", + "county": "Seneca", + "display": "Attica" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-472894309880707932-2456", + "name": "DataLogix Company", + "city": { + "name": "Bothell", + "code": "WA", + "state": "Washington", + "county": "Snohomish", + "display": "Mill Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6633138703739293312-2457", + "name": "Dun \u0026 Bradstreet Inc", + "city": { + "name": "Ashville", + "code": "NY", + "state": "New York", + "county": "Chautauqua", + "display": "Ashville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2740175689707207935-2458", + "name": "Keychain Logistics Inc", + "city": { + "name": "Pretty Prairie", + "code": "KS", + "state": "Kansas", + "county": "Reno", + "display": "Pretty Pr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-973420850686039194-2459", + "name": "FarmLogs Company", + "city": { + "name": "Centralia", + "code": "IL", + "state": "Illinois", + "county": "Marion", + "display": "Finney Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4628179438794865323-2460", + "name": "Healthline LLC", + "city": { + "name": "Frenchburg", + "code": "KY", + "state": "Kentucky", + "county": "Menifee", + "display": "Frenchburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-812070531814022802-2461", + "name": "Rank and Filed Company", + "city": { + "name": "Sherman", + "code": "IL", + "state": "Illinois", + "county": "Sangamon", + "display": "Barclay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8227313131525538355-2462", + "name": "NerdWallet Company", + "city": { + "name": "Mcarthur", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Little Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6795703493079122169-2463", + "name": "Earth Networks Corporation", + "city": { + "name": "Dale", + "code": "TX", + "state": "Texas", + "county": "Caldwell", + "display": "Dale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1583053149719095853-2464", + "name": "Moody's LLC", + "city": { + "name": "West Haven", + "code": "CT", + "state": "Connecticut", + "county": "New Haven", + "display": "N Haven" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1141385496950682132-2465", + "name": "OpenCounter Corporation", + "city": { + "name": "Leslie", + "code": "MO", + "state": "Missouri", + "county": "Franklin", + "display": "Leslie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7614661450723971471-2466", + "name": "PublicEngines Corp", + "city": { + "name": "Pequot Lakes", + "code": "MN", + "state": "Minnesota", + "county": "Crow Wing", + "display": "Breezy Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7681557402598216329-2467", + "name": "Social Explorer Incorporated", + "city": { + "name": "Port Sulphur", + "code": "LA", + "state": "Louisiana", + "county": "Plaquemines", + "display": "Potash" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7481343284006433183-2468", + "name": "HDScores, Inc", + "city": { + "name": "Huntington Station", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Huntington Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7969260272973078311-2469", + "name": "Social Explorer Incorporated", + "city": { + "name": "Bath Springs", + "code": "TN", + "state": "Tennessee", + "county": "Decatur", + "display": "Bath Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1770633898699061716-2470", + "name": "BillGuard Company", + "city": { + "name": "Chittenango", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Chittenango" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3009338709149417826-2471", + "name": "Aureus Sciences Inc", + "city": { + "name": "Lyndonville", + "code": "VT", + "state": "Vermont", + "county": "Caledonia", + "display": "South Wheelock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8842176769997147929-2472", + "name": "Innography Corp", + "city": { + "name": "Hyde Park", + "code": "UT", + "state": "Utah", + "county": "Cache", + "display": "Hyde Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8817107318094658717-2473", + "name": "SnapSense Corp", + "city": { + "name": "Raleigh", + "code": "ND", + "state": "North Dakota", + "county": "Grant", + "display": "Saint Gertrude" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3408432116418326370-2474", + "name": "Lenddo Corp", + "city": { + "name": "Kersey", + "code": "CO", + "state": "Colorado", + "county": "Weld", + "display": "Kersey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3655845999638824255-2475", + "name": "People Power LLC", + "city": { + "name": "Quincy", + "code": "IL", + "state": "Illinois", + "county": "Adams", + "display": "Marblehead" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7155792339884788749-2476", + "name": "Informatica Company", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Arsenal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5413178555309268964-2477", + "name": "Vimo Incorporated", + "city": { + "name": "Los Alamos", + "code": "NM", + "state": "New Mexico", + "county": "Los Alamos", + "display": "Bandelier National Monument" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-483430354810906164-2478", + "name": "IPHIX Incorporated", + "city": { + "name": "Vienna", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Oakton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6757501573109022206-2479", + "name": "Xcential Company", + "city": { + "name": "New Hampton", + "code": "IA", + "state": "Iowa", + "county": "Chickasaw", + "display": "North Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2605866213352788067-2480", + "name": "StreetEasy Corp", + "city": { + "name": "Penn", + "code": "ND", + "state": "North Dakota", + "county": "Ramsey", + "display": "Penn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4788326195765327274-2481", + "name": "GetRaised Corp", + "city": { + "name": "Wood River", + "code": "NE", + "state": "Nebraska", + "county": "Hall", + "display": "Prosser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5801910559554334312-2482", + "name": "Moody's Corporation", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Jersey Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2352779258174412966-2483", + "name": "Liquid Robotics LLC", + "city": { + "name": "Mackinac Island", + "code": "MI", + "state": "Michigan", + "county": "Mackinac", + "display": "Mackinac Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-863902345767508165-2484", + "name": "PlanetEcosystems Inc", + "city": { + "name": "Elizabeth", + "code": "NJ", + "state": "New Jersey", + "county": "Union", + "display": "Parkandbush" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3198192630085858693-2485", + "name": "Recargo Inc", + "city": { + "name": "Summersville", + "code": "MO", + "state": "Missouri", + "county": "Texas", + "display": "Summersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4948179805796436551-2486", + "name": "State Farm Insurance Incorporated", + "city": { + "name": "Westfield", + "code": "PA", + "state": "Pennsylvania", + "county": "Tioga", + "display": "Westfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4735126851483663186-2487", + "name": "Biovia Corp", + "city": { + "name": "Troup", + "code": "TX", + "state": "Texas", + "county": "Smith", + "display": "Griffin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4736511271381789913-2488", + "name": "Recargo Corporation", + "city": { + "name": "Bulpitt", + "code": "IL", + "state": "Illinois", + "county": "Christian", + "display": "Bulpitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8368969477862595985-2489", + "name": "GovTribe Inc", + "city": { + "name": "Sutherland Springs", + "code": "TX", + "state": "Texas", + "county": "Wilson", + "display": "Sutherland Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5051446783408846324-2490", + "name": "CoolClimate Incorporated", + "city": { + "name": "Franklin Springs", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Franklin Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2871510441287179273-2491", + "name": "Nautilytics Inc", + "city": { + "name": "Red Level", + "code": "AL", + "state": "Alabama", + "county": "Covington", + "display": "Red Level" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2455040378979801340-2492", + "name": "PublicEngines LLC", + "city": { + "name": "Calpine", + "code": "CA", + "state": "California", + "county": "Sierra", + "display": "Calpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3730803248569901034-2493", + "name": "HelloWallet Incorporated", + "city": { + "name": "Springtown", + "code": "PA", + "state": "Pennsylvania", + "county": "Bucks", + "display": "Springtown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4532570297948078418-2494", + "name": "Factual Corporation", + "city": { + "name": "Ruby", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Ruby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2181316849164534460-2495", + "name": "StreamLink Software Incorporated", + "city": { + "name": "Mission", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Granjeno" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3096209084711226733-2496", + "name": "College Board Corp", + "city": { + "name": "Mckinney", + "code": "TX", + "state": "Texas", + "county": "Collin", + "display": "Mc Kinney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5338913640684018058-2497", + "name": "FindTheBest.com LLC", + "city": { + "name": "Clear Creek", + "code": "WV", + "state": "West Virginia", + "county": "Raleigh", + "display": "Clear Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-273601471739057572-2498", + "name": "IMS Health LLC", + "city": { + "name": "Waite Park", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Waite Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7273491493632883322-2499", + "name": "PowerAdvocate Corporation", + "city": { + "name": "Alma", + "code": "WI", + "state": "Wisconsin", + "county": "Buffalo", + "display": "Cream" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4095634463961957322-2500", + "name": "PayScale, Incorporated", + "city": { + "name": "Carrollton", + "code": "GA", + "state": "Georgia", + "county": "Carroll", + "display": "University Of West Georgia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1497799383016573418-2501", + "name": "Geofeedia Corp", + "city": { + "name": "Mount Pleasant", + "code": "AR", + "state": "Arkansas", + "county": "Izard", + "display": "Mount Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8416957053740386013-2502", + "name": "Headlight Corp", + "city": { + "name": "Columbia", + "code": "LA", + "state": "Louisiana", + "county": "Caldwell", + "display": "Eastside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6807274136712345062-2503", + "name": "CareSet Systems Incorporated", + "city": { + "name": "Durand", + "code": "MI", + "state": "Michigan", + "county": "Shiawassee", + "display": "Durand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7909707713258198252-2504", + "name": "Energy Points, Corporation", + "city": { + "name": "Lindale", + "code": "GA", + "state": "Georgia", + "county": "Floyd", + "display": "Lindale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2296424146811468092-2505", + "name": "Maponics LLC", + "city": { + "name": "Dukedom", + "code": "TN", + "state": "Tennessee", + "county": "Weakley", + "display": "Dukedom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1777394295000820527-2506", + "name": "Glassy Media LLC", + "city": { + "name": "Grandfalls", + "code": "TX", + "state": "Texas", + "county": "Ward", + "display": "Royalty" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1568911008502582758-2507", + "name": "Workhands Corporation", + "city": { + "name": "Fredonia", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Fredonia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4528935489579127109-2508", + "name": "REI Systems Incorporated", + "city": { + "name": "Excelsior Springs", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "Wood Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4337462820485204723-2509", + "name": "Aunt Bertha, LLC", + "city": { + "name": "Kankakee", + "code": "IL", + "state": "Illinois", + "county": "Kankakee", + "display": "Irwin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5876915796809974624-2510", + "name": "Equifax Corporation", + "city": { + "name": "Knoxville", + "code": "TN", + "state": "Tennessee", + "county": "Knox", + "display": "Lonsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7419021018382497512-2511", + "name": "Parsons Brinckerhoff Inc", + "city": { + "name": "Schoolcraft", + "code": "MI", + "state": "Michigan", + "county": "Kalamazoo", + "display": "Schoolcraft" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1011105167618416044-2512", + "name": "Trintech LLC", + "city": { + "name": "Sinton", + "code": "TX", + "state": "Texas", + "county": "San Patricio", + "display": "Papalote" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4591627374569987217-2513", + "name": "Palantir Technologies Company", + "city": { + "name": "Griffin", + "code": "GA", + "state": "Georgia", + "county": "Spalding", + "display": "Griffin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8058271283118570284-2514", + "name": "WebMD Incorporated", + "city": { + "name": "Saint Marie", + "code": "MT", + "state": "Montana", + "county": "Valley", + "display": "Saint Marie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3004282437807026660-2515", + "name": "SocialEffort LLC", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Naval Base" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4623651381514035525-2516", + "name": "SeeClickFix Company", + "city": { + "name": "Kasson", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "Canisteo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6895853593204588288-2517", + "name": "MicroBilt Inc", + "city": { + "name": "Calabash", + "code": "NC", + "state": "North Carolina", + "county": "Brunswick", + "display": "Carolina Shores" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6454321859739023550-2518", + "name": "Geofeedia Incorporated", + "city": { + "name": "White Heath", + "code": "IL", + "state": "Illinois", + "county": "Piatt", + "display": "White Heath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-144004600076075728-2519", + "name": "Chemical Abstracts Service Corp", + "city": { + "name": "Ward Cove", + "code": "AK", + "state": "Alaska", + "county": "Ketchikan Gateway", + "display": "Ward Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2284693551317693864-2520", + "name": "Charles Schwab Company", + "city": { + "name": "Sugarloaf", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Sugarloaf" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9176579446507748346-2521", + "name": "Construction Monitor Corporation", + "city": { + "name": "Robinson Creek", + "code": "KY", + "state": "Kentucky", + "county": "Pike", + "display": "Robinson Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-43089131361270265-2522", + "name": "Informatica Inc", + "city": { + "name": "Ogden", + "code": "IL", + "state": "Illinois", + "county": "Champaign", + "display": "Ogden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4536040520397687130-2523", + "name": "CARFAX Corporation", + "city": { + "name": "Dugspur", + "code": "VA", + "state": "Virginia", + "county": "Carroll", + "display": "Dugspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6055326459391416352-2524", + "name": "Healthline Corp", + "city": { + "name": "Middlesex", + "code": "NC", + "state": "North Carolina", + "county": "Nash", + "display": "Middlesex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1219028576265091383-2525", + "name": "Sage Bionetworks Incorporated", + "city": { + "name": "Magnolia", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Magnolia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3290766533823924715-2526", + "name": "Redfin Inc", + "city": { + "name": "Bergland", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Bergland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6953325169564155348-2527", + "name": "Xatori Corp", + "city": { + "name": "Martin City", + "code": "MT", + "state": "Montana", + "county": "Flathead", + "display": "Martin City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-340623495845989950-2528", + "name": "KPMG Inc", + "city": { + "name": "West Hartford", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Bishop's Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-766054246501797272-2529", + "name": "Kyruus LLC", + "city": { + "name": "Freistatt", + "code": "MO", + "state": "Missouri", + "county": "Lawrence", + "display": "Freistatt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8089507133915395778-2530", + "name": "Intermap Technologies LLC", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Wilkes Barre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2478786586424327152-2531", + "name": "ASC Partners Inc", + "city": { + "name": "Roca", + "code": "NE", + "state": "Nebraska", + "county": "Lancaster", + "display": "Saltillo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8626443857861818200-2532", + "name": "OnStar Company", + "city": { + "name": "Minneapolis", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Wells Fargo Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6584836505046303176-2533", + "name": "Epsilon Corp", + "city": { + "name": "Orient", + "code": "IA", + "state": "Iowa", + "county": "Adair", + "display": "Zion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1806218515051014113-2534", + "name": "National Van Lines Corporation", + "city": { + "name": "Grayson", + "code": "KY", + "state": "Kentucky", + "county": "Carter", + "display": "Jeriel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4957384230402608120-2535", + "name": "Kroll Bond Ratings Agency LLC", + "city": { + "name": "Slaterville Springs", + "code": "NY", + "state": "New York", + "county": "Tompkins", + "display": "Slaterville Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8328385771809879730-2536", + "name": "Analytica Inc", + "city": { + "name": "Buffalo", + "code": "MN", + "state": "Minnesota", + "county": "Wright", + "display": "Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4069491125117873743-2537", + "name": "gRadiant Research LLC", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Nys Dept Of Tax \u0026 Finance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-567826200493149981-2538", + "name": "Code for America Corp", + "city": { + "name": "New Harmony", + "code": "UT", + "state": "Utah", + "county": "Washington", + "display": "New Harmony" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7312287697749731058-2539", + "name": "Keychain Logistics LLC", + "city": { + "name": "Le Roy", + "code": "WV", + "state": "West Virginia", + "county": "Jackson", + "display": "Duncan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6865533481520131725-2540", + "name": "Moody's Corporation", + "city": { + "name": "Kouts", + "code": "IN", + "state": "Indiana", + "county": "Porter", + "display": "Kouts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8444237469637032235-2541", + "name": "Quandl Corp", + "city": { + "name": "Tonopah", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Tonopah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3699683917548275368-2542", + "name": "Cerner Inc", + "city": { + "name": "South Thomaston", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "South Thomaston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4250443201940340252-2543", + "name": "Civic Insight Corp", + "city": { + "name": "Simpson", + "code": "IL", + "state": "Illinois", + "county": "Johnson", + "display": "Robbs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5181396812896084246-2544", + "name": "Vizzuality Inc", + "city": { + "name": "Overland Park", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "Merriam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4012063099174925907-2545", + "name": "The Bridgespan Group Incorporated", + "city": { + "name": "Cedar Springs", + "code": "GA", + "state": "Georgia", + "county": "Early", + "display": "Cedar Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6136484257290182070-2546", + "name": "Graematter, Corporation", + "city": { + "name": "Curtis Bay", + "code": "MD", + "state": "Maryland", + "county": "Anne Arundel", + "display": "Brooklyn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6052385180272353754-2547", + "name": "POPVOX LLC", + "city": { + "name": "Hannibal", + "code": "NY", + "state": "New York", + "county": "Oswego", + "display": "Hannibal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4835833102039468308-2548", + "name": "Adobe Digital Government Incorporated", + "city": { + "name": "Elmore", + "code": "AL", + "state": "Alabama", + "county": "Elmore", + "display": "Elmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9041745191088168602-2549", + "name": "Fujitsu Corp", + "city": { + "name": "Stow", + "code": "NY", + "state": "New York", + "county": "Chautauqua", + "display": "Stow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1911542469709403002-2550", + "name": "Factset Incorporated", + "city": { + "name": "Brentwood", + "code": "TN", + "state": "Tennessee", + "county": "Williamson", + "display": "Brentwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3244349490636305786-2551", + "name": "Lawdragon Inc", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Richville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8018761935964078410-2552", + "name": "xDayta Inc", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Int Group Plans Inc" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8450868686467433109-2553", + "name": "Poncho App Company", + "city": { + "name": "Charleston", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Charleston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7032476775163256530-2554", + "name": "FlightView Corporation", + "city": { + "name": "Charleston AFB", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "No Chas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5741392547845106214-2555", + "name": "REI Systems Company", + "city": { + "name": "Camden", + "code": "IN", + "state": "Indiana", + "county": "Carroll", + "display": "Camden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9143558657399432170-2556", + "name": "Govzilla, Inc", + "city": { + "name": "South Hamilton", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "S Hamilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2139934081204300570-2557", + "name": "Credit Sesame Inc", + "city": { + "name": "Beaverton", + "code": "AL", + "state": "Alabama", + "county": "Lamar", + "display": "Beaverton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5393197416206182409-2558", + "name": "First Fuel Software Corporation", + "city": { + "name": "Grenville", + "code": "NM", + "state": "New Mexico", + "county": "Union", + "display": "Grenville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2775914561047679579-2559", + "name": "Solar Census LLC", + "city": { + "name": "Rickreall", + "code": "OR", + "state": "Oregon", + "county": "Polk", + "display": "Rickreall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9069522155823202190-2560", + "name": "Wheaton World Wide Moving Corporation", + "city": { + "name": "Oak Brook", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Oak Brook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5987192139880842490-2561", + "name": "PlanetEcosystems Incorporated", + "city": { + "name": "Independence", + "code": "LA", + "state": "Louisiana", + "county": "Tangipahoa", + "display": "Independence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4534263887890979749-2562", + "name": "PowerAdvocate Inc", + "city": { + "name": "Sutter Creek", + "code": "CA", + "state": "California", + "county": "Amador", + "display": "Sutter Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7051907219512500251-2563", + "name": "Roadify Transit Corp", + "city": { + "name": "Grosse Tete", + "code": "LA", + "state": "Louisiana", + "county": "Iberville", + "display": "Grosse Tete" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8473808178859876231-2564", + "name": "Urban Mapping, Inc", + "city": { + "name": "Crook", + "code": "CO", + "state": "Colorado", + "county": "Logan", + "display": "Crook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5257636256083357745-2565", + "name": "Loqate, Incorporated", + "city": { + "name": "Marion", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4770460435769696944-2566", + "name": "BetterLesson Corp", + "city": { + "name": "New Madrid", + "code": "MO", + "state": "Missouri", + "county": "New Madrid", + "display": "Howardville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5284483147312896396-2567", + "name": "Zillow Company", + "city": { + "name": "Trinidad", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Jansen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6960520151058622884-2568", + "name": "Sophic Systems Alliance LLC", + "city": { + "name": "Lashmeet", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Lashmeet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5502286438227514341-2569", + "name": "Trintech Incorporated", + "city": { + "name": "Redondo Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Redondo Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2564302913345453753-2570", + "name": "Earth Networks Corporation", + "city": { + "name": "Dayton", + "code": "TN", + "state": "Tennessee", + "county": "Rhea", + "display": "Dayton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6331615840585663182-2571", + "name": "Bloomberg Inc", + "city": { + "name": "Amana", + "code": "IA", + "state": "Iowa", + "county": "Iowa", + "display": "Amana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-973065648053131829-2572", + "name": "Legal Science Partners Incorporated", + "city": { + "name": "Porcupine", + "code": "SD", + "state": "South Dakota", + "county": "Shannon", + "display": "Rockyford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5120838883209491307-2573", + "name": "OnDeck Corp", + "city": { + "name": "Fort Gratiot", + "code": "MI", + "state": "Michigan", + "county": "Saint Clair", + "display": "Burtchville Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7686731312423260939-2574", + "name": "Copyright Clearance Center Company", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Miami Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5289940216499408966-2575", + "name": "LoopNet Incorporated", + "city": { + "name": "Salters", + "code": "SC", + "state": "South Carolina", + "county": "Williamsburg", + "display": "Trio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6306826548481271499-2576", + "name": "OpenCounter Corp", + "city": { + "name": "Putney", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "Putney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5453080345396839440-2577", + "name": "Onvia Company", + "city": { + "name": "Hurricane", + "code": "UT", + "state": "Utah", + "county": "Washington", + "display": "Apple Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4112980073866273963-2578", + "name": "realtor.com Incorporated", + "city": { + "name": "Ina", + "code": "IL", + "state": "Illinois", + "county": "Jefferson", + "display": "Ina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1052659072211759906-2579", + "name": "Rapid Cycle Solutions Inc", + "city": { + "name": "West Union", + "code": "IA", + "state": "Iowa", + "county": "Fayette", + "display": "West Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4386715553561385566-2580", + "name": "Food+Tech Connect Incorporated", + "city": { + "name": "Lenzburg", + "code": "IL", + "state": "Illinois", + "county": "Saint Clair", + "display": "Lenzburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6129073863194677549-2581", + "name": "Earthquake Alert Corp", + "city": { + "name": "Fort Calhoun", + "code": "NE", + "state": "Nebraska", + "county": "Washington", + "display": "Fort Calhoun" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5906013864331978096-2582", + "name": "Mercaris Corp", + "city": { + "name": "Hollansburg", + "code": "OH", + "state": "Ohio", + "county": "Darke", + "display": "Hollansburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9030784937335194113-2583", + "name": "HERE LLC", + "city": { + "name": "Beaumont", + "code": "TX", + "state": "Texas", + "county": "Jefferson", + "display": "Taylor Landing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1074349914826166139-2584", + "name": "Weight Watchers Incorporated", + "city": { + "name": "Westwood", + "code": "CA", + "state": "California", + "county": "Lassen", + "display": "Westwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1883845783596292417-2585", + "name": "Rank and Filed Corporation", + "city": { + "name": "South Hamilton", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "S Hamilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5766018497546294006-2586", + "name": "Chubb Corporation", + "city": { + "name": "Big Oak Flat", + "code": "CA", + "state": "California", + "county": "Tuolumne", + "display": "Big Oak Flat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7133594580770202721-2587", + "name": "CoolClimate Corporation", + "city": { + "name": "Meridian", + "code": "CA", + "state": "California", + "county": "Sutter", + "display": "Sycamore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5746675501435815396-2588", + "name": "AtSite Corp", + "city": { + "name": "Victoria", + "code": "MS", + "state": "Mississippi", + "county": "Marshall", + "display": "Victoria" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7012249862582921183-2589", + "name": "Everyday Health Inc", + "city": { + "name": "Silverstreet", + "code": "SC", + "state": "South Carolina", + "county": "Newberry", + "display": "Silverstreet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1610659995700705077-2590", + "name": "Way Better Patents Corporation", + "city": { + "name": "Wedderburn", + "code": "OR", + "state": "Oregon", + "county": "Curry", + "display": "Wedderburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2001018928730927506-2591", + "name": "Accela Company", + "city": { + "name": "Elkton", + "code": "KY", + "state": "Kentucky", + "county": "Todd", + "display": "Allegre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4248705518414283694-2592", + "name": "Plus-U Incorporated", + "city": { + "name": "North Waterboro", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "N Waterboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3558255301254763863-2593", + "name": "Avvo LLC", + "city": { + "name": "Marshfield", + "code": "MO", + "state": "Missouri", + "county": "Webster", + "display": "Marshfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1450710047350778073-2594", + "name": "Marlin Alter and Associates Company", + "city": { + "name": "Walsenburg", + "code": "CO", + "state": "Colorado", + "county": "Huerfano", + "display": "Farisita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3141407755742200079-2595", + "name": "MuckRock.com LLC", + "city": { + "name": "Aberdeen", + "code": "MS", + "state": "Mississippi", + "county": "Monroe", + "display": "Centralgrove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3383047860078544995-2596", + "name": "Bekins Inc", + "city": { + "name": "Muse", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Muse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2924483980932162287-2597", + "name": "DataWeave Corporation", + "city": { + "name": "Mc Clure", + "code": "PA", + "state": "Pennsylvania", + "county": "Mifflin", + "display": "Mc Clure" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4025641259490956154-2598", + "name": "Panjiva Corporation", + "city": { + "name": "Jacksonville", + "code": "FL", + "state": "Florida", + "county": "Duval", + "display": "Nas Jax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3670889336673996241-2599", + "name": "Appallicious Inc", + "city": { + "name": "Burlington", + "code": "VT", + "state": "Vermont", + "county": "Chittenden", + "display": "Burlngtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5192176197638907756-2600", + "name": "Everyday Health Company", + "city": { + "name": "International Falls", + "code": "MN", + "state": "Minnesota", + "county": "Koochiching", + "display": "International Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7086305801647252246-2601", + "name": "Housefax Company", + "city": { + "name": "Buffalo", + "code": "MN", + "state": "Minnesota", + "county": "Wright", + "display": "Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8791553255822496639-2602", + "name": "BaleFire Global Inc", + "city": { + "name": "Spencer", + "code": "ID", + "state": "Idaho", + "county": "Clark", + "display": "Dubois" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6576755010906771304-2603", + "name": "DataLogix Incorporated", + "city": { + "name": "Wolcottville", + "code": "IN", + "state": "Indiana", + "county": "Lagrange", + "display": "Witmer Manor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5241830425866328355-2604", + "name": "OnStar Inc", + "city": { + "name": "Gleneden Beach", + "code": "OR", + "state": "Oregon", + "county": "Lincoln", + "display": "Gleneden Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3993979315566063359-2605", + "name": "GuideStar Incorporated", + "city": { + "name": "Morse Mill", + "code": "MO", + "state": "Missouri", + "county": "Jefferson", + "display": "Morse Mill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2802059551832234561-2606", + "name": "Personal Democracy Media Corporation", + "city": { + "name": "Scottsdale", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Scottsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9199507180311600743-2607", + "name": "Galorath orporated Corporation", + "city": { + "name": "Big Bend National Park", + "code": "TX", + "state": "Texas", + "county": "Brewster", + "display": "Big Bend National Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8592583893687682276-2608", + "name": "Barchart Incorporated", + "city": { + "name": "Clarksburg", + "code": "MD", + "state": "Maryland", + "county": "Montgomery", + "display": "Hyattstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5659543426493675470-2609", + "name": "Cambridge Semantics Corporation", + "city": { + "name": "Daisetta", + "code": "TX", + "state": "Texas", + "county": "Liberty", + "display": "Daisetta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3953817687342951147-2610", + "name": "FutureAdvisor Corporation", + "city": { + "name": "Koeltztown", + "code": "MO", + "state": "Missouri", + "county": "Osage", + "display": "Koeltztown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1441771538764598428-2611", + "name": "Tendril Corp", + "city": { + "name": "Hanover", + "code": "MD", + "state": "Maryland", + "county": "Anne Arundel", + "display": "Hanover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5513042852105952465-2612", + "name": "People Power Corporation", + "city": { + "name": "Eldorado", + "code": "IL", + "state": "Illinois", + "county": "Saline", + "display": "College Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3046349000245602887-2613", + "name": "Construction Monitor Incorporated", + "city": { + "name": "Walnut Bottom", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Walnut Bottom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4995337711161975359-2614", + "name": "GitHub LLC", + "city": { + "name": "Mount Holly", + "code": "VA", + "state": "Virginia", + "county": "Westmoreland", + "display": "Mount Holly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4980449004677394700-2615", + "name": "Scale Unlimited Company", + "city": { + "name": "Howes", + "code": "SD", + "state": "South Dakota", + "county": "Meade", + "display": "Bridger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8725577241991016537-2616", + "name": "Impaq International Inc", + "city": { + "name": "Washington", + "code": "TX", + "state": "Texas", + "county": "Washington", + "display": "Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4802463486696731856-2617", + "name": "Atlas Van Lines Corporation", + "city": { + "name": "Jeffersonville", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Jeffersonvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2529390264781461105-2618", + "name": "Legal Science Partners Company", + "city": { + "name": "Oriskany", + "code": "VA", + "state": "Virginia", + "county": "Botetourt", + "display": "Oriskany" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1937226990307467119-2619", + "name": "Factset Corp", + "city": { + "name": "Niobrara", + "code": "NE", + "state": "Nebraska", + "county": "Knox", + "display": "Niobrara" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-64901988099335463-2620", + "name": "Ranku Incorporated", + "city": { + "name": "North Bloomfield", + "code": "OH", + "state": "Ohio", + "county": "Trumbull", + "display": "Lockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1386982178360317073-2621", + "name": "Brightscope Inc", + "city": { + "name": "Jennerstown", + "code": "PA", + "state": "Pennsylvania", + "county": "Somerset", + "display": "Jennerstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3649348173484868031-2622", + "name": "HDScores, LLC", + "city": { + "name": "San Benito", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Yescas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7123159208172591452-2623", + "name": "Progressive Insurance Group Inc", + "city": { + "name": "Truckee", + "code": "CA", + "state": "California", + "county": "Nevada", + "display": "Prosser Lakeview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-130032227543871712-2624", + "name": "IFI CLAIMS Patent Services LLC", + "city": { + "name": "Inverness", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Inverness" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8324300446030456316-2625", + "name": "BetterLesson Company", + "city": { + "name": "Matlock", + "code": "IA", + "state": "Iowa", + "county": "Sioux", + "display": "Matlock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-746515229410880157-2626", + "name": "Evidera Corp", + "city": { + "name": "Novinger", + "code": "MO", + "state": "Missouri", + "county": "Adair", + "display": "Stahl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7528066865299316934-2627", + "name": "Mango Transit Corporation", + "city": { + "name": "Pitcairn", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Monroeville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4194850424128076680-2628", + "name": "LoseIt.com Incorporated", + "city": { + "name": "Baldwin Park", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Baldwin Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6604140837109300657-2629", + "name": "Zurich Insurance Corp", + "city": { + "name": "Waverly", + "code": "GA", + "state": "Georgia", + "county": "Camden", + "display": "Spring Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3268771562867651537-2630", + "name": "Housefax Corporation", + "city": { + "name": "Fort Worth", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Federal Aviation Administrat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5411150358631065913-2631", + "name": "Equifax Company", + "city": { + "name": "Pleasanton", + "code": "NE", + "state": "Nebraska", + "county": "Buffalo", + "display": "Rusco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1956556568342896912-2632", + "name": "Recargo Company", + "city": { + "name": "Andrews", + "code": "TX", + "state": "Texas", + "county": "Andrews", + "display": "Andrews" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3249888710731571875-2633", + "name": "FlightAware Inc", + "city": { + "name": "Southfield", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Southfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5625088189862627866-2634", + "name": "DataMarket Incorporated", + "city": { + "name": "Orient", + "code": "IA", + "state": "Iowa", + "county": "Adair", + "display": "Zion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6553115747020183653-2635", + "name": "BetterLesson Inc", + "city": { + "name": "Loomis", + "code": "WA", + "state": "Washington", + "county": "Okanogan", + "display": "Loomis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5938005732932692945-2636", + "name": "Kyruus LLC", + "city": { + "name": "Bay Pines", + "code": "FL", + "state": "Florida", + "county": "Pinellas", + "display": "Bay Pines" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-989198469667118386-2637", + "name": "Alltuition Corp", + "city": { + "name": "Snoqualmie Pass", + "code": "WA", + "state": "Washington", + "county": "Kittitas", + "display": "Snoqualmie Ps" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8113560356109833465-2638", + "name": "H3 Biomedicine Corporation", + "city": { + "name": "Foresthill", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Todd Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6945687780949239951-2639", + "name": "optiGov Corporation", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Peoples Gas And Light" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8899488851278713808-2640", + "name": "BuildFax LLC", + "city": { + "name": "Kings Canyon National Pk", + "code": "CA", + "state": "California", + "county": "Tulare", + "display": "Kings Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5589056845111722800-2641", + "name": "OSIsoft Inc", + "city": { + "name": "O Fallon", + "code": "IL", + "state": "Illinois", + "county": "Saint Clair", + "display": "O Fallon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2264507755920962744-2642", + "name": "Tableau Software Corporation", + "city": { + "name": "Amarillo", + "code": "TX", + "state": "Texas", + "county": "Randall", + "display": "Timbercrk Cyn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2465233287986409406-2643", + "name": "Urban Airship Corp", + "city": { + "name": "South Fork", + "code": "CO", + "state": "Colorado", + "county": "Rio Grande", + "display": "Alpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3857677319384203645-2644", + "name": "Simple Energy Corp", + "city": { + "name": "Spring Lake", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Spring Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8901295938499372629-2645", + "name": "Xignite Incorporated", + "city": { + "name": "Decatur", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Dunaire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5078221585663066101-2646", + "name": "Intermap Technologies Company", + "city": { + "name": "New Castle", + "code": "IN", + "state": "Indiana", + "county": "Henry", + "display": "Messick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1342322133068639698-2647", + "name": "Scale Unlimited Incorporated", + "city": { + "name": "Caret", + "code": "VA", + "state": "Virginia", + "county": "Essex", + "display": "Supply" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7883902392985734863-2648", + "name": "PlanetEcosystems LLC", + "city": { + "name": "Darien", + "code": "GA", + "state": "Georgia", + "county": "Mcintosh", + "display": "Darien" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7297910931689622401-2649", + "name": "Bloomberg Corp", + "city": { + "name": "Grant", + "code": "LA", + "state": "Louisiana", + "county": "Allen", + "display": "Grant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9122051473032782934-2650", + "name": "PublicEngines Inc", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Crafton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5202383889378438838-2651", + "name": "Amazon Web Services Corporation", + "city": { + "name": "Luana", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Luana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2131770006253284652-2652", + "name": "CoreLogic Incorporated", + "city": { + "name": "Buffalo", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "University Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6825997951748764221-2653", + "name": "Robinson + Yu Incorporated", + "city": { + "name": "Newport", + "code": "OR", + "state": "Oregon", + "county": "Lincoln", + "display": "Agate Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1189614323337917143-2654", + "name": "GovTribe Corp", + "city": { + "name": "San Pablo", + "code": "CA", + "state": "California", + "county": "Contra Costa", + "display": "Richmond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5254000650599753549-2655", + "name": "Captricity Inc", + "city": { + "name": "Greencastle", + "code": "PA", + "state": "Pennsylvania", + "county": "Franklin", + "display": "Greencastle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2540954203781949961-2656", + "name": "YourMapper Inc", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Nevada Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3818919656473357775-2657", + "name": "Aidin Corporation", + "city": { + "name": "Pearl", + "code": "MS", + "state": "Mississippi", + "county": "Rankin", + "display": "Jax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-209762385490174872-2658", + "name": "Geofeedia Inc", + "city": { + "name": "New Paris", + "code": "PA", + "state": "Pennsylvania", + "county": "Bedford", + "display": "New Paris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6676004084610440915-2659", + "name": "Iodine Corp", + "city": { + "name": "Boomer", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Boomer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6212478283158058191-2660", + "name": "Webitects Company", + "city": { + "name": "Belle Vernon", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "North Belle Vernon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8537980705845565731-2661", + "name": "Alltuition LLC", + "city": { + "name": "Albuquerque", + "code": "NM", + "state": "New Mexico", + "county": "Bernalillo", + "display": "Los Ranchos" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4198929475397623157-2662", + "name": "Equilar Corporation", + "city": { + "name": "Stanwood", + "code": "WA", + "state": "Washington", + "county": "Snohomish", + "display": "Camano Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4851349794076304586-2663", + "name": "PlanetEcosystems Incorporated", + "city": { + "name": "Monticello", + "code": "MS", + "state": "Mississippi", + "county": "Lawrence", + "display": "Robinwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1220346728902134996-2664", + "name": "Chubb Company", + "city": { + "name": "Greenwich", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Greenwich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1077521358967021295-2665", + "name": "ideas42 LLC", + "city": { + "name": "Cleveland", + "code": "OH", + "state": "Ohio", + "county": "Cuyahoga", + "display": "Pepper Pike" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3794564521832417703-2666", + "name": "Allianz Inc", + "city": { + "name": "Bangor", + "code": "PA", + "state": "Pennsylvania", + "county": "Northampton", + "display": "Bangor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2174699156418811023-2667", + "name": "Computer Packages LLC", + "city": { + "name": "Sentinel Butte", + "code": "ND", + "state": "North Dakota", + "county": "Golden Valley", + "display": "Sentinel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2500857726277101342-2668", + "name": "WeMakeItSafer LLC", + "city": { + "name": "Comstock", + "code": "NE", + "state": "Nebraska", + "county": "Custer", + "display": "Comstock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8436668088346167584-2669", + "name": "Revelstone Incorporated", + "city": { + "name": "Summertown", + "code": "TN", + "state": "Tennessee", + "county": "Lawrence", + "display": "Summertown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1551798311297598668-2670", + "name": "karmadata Corporation", + "city": { + "name": "Gloster", + "code": "MS", + "state": "Mississippi", + "county": "Amite", + "display": "Bewelcome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8476723181228377424-2671", + "name": "United Mayflower LLC", + "city": { + "name": "Onia", + "code": "AR", + "state": "Arkansas", + "county": "Stone", + "display": "Onia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3006229106341278206-2672", + "name": "Aunt Bertha, Corp", + "city": { + "name": "Ijamsville", + "code": "MD", + "state": "Maryland", + "county": "Frederick", + "display": "Ijamsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8789657236437911709-2673", + "name": "Personal Democracy Media Corporation", + "city": { + "name": "Verndale", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Wing River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8580577567766199122-2674", + "name": "Scale Unlimited Inc", + "city": { + "name": "Bala Cynwyd", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Belmont Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5021415694655727991-2675", + "name": "Relationship Science Company", + "city": { + "name": "Telford", + "code": "TN", + "state": "Tennessee", + "county": "Washington", + "display": "Telford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4818306594044522875-2676", + "name": "xDayta Company", + "city": { + "name": "Richmond", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Richmond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3107445720124732533-2677", + "name": "Personal Democracy Media Corp", + "city": { + "name": "West Concord", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "West Concord" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4161336067781658627-2678", + "name": "mHealthCoach Inc", + "city": { + "name": "White Plains", + "code": "KY", + "state": "Kentucky", + "county": "Hopkins", + "display": "White Plains" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8297003130090346294-2679", + "name": "Noesis Corp", + "city": { + "name": "Plantation", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Broward Mall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4814832206789461557-2680", + "name": "Verdafero LLC", + "city": { + "name": "Franklin", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "Eastbrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1784234418329142977-2681", + "name": "HERE Company", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Poplar Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7016810461394945424-2682", + "name": "SnapSense Inc", + "city": { + "name": "Blanch", + "code": "NC", + "state": "North Carolina", + "county": "Caswell", + "display": "Blanch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8819859265436514556-2683", + "name": "Kaiser Permanante Corporation", + "city": { + "name": "Dayton", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "Dayton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5110797823568396775-2684", + "name": "Outline Company", + "city": { + "name": "Fallon", + "code": "NV", + "state": "Nevada", + "county": "Churchill", + "display": "Fallon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1611803047243987076-2685", + "name": "SmartProcure Inc", + "city": { + "name": "Lancaster", + "code": "VA", + "state": "Virginia", + "county": "Lancaster", + "display": "Lancaster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5021023840894520846-2686", + "name": "ConnectEDU Corporation", + "city": { + "name": "Belle", + "code": "WV", + "state": "West Virginia", + "county": "Kanawha", + "display": "Witcher" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3484564209636498362-2687", + "name": "Acxiom Corporation", + "city": { + "name": "Aspermont", + "code": "TX", + "state": "Texas", + "county": "Stonewall", + "display": "Peacock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8288401537735459062-2688", + "name": "Castle Biosciences Corporation", + "city": { + "name": "Amery", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Little Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8958889377381109030-2689", + "name": "Urban Mapping, Corp", + "city": { + "name": "Moriah", + "code": "NY", + "state": "New York", + "county": "Essex", + "display": "Moriah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6878965475561474661-2690", + "name": "Equifax Company", + "city": { + "name": "Mossy Head", + "code": "FL", + "state": "Florida", + "county": "Walton", + "display": "Defuniak Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7930660862065314405-2691", + "name": "POPVOX LLC", + "city": { + "name": "Sherrard", + "code": "IL", + "state": "Illinois", + "county": "Mercer", + "display": "Cable" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5389209302692431648-2692", + "name": "Construction Monitor LLC", + "city": { + "name": "Tooele", + "code": "UT", + "state": "Utah", + "county": "Tooele", + "display": "Tooele Army Depot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4459153522132451389-2693", + "name": "Symcat Company", + "city": { + "name": "Morrilton", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Oppelo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-15494368821182864-2694", + "name": "Consumer Reports Company", + "city": { + "name": "Alloy", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Alloy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5664400048405896491-2695", + "name": "LegiStorm LLC", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Astrodome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3833527686779540383-2696", + "name": "Govzilla, Corp", + "city": { + "name": "Eminence", + "code": "KY", + "state": "Kentucky", + "county": "Henry", + "display": "Eminence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-487869127392943847-2697", + "name": "EarthObserver App Corp", + "city": { + "name": "Decatur", + "code": "IL", + "state": "Illinois", + "county": "Macon", + "display": "Long Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4393097444934014675-2698", + "name": "Adaptive LLC", + "city": { + "name": "Winston", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Winston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1475856861202356719-2699", + "name": "DataLogix LLC", + "city": { + "name": "Jumping Branch", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Streeter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7086790374083418901-2700", + "name": "Dow Jones \u0026 Co LLC", + "city": { + "name": "Gibson", + "code": "IA", + "state": "Iowa", + "county": "Keokuk", + "display": "Gibson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2972909441472295916-2701", + "name": "Cappex Inc", + "city": { + "name": "Freedom", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Arney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3438503358367149550-2702", + "name": "AllState Insurance Group Company", + "city": { + "name": "Huntington", + "code": "IN", + "state": "Indiana", + "county": "Huntington", + "display": "Bowerstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7478099770616925796-2703", + "name": "JJ Keller Corp", + "city": { + "name": "Pawnee", + "code": "IL", + "state": "Illinois", + "county": "Sangamon", + "display": "Pawnee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6288393568038374350-2704", + "name": "Junar, Incorporated", + "city": { + "name": "Moscow", + "code": "ID", + "state": "Idaho", + "county": "Latah", + "display": "University Of Idaho" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4837202709798073660-2705", + "name": "EMC Corp", + "city": { + "name": "Washington", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7805896995947263054-2706", + "name": "Housefax Incorporated", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "K C" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5348846105980659579-2707", + "name": "IMS Health Inc", + "city": { + "name": "Hartly", + "code": "DE", + "state": "Delaware", + "county": "Kent", + "display": "Hartly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5165655536990444712-2708", + "name": "OpenGov Inc", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Ny Secretary Of State" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4671850692411474134-2709", + "name": "Citigroup LLC", + "city": { + "name": "Egnar", + "code": "CO", + "state": "Colorado", + "county": "San Miguel", + "display": "Egnar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4262325451887767171-2710", + "name": "TrustedID LLC", + "city": { + "name": "Afton", + "code": "TN", + "state": "Tennessee", + "county": "Greene", + "display": "Afton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8005959437213008726-2711", + "name": "Think Computer Incorporated", + "city": { + "name": "Pine Grove", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "De Turksville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-549081453131826452-2712", + "name": "Ensco Incorporated", + "city": { + "name": "Dutzow", + "code": "MO", + "state": "Missouri", + "county": "Warren", + "display": "Dutzow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8141291568195754812-2713", + "name": "Fidelity Investments Inc", + "city": { + "name": "Gastonia", + "code": "NC", + "state": "North Carolina", + "county": "Gaston", + "display": "Smyre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2325660539912004481-2714", + "name": "Impact Forecasting Corp", + "city": { + "name": "Powellville", + "code": "MD", + "state": "Maryland", + "county": "Wicomico", + "display": "Powellville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5034168349978956090-2715", + "name": "Appallicious Inc", + "city": { + "name": "Bloomville", + "code": "OH", + "state": "Ohio", + "county": "Seneca", + "display": "Bloomville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7754846707922679526-2716", + "name": "Personal, Inc", + "city": { + "name": "Keyport", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Keyport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5710893700393430999-2717", + "name": "Roadify Transit Corp", + "city": { + "name": "Zephyr Cove", + "code": "NV", + "state": "Nevada", + "county": "Douglas", + "display": "Pinewild" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5998905788775426856-2718", + "name": "LegiNation, Corp", + "city": { + "name": "Dunbar", + "code": "WV", + "state": "West Virginia", + "county": "Kanawha", + "display": "Dunbar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4052212903448841787-2719", + "name": "Fastcase Inc", + "city": { + "name": "West Portsmouth", + "code": "OH", + "state": "Ohio", + "county": "Scioto", + "display": "Portsmouth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6054415064428065018-2720", + "name": "Keychain Logistics Company", + "city": { + "name": "Central", + "code": "UT", + "state": "Utah", + "county": "Washington", + "display": "Central" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-600514110919001934-2721", + "name": "Telenav Corporation", + "city": { + "name": "Compton", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Crystal City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2299688124540611142-2722", + "name": "BetterLesson Corporation", + "city": { + "name": "Commerce", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Commerce" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8316663829544280220-2723", + "name": "CoolClimate Inc", + "city": { + "name": "Riverside", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Box Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8045893868783913074-2724", + "name": "Junyo Corp", + "city": { + "name": "Lashmeet", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Lashmeet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8266562149973324436-2725", + "name": "Energy Solutions Forum Incorporated", + "city": { + "name": "Lebanon", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Bolton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5793330925184919921-2726", + "name": "ASC Partners Incorporated", + "city": { + "name": "Columbia", + "code": "SC", + "state": "South Carolina", + "county": "Richland", + "display": "Bluff Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9027938211934002868-2727", + "name": "Progressive Insurance Group Corp", + "city": { + "name": "Lapeer", + "code": "MI", + "state": "Michigan", + "county": "Lapeer", + "display": "Lake Nepessing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-230536053268600314-2728", + "name": "ClearHealthCosts Company", + "city": { + "name": "Candor", + "code": "NY", + "state": "New York", + "county": "Tioga", + "display": "Candor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4617746503659283039-2729", + "name": "ConnectEDU Inc", + "city": { + "name": "Big Rock", + "code": "IL", + "state": "Illinois", + "county": "Kane", + "display": "Big Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4686911943399463022-2730", + "name": "TrustedID Incorporated", + "city": { + "name": "Afton", + "code": "OK", + "state": "Oklahoma", + "county": "Ottawa", + "display": "Cleora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3695642511413647261-2731", + "name": "Sophic Systems Alliance Corporation", + "city": { + "name": "West Medford", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "West Medford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6189802600311723125-2732", + "name": "Urban Airship Company", + "city": { + "name": "Merrill", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Merrill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3289120517649230566-2733", + "name": "realtor.com LLC", + "city": { + "name": "New Castle", + "code": "IN", + "state": "Indiana", + "county": "Henry", + "display": "Messick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2059647227627535016-2734", + "name": "Rezolve Group LLC", + "city": { + "name": "Orange Springs", + "code": "FL", + "state": "Florida", + "county": "Marion", + "display": "Orange Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7071235852304663857-2735", + "name": "Weather Channel Inc", + "city": { + "name": "Hibbing", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Ruby Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-907769620900652743-2736", + "name": "Climate Company", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "West University Place" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2330297743676937340-2737", + "name": "Rezolve Group LLC", + "city": { + "name": "Hitchita", + "code": "OK", + "state": "Oklahoma", + "county": "Mcintosh", + "display": "Hitchita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-815034595677714224-2738", + "name": "PeerJ Corporation", + "city": { + "name": "Highland Mills", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Highland Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2114122055126160160-2739", + "name": "Adaptive Corporation", + "city": { + "name": "Mc Intyre", + "code": "PA", + "state": "Pennsylvania", + "county": "Indiana", + "display": "Mcintyre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-370054302386905042-2740", + "name": "PayScale, Inc", + "city": { + "name": "Grand Junction", + "code": "CO", + "state": "Colorado", + "county": "Mesa", + "display": "Appleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8405190081876581847-2741", + "name": "Altova Inc", + "city": { + "name": "Mount Carmel", + "code": "IL", + "state": "Illinois", + "county": "Wabash", + "display": "Maud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2394721171973527126-2742", + "name": "Intermap Technologies Incorporated", + "city": { + "name": "Calpine", + "code": "CA", + "state": "California", + "county": "Sierra", + "display": "Calpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4648012878634795456-2743", + "name": "Impact Forecasting Company", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Alder Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6574076295203887748-2744", + "name": "karmadata Corp", + "city": { + "name": "Amityville", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "N Amityville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1371081251618962303-2745", + "name": "StreamLink Software Corp", + "city": { + "name": "Cortaro", + "code": "AZ", + "state": "Arizona", + "county": "Pima", + "display": "Cortaro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-810586091842037977-2746", + "name": "Caspio Inc", + "city": { + "name": "Commerce Township", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Commerce Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3566198845058831783-2747", + "name": "The Vanguard Group Inc", + "city": { + "name": "Springfield", + "code": "MO", + "state": "Missouri", + "county": "Greene", + "display": "Missouri State University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2388910879535656729-2748", + "name": "Merrill Corp", + "city": { + "name": "Susanville", + "code": "CA", + "state": "California", + "county": "Lassen", + "display": "Spaulding" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7701282460889563343-2749", + "name": "Apextech LLC", + "city": { + "name": "Worthington", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "Worthington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7145877623761909277-2750", + "name": "REI Systems Company", + "city": { + "name": "Rampart", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Rampart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2701912215371503429-2751", + "name": "eScholar Corp", + "city": { + "name": "Loysville", + "code": "PA", + "state": "Pennsylvania", + "county": "Perry", + "display": "Ne Madison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4623256134232214013-2752", + "name": "WebFilings Company", + "city": { + "name": "Dayton", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Wpafb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3983913916900145438-2753", + "name": "Locavore LLC", + "city": { + "name": "Kalamazoo", + "code": "MI", + "state": "Michigan", + "county": "Kalamazoo", + "display": "Parchment" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5686124383441451693-2754", + "name": "Estately Inc", + "city": { + "name": "Powellville", + "code": "MD", + "state": "Maryland", + "county": "Wicomico", + "display": "Powellville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2935912342743085023-2755", + "name": "ProPublica Company", + "city": { + "name": "Elko", + "code": "GA", + "state": "Georgia", + "county": "Houston", + "display": "Elko" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6354774712356498957-2756", + "name": "Rank and Filed Company", + "city": { + "name": "Water Mill", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Watermill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3324773906196482589-2757", + "name": "Deloitte Incorporated", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Bar Code Term Annex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6188531715664058531-2758", + "name": "Stevens Worldwide Van Lines LLC", + "city": { + "name": "Edwards", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "South Edwards" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-746928370666573-2759", + "name": "Lucid Corp", + "city": { + "name": "Arlington", + "code": "VA", + "state": "Virginia", + "county": "Arlington", + "display": "Navy Sea Systems Command" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-777440493382771805-2760", + "name": "Yelp Incorporated", + "city": { + "name": "Tennyson", + "code": "IN", + "state": "Indiana", + "county": "Warrick", + "display": "Folsomvle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5294572671870094595-2761", + "name": "BuildZoom Corp", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Arkansas Louisiana Gas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-757484774443026476-2762", + "name": "Dun \u0026 Bradstreet LLC", + "city": { + "name": "Burlingame", + "code": "KS", + "state": "Kansas", + "county": "Osage", + "display": "Burlingame" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7854332879356319545-2763", + "name": "Accela Inc", + "city": { + "name": "Crumpler", + "code": "NC", + "state": "North Carolina", + "county": "Ashe", + "display": "Nathans Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2804072079223311850-2764", + "name": "College Board LLC", + "city": { + "name": "Duluth", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Proctor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-877535964992688578-2765", + "name": "NuCivic Company", + "city": { + "name": "Scobey", + "code": "MS", + "state": "Mississippi", + "county": "Yalobusha", + "display": "Scobey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-71631997747501121-2766", + "name": "Verdafero LLC", + "city": { + "name": "Earlville", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Earlville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8119211604197309433-2767", + "name": "Fastcase Company", + "city": { + "name": "Grand Mound", + "code": "IA", + "state": "Iowa", + "county": "Clinton", + "display": "Grand Mound" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8050378937662417059-2768", + "name": "Factset LLC", + "city": { + "name": "Holdenville", + "code": "OK", + "state": "Oklahoma", + "county": "Hughes", + "display": "Spaulding" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8170827842447777774-2769", + "name": "SmartProcure Inc", + "city": { + "name": "Pomeroy", + "code": "IA", + "state": "Iowa", + "county": "Calhoun", + "display": "Pomeroy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8946250869158909967-2770", + "name": "Aquicore LLC", + "city": { + "name": "South Richmond Hill", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "South Richmond Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6219509785070582609-2771", + "name": "Synthicity Corp", + "city": { + "name": "Fort Belvoir", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Fort Belvoir" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4043645675209301909-2772", + "name": "ProPublica Inc", + "city": { + "name": "Ragland", + "code": "WV", + "state": "West Virginia", + "county": "Mingo", + "display": "Ragland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7384900574206999199-2773", + "name": "Dabo Health Corp", + "city": { + "name": "Nathrop", + "code": "CO", + "state": "Colorado", + "county": "Chaffee", + "display": "Nathrop" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2417643266795297980-2774", + "name": "Sterling Infosystems LLC", + "city": { + "name": "Marysville", + "code": "CA", + "state": "California", + "county": "Yuba", + "display": "Hallwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5499258179582524892-2775", + "name": "Berkery Noyes MandASoft Incorporated", + "city": { + "name": "Alloway", + "code": "NJ", + "state": "New Jersey", + "county": "Salem", + "display": "Paradise Lakes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3339979463921571392-2776", + "name": "Vimo LLC", + "city": { + "name": "Big Pine Key", + "code": "FL", + "state": "Florida", + "county": "Monroe", + "display": "Summrlnd Key" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3310722767537691820-2777", + "name": "Computer Packages LLC", + "city": { + "name": "Bradford", + "code": "TN", + "state": "Tennessee", + "county": "Gibson", + "display": "Bradford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4919534028975039260-2778", + "name": "College Abacus, an ECMC initiative Corp", + "city": { + "name": "North Turner", + "code": "ME", + "state": "Maine", + "county": "Androscoggin", + "display": "North Turner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2344369294143236785-2779", + "name": "StreetCred Software, Inc", + "city": { + "name": "Estero", + "code": "FL", + "state": "Florida", + "county": "Lee", + "display": "Estero" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8396665970205689982-2780", + "name": "ProgrammableWeb Company", + "city": { + "name": "Liberty Corner", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Liberty Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8013395773949977239-2781", + "name": "People Power Corporation", + "city": { + "name": "Washburn", + "code": "ND", + "state": "North Dakota", + "county": "Mclean", + "display": "Falkirk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6709580761196811928-2782", + "name": "Computer Packages Corporation", + "city": { + "name": "Forest Knolls", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Forest Knolls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6022974110687088585-2783", + "name": "Housefax Company", + "city": { + "name": "Pocahontas", + "code": "IL", + "state": "Illinois", + "county": "Bond", + "display": "Jamestown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8419873006552606755-2784", + "name": "Quid Company", + "city": { + "name": "Nalcrest", + "code": "FL", + "state": "Florida", + "county": "Polk", + "display": "Nalcrest" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-803434345228807540-2785", + "name": "Practice Fusion Corporation", + "city": { + "name": "Marion", + "code": "LA", + "state": "Louisiana", + "county": "Union", + "display": "Litroe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2332334313847780687-2786", + "name": "PlaceILive.com Incorporated", + "city": { + "name": "Riesel", + "code": "TX", + "state": "Texas", + "county": "Mclennan", + "display": "Otto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3739660730944009361-2787", + "name": "ReciPal Corporation", + "city": { + "name": "Hartsburg", + "code": "MO", + "state": "Missouri", + "county": "Boone", + "display": "Wilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6767090758856361723-2788", + "name": "Predilytics Corp", + "city": { + "name": "Sturtevant", + "code": "WI", + "state": "Wisconsin", + "county": "Racine", + "display": "Mount Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1911744741587480210-2789", + "name": "SpotCrime Inc", + "city": { + "name": "Walnut Ridge", + "code": "AR", + "state": "Arkansas", + "county": "Lawrence", + "display": "Wms College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7635240314042400242-2790", + "name": "Junar, Inc", + "city": { + "name": "Topsfield", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Topsfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1133997914914298011-2791", + "name": "Healthgrades Inc", + "city": { + "name": "Mound", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Orono" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2233142145543870823-2792", + "name": "Chemical Abstracts Service Incorporated", + "city": { + "name": "Kewaskum", + "code": "WI", + "state": "Wisconsin", + "county": "Washington", + "display": "Kewaskum" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7131824283498486302-2793", + "name": "State Farm Insurance LLC", + "city": { + "name": "Little Compton", + "code": "RI", + "state": "Rhode Island", + "county": "Newport", + "display": "Little Compton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6599936586233308262-2794", + "name": "NerdWallet Company", + "city": { + "name": "Florence", + "code": "AL", + "state": "Alabama", + "county": "Lauderdale", + "display": "Univ Of North Ala" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2409183316280065820-2795", + "name": "Municode LLC", + "city": { + "name": "Columbia", + "code": "SC", + "state": "South Carolina", + "county": "Richland", + "display": "Forest Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2065838588378747443-2796", + "name": "STILLWATER SUPERCOMPUTING INC Incorporated", + "city": { + "name": "Houtzdale", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Ginter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6984958032684170885-2797", + "name": "How's My Offer? Company", + "city": { + "name": "Pine Grove", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "De Turksville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-319868584428231057-2798", + "name": "Relationship Science LLC", + "city": { + "name": "Cynthiana", + "code": "KY", + "state": "Kentucky", + "county": "Harrison", + "display": "Leesburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7386916455123441575-2799", + "name": "SpotHero.com LLC", + "city": { + "name": "Gravity", + "code": "IA", + "state": "Iowa", + "county": "Taylor", + "display": "Gravity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7422258008728945237-2800", + "name": "Ontodia, Corp", + "city": { + "name": "Mount Vernon", + "code": "KY", + "state": "Kentucky", + "county": "Rockcastle", + "display": "Climax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3834780785666994060-2801", + "name": "Department of Better Technology Company", + "city": { + "name": "Dawson", + "code": "AL", + "state": "Alabama", + "county": "De Kalb", + "display": "Dawson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8953023372169578025-2802", + "name": "KPMG LLC", + "city": { + "name": "Woody", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Woody" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5548299818308483932-2803", + "name": "Mint Company", + "city": { + "name": "Springfield", + "code": "MO", + "state": "Missouri", + "county": "Greene", + "display": "Missouri State University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3689772821466112566-2804", + "name": "PlanetEcosystems LLC", + "city": { + "name": "Richfield", + "code": "UT", + "state": "Utah", + "county": "Sevier", + "display": "Venice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1451139942539418762-2805", + "name": "American Red Ball Movers Incorporated", + "city": { + "name": "Charenton", + "code": "LA", + "state": "Louisiana", + "county": "Saint Mary", + "display": "Charenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7805070121621228217-2806", + "name": "Compared Care LLC", + "city": { + "name": "Santa Fe", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "New Mexico State Capitol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7319939660894529642-2807", + "name": "Roadify Transit Incorporated", + "city": { + "name": "Saint Vrain", + "code": "NM", + "state": "New Mexico", + "county": "Curry", + "display": "Saint Vrain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1970376078558393172-2808", + "name": "Fastcase Corporation", + "city": { + "name": "Somers", + "code": "NY", + "state": "New York", + "county": "Westchester", + "display": "Somers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2457702550966200980-2809", + "name": "Workhands Incorporated", + "city": { + "name": "Pleasant Plains", + "code": "AR", + "state": "Arkansas", + "county": "Independence", + "display": "Pleasant Plains" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5362140778889578478-2810", + "name": "RedLaser LLC", + "city": { + "name": "Browder", + "code": "KY", + "state": "Kentucky", + "county": "Muhlenberg", + "display": "Browder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8771652061264107173-2811", + "name": "Xignite Inc", + "city": { + "name": "Augusta", + "code": "GA", + "state": "Georgia", + "county": "Richmond", + "display": "Railroad Retirement Board" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6418810496222707066-2812", + "name": "Rank and Filed Inc", + "city": { + "name": "Trenton", + "code": "TX", + "state": "Texas", + "county": "Fannin", + "display": "Trenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8136313001784036175-2813", + "name": "SAS LLC", + "city": { + "name": "High Point", + "code": "NC", + "state": "North Carolina", + "county": "Guilford", + "display": "Glenola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4623936421763069929-2814", + "name": "Teradata Incorporated", + "city": { + "name": "Danville", + "code": "VT", + "state": "Vermont", + "county": "Caledonia", + "display": "Danville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4451452191532729375-2815", + "name": "Moody's Corp", + "city": { + "name": "Lena", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Gooberville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8314972122484284347-2816", + "name": "BetterLesson Company", + "city": { + "name": "Stevenson", + "code": "WA", + "state": "Washington", + "county": "Skamania", + "display": "Skamania" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-239094355112619542-2817", + "name": "Cerner Inc", + "city": { + "name": "Lake Wilson", + "code": "MN", + "state": "Minnesota", + "county": "Murray", + "display": "Hadley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6028810783304602274-2818", + "name": "SAP Corporation", + "city": { + "name": "Reliance", + "code": "WY", + "state": "Wyoming", + "county": "Sweetwater", + "display": "Reliance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2116415622128482082-2819", + "name": "Boston Consulting Group Corporation", + "city": { + "name": "Maysel", + "code": "WV", + "state": "West Virginia", + "county": "Clay", + "display": "Maysel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1390151021618233542-2820", + "name": "Revelstone LLC", + "city": { + "name": "Mount Arlington", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Mount Arlington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6330576106239719766-2821", + "name": "Golden Helix Incorporated", + "city": { + "name": "East Hickory", + "code": "PA", + "state": "Pennsylvania", + "county": "Forest", + "display": "Endeavor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2584184927986693965-2822", + "name": "Allianz Incorporated", + "city": { + "name": "Mc Clure", + "code": "OH", + "state": "Ohio", + "county": "Henry", + "display": "Grelton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7994577199741693780-2823", + "name": "SimpleTuition Corp", + "city": { + "name": "Salome", + "code": "AZ", + "state": "Arizona", + "county": "La Paz", + "display": "Salome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8030992783057907332-2824", + "name": "State Farm Insurance Corp", + "city": { + "name": "Gloster", + "code": "MS", + "state": "Mississippi", + "county": "Amite", + "display": "Bewelcome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3343735909068794007-2825", + "name": "Lenddo Inc", + "city": { + "name": "Ruidoso", + "code": "NM", + "state": "New Mexico", + "county": "Lincoln", + "display": "Ruidoso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1150580830525839165-2826", + "name": "Yahoo Inc", + "city": { + "name": "Kanawha Head", + "code": "WV", + "state": "West Virginia", + "county": "Upshur", + "display": "Kanawha Head" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8341656945144408157-2827", + "name": "CityScan Inc", + "city": { + "name": "Attleboro Falls", + "code": "MA", + "state": "Massachusetts", + "county": "Bristol", + "display": "North Attleboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7869921020381450909-2828", + "name": "Buildingeye Inc", + "city": { + "name": "Minden", + "code": "NV", + "state": "Nevada", + "county": "Douglas", + "display": "Minden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3089503578624403930-2829", + "name": "Boston Consulting Group Corporation", + "city": { + "name": "Newport", + "code": "OR", + "state": "Oregon", + "county": "Lincoln", + "display": "Agate Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7135030304005608107-2830", + "name": "Plus-U Inc", + "city": { + "name": "Media", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Rose Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4801464758482472795-2831", + "name": "College Abacus, an ECMC initiative Inc", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Univ Nv Las Vegas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-868467205673418801-2832", + "name": "Sophic Systems Alliance Corp", + "city": { + "name": "Paintsville", + "code": "KY", + "state": "Kentucky", + "county": "Johnson", + "display": "Paintsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5184540012250935280-2833", + "name": "LegiStorm Corporation", + "city": { + "name": "Wichita", + "code": "KS", + "state": "Kansas", + "county": "Sedgwick", + "display": "Eastborough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7079702634642538007-2834", + "name": "TrueCar Inc", + "city": { + "name": "Garwin", + "code": "IA", + "state": "Iowa", + "county": "Tama", + "display": "Green Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8115727027297452429-2835", + "name": "Aunt Bertha, Inc", + "city": { + "name": "Dahlonega", + "code": "GA", + "state": "Georgia", + "county": "Lumpkin", + "display": "North Georgia College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7438073302145154797-2836", + "name": "Seabourne Corporation", + "city": { + "name": "Tchula", + "code": "MS", + "state": "Mississippi", + "county": "Holmes", + "display": "Thornton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7965793567885554109-2837", + "name": "FlightAware Corp", + "city": { + "name": "Newaygo", + "code": "MI", + "state": "Michigan", + "county": "Newaygo", + "display": "Croton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1925352084401154406-2838", + "name": "The Bridgespan Group Corporation", + "city": { + "name": "Pansey", + "code": "AL", + "state": "Alabama", + "county": "Houston", + "display": "Pansey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1615597347255502615-2839", + "name": "Cambridge Semantics Corporation", + "city": { + "name": "Catawissa", + "code": "PA", + "state": "Pennsylvania", + "county": "Columbia", + "display": "Parrs Mill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-555969204385761941-2840", + "name": "Boston Consulting Group Inc", + "city": { + "name": "Nicoma Park", + "code": "OK", + "state": "Oklahoma", + "county": "Oklahoma", + "display": "Nicoma Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1689075041812944168-2841", + "name": "SAP Corp", + "city": { + "name": "Many", + "code": "LA", + "state": "Louisiana", + "county": "Sabine", + "display": "Rattan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5913575896161716833-2842", + "name": "Uber Corporation", + "city": { + "name": "Lost Hills", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Lost Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-407775743585561064-2843", + "name": "Owler Inc", + "city": { + "name": "New Paris", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "New Paris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4792277001154349441-2844", + "name": "Captricity Corporation", + "city": { + "name": "Flagler", + "code": "CO", + "state": "Colorado", + "county": "Kit Carson", + "display": "Flagler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-643168938875072399-2845", + "name": "BetterLesson Corporation", + "city": { + "name": "Ballwin", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Sherman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3179073957928220890-2846", + "name": "Trulia Incorporated", + "city": { + "name": "Green Mountain", + "code": "NC", + "state": "North Carolina", + "county": "Yancey", + "display": "Green Mt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6079125231640809802-2847", + "name": "Peterson's Corporation", + "city": { + "name": "New Paris", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "New Paris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-679821090127489592-2848", + "name": "Allied Van Lines Incorporated", + "city": { + "name": "Lamesa", + "code": "TX", + "state": "Texas", + "county": "Dawson", + "display": "Lamesa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3924798642220101745-2849", + "name": "Buildingeye Corp", + "city": { + "name": "Holland", + "code": "MA", + "state": "Massachusetts", + "county": "Hampden", + "display": "Holland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-866281894567894237-2850", + "name": "Poncho App Corp", + "city": { + "name": "Shippensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Pinola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7566858703804923606-2851", + "name": "United Mayflower Corporation", + "city": { + "name": "Belle Glade", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Belle Glade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7054470773847839826-2852", + "name": "Investormill Company", + "city": { + "name": "Guilford", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Guilford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7286897952747851861-2853", + "name": "Nautilytics Inc", + "city": { + "name": "Bulpitt", + "code": "IL", + "state": "Illinois", + "county": "Christian", + "display": "Bulpitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5714573894740407696-2854", + "name": "FlightStats Corporation", + "city": { + "name": "Greenup", + "code": "KY", + "state": "Kentucky", + "county": "Greenup", + "display": "Lloyd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5179780411647694846-2855", + "name": "Splunk Inc", + "city": { + "name": "Riverside", + "code": "NJ", + "state": "New Jersey", + "county": "Burlington", + "display": "North Delran" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7551467930430372207-2856", + "name": "Relationship Science Corporation", + "city": { + "name": "Hamer", + "code": "SC", + "state": "South Carolina", + "county": "Dillon", + "display": "S Of Border" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3811086958972616797-2857", + "name": "Maponics LLC", + "city": { + "name": "Milton", + "code": "DE", + "state": "Delaware", + "county": "Sussex", + "display": "Milton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3671406225631151673-2858", + "name": "Stormpulse Inc", + "city": { + "name": "East Poland", + "code": "ME", + "state": "Maine", + "county": "Androscoggin", + "display": "East Poland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6519714290036950042-2859", + "name": "Appallicious Corporation", + "city": { + "name": "Southport", + "code": "NC", + "state": "North Carolina", + "county": "Brunswick", + "display": "Southport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4395307071477118125-2860", + "name": "GoodGuide Corporation", + "city": { + "name": "Wellfleet", + "code": "NE", + "state": "Nebraska", + "county": "Lincoln", + "display": "Wellfleet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3687694582785171665-2861", + "name": "Rand McNally LLC", + "city": { + "name": "Culloden", + "code": "WV", + "state": "West Virginia", + "county": "Cabell", + "display": "Culloden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4350861056619528632-2862", + "name": "eInstitutional Inc", + "city": { + "name": "Alma", + "code": "NE", + "state": "Nebraska", + "county": "Harlan", + "display": "Prairie Dog" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8080911790179361536-2863", + "name": "Enervee Corporation", + "city": { + "name": "Conda", + "code": "ID", + "state": "Idaho", + "county": "Caribou", + "display": "Soda Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5208993666373066067-2864", + "name": "CoreLogic Company", + "city": { + "name": "Saginaw", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Brevator" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2651534252231925915-2865", + "name": "Tendril LLC", + "city": { + "name": "Catharpin", + "code": "VA", + "state": "Virginia", + "county": "Prince William", + "display": "Catharpin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7855244954587623638-2866", + "name": "SmartAsset Inc", + "city": { + "name": "Piseco", + "code": "NY", + "state": "New York", + "county": "Hamilton", + "display": "Arietta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3807359813755995270-2867", + "name": "NERA Economic Consulting Corp", + "city": { + "name": "Waterloo", + "code": "NY", + "state": "New York", + "county": "Seneca", + "display": "Waterloo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2970243013900993384-2868", + "name": "CONNECT-DOT LLC", + "city": { + "name": "Elmhurst", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Elmhurst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1541637701090670841-2869", + "name": "StreetEasy LLC", + "city": { + "name": "King Cove", + "code": "AK", + "state": "Alaska", + "county": "Aleutians East", + "display": "King Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8734343346324477050-2870", + "name": "State Farm Insurance Inc", + "city": { + "name": "Waterloo", + "code": "IA", + "state": "Iowa", + "county": "Black Hawk", + "display": "Washburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6146322995185800612-2871", + "name": "Tendril Corporation", + "city": { + "name": "Winthrop Harbor", + "code": "IL", + "state": "Illinois", + "county": "Lake", + "display": "Winthrop Hbr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3702276438753230152-2872", + "name": "Housefax Corp", + "city": { + "name": "North Port", + "code": "FL", + "state": "Florida", + "county": "Sarasota", + "display": "Venice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2366536198415328030-2873", + "name": "MapQuest Inc", + "city": { + "name": "Kearneysville", + "code": "WV", + "state": "West Virginia", + "county": "Jefferson", + "display": "Kearneysville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5063641111375292536-2874", + "name": "Expert Health Data Programming, Company", + "city": { + "name": "Aspermont", + "code": "TX", + "state": "Texas", + "county": "Stonewall", + "display": "Peacock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5391723929097199247-2875", + "name": "Exversion Corporation", + "city": { + "name": "Newell", + "code": "SD", + "state": "South Dakota", + "county": "Butte", + "display": "Newell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7511277425503615716-2876", + "name": "Quandl Corporation", + "city": { + "name": "SF", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Sf" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-693201502358818059-2877", + "name": "SigFig LLC", + "city": { + "name": "Geddes", + "code": "SD", + "state": "South Dakota", + "county": "Charles Mix", + "display": "Geddes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4104005436703735214-2878", + "name": "Lending Club LLC", + "city": { + "name": "Princeton", + "code": "TX", + "state": "Texas", + "county": "Collin", + "display": "Princeton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7506638577532652023-2879", + "name": "Computer Packages Corp", + "city": { + "name": "Richwood", + "code": "OH", + "state": "Ohio", + "county": "Union", + "display": "Richwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7473095213131427606-2880", + "name": "OnStar Corp", + "city": { + "name": "Cross Junction", + "code": "VA", + "state": "Virginia", + "county": "Frederick", + "display": "Whitacre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7341397483641711126-2881", + "name": "Allied Van Lines Inc", + "city": { + "name": "Tupper Lake", + "code": "NY", + "state": "New York", + "county": "Franklin", + "display": "Tupper Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8310740670665659810-2882", + "name": "Galorath orporated LLC", + "city": { + "name": "Shippensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Mowersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6523133284504202161-2883", + "name": "Next Step Living Incorporated", + "city": { + "name": "Jumping Branch", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Streeter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-442140063697219039-2884", + "name": "Rapid Cycle Solutions LLC", + "city": { + "name": "Cobalt", + "code": "CT", + "state": "Connecticut", + "county": "Middlesex", + "display": "Cobalt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7129035851956144194-2885", + "name": "Boston Consulting Group Corp", + "city": { + "name": "Zuni", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Ramah Community" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-391644290538145308-2886", + "name": "Climate Company", + "city": { + "name": "Alto", + "code": "TX", + "state": "Texas", + "county": "Cherokee", + "display": "Redlawn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7543962551719176025-2887", + "name": "OnStar Incorporated", + "city": { + "name": "Sykesville", + "code": "PA", + "state": "Pennsylvania", + "county": "Jefferson", + "display": "Sykesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2146533945207140774-2888", + "name": "NerdWallet Incorporated", + "city": { + "name": "South Hutchinson", + "code": "KS", + "state": "Kansas", + "county": "Reno", + "display": "So Hutchinson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8650985596856857592-2889", + "name": "Business and Legal Resources Inc", + "city": { + "name": "Mcgregor", + "code": "MN", + "state": "Minnesota", + "county": "Aitkin", + "display": "Spalding" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2929956292638035305-2890", + "name": "SmartAsset Incorporated", + "city": { + "name": "Frenchburg", + "code": "KY", + "state": "Kentucky", + "county": "Menifee", + "display": "Frenchburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2146903221829059721-2891", + "name": "Ontodia, Company", + "city": { + "name": "Port Orchard", + "code": "WA", + "state": "Washington", + "county": "Kitsap", + "display": "Parkwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8412979551423430638-2892", + "name": "Enervee LLC", + "city": { + "name": "Inverness", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Inverness" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-140636107483292568-2893", + "name": "Stevens Worldwide Van Lines LLC", + "city": { + "name": "Marathon", + "code": "IA", + "state": "Iowa", + "county": "Buena Vista", + "display": "Marathon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4150183044880378725-2894", + "name": "New Media Parents LLC", + "city": { + "name": "Meyersville", + "code": "TX", + "state": "Texas", + "county": "De Witt", + "display": "Meyersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4850693092238233584-2895", + "name": "Maponics Company", + "city": { + "name": "Dayton", + "code": "OH", + "state": "Ohio", + "county": "Montgomery", + "display": "Dayton Courtesy Reply Mail" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-514878221318006826-2896", + "name": "NextBus Corporation", + "city": { + "name": "Spanish Fork", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Cover Bridge Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7020811037805781050-2897", + "name": "TowerData Corporation", + "city": { + "name": "Floydada", + "code": "TX", + "state": "Texas", + "county": "Floyd", + "display": "Floydada" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2905767824673347180-2898", + "name": "Remi Corp", + "city": { + "name": "Georgetown", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Georgetown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6616915640842589748-2899", + "name": "OpenPlans Company", + "city": { + "name": "Fort Plain", + "code": "NY", + "state": "New York", + "county": "Montgomery", + "display": "Sand Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-253379519344182666-2900", + "name": "BillGuard Company", + "city": { + "name": "Central City", + "code": "KY", + "state": "Kentucky", + "county": "Muhlenberg", + "display": "Central Cty" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4879515378381766362-2901", + "name": "Equilar Inc", + "city": { + "name": "Selinsgrove", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Blue Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2551861247867139697-2902", + "name": "BaleFire Global Corporation", + "city": { + "name": "Cleveland", + "code": "OH", + "state": "Ohio", + "county": "Cuyahoga", + "display": "Brooklyn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-601957197879170100-2903", + "name": "FlightView Incorporated", + "city": { + "name": "Belleville", + "code": "WI", + "state": "Wisconsin", + "county": "Dane", + "display": "Belleville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2799752040467516705-2904", + "name": "Captricity Corporation", + "city": { + "name": "Mc Bee", + "code": "SC", + "state": "South Carolina", + "county": "Chesterfield", + "display": "Mc Bee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3148224054875976420-2905", + "name": "Compared Care Company", + "city": { + "name": "Jamestown", + "code": "PA", + "state": "Pennsylvania", + "county": "Mercer", + "display": "Westford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1011347283865400609-2906", + "name": "Junar, Company", + "city": { + "name": "Rickreall", + "code": "OR", + "state": "Oregon", + "county": "Polk", + "display": "Rickreall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5462664655362562474-2907", + "name": "PEV4me.com LLC", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Stuyvsnt Plz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4278191505289683164-2908", + "name": "Russell Investments LLC", + "city": { + "name": "Auburn", + "code": "NY", + "state": "New York", + "county": "Cayuga", + "display": "Aurelius" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-46195386851398592-2909", + "name": "Ranku Corp", + "city": { + "name": "Yuma", + "code": "CO", + "state": "Colorado", + "county": "Yuma", + "display": "Yuma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5608015996552222914-2910", + "name": "PYA Analytics LLC", + "city": { + "name": "Rochester", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Oakland Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3819931891963608186-2911", + "name": "The DocGraph Journal LLC", + "city": { + "name": "Coal City", + "code": "IL", + "state": "Illinois", + "county": "Grundy", + "display": "Eileen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6777472940318029435-2912", + "name": "Chubb Company", + "city": { + "name": "North Montpelier", + "code": "VT", + "state": "Vermont", + "county": "Washington", + "display": "N Montpelier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2744366918203748465-2913", + "name": "Arpin Van Lines Corporation", + "city": { + "name": "Murrells Inlet", + "code": "SC", + "state": "South Carolina", + "county": "Horry", + "display": "Garden City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3867464679921341614-2914", + "name": "Aquicore Company", + "city": { + "name": "Lena", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Gooberville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1837024839357176940-2915", + "name": "AutoGrid Systems Company", + "city": { + "name": "Manorville", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Manorville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2039392061292134351-2916", + "name": "Weather Decision Technologies Inc", + "city": { + "name": "Elizabethtown", + "code": "KY", + "state": "Kentucky", + "county": "Hardin", + "display": "E Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2596750502854473145-2917", + "name": "Peterson's Company", + "city": { + "name": "Duson", + "code": "LA", + "state": "Louisiana", + "county": "Lafayette", + "display": "Duson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8744082766216634064-2918", + "name": "Quandl Corporation", + "city": { + "name": "Pleasant Unity", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Pleasant Unity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8949228297091197046-2919", + "name": "Credit Karma Corporation", + "city": { + "name": "Durants Neck", + "code": "NC", + "state": "North Carolina", + "county": "Perquimans", + "display": "Hertford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7007966321091091707-2920", + "name": "indoo.rs Corporation", + "city": { + "name": "Mount Hope", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Mount Hope" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4091895436774447708-2921", + "name": "Forrester Research Corporation", + "city": { + "name": "Sicily Island", + "code": "LA", + "state": "Louisiana", + "county": "Catahoula", + "display": "Sicily Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4201965112952250917-2922", + "name": "Ranku Company", + "city": { + "name": "Jenner", + "code": "CA", + "state": "California", + "county": "Sonoma", + "display": "Jenner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7160982815085702523-2923", + "name": "eInstitutional Corporation", + "city": { + "name": "Cleveland", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Windsor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4558176749504864759-2924", + "name": "Fastcase LLC", + "city": { + "name": "Farmer", + "code": "OH", + "state": "Ohio", + "county": "Defiance", + "display": "Farmer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4313323389964407203-2925", + "name": "ProgrammableWeb LLC", + "city": { + "name": "Maud", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Maud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8183513521153519060-2926", + "name": "Civic Insight Incorporated", + "city": { + "name": "Mclean", + "code": "TX", + "state": "Texas", + "county": "Gray", + "display": "Mclean" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1018368480553503776-2927", + "name": "Rank and Filed Corp", + "city": { + "name": "Barnegat Light", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Barnegat Light" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2176408965498264218-2928", + "name": "Ontodia, Corp", + "city": { + "name": "Valley Stream", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Valley Stream" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7279352338994932997-2929", + "name": "Calcbench, Corporation", + "city": { + "name": "Fairfax Station", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Fx Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4890421384708709302-2930", + "name": "HealthPocket, Corporation", + "city": { + "name": "Oxford", + "code": "ME", + "state": "Maine", + "county": "Oxford", + "display": "Otisfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3103385895161149676-2931", + "name": "Think Computer LLC", + "city": { + "name": "Falkville", + "code": "AL", + "state": "Alabama", + "county": "Morgan", + "display": "Falkville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6132855678074981962-2932", + "name": "Innography Incorporated", + "city": { + "name": "Spencer", + "code": "ID", + "state": "Idaho", + "county": "Clark", + "display": "Dubois" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1596192564930001212-2933", + "name": "Food+Tech Connect Company", + "city": { + "name": "Maydelle", + "code": "TX", + "state": "Texas", + "county": "Cherokee", + "display": "Maydelle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1481253998814412742-2934", + "name": "iMedicare LLC", + "city": { + "name": "Hillsboro", + "code": "OR", + "state": "Oregon", + "county": "Washington", + "display": "West Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5710050892104537783-2935", + "name": "United Mayflower Corporation", + "city": { + "name": "Gwynedd", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Gwynedd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5491409673542965108-2936", + "name": "StockSmart LLC", + "city": { + "name": "Boydton", + "code": "VA", + "state": "Virginia", + "county": "Mecklenburg", + "display": "Palmersprings" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4080158677397061226-2937", + "name": "Computer Packages Corporation", + "city": { + "name": "Lemoyne", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Wormleysburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1108056934901784418-2938", + "name": "Cappex Corp", + "city": { + "name": "Woodville", + "code": "WV", + "state": "West Virginia", + "county": "Boone", + "display": "Woodville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7003046092169701097-2939", + "name": "Votizen Inc", + "city": { + "name": "Gagetown", + "code": "MI", + "state": "Michigan", + "county": "Tuscola", + "display": "Gagetown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6356165418833387306-2940", + "name": "Ontodia, Corp", + "city": { + "name": "North Salem", + "code": "NH", + "state": "New Hampshire", + "county": "Rockingham", + "display": "No Salem" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8317504678477625360-2941", + "name": "Ranku Incorporated", + "city": { + "name": "Bay Port", + "code": "MI", + "state": "Michigan", + "county": "Huron", + "display": "Bay Port" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7403504671419649114-2942", + "name": "Xcential Inc", + "city": { + "name": "Drury", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Drury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3047034943572905337-2943", + "name": "FarmLogs Inc", + "city": { + "name": "Foxboro", + "code": "MA", + "state": "Massachusetts", + "county": "Norfolk", + "display": "Foxboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4867234178452411598-2944", + "name": "AutoGrid Systems LLC", + "city": { + "name": "Fort Hood", + "code": "TX", + "state": "Texas", + "county": "Bell", + "display": "Chaffee Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2409499528352863880-2945", + "name": "The DocGraph Journal Incorporated", + "city": { + "name": "Fence Lake", + "code": "NM", + "state": "New Mexico", + "county": "Cibola", + "display": "Trechado" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2714292628411312882-2946", + "name": "Telenav Corp", + "city": { + "name": "Dundas", + "code": "MN", + "state": "Minnesota", + "county": "Rice", + "display": "Dundas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4844333545434389646-2947", + "name": "Be Informed Corp", + "city": { + "name": "Hope", + "code": "IN", + "state": "Indiana", + "county": "Bartholomew", + "display": "Hope" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3805949364623917447-2948", + "name": "People Power Company", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Swepco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8209466823803346533-2949", + "name": "Investormill Inc", + "city": { + "name": "Mooresboro", + "code": "NC", + "state": "North Carolina", + "county": "Cleveland", + "display": "Mooresboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6805058582765482239-2950", + "name": "CoreLogic Incorporated", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Pgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6981446179430579035-2951", + "name": "Mint Corporation", + "city": { + "name": "Chatom", + "code": "AL", + "state": "Alabama", + "county": "Washington", + "display": "Chatom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4005718854845093218-2952", + "name": "KLD Research Corporation", + "city": { + "name": "Cortez", + "code": "CO", + "state": "Colorado", + "county": "Montezuma", + "display": "Arriola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-196779139521276346-2953", + "name": "Computer Packages Inc", + "city": { + "name": "Detroit", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Chase Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6971093731419222431-2954", + "name": "SpeSo Health Company", + "city": { + "name": "Detroit", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Chase Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5253129232408049999-2955", + "name": "Rank and Filed Corporation", + "city": { + "name": "Gallup", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Williams Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3082608881766081875-2956", + "name": "xDayta Company", + "city": { + "name": "Saint Bernard", + "code": "LA", + "state": "Louisiana", + "county": "Saint Bernard", + "display": "Reggio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1362149207325787328-2957", + "name": "LegiNation, Corporation", + "city": { + "name": "Andover", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Internal Revenue Service" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3507726246444684314-2958", + "name": "Graematter, Corp", + "city": { + "name": "Dixon", + "code": "IL", + "state": "Illinois", + "county": "Lee", + "display": "Prairieville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9059970787703605453-2959", + "name": "Symcat Incorporated", + "city": { + "name": "Marks", + "code": "MS", + "state": "Mississippi", + "county": "Quitman", + "display": "Marks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7773122735114206622-2960", + "name": "Vital Axiom | Niinja Corp", + "city": { + "name": "Harveysburg", + "code": "OH", + "state": "Ohio", + "county": "Warren", + "display": "Massie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2642582052445802337-2961", + "name": "Civis Analytics LLC", + "city": { + "name": "Selman City", + "code": "TX", + "state": "Texas", + "county": "Rusk", + "display": "Turnertown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5408434964190823270-2962", + "name": "Suddath LLC", + "city": { + "name": "Millinocket", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Long A Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4403239330009925815-2963", + "name": "Mozio Corp", + "city": { + "name": "Minneapolis", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Brooklyn Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7515433274145687469-2964", + "name": "Optensity Corporation", + "city": { + "name": "Richmond", + "code": "VA", + "state": "Virginia", + "county": "Richmond City", + "display": "Va Dept Tax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2413834947175189160-2965", + "name": "3 Round Stones, Corporation", + "city": { + "name": "Recluse", + "code": "WY", + "state": "Wyoming", + "county": "Campbell", + "display": "Recluse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6285875166027351526-2966", + "name": "Xatori Corp", + "city": { + "name": "Marine On Saint Croix", + "code": "MN", + "state": "Minnesota", + "county": "Washington", + "display": "Marine On Saint Croix" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4889516171547377357-2967", + "name": "PatientsLikeMe Corp", + "city": { + "name": "Savage", + "code": "MD", + "state": "Maryland", + "county": "Howard", + "display": "Savage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4677624223228211786-2968", + "name": "Child Care Desk LLC", + "city": { + "name": "Saint John", + "code": "KS", + "state": "Kansas", + "county": "Stafford", + "display": "Saint John" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3402933978478013628-2969", + "name": "Mint LLC", + "city": { + "name": "Sopchoppy", + "code": "FL", + "state": "Florida", + "county": "Wakulla", + "display": "Sopchoppy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5506040344742255975-2970", + "name": "Child Care Desk Corp", + "city": { + "name": "Baldwin", + "code": "MI", + "state": "Michigan", + "county": "Lake", + "display": "Baldwin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-635870121895803876-2971", + "name": "R R Donnelley Corporation", + "city": { + "name": "Blackduck", + "code": "MN", + "state": "Minnesota", + "county": "Beltrami", + "display": "Blackduck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-301554049623129083-2972", + "name": "Open Data Nation Corp", + "city": { + "name": "Boise", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Intermountain Gas Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8532985284514351143-2973", + "name": "Vitals Company", + "city": { + "name": "Williamsburg", + "code": "NM", + "state": "New Mexico", + "county": "Sierra", + "display": "Las Palomas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8278317799370114557-2974", + "name": "Ceiba Solutions Corporation", + "city": { + "name": "Kansas City", + "code": "KS", + "state": "Kansas", + "county": "Wyandotte", + "display": "Edwardsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3505514864289125922-2975", + "name": "Marlin Alter and Associates Corp", + "city": { + "name": "Melbourne", + "code": "IA", + "state": "Iowa", + "county": "Marshall", + "display": "Melbourne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7944069488837132558-2976", + "name": "Everyday Health Incorporated", + "city": { + "name": "Carrollton", + "code": "GA", + "state": "Georgia", + "county": "Carroll", + "display": "University Of West Georgia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9213172317534362616-2977", + "name": "Marlin \u0026 Associates Company", + "city": { + "name": "Sugarcreek", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Shanesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-464948934412929893-2978", + "name": "Berkshire Hathaway Corp", + "city": { + "name": "Attleboro", + "code": "MA", + "state": "Massachusetts", + "county": "Bristol", + "display": "South Attleboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-164077950966928719-2979", + "name": "Charles River Associates Corporation", + "city": { + "name": "Montgomery", + "code": "IN", + "state": "Indiana", + "county": "Daviess", + "display": "Glendale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4494776235650951465-2980", + "name": "McKinsey Incorporated", + "city": { + "name": "Mooresboro", + "code": "NC", + "state": "North Carolina", + "county": "Cleveland", + "display": "Mooresboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2765204389371197240-2981", + "name": "Civis Analytics LLC", + "city": { + "name": "Arapahoe", + "code": "NC", + "state": "North Carolina", + "county": "Pamlico", + "display": "Minnesott Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6986757747204666960-2982", + "name": "Quertle Corporation", + "city": { + "name": "Santa Fe", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "New Mexico State Capitol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7988276196462071894-2983", + "name": "Municode Incorporated", + "city": { + "name": "Lovelock", + "code": "NV", + "state": "Nevada", + "county": "Pershing", + "display": "Oreana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1976402334349360723-2984", + "name": "Acxiom Inc", + "city": { + "name": "Round Lake", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Round Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8773370526641455066-2985", + "name": "Lucid Company", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Dept Agriculture" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7567576333916807437-2986", + "name": "TrustedID Corp", + "city": { + "name": "Northfield", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Thomaston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2198495675539745479-2987", + "name": "USSearch Incorporated", + "city": { + "name": "Columbia City", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Collins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3024933709658290191-2988", + "name": "Careset.com Company", + "city": { + "name": "Middleburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Meiser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7117206893360565976-2989", + "name": "TrustedID Corp", + "city": { + "name": "Troutdale", + "code": "OR", + "state": "Oregon", + "county": "Multnomah", + "display": "Troutdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3681843594035583162-2990", + "name": "Trulia LLC", + "city": { + "name": "Saluda", + "code": "SC", + "state": "South Carolina", + "county": "Saluda", + "display": "Emory" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1208219762759736461-2991", + "name": "Cambridge Semantics Inc", + "city": { + "name": "Mora", + "code": "MN", + "state": "Minnesota", + "county": "Kanabec", + "display": "Knife Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4433175350465179342-2992", + "name": "Child Care Desk Company", + "city": { + "name": "Boron", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Boron" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7476877177625163696-2993", + "name": "CB Insights Corporation", + "city": { + "name": "Refton", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Refton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6968394608448285694-2994", + "name": "Sage Bionetworks Incorporated", + "city": { + "name": "Dallesport", + "code": "WA", + "state": "Washington", + "county": "Klickitat", + "display": "Dallesport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1772296789942531062-2995", + "name": "Castle Biosciences Inc", + "city": { + "name": "Crouseville", + "code": "ME", + "state": "Maine", + "county": "Aroostook", + "display": "Crouseville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2616727941855690741-2996", + "name": "Civic Insight Corp", + "city": { + "name": "Excelsior", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Greenwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2497356406652366047-2997", + "name": "Junar, Incorporated", + "city": { + "name": "Jarrettsville", + "code": "MD", + "state": "Maryland", + "county": "Harford", + "display": "Jarrettsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5551418791265284712-2998", + "name": "LegiNation, LLC", + "city": { + "name": "Stonewall", + "code": "TX", + "state": "Texas", + "county": "Gillespie", + "display": "Stonewall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6762654784277394634-2999", + "name": "North American Van Lines Corp", + "city": { + "name": "Pitcairn", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Monroeville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6567165519976544380-3000", + "name": "TrueCar Inc", + "city": { + "name": "Wood River", + "code": "NE", + "state": "Nebraska", + "county": "Hall", + "display": "Prosser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-303065807948782269-3001", + "name": "Solar Census Incorporated", + "city": { + "name": "Haugen", + "code": "WI", + "state": "Wisconsin", + "county": "Barron", + "display": "Haugen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4101027311411430517-3002", + "name": "Geolytics Company", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Dept Of State" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1750075654285908561-3003", + "name": "Lending Club Company", + "city": { + "name": "Lake Worth", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Greenacres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7176264118387390339-3004", + "name": "Zillow Inc", + "city": { + "name": "Yellowstone National Park", + "code": "WY", + "state": "Wyoming", + "county": "Park", + "display": "Mammoth Hot Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7751454550862065679-3005", + "name": "College Abacus, an ECMC initiative LLC", + "city": { + "name": "Fresh Meadows", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Pomonok" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7837094956899105540-3006", + "name": "ReciPal Corp", + "city": { + "name": "Overland Park", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "Shawnee Msn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2335959826458249953-3007", + "name": "Kyruus LLC", + "city": { + "name": "Albers", + "code": "IL", + "state": "Illinois", + "county": "Clinton", + "display": "Damiansville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2540137346102831133-3008", + "name": "Sage Bionetworks Company", + "city": { + "name": "Martin City", + "code": "MT", + "state": "Montana", + "county": "Flathead", + "display": "Martin City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2757908549462033115-3009", + "name": "Be Informed Corp", + "city": { + "name": "Wilmington", + "code": "DE", + "state": "Delaware", + "county": "New Castle", + "display": "Bellefonte" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1901170540836694655-3010", + "name": "Innography Inc", + "city": { + "name": "Bridgewater", + "code": "MA", + "state": "Massachusetts", + "county": "Plymouth", + "display": "Bridgewater State College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7791810306945587338-3011", + "name": "The Vanguard Group LLC", + "city": { + "name": "Perry Point", + "code": "MD", + "state": "Maryland", + "county": "Cecil", + "display": "Perry Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2194035302020328140-3012", + "name": "Fuzion Apps, Inc", + "city": { + "name": "Boyd", + "code": "MN", + "state": "Minnesota", + "county": "Lac Qui Parle", + "display": "Boyd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1320215524400465926-3013", + "name": "Everyday Health Incorporated", + "city": { + "name": "Welch", + "code": "MN", + "state": "Minnesota", + "county": "Goodhue", + "display": "Welch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9049648023328973058-3014", + "name": "MedWatcher LLC", + "city": { + "name": "Oilville", + "code": "VA", + "state": "Virginia", + "county": "Goochland", + "display": "Oilville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4636229662717205116-3015", + "name": "Stevens Worldwide Van Lines Company", + "city": { + "name": "Collyer", + "code": "KS", + "state": "Kansas", + "county": "Trego", + "display": "Collyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3404160775247558679-3016", + "name": "IPHIX Corp", + "city": { + "name": "Malta", + "code": "ID", + "state": "Idaho", + "county": "Cassia", + "display": "Malta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7073350843443928884-3017", + "name": "Standard and Poor's Corporation", + "city": { + "name": "Gwynn Oak", + "code": "MD", + "state": "Maryland", + "county": "Baltimore", + "display": "Gwynn Oak" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2961769422047898219-3018", + "name": "FlightStats Incorporated", + "city": { + "name": "Sag Harbor", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Sag Harbor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3539286470942086123-3019", + "name": "Cerner Corp", + "city": { + "name": "Rockland", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "Rockland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3400821136280152716-3020", + "name": "AtSite Incorporated", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Ny Agr And Mkts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5579018476657162158-3021", + "name": "OptumInsight LLC", + "city": { + "name": "Howe", + "code": "TX", + "state": "Texas", + "county": "Grayson", + "display": "Dorchester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4028814020985650007-3022", + "name": "J.P. Morgan Chase Company", + "city": { + "name": "National Mine", + "code": "MI", + "state": "Michigan", + "county": "Marquette", + "display": "National Mine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6721088742880851709-3023", + "name": "Wheaton World Wide Moving Incorporated", + "city": { + "name": "Waunakee", + "code": "WI", + "state": "Wisconsin", + "county": "Dane", + "display": "Westport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-277202892954130639-3024", + "name": "Eat Shop Sleep Corporation", + "city": { + "name": "Laird Hill", + "code": "TX", + "state": "Texas", + "county": "Rusk", + "display": "Laird Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3505161207678986436-3025", + "name": "SeeClickFix LLC", + "city": { + "name": "Hazard", + "code": "KY", + "state": "Kentucky", + "county": "Perry", + "display": "Hazard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5399078865432157693-3026", + "name": "Jurispect Incorporated", + "city": { + "name": "Post Falls", + "code": "ID", + "state": "Idaho", + "county": "Kootenai", + "display": "State Line" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6026220259816059943-3027", + "name": "Chemical Abstracts Service Inc", + "city": { + "name": "Monee", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Monee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7680709363911210723-3028", + "name": "Aunt Bertha, Corp", + "city": { + "name": "Kelford", + "code": "NC", + "state": "North Carolina", + "county": "Bertie", + "display": "Kelford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7562501850338387230-3029", + "name": "Spokeo LLC", + "city": { + "name": "Belvedere Tiburon", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Bel Tiburon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6655535364104085084-3030", + "name": "TransUnion Corporation", + "city": { + "name": "Syracuse", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Dewitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6024959130965792965-3031", + "name": "Construction Monitor Corp", + "city": { + "name": "Swords Creek", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Dye" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-264585374128742820-3032", + "name": "Vital Axiom | Niinja Company", + "city": { + "name": "Saint Leo", + "code": "FL", + "state": "Florida", + "county": "Pasco", + "display": "Saint Leo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8670345502508261969-3033", + "name": "Brightscope Incorporated", + "city": { + "name": "Mc Indoe Falls", + "code": "VT", + "state": "Vermont", + "county": "Caledonia", + "display": "Mc Indoe Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7649550220624958902-3034", + "name": "PossibilityU Inc", + "city": { + "name": "Galway", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Hagedorns Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-345454732107396204-3035", + "name": "Epsilon LLC", + "city": { + "name": "Pohnpei", + "code": "FM", + "state": "Federated States of Micronesia", + "county": "Federated States Of Micro", + "display": "Ponape" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2234969309485639421-3036", + "name": "Glassy Media Inc", + "city": { + "name": "Mc Clure", + "code": "PA", + "state": "Pennsylvania", + "county": "Mifflin", + "display": "Mc Clure" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3838833893912363809-3037", + "name": "YourMapper Incorporated", + "city": { + "name": "Weippe", + "code": "ID", + "state": "Idaho", + "county": "Clearwater", + "display": "Weippe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3351113847031173305-3038", + "name": "Numedii Corp", + "city": { + "name": "Trevett", + "code": "ME", + "state": "Maine", + "county": "Lincoln", + "display": "Trevett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3780582802825612357-3039", + "name": "GoodGuide Incorporated", + "city": { + "name": "Rulo", + "code": "NE", + "state": "Nebraska", + "county": "Richardson", + "display": "Rulo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5198067638149067840-3040", + "name": "Maponics Incorporated", + "city": { + "name": "Perry Point", + "code": "MD", + "state": "Maryland", + "county": "Cecil", + "display": "Perry Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-776180798552607792-3041", + "name": "HealthPocket, LLC", + "city": { + "name": "East Peoria", + "code": "IL", + "state": "Illinois", + "county": "Tazewell", + "display": "Bayview Gardens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9051949319940533543-3042", + "name": "Peterson's Corp", + "city": { + "name": "Adamsville", + "code": "RI", + "state": "Rhode Island", + "county": "Newport", + "display": "Adamsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6614803028872981226-3043", + "name": "Exversion Corp", + "city": { + "name": "Fort Gibson", + "code": "OK", + "state": "Oklahoma", + "county": "Muskogee", + "display": "Fort Gibson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2320120966017989341-3044", + "name": "Bloomberg LLC", + "city": { + "name": "Richmond Dale", + "code": "OH", + "state": "Ohio", + "county": "Ross", + "display": "Richmond Dale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8655196411521707159-3045", + "name": "U.S. News Schools Company", + "city": { + "name": "Kirkwood", + "code": "IL", + "state": "Illinois", + "county": "Warren", + "display": "Tompkins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-750921464734895083-3046", + "name": "Evidera Corp", + "city": { + "name": "Derby", + "code": "IN", + "state": "Indiana", + "county": "Perry", + "display": "Dexter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1086076066606187122-3047", + "name": "Business Monitor International Corp", + "city": { + "name": "Salemburg", + "code": "NC", + "state": "North Carolina", + "county": "Sampson", + "display": "Salemburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8017308464206802615-3048", + "name": "BillGuard Corporation", + "city": { + "name": "Palmyra", + "code": "VA", + "state": "Virginia", + "county": "Fluvanna", + "display": "Bybee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3091664355181929699-3049", + "name": "Investormill Corporation", + "city": { + "name": "Swedesboro", + "code": "NJ", + "state": "New Jersey", + "county": "Gloucester", + "display": "Logan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6369172482643780495-3050", + "name": "Propeller Health Corporation", + "city": { + "name": "Atlantic Beach", + "code": "FL", + "state": "Florida", + "county": "Duval", + "display": "Jacksonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4668101899738025843-3051", + "name": "Thinknum Corp", + "city": { + "name": "Cromwell", + "code": "IN", + "state": "Indiana", + "county": "Noble", + "display": "Knapp Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8223775414656818657-3052", + "name": "IFI CLAIMS Patent Services Inc", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Los Angls AFB" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6795141949741450932-3053", + "name": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6818678999563004956-3054", + "name": "Scale Unlimited Company", + "city": { + "name": "Concan", + "code": "TX", + "state": "Texas", + "county": "Uvalde", + "display": "Concan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3440693357072304703-3055", + "name": "Government Transaction Services LLC", + "city": { + "name": "Wagener", + "code": "SC", + "state": "South Carolina", + "county": "Aiken", + "display": "Wagener" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1744130065243465993-3056", + "name": "Smartronix Inc", + "city": { + "name": "Towanda", + "code": "KS", + "state": "Kansas", + "county": "Butler", + "display": "Towanda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8237760998384950451-3057", + "name": "Business and Legal Resources Inc", + "city": { + "name": "Brookport", + "code": "IL", + "state": "Illinois", + "county": "Massac", + "display": "Shady Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3627499184078191491-3058", + "name": "Lawdragon Incorporated", + "city": { + "name": "Cherokee Village", + "code": "AR", + "state": "Arkansas", + "county": "Sharp", + "display": "Cherokee Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4857862497359076576-3059", + "name": "Booz Allen Hamilton Corp", + "city": { + "name": "Tallulah", + "code": "LA", + "state": "Louisiana", + "county": "Madison", + "display": "Tallulah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6926577235053264140-3060", + "name": "Revaluate Incorporated", + "city": { + "name": "Vicksburg", + "code": "MS", + "state": "Mississippi", + "county": "Warren", + "display": "Bovina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7982767515420111537-3061", + "name": "Knowledge Agency Corporation", + "city": { + "name": "Reno", + "code": "NV", + "state": "Nevada", + "county": "Washoe", + "display": "Red Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8012383736573128269-3062", + "name": "Smartronix Corporation", + "city": { + "name": "Newhall", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Newhall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4716291218774945334-3063", + "name": "Knoema Corp", + "city": { + "name": "Peru", + "code": "IN", + "state": "Indiana", + "county": "Miami", + "display": "Peru" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8229436094473694047-3064", + "name": "Loqate, Company", + "city": { + "name": "Ardmore", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Ardmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-120764735545231530-3065", + "name": "HERE Incorporated", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Commercial National Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-881766433366097126-3066", + "name": "Government Transaction Services Company", + "city": { + "name": "Westhampton", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "W Hampton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2041739147283227309-3067", + "name": "AtSite Incorporated", + "city": { + "name": "Drury", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Drury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6774209397202669438-3068", + "name": "Golden Helix Incorporated", + "city": { + "name": "Amboy", + "code": "WA", + "state": "Washington", + "county": "Clark", + "display": "Chelatchie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3560692577711315656-3069", + "name": "Personal, Corporation", + "city": { + "name": "Kasson", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "Canisteo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1484873941444791120-3070", + "name": "Department of Better Technology Company", + "city": { + "name": "Jal", + "code": "NM", + "state": "New Mexico", + "county": "Lea", + "display": "Bennett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2901311758395337892-3071", + "name": "Sophic Systems Alliance Corp", + "city": { + "name": "Portola Valley", + "code": "CA", + "state": "California", + "county": "San Mateo", + "display": "Portola Vally" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5162955800215361763-3072", + "name": "SimpleTuition Incorporated", + "city": { + "name": "La Place", + "code": "IL", + "state": "Illinois", + "county": "Piatt", + "display": "La Place" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-791245701562077170-3073", + "name": "IPHIX Corp", + "city": { + "name": "Belden", + "code": "MS", + "state": "Mississippi", + "county": "Lee", + "display": "Belden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4677713313792033825-3074", + "name": "Knowledge Agency Corp", + "city": { + "name": "Manor", + "code": "TX", + "state": "Texas", + "county": "Travis", + "display": "Daffan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5600512735016871670-3075", + "name": "Dabo Health Inc", + "city": { + "name": "Kankakee", + "code": "IL", + "state": "Illinois", + "county": "Kankakee", + "display": "Irwin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4177304236573337757-3076", + "name": "SnapSense Incorporated", + "city": { + "name": "Paradox", + "code": "NY", + "state": "New York", + "county": "Essex", + "display": "Paradox" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-279613543011853082-3077", + "name": "Berkery Noyes MandASoft Company", + "city": { + "name": "Gorham", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Gorham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2918982841993776350-3078", + "name": "TrustedID Incorporated", + "city": { + "name": "Bellbrook", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Beaver Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1164612379303368988-3079", + "name": "Vitals Corp", + "city": { + "name": "Falcon Heights", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "Falcon Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6695925525485457435-3080", + "name": "Allianz Corp", + "city": { + "name": "Drayton Plains", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Drayton Plains" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8951472835893960602-3081", + "name": "Enigma.io Inc", + "city": { + "name": "Averill", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Averill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-541233191531662659-3082", + "name": "Government Transaction Services LLC", + "city": { + "name": "Akron", + "code": "OH", + "state": "Ohio", + "county": "Summit", + "display": "Akron Business Reply" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3017625556099891327-3083", + "name": "OSIsoft Corp", + "city": { + "name": "Jackson", + "code": "TN", + "state": "Tennessee", + "county": "Madison", + "display": "Bemis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8858706569587681499-3084", + "name": "Connotate Incorporated", + "city": { + "name": "Waynesfield", + "code": "OH", + "state": "Ohio", + "county": "Auglaize", + "display": "Waynesfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8929158019817347440-3085", + "name": "FindTheBest.com LLC", + "city": { + "name": "Rampart", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Rampart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8488235111353093307-3086", + "name": "Stevens Worldwide Van Lines Inc", + "city": { + "name": "Oneonta", + "code": "NY", + "state": "New York", + "county": "Otsego", + "display": "North Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1327853550293008064-3087", + "name": "FlightView Inc", + "city": { + "name": "Huntington", + "code": "WV", + "state": "West Virginia", + "county": "Cabell", + "display": "Huntington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5352945656930560459-3088", + "name": "Moody's Company", + "city": { + "name": "Hampton", + "code": "AR", + "state": "Arkansas", + "county": "Calhoun", + "display": "Hampton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5687611623022057221-3089", + "name": "Berkery Noyes MandASoft Company", + "city": { + "name": "Tonasket", + "code": "WA", + "state": "Washington", + "county": "Okanogan", + "display": "Aeneas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-838399978809823224-3090", + "name": "Sage Bionetworks Incorporated", + "city": { + "name": "Springhill", + "code": "LA", + "state": "Louisiana", + "county": "Webster", + "display": "Springhill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2626493257348883595-3091", + "name": "Environmental Data Resources Incorporated", + "city": { + "name": "Lexington", + "code": "TN", + "state": "Tennessee", + "county": "Henderson", + "display": "Lexington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6636801957865916271-3092", + "name": "PatientsLikeMe Inc", + "city": { + "name": "Ganado", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Cornfields" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2152479717578453771-3093", + "name": "OnDeck Corporation", + "city": { + "name": "Forestport", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Kayuta Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1270922645984391386-3094", + "name": "Uber Inc", + "city": { + "name": "Rosebud", + "code": "TX", + "state": "Texas", + "county": "Falls", + "display": "Rosebud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9156218577702997960-3095", + "name": "Lending Club Company", + "city": { + "name": "Awendaw", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Awendaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4433259824635749475-3096", + "name": "TrialTrove Corporation", + "city": { + "name": "Village Of Nagog Woods", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Village Of Nagog Woods" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8217406262955310342-3097", + "name": "Sage Bionetworks Corp", + "city": { + "name": "San Benito", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Yescas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3764999252481012776-3098", + "name": "Datamyne Corp", + "city": { + "name": "Keyser", + "code": "WV", + "state": "West Virginia", + "county": "Mineral", + "display": "Scherr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1833423276705815151-3099", + "name": "CONNECT-DOT Incorporated", + "city": { + "name": "Lake Norden", + "code": "SD", + "state": "South Dakota", + "county": "Hamlin", + "display": "Alsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1869768369359575809-3100", + "name": "Foursquare Incorporated", + "city": { + "name": "Shidler", + "code": "OK", + "state": "Oklahoma", + "county": "Osage", + "display": "Foraker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6245375767495690753-3101", + "name": "Earth Networks Incorporated", + "city": { + "name": "Leaf River", + "code": "IL", + "state": "Illinois", + "county": "Ogle", + "display": "Leaf River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2445808049092003892-3102", + "name": "Chemical Abstracts Service Company", + "city": { + "name": "San Miguel", + "code": "CA", + "state": "California", + "county": "San Luis Obispo", + "display": "San Miguel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8174328864871482696-3103", + "name": "TuvaLabs Company", + "city": { + "name": "Nordheim", + "code": "TX", + "state": "Texas", + "county": "De Witt", + "display": "Nordheim" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-244873159296321209-3104", + "name": "Revelstone LLC", + "city": { + "name": "Kellyton", + "code": "AL", + "state": "Alabama", + "county": "Coosa", + "display": "Kellyton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9056425293593458943-3105", + "name": "Adaptive Corporation", + "city": { + "name": "Schaumburg", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Schaumburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6435479624371564428-3106", + "name": "Kyruus Incorporated", + "city": { + "name": "Roebling", + "code": "NJ", + "state": "New Jersey", + "county": "Burlington", + "display": "Roebling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-108300845224474151-3107", + "name": "Palantir Technologies Corporation", + "city": { + "name": "Castalian Springs", + "code": "TN", + "state": "Tennessee", + "county": "Sumner", + "display": "Castalian Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3974574701733610451-3108", + "name": "Ayasdi Company", + "city": { + "name": "Narrows", + "code": "VA", + "state": "Virginia", + "county": "Giles", + "display": "Narrows" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5915520456056308586-3109", + "name": "LegiNation, LLC", + "city": { + "name": "Saint Cloud", + "code": "FL", + "state": "Florida", + "county": "Osceola", + "display": "Harmony" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4942552178845291439-3110", + "name": "Peterson's Inc", + "city": { + "name": "Woodworth", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Timberlake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1469226322518836694-3111", + "name": "SocialEffort Corp", + "city": { + "name": "San Luis", + "code": "CO", + "state": "Colorado", + "county": "Costilla", + "display": "San Francisco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3881365376513809423-3112", + "name": "Aidin LLC", + "city": { + "name": "Remer", + "code": "MN", + "state": "Minnesota", + "county": "Cass", + "display": "Lima" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3763337530153480938-3113", + "name": "Bekins Inc", + "city": { + "name": "Maitland", + "code": "MO", + "state": "Missouri", + "county": "Holt", + "display": "Maitland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2697563094304643582-3114", + "name": "ClearStory Data Corp", + "city": { + "name": "Eagle", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Eagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1355708291672770680-3115", + "name": "BuildFax Incorporated", + "city": { + "name": "Cavalier", + "code": "ND", + "state": "North Dakota", + "county": "Pembina", + "display": "Cavalier Afs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6391510298108523149-3116", + "name": "Revaluate Company", + "city": { + "name": "Angleton", + "code": "TX", + "state": "Texas", + "county": "Brazoria", + "display": "Angleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4867429398373655775-3117", + "name": "Dabo Health Corporation", + "city": { + "name": "Marion", + "code": "AR", + "state": "Arkansas", + "county": "Crittenden", + "display": "Marion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2139217083532865569-3118", + "name": "Innovest Systems Incorporated", + "city": { + "name": "Cross Junction", + "code": "VA", + "state": "Virginia", + "county": "Frederick", + "display": "Whitacre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4840463391881527530-3119", + "name": "LexisNexis LLC", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Loehmanns Plaza" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2054606270008604569-3120", + "name": "Datamyne LLC", + "city": { + "name": "Dante", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Trammel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6240940976405287754-3121", + "name": "FindTheBest.com Incorporated", + "city": { + "name": "Ruso", + "code": "ND", + "state": "North Dakota", + "county": "Mclean", + "display": "Ruso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3102905148705796345-3122", + "name": "HealthMap Inc", + "city": { + "name": "Greenwood", + "code": "SC", + "state": "South Carolina", + "county": "Greenwood", + "display": "Gwd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8704787610435132666-3123", + "name": "Optensity Incorporated", + "city": { + "name": "Union City", + "code": "OK", + "state": "Oklahoma", + "county": "Canadian", + "display": "Union City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6216752774888009356-3124", + "name": "Boston Consulting Group Inc", + "city": { + "name": "Mount Sterling", + "code": "WI", + "state": "Wisconsin", + "county": "Crawford", + "display": "Mt Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4431338684893243288-3125", + "name": "Compared Care Company", + "city": { + "name": "Temperanceville", + "code": "VA", + "state": "Virginia", + "county": "Accomack", + "display": "Temperanceville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1434244006496488333-3126", + "name": "Oliver Wyman Corporation", + "city": { + "name": "Viborg", + "code": "SD", + "state": "South Dakota", + "county": "Turner", + "display": "Swan Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4434053574525803116-3127", + "name": "Compared Care Company", + "city": { + "name": "Woodson", + "code": "TX", + "state": "Texas", + "county": "Throckmorton", + "display": "Woodson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5668950766988481916-3128", + "name": "Atlas Van Lines Corp", + "city": { + "name": "Clinton", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Clinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8308303928144570396-3129", + "name": "Locavore LLC", + "city": { + "name": "Sinton", + "code": "TX", + "state": "Texas", + "county": "San Patricio", + "display": "Papalote" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7797888477601470453-3130", + "name": "Headlight LLC", + "city": { + "name": "Crowley", + "code": "TX", + "state": "Texas", + "county": "Tarrant", + "display": "Crowley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9145138528746371959-3131", + "name": "Mercaris Corporation", + "city": { + "name": "Cairo", + "code": "WV", + "state": "West Virginia", + "county": "Ritchie", + "display": "Cairo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5623471948479744253-3132", + "name": "Innography Incorporated", + "city": { + "name": "East Worcester", + "code": "NY", + "state": "New York", + "county": "Otsego", + "display": "E Worcester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-521862196996358114-3133", + "name": "GuideStar Corporation", + "city": { + "name": "Equinunk", + "code": "PA", + "state": "Pennsylvania", + "county": "Wayne", + "display": "Equinunk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7633145660682776125-3134", + "name": "Owler Incorporated", + "city": { + "name": "Swanton", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Maquam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-710783813082433360-3135", + "name": "Abt Associates Incorporated", + "city": { + "name": "Marengo", + "code": "IN", + "state": "Indiana", + "county": "Crawford", + "display": "Hogtown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-114106871435839638-3136", + "name": "Allianz Corp", + "city": { + "name": "Black Hawk", + "code": "CO", + "state": "Colorado", + "county": "Gilpin", + "display": "Black Hawk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4263020483210915115-3137", + "name": "PEV4me.com Inc", + "city": { + "name": "Boncarbo", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Boncarbo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3650340903090432549-3138", + "name": "HealthPocket, Incorporated", + "city": { + "name": "Freistatt", + "code": "MO", + "state": "Missouri", + "county": "Lawrence", + "display": "Freistatt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3210028094135637544-3139", + "name": "OTC Markets Corp", + "city": { + "name": "Crescent City", + "code": "CA", + "state": "California", + "county": "Del Norte", + "display": "Northcrest" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5803736781290275856-3140", + "name": "Fidelity Investments Company", + "city": { + "name": "Unalakleet", + "code": "AK", + "state": "Alaska", + "county": "Nome", + "display": "Unalakleet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5974852356250430689-3141", + "name": "PatientsLikeMe LLC", + "city": { + "name": "Fort Benning", + "code": "GA", + "state": "Georgia", + "county": "Muscogee", + "display": "Columbus" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7206503629713207721-3142", + "name": "Palantir Technologies LLC", + "city": { + "name": "Eagleville", + "code": "CA", + "state": "California", + "county": "Modoc", + "display": "Eagleville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3080344726678987856-3143", + "name": "Zonability Company", + "city": { + "name": "Tacoma", + "code": "WA", + "state": "Washington", + "county": "Pierce", + "display": "World Vision Brm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6648361945391608883-3144", + "name": "Child Care Desk Corporation", + "city": { + "name": "Quaker City", + "code": "OH", + "state": "Ohio", + "county": "Guernsey", + "display": "Quaker City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2625618742653085817-3145", + "name": "Propeller Health Company", + "city": { + "name": "New Lebanon", + "code": "NY", + "state": "New York", + "county": "Columbia", + "display": "Lebanon Spg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8354339915175057604-3146", + "name": "The DocGraph Journal Inc", + "city": { + "name": "Drums", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Drums" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5304956303148120207-3147", + "name": "Relationship Science Company", + "city": { + "name": "Arlington Heights", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Arlington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2986914149891623122-3148", + "name": "Owler LLC", + "city": { + "name": "Parkers Lake", + "code": "KY", + "state": "Kentucky", + "county": "Mccreary", + "display": "Parkers Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3314553203644347380-3149", + "name": "SocialEffort Corp", + "city": { + "name": "Anaconda", + "code": "MT", + "state": "Montana", + "county": "Deer Lodge", + "display": "Fairmont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6757307302503685369-3150", + "name": "Golden Helix LLC", + "city": { + "name": "Burgettstown", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Burgettstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5687026955818400712-3151", + "name": "Sophic Systems Alliance Corporation", + "city": { + "name": "North Grafton", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "North Grafton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7281845372179525450-3152", + "name": "Legal Science Partners Incorporated", + "city": { + "name": "Sauk Centre", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Sauk Centre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3711766593750104900-3153", + "name": "Experian Incorporated", + "city": { + "name": "Laguna", + "code": "NM", + "state": "New Mexico", + "county": "Cibola", + "display": "Mesita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5444105542492931078-3154", + "name": "Google Maps Corporation", + "city": { + "name": "Trenton", + "code": "NC", + "state": "North Carolina", + "county": "Jones", + "display": "Trenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7471696567455815454-3155", + "name": "Rand McNally Company", + "city": { + "name": "Central City", + "code": "KY", + "state": "Kentucky", + "county": "Muhlenberg", + "display": "Central Cty" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3574079680209320527-3156", + "name": "MicroBilt Inc", + "city": { + "name": "Goldendale", + "code": "WA", + "state": "Washington", + "county": "Klickitat", + "display": "Maryhill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7252529842208004947-3157", + "name": "LOGIXDATA, Company", + "city": { + "name": "Pleasantville", + "code": "PA", + "state": "Pennsylvania", + "county": "Venango", + "display": "Pleasantville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2807801504648733940-3158", + "name": "PossibilityU Company", + "city": { + "name": "Chocowinity", + "code": "NC", + "state": "North Carolina", + "county": "Beaufort", + "display": "Chocowinity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-648048677719017108-3159", + "name": "Trintech Corp", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Swepco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1640546674099700898-3160", + "name": "Dow Jones \u0026 Co Corp", + "city": { + "name": "Mount Victoria", + "code": "MD", + "state": "Maryland", + "county": "Charles", + "display": "Mt Victoria" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4354513065023791644-3161", + "name": "Weather Channel Corp", + "city": { + "name": "Sparks", + "code": "NV", + "state": "Nevada", + "county": "Washoe", + "display": "Lockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2513532433880234746-3162", + "name": "ConnectEDU Incorporated", + "city": { + "name": "Gilberts", + "code": "IL", + "state": "Illinois", + "county": "Kane", + "display": "Gilberts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7628327065240528383-3163", + "name": "NERA Economic Consulting Corporation", + "city": { + "name": "Craftsbury", + "code": "VT", + "state": "Vermont", + "county": "Orleans", + "display": "East Craftsbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7663986279275180535-3164", + "name": "WebFilings Corp", + "city": { + "name": "Mineral Springs", + "code": "AR", + "state": "Arkansas", + "county": "Howard", + "display": "Mineral Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6911050781094419695-3165", + "name": "Chemical Abstracts Service Incorporated", + "city": { + "name": "Owens Cross Roads", + "code": "AL", + "state": "Alabama", + "county": "Madison", + "display": "Owens X Rds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2187059331806383833-3166", + "name": "OnStar LLC", + "city": { + "name": "Cedarville", + "code": "WV", + "state": "West Virginia", + "county": "Gilmer", + "display": "Flower" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5317790921718357955-3167", + "name": "Archimedes Corp", + "city": { + "name": "Stow", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Stow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7153866510367993618-3168", + "name": "Mint LLC", + "city": { + "name": "Little Compton", + "code": "RI", + "state": "Rhode Island", + "county": "Newport", + "display": "Little Compton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-981400286539479205-3169", + "name": "Uber Inc", + "city": { + "name": "Corona", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Queens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4249012591016956789-3170", + "name": "Quertle Company", + "city": { + "name": "Prescott", + "code": "KS", + "state": "Kansas", + "county": "Linn", + "display": "Prescott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4243959587863917605-3171", + "name": "Liberty Mutual Insurance Cos Corporation", + "city": { + "name": "Waterloo", + "code": "IL", + "state": "Illinois", + "county": "Monroe", + "display": "Saint Joe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6294450078828098307-3172", + "name": "Equal Speed Corporation", + "city": { + "name": "Leon", + "code": "OK", + "state": "Oklahoma", + "county": "Love", + "display": "Leon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8456087514755299670-3173", + "name": "Bloomberg Corporation", + "city": { + "name": "Whitestone", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Flushing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6258962885552155026-3174", + "name": "Datamyne LLC", + "city": { + "name": "Mc Kenzie", + "code": "TN", + "state": "Tennessee", + "county": "Carroll", + "display": "Mc Kenzie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7159054587093859055-3175", + "name": "Marinexplore, Inc", + "city": { + "name": "Cambridge", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Weller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7395767884514930647-3176", + "name": "MuckRock.com Corp", + "city": { + "name": "Hot Springs", + "code": "VA", + "state": "Virginia", + "county": "Bath", + "display": "Bacova Jnctn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6152056295762245090-3177", + "name": "Aureus Sciences Corp", + "city": { + "name": "Belt", + "code": "MT", + "state": "Montana", + "county": "Cascade", + "display": "Wayne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3433931616175396794-3178", + "name": "PIXIA Incorporated", + "city": { + "name": "Hobucken", + "code": "NC", + "state": "North Carolina", + "county": "Pamlico", + "display": "Hobucken" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6325935861916306506-3179", + "name": "xDayta Company", + "city": { + "name": "Fredericksburg", + "code": "IA", + "state": "Iowa", + "county": "Chickasaw", + "display": "Fredericksbrg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4042397726835966953-3180", + "name": "TransUnion Corp", + "city": { + "name": "Hickman", + "code": "NE", + "state": "Nebraska", + "county": "Lancaster", + "display": "Holland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5724870863742989757-3181", + "name": "DataLogix LLC", + "city": { + "name": "Lemoyne", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Wormleysburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3733689042457494770-3182", + "name": "Morgan Stanley Corporation", + "city": { + "name": "Merrick", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Merrick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1785030034094055145-3183", + "name": "HopStop Company", + "city": { + "name": "Kasson", + "code": "MN", + "state": "Minnesota", + "county": "Dodge", + "display": "Canisteo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7739848669825870390-3184", + "name": "KidAdmit, Inc", + "city": { + "name": "Enfield Center", + "code": "NH", + "state": "New Hampshire", + "county": "Grafton", + "display": "Enfield Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8580258262792359624-3185", + "name": "NuCivic Corporation", + "city": { + "name": "Newton Lower Falls", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Newton Lower Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8872610397131286905-3186", + "name": "CoolClimate Inc", + "city": { + "name": "Freeport", + "code": "KS", + "state": "Kansas", + "county": "Harper", + "display": "Freeport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2233103155845021426-3187", + "name": "TagniFi Inc", + "city": { + "name": "Quail Valley", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Canyon Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3452029762683836559-3188", + "name": "indoo.rs Incorporated", + "city": { + "name": "Ratcliff", + "code": "AR", + "state": "Arkansas", + "county": "Logan", + "display": "Ratcliff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6154576917757040273-3189", + "name": "Farmers Corp", + "city": { + "name": "Alma", + "code": "NE", + "state": "Nebraska", + "county": "Harlan", + "display": "Prairie Dog" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-913197497925320988-3190", + "name": "CoreLogic Corp", + "city": { + "name": "Alma", + "code": "NE", + "state": "Nebraska", + "county": "Harlan", + "display": "Prairie Dog" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6958088737883008849-3191", + "name": "Arpin Van Lines Corporation", + "city": { + "name": "Elgin", + "code": "TX", + "state": "Texas", + "county": "Bastrop", + "display": "Elgin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2792778010715577769-3192", + "name": "Relationship Science Incorporated", + "city": { + "name": "Selbyville", + "code": "DE", + "state": "Delaware", + "county": "Sussex", + "display": "West Fenwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2044609975475396177-3193", + "name": "PricewaterhouseCoopers Incorporated", + "city": { + "name": "Kirkland", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Totem Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5296396337577877847-3194", + "name": "Castle Biosciences Company", + "city": { + "name": "Wallingford", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Nether Providence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8875503349203624147-3195", + "name": "Remi LLC", + "city": { + "name": "Solana Beach", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Solana Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5569845097739828600-3196", + "name": "AutoGrid Systems Inc", + "city": { + "name": "Cornucopia", + "code": "WI", + "state": "Wisconsin", + "county": "Bayfield", + "display": "Cornucopia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8701862092385727698-3197", + "name": "Civis Analytics Company", + "city": { + "name": "Eagleville", + "code": "CA", + "state": "California", + "county": "Modoc", + "display": "Eagleville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5020446661873713027-3198", + "name": "Civic Impulse LLC", + "city": { + "name": "Windsor", + "code": "ME", + "state": "Maine", + "county": "Kennebec", + "display": "Windsor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3863664949839408676-3199", + "name": "Noesis Company", + "city": { + "name": "Flat Rock", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Brownstwn Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2554103663936978273-3200", + "name": "StockSmart Company", + "city": { + "name": "Pleasant Plain", + "code": "OH", + "state": "Ohio", + "county": "Warren", + "display": "Edenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4098791226593642061-3201", + "name": "Owler Inc", + "city": { + "name": "Snoqualmie Pass", + "code": "WA", + "state": "Washington", + "county": "Kittitas", + "display": "Snoqualmie Ps" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9182705424105420540-3202", + "name": "ProgrammableWeb Corporation", + "city": { + "name": "Beach Haven", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Harvey Cedars" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6071164198213351167-3203", + "name": "NextBus Corporation", + "city": { + "name": "Clayton", + "code": "TX", + "state": "Texas", + "county": "Panola", + "display": "Clayton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8325335055044131155-3204", + "name": "Xcential LLC", + "city": { + "name": "Westfield", + "code": "PA", + "state": "Pennsylvania", + "county": "Tioga", + "display": "Elmer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6603418966727277992-3205", + "name": "Healthgrades Corporation", + "city": { + "name": "Somerset", + "code": "TX", + "state": "Texas", + "county": "Bexar", + "display": "Somerset" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7724007131211897535-3206", + "name": "Certara Incorporated", + "city": { + "name": "Gardner", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "Gardner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8452361727072459356-3207", + "name": "Healthline LLC", + "city": { + "name": "Harvey", + "code": "ND", + "state": "North Dakota", + "county": "Wells", + "display": "Hamberg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8795333657060116675-3208", + "name": "StreetEasy LLC", + "city": { + "name": "Limeport", + "code": "PA", + "state": "Pennsylvania", + "county": "Lehigh", + "display": "Limeport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7963390744202618487-3209", + "name": "Funding Circle Inc", + "city": { + "name": "North Miami Beach", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Miami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7491786326128345244-3210", + "name": "Wolters Kluwer Inc", + "city": { + "name": "Roanoke", + "code": "TX", + "state": "Texas", + "county": "Denton", + "display": "Westlake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7967118878520669207-3211", + "name": "US Green Data Corporation", + "city": { + "name": "Troup", + "code": "TX", + "state": "Texas", + "county": "Smith", + "display": "Griffin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2195691385468326390-3212", + "name": "PublicEngines Corp", + "city": { + "name": "Thayne", + "code": "WY", + "state": "Wyoming", + "county": "Lincoln", + "display": "Star Vly Rnch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5849188459042726637-3213", + "name": "AccuWeather Corporation", + "city": { + "name": "Fishers", + "code": "NY", + "state": "New York", + "county": "Ontario", + "display": "Fishers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3661815611572669687-3214", + "name": "Level One Technologies Incorporated", + "city": { + "name": "Clifford", + "code": "IN", + "state": "Indiana", + "county": "Bartholomew", + "display": "Clifford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2863387328857630046-3215", + "name": "Iodine Incorporated", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Pgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3270159172791425179-3216", + "name": "Aunt Bertha, Corporation", + "city": { + "name": "La Veta", + "code": "CO", + "state": "Colorado", + "county": "Huerfano", + "display": "Wahatoya" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2965659920474667485-3217", + "name": "Peterson's Incorporated", + "city": { + "name": "Dinero", + "code": "TX", + "state": "Texas", + "county": "Live Oak", + "display": "Mount Lucas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6994506137373746828-3218", + "name": "Science Exchange Incorporated", + "city": { + "name": "Mount Vernon", + "code": "IA", + "state": "Iowa", + "county": "Linn", + "display": "Mount Vernon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2919099918776042889-3219", + "name": "Epsilon Corporation", + "city": { + "name": "Montpelier Station", + "code": "VA", + "state": "Virginia", + "county": "Orange", + "display": "Montpelier Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8142640648320014281-3220", + "name": "Energy Points, Corporation", + "city": { + "name": "Starkweather", + "code": "ND", + "state": "North Dakota", + "county": "Ramsey", + "display": "Starkweather" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3210130796535843212-3221", + "name": "Ceiba Solutions Company", + "city": { + "name": "Gillett", + "code": "WI", + "state": "Wisconsin", + "county": "Oconto", + "display": "Pulcifer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6951491514878063637-3222", + "name": "Aquicore Incorporated", + "city": { + "name": "Cayucos", + "code": "CA", + "state": "California", + "county": "San Luis Obispo", + "display": "Cayucos" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1261618183671180042-3223", + "name": "TagniFi Corporation", + "city": { + "name": "Moscow", + "code": "ID", + "state": "Idaho", + "county": "Latah", + "display": "University Of Idaho" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5202476052862107121-3224", + "name": "Qado Energy, Incorporated", + "city": { + "name": "Mount Pleasant", + "code": "TX", + "state": "Texas", + "county": "Titus", + "display": "Mt Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8263942522052874535-3225", + "name": "Rapid Cycle Solutions Corporation", + "city": { + "name": "Ganado", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Cornfields" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1147601219165276827-3226", + "name": "CARFAX Corp", + "city": { + "name": "Globe", + "code": "AZ", + "state": "Arizona", + "county": "Gila", + "display": "Globe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8900513563463538984-3227", + "name": "Aureus Sciences Company", + "city": { + "name": "Clements", + "code": "CA", + "state": "California", + "county": "San Joaquin", + "display": "Clements" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3266479277466968158-3228", + "name": "Capital Cube Corporation", + "city": { + "name": "Paicines", + "code": "CA", + "state": "California", + "county": "San Benito", + "display": "Panoche" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4716729733069346138-3229", + "name": "SolarList Incorporated", + "city": { + "name": "Kirkland", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Kingsgate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-819509950760356916-3230", + "name": "STILLWATER SUPERCOMPUTING INC LLC", + "city": { + "name": "Shepherd", + "code": "MT", + "state": "Montana", + "county": "Yellowstone", + "display": "Shepherd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4866887761377981932-3231", + "name": "WattzOn Corp", + "city": { + "name": "Des Moines", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Visa Mastercard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3247384077018081067-3232", + "name": "Compendia Bioscience Life Technologies Corp", + "city": { + "name": "Hawleyville", + "code": "CT", + "state": "Connecticut", + "county": "Fairfield", + "display": "Hawleyville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8760223531984753687-3233", + "name": "Careset.com Corp", + "city": { + "name": "Brownsboro", + "code": "TX", + "state": "Texas", + "county": "Henderson", + "display": "Edom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5499251728030067555-3234", + "name": "Fuzion Apps, Incorporated", + "city": { + "name": "Indio", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Bermuda Dunes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4883093332918037158-3235", + "name": "SeeClickFix Inc", + "city": { + "name": "Louisburg", + "code": "KS", + "state": "Kansas", + "county": "Miami", + "display": "Louisburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2045602017642414686-3236", + "name": "US Green Data Corp", + "city": { + "name": "Mount Carmel", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Mt Carmel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6660948071711161156-3237", + "name": "Rezolve Group Incorporated", + "city": { + "name": "Goliad", + "code": "TX", + "state": "Texas", + "county": "Goliad", + "display": "Goliad" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-585581751431834219-3238", + "name": "Energy Solutions Forum LLC", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Bunker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7625744707891709780-3239", + "name": "Outline Inc", + "city": { + "name": "Young America", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Young America" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6898173409941669622-3240", + "name": "Morgan Stanley Inc", + "city": { + "name": "Redondo Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Redondo Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6502480674675948548-3241", + "name": "Ecodesk Inc", + "city": { + "name": "New Hampton", + "code": "IA", + "state": "Iowa", + "county": "Chickasaw", + "display": "North Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8165259065101641259-3242", + "name": "Garmin Incorporated", + "city": { + "name": "Greenwich", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Greenwich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8785057338871836276-3243", + "name": "MuckRock.com Corp", + "city": { + "name": "Kenna", + "code": "WV", + "state": "West Virginia", + "county": "Jackson", + "display": "Kentuck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4577706557301995494-3244", + "name": "How's My Offer? Corporation", + "city": { + "name": "Barhamsville", + "code": "VA", + "state": "Virginia", + "county": "New Kent", + "display": "Barhamsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1086735277660519152-3245", + "name": "Lending Club Inc", + "city": { + "name": "Houston", + "code": "AR", + "state": "Arkansas", + "county": "Perry", + "display": "Stony Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3018104210240213816-3246", + "name": "PEV4me.com Incorporated", + "city": { + "name": "Duluth", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "West Duluth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8196064294414457237-3247", + "name": "Fuzion Apps, LLC", + "city": { + "name": "Swarthmore", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Swarthmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8206540897364577846-3248", + "name": "HERE Incorporated", + "city": { + "name": "Falcon Heights", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "Falcon Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7873063433614914838-3249", + "name": "LoseIt.com LLC", + "city": { + "name": "Sharpsburg", + "code": "MD", + "state": "Maryland", + "county": "Washington", + "display": "Sharpsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9129521430448403786-3250", + "name": "MarketSense LLC", + "city": { + "name": "Black Hawk", + "code": "SD", + "state": "South Dakota", + "county": "Meade", + "display": "Summerset" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1655786618277315244-3251", + "name": "McGraw Hill Financial Company", + "city": { + "name": "Galena", + "code": "KS", + "state": "Kansas", + "county": "Cherokee", + "display": "Lowell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6509466430390634304-3252", + "name": "Zonability Inc", + "city": { + "name": "Parksville", + "code": "KY", + "state": "Kentucky", + "county": "Boyle", + "display": "Parksville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-311637717214665668-3253", + "name": "Tendril Company", + "city": { + "name": "Tippecanoe", + "code": "IN", + "state": "Indiana", + "county": "Marshall", + "display": "Tippecanoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7011110487703981072-3254", + "name": "DataMade LLC", + "city": { + "name": "Elkton", + "code": "VA", + "state": "Virginia", + "county": "Rockingham", + "display": "Elkton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7349574685554527889-3255", + "name": "SmartAsset LLC", + "city": { + "name": "Corning", + "code": "KS", + "state": "Kansas", + "county": "Nemaha", + "display": "Corning" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7596120121125683285-3256", + "name": "WeMakeItSafer LLC", + "city": { + "name": "Brenham", + "code": "TX", + "state": "Texas", + "county": "Washington", + "display": "Gay Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7528856599096808193-3257", + "name": "Zonability LLC", + "city": { + "name": "NSL", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "Nsl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6099216200680606768-3258", + "name": "Embark Corporation", + "city": { + "name": "Sargentville", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "Sargentville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2142102233506025737-3259", + "name": "HDScores, Corporation", + "city": { + "name": "Bangor", + "code": "WI", + "state": "Wisconsin", + "county": "La Crosse", + "display": "Middle Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8589718062938762360-3260", + "name": "LoseIt.com Company", + "city": { + "name": "Lime Springs", + "code": "IA", + "state": "Iowa", + "county": "Howard", + "display": "Bonair" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3881491051581974778-3261", + "name": "Headlight LLC", + "city": { + "name": "Stennis Space Center", + "code": "MS", + "state": "Mississippi", + "county": "Hancock", + "display": "Stennis Space Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6517146820329962535-3262", + "name": "LexisNexis Corp", + "city": { + "name": "Wiscasset", + "code": "ME", + "state": "Maine", + "county": "Lincoln", + "display": "Westport Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7469483476971294659-3263", + "name": "US Green Data Corporation", + "city": { + "name": "Oklahoma City", + "code": "OK", + "state": "Oklahoma", + "county": "Oklahoma", + "display": "Warr Acres" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7469009754044012744-3264", + "name": "Appallicious Company", + "city": { + "name": "New Century", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "New Century" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4906135453340267412-3265", + "name": "Granicus Corp", + "city": { + "name": "Lovell", + "code": "ME", + "state": "Maine", + "county": "Oxford", + "display": "Lovell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5632033423268730805-3266", + "name": "iMedicare Company", + "city": { + "name": "Paintsville", + "code": "KY", + "state": "Kentucky", + "county": "Johnson", + "display": "Paintsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-841863267742276059-3267", + "name": "PatientsLikeMe Corp", + "city": { + "name": "Newark", + "code": "DE", + "state": "Delaware", + "county": "New Castle", + "display": "Christiana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8192925238142853819-3268", + "name": "Trintech Incorporated", + "city": { + "name": "Grand Junction", + "code": "CO", + "state": "Colorado", + "county": "Mesa", + "display": "Fruitvale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3779935643877449026-3269", + "name": "Enervee Incorporated", + "city": { + "name": "Bloomfield", + "code": "NY", + "state": "New York", + "county": "Ontario", + "display": "Holcomb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-108591449583024783-3270", + "name": "Stormpulse Company", + "city": { + "name": "Gastonia", + "code": "NC", + "state": "North Carolina", + "county": "Gaston", + "display": "Smyre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6617871565299801682-3271", + "name": "Aidin Corporation", + "city": { + "name": "Nahcotta", + "code": "WA", + "state": "Washington", + "county": "Pacific", + "display": "Nahcotta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2104855243105749723-3272", + "name": "The Govtech Fund Corporation", + "city": { + "name": "Monmouth", + "code": "IA", + "state": "Iowa", + "county": "Jackson", + "display": "Canton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8726473742563343635-3273", + "name": "Avalara Incorporated", + "city": { + "name": "West Wardsboro", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "Stratton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6369703656479761294-3274", + "name": "MapQuest LLC", + "city": { + "name": "Amargosa Valley", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Amargosa Vly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4133204411382845813-3275", + "name": "PlotWatt Incorporated", + "city": { + "name": "Hillsdale", + "code": "KS", + "state": "Kansas", + "county": "Miami", + "display": "Hillsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2287117399315630523-3276", + "name": "Buildingeye Incorporated", + "city": { + "name": "Ingomar", + "code": "MT", + "state": "Montana", + "county": "Rosebud", + "display": "Ingomar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7300775213744130977-3277", + "name": "Teradata Corp", + "city": { + "name": "Arrow Rock", + "code": "MO", + "state": "Missouri", + "county": "Saline", + "display": "Arrow Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8440726225891348639-3278", + "name": "GitHub Incorporated", + "city": { + "name": "Littlefield", + "code": "TX", + "state": "Texas", + "county": "Lamb", + "display": "Littlefield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8596835284456133204-3279", + "name": "Weight Watchers Company", + "city": { + "name": "Moscow", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Covington Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-826499446918591108-3280", + "name": "Splunk Corporation", + "city": { + "name": "South Point", + "code": "OH", + "state": "Ohio", + "county": "Lawrence", + "display": "Southpoint" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2780146744504484835-3281", + "name": "Civic Impulse Inc", + "city": { + "name": "Mount Hope", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Mount Hope" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-331591287522513092-3282", + "name": "Aidin Inc", + "city": { + "name": "Webster", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Webster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6322346449100325122-3283", + "name": "EMC Corporation", + "city": { + "name": "North Pownal", + "code": "VT", + "state": "Vermont", + "county": "Bennington", + "display": "N Pownal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6562330292092069753-3284", + "name": "HERE Inc", + "city": { + "name": "Corning", + "code": "OH", + "state": "Ohio", + "county": "Perry", + "display": "Corning" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5552092434232768089-3285", + "name": "Mint Corporation", + "city": { + "name": "Blackduck", + "code": "MN", + "state": "Minnesota", + "county": "Beltrami", + "display": "Blackduck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6786136472098758944-3286", + "name": "Nationwide Mutual Insurance Company Incorporated", + "city": { + "name": "Sequim", + "code": "WA", + "state": "Washington", + "county": "Clallam", + "display": "Sequim" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-649814319114948439-3287", + "name": "Marlin Alter and Associates Corporation", + "city": { + "name": "Virgie", + "code": "KY", + "state": "Kentucky", + "county": "Pike", + "display": "Virgie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4487543379037719237-3288", + "name": "T. Rowe Price Incorporated", + "city": { + "name": "Bradyville", + "code": "TN", + "state": "Tennessee", + "county": "Cannon", + "display": "Bradyville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7590772226192787429-3289", + "name": "Glassy Media LLC", + "city": { + "name": "Mechanicsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Silver Spg Tp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1653398011814267830-3290", + "name": "Knoema Company", + "city": { + "name": "Gans", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Lake Lynn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4544096871587799350-3291", + "name": "SpaceCurve Incorporated", + "city": { + "name": "Twin Lakes", + "code": "MN", + "state": "Minnesota", + "county": "Freeborn", + "display": "Twin Lakes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2470599134497064791-3292", + "name": "OnDeck LLC", + "city": { + "name": "Sturtevant", + "code": "WI", + "state": "Wisconsin", + "county": "Racine", + "display": "Sturtevant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6236403914782054328-3293", + "name": "ProPublica Company", + "city": { + "name": "Harrison", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Harrison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7121916115126204620-3294", + "name": "Relationship Science Corp", + "city": { + "name": "Hardeeville", + "code": "SC", + "state": "South Carolina", + "county": "Jasper", + "display": "Limehouse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5912961601783654441-3295", + "name": "JJ Keller LLC", + "city": { + "name": "Hickman", + "code": "NE", + "state": "Nebraska", + "county": "Lancaster", + "display": "Holland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8062887168839791545-3296", + "name": "NerdWallet LLC", + "city": { + "name": "Bradenton", + "code": "FL", + "state": "Florida", + "county": "Manatee", + "display": "Braden River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-652448622617784034-3297", + "name": "Code-N LLC", + "city": { + "name": "Whitesboro", + "code": "TX", + "state": "Texas", + "county": "Grayson", + "display": "Whitesboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6545568949602327087-3298", + "name": "SpeSo Health Corp", + "city": { + "name": "Rowland Heights", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Rowland Hgts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2407309105264165209-3299", + "name": "Certara Corp", + "city": { + "name": "Milroy", + "code": "MN", + "state": "Minnesota", + "county": "Redwood", + "display": "Milroy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-808345630371777398-3300", + "name": "Xatori Corp", + "city": { + "name": "Rexford", + "code": "KS", + "state": "Kansas", + "county": "Thomas", + "display": "Menlo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8456589800173565241-3301", + "name": "Kyruus Corporation", + "city": { + "name": "Little Mountain", + "code": "SC", + "state": "South Carolina", + "county": "Newberry", + "display": "Little Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6690112551631877093-3302", + "name": "Booz Allen Hamilton Incorporated", + "city": { + "name": "Prophetstown", + "code": "IL", + "state": "Illinois", + "county": "Whiteside", + "display": "Leon Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6397741694924467703-3303", + "name": "ProgrammableWeb Corporation", + "city": { + "name": "Whittier", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Pico Rivera" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3859551093399003250-3304", + "name": "IW Financial Incorporated", + "city": { + "name": "Galena", + "code": "KS", + "state": "Kansas", + "county": "Cherokee", + "display": "Lowell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7401130283303968001-3305", + "name": "Think Computer Inc", + "city": { + "name": "Wingdale", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Wingdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-718536789383417216-3306", + "name": "Business Monitor International Company", + "city": { + "name": "Lowell", + "code": "OR", + "state": "Oregon", + "county": "Lane", + "display": "Lowell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3209663131513643711-3307", + "name": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-342916699790395572-3308", + "name": "eScholar LLC", + "city": { + "name": "Cynthiana", + "code": "KY", + "state": "Kentucky", + "county": "Harrison", + "display": "Leesburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6893899684050124557-3309", + "name": "NonprofitMetrics Corp", + "city": { + "name": "Topock", + "code": "AZ", + "state": "Arizona", + "county": "Mohave", + "display": "Topock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6425218923974404209-3310", + "name": "Knoema Corp", + "city": { + "name": "Clayton", + "code": "NM", + "state": "New Mexico", + "county": "Union", + "display": "Clapham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7852834454093480811-3311", + "name": "IPHIX Corporation", + "city": { + "name": "Whittier", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Pico Rivera" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-90324356016563373-3312", + "name": "Palantir Technologies Incorporated", + "city": { + "name": "Orlando", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Wells Fargo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7657439070724714110-3313", + "name": "WattzOn Corp", + "city": { + "name": "Drake", + "code": "ND", + "state": "North Dakota", + "county": "Mchenry", + "display": "Guthrie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1081435265720247843-3314", + "name": "Barchart Inc", + "city": { + "name": "Green Pond", + "code": "SC", + "state": "South Carolina", + "county": "Colleton", + "display": "Green Pond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3165543162129468369-3315", + "name": "Charles Schwab Inc", + "city": { + "name": "Vinita", + "code": "OK", + "state": "Oklahoma", + "county": "Craig", + "display": "White Oak" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4773766131965446020-3316", + "name": "nGAP orporated Corporation", + "city": { + "name": "Lemoyne", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Washington Ht" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1172180317590258530-3317", + "name": "US Green Data LLC", + "city": { + "name": "Bridgman", + "code": "MI", + "state": "Michigan", + "county": "Berrien", + "display": "Bridgman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5066397911541744945-3318", + "name": "CAN Capital Corp", + "city": { + "name": "Zuni", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Ramah Community" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2843790906479453901-3319", + "name": "Cloudmade Inc", + "city": { + "name": "Good Hart", + "code": "MI", + "state": "Michigan", + "county": "Emmet", + "display": "Harbor Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1760250685977389958-3320", + "name": "Quandl LLC", + "city": { + "name": "Mc Gregor", + "code": "TX", + "state": "Texas", + "county": "Mclennan", + "display": "Mc Gregor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2194933033108596240-3321", + "name": "Think Computer Corporation", + "city": { + "name": "Richwood", + "code": "OH", + "state": "Ohio", + "county": "Union", + "display": "Richwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1287583560197581737-3322", + "name": "indoo.rs Incorporated", + "city": { + "name": "Avenel", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "Avenel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6104951970479659059-3323", + "name": "Standard and Poor's Inc", + "city": { + "name": "Cornwall On Hudson", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Cornwall Hud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1250836073067527792-3324", + "name": "iMedicare LLC", + "city": { + "name": "Independence", + "code": "LA", + "state": "Louisiana", + "county": "Tangipahoa", + "display": "Independence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8520194563329465473-3325", + "name": "Graematter, Inc", + "city": { + "name": "West Warren", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "W Warren" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8135868659035932391-3326", + "name": "Splunk Incorporated", + "city": { + "name": "Blodgett Mills", + "code": "NY", + "state": "New York", + "county": "Cortland", + "display": "Blodgett Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7441744378305390336-3327", + "name": "Informatica Inc", + "city": { + "name": "Hinton", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Hinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6423066347656691085-3328", + "name": "Cambridge Information Group Corporation", + "city": { + "name": "Chagrin Falls", + "code": "OH", + "state": "Ohio", + "county": "Geauga", + "display": "Chagrin Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1180556783440820487-3329", + "name": "Berkshire Hathaway Corporation", + "city": { + "name": "Hartstown", + "code": "PA", + "state": "Pennsylvania", + "county": "Crawford", + "display": "Hartstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2794604847469998393-3330", + "name": "IPHIX Company", + "city": { + "name": "Watertown", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Fort Drum" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4033119862424556091-3331", + "name": "Civic Insight Inc", + "city": { + "name": "Hannibal", + "code": "NY", + "state": "New York", + "county": "Oswego", + "display": "Hannibal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2600555013686001620-3332", + "name": "Practice Fusion Corporation", + "city": { + "name": "Saint Charles", + "code": "MO", + "state": "Missouri", + "county": "Saint Charles", + "display": "Weldon Spring Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9045241992175971061-3333", + "name": "Docket Alarm, LLC", + "city": { + "name": "Waikoloa", + "code": "HI", + "state": "Hawaii", + "county": "Hawaii", + "display": "Waikoloa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1053847941102379667-3334", + "name": "Food+Tech Connect Company", + "city": { + "name": "Cedarville", + "code": "WV", + "state": "West Virginia", + "county": "Gilmer", + "display": "Flower" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3964366772056344135-3335", + "name": "Forrester Research Corporation", + "city": { + "name": "Thiells", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "Thiells" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6200206361667979893-3336", + "name": "Galorath orporated Inc", + "city": { + "name": "Coal City", + "code": "IN", + "state": "Indiana", + "county": "Owen", + "display": "Daggett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9121071518901442261-3337", + "name": "CitySourced Corp", + "city": { + "name": "North Chicago", + "code": "IL", + "state": "Illinois", + "county": "Lake", + "display": "Abbott Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6561739931743646707-3338", + "name": "Kyruus Inc", + "city": { + "name": "Fleetwood", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Ruscombmanor Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3976219282663975067-3339", + "name": "Bekins Corp", + "city": { + "name": "Perkins", + "code": "MI", + "state": "Michigan", + "county": "Delta", + "display": "Perkins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3819153669423735011-3340", + "name": "Civis Analytics Corp", + "city": { + "name": "West Lebanon", + "code": "PA", + "state": "Pennsylvania", + "county": "Indiana", + "display": "West Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5591845699978271130-3341", + "name": "Allied Van Lines Inc", + "city": { + "name": "Penn Yan", + "code": "NY", + "state": "New York", + "county": "Yates", + "display": "Penn Yan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8716454492250109691-3342", + "name": "Lawdragon Company", + "city": { + "name": "Jacob", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Neunert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8337763497763306903-3343", + "name": "Canon Company", + "city": { + "name": "South Fork", + "code": "CO", + "state": "Colorado", + "county": "Rio Grande", + "display": "Alpine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6052372446979727630-3344", + "name": "CareSet Systems Corp", + "city": { + "name": "Pocopson", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Pocopson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8183524988859320491-3345", + "name": "TagniFi Corporation", + "city": { + "name": "Sand Springs", + "code": "OK", + "state": "Oklahoma", + "county": "Tulsa", + "display": "Sandsprings" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6619649214943389444-3346", + "name": "HealthPocket, Company", + "city": { + "name": "Frankston", + "code": "TX", + "state": "Texas", + "county": "Anderson", + "display": "Berryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2635280566702250575-3347", + "name": "GovTribe Incorporated", + "city": { + "name": "Sarah Ann", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Sarah Ann" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-455006763703687429-3348", + "name": "Quertle Corporation", + "city": { + "name": "New Woodstock", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Sheds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2819362200003246051-3349", + "name": "Teradata Company", + "city": { + "name": "Orogrande", + "code": "NM", + "state": "New Mexico", + "county": "Otero", + "display": "Orogrande" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6456404265238532906-3350", + "name": "Oversight Systems Corp", + "city": { + "name": "Quaker City", + "code": "OH", + "state": "Ohio", + "county": "Guernsey", + "display": "Quaker City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1540261320836832330-3351", + "name": "AtSite LLC", + "city": { + "name": "Deposit", + "code": "NY", + "state": "New York", + "county": "Broome", + "display": "North Sanford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2251263507350473625-3352", + "name": "Sterling Infosystems Company", + "city": { + "name": "Kenedy", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Kenedy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4105226568905430938-3353", + "name": "Alltuition Inc", + "city": { + "name": "Mc Ewen", + "code": "TN", + "state": "Tennessee", + "county": "Humphreys", + "display": "Mcewen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7645208853276886233-3354", + "name": "Thinknum Corporation", + "city": { + "name": "Plymouth", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Plymouth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2099229644682698948-3355", + "name": "IFI CLAIMS Patent Services Corporation", + "city": { + "name": "Richland Center", + "code": "WI", + "state": "Wisconsin", + "county": "Richland", + "display": "Richland Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7096551380148544520-3356", + "name": "PatientsLikeMe Corporation", + "city": { + "name": "Richardson", + "code": "TX", + "state": "Texas", + "county": "Dallas", + "display": "Richardson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-193049009919977522-3357", + "name": "Vizzuality Inc", + "city": { + "name": "Memphis", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "International Paper Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8744268315117312937-3358", + "name": "GoodGuide Incorporated", + "city": { + "name": "Streator", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Streator West" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8053147027945463404-3359", + "name": "Walk Score Company", + "city": { + "name": "Vergennes", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Oraville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5287409913317297704-3360", + "name": "Stevens Worldwide Van Lines LLC", + "city": { + "name": "East Wenatchee", + "code": "WA", + "state": "Washington", + "county": "Douglas", + "display": "East Wenatchee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8307944518115287876-3361", + "name": "Intermap Technologies Company", + "city": { + "name": "Jameson", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Jameson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1375492148149143870-3362", + "name": "MapQuest Inc", + "city": { + "name": "Mchenry", + "code": "ND", + "state": "North Dakota", + "county": "Foster", + "display": "Mchenry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5192587967710868559-3363", + "name": "CitySourced Corp", + "city": { + "name": "Maben", + "code": "MS", + "state": "Mississippi", + "county": "Webster", + "display": "Maben" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4981617372392520582-3364", + "name": "FindTheBest.com Inc", + "city": { + "name": "Netcong", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Netcong" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5477789827358727856-3365", + "name": "McKinsey Corp", + "city": { + "name": "Eminence", + "code": "KY", + "state": "Kentucky", + "county": "Henry", + "display": "Eminence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-756815190632761024-3366", + "name": "Cambridge Information Group Inc", + "city": { + "name": "Whitmire", + "code": "SC", + "state": "South Carolina", + "county": "Newberry", + "display": "Whitmire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2784707317143084851-3367", + "name": "Iodine Corp", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Jersey Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3598885844433504991-3368", + "name": "CliniCast Inc", + "city": { + "name": "Grampian", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Grampian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3890252735666299477-3369", + "name": "Citigroup Inc", + "city": { + "name": "Midland", + "code": "SD", + "state": "South Dakota", + "county": "Haakon", + "display": "Kirley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5650009472344625335-3370", + "name": "OpenPlans Company", + "city": { + "name": "Haugen", + "code": "WI", + "state": "Wisconsin", + "county": "Barron", + "display": "Haugen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4663663290946076506-3371", + "name": "Lumesis, Company", + "city": { + "name": "Kemp", + "code": "TX", + "state": "Texas", + "county": "Kaufman", + "display": "Seven Points" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1125885300557089989-3372", + "name": "Votizen Company", + "city": { + "name": "Stoddard", + "code": "NH", + "state": "New Hampshire", + "county": "Cheshire", + "display": "Stoddard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4372709575392718298-3373", + "name": "Cloudmade Corporation", + "city": { + "name": "Seattle", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "East Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5508385433471571590-3374", + "name": "College Abacus, an ECMC initiative Corporation", + "city": { + "name": "Chico", + "code": "CA", + "state": "California", + "county": "Butte", + "display": "Chapmantown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1292755361804279777-3375", + "name": "GovTribe Corp", + "city": { + "name": "Saint Clair", + "code": "MN", + "state": "Minnesota", + "county": "Blue Earth", + "display": "Saint Clair" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1211912007361060746-3376", + "name": "eScholar Inc", + "city": { + "name": "Armstrong Creek", + "code": "WI", + "state": "Wisconsin", + "county": "Forest", + "display": "Armstrong Crk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2370809931928801088-3377", + "name": "Equilar LLC", + "city": { + "name": "Kirkland", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Kingsgate" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5844283153745856860-3378", + "name": "Dabo Health Company", + "city": { + "name": "Amity", + "code": "AR", + "state": "Arkansas", + "county": "Clark", + "display": "Caney Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8288599862972308383-3379", + "name": "Rand McNally Corporation", + "city": { + "name": "Wood River", + "code": "NE", + "state": "Nebraska", + "county": "Hall", + "display": "Prosser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1343057278163502330-3380", + "name": "Optensity Corporation", + "city": { + "name": "Sugarcreek", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Shanesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7175260871668824287-3381", + "name": "Spokeo Inc", + "city": { + "name": "Westport", + "code": "PA", + "state": "Pennsylvania", + "county": "Clinton", + "display": "Westport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6661899028320474234-3382", + "name": "Earthquake Alert LLC", + "city": { + "name": "Nashville", + "code": "TN", + "state": "Tennessee", + "county": "Davidson", + "display": "Berry Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5031653906018838265-3383", + "name": "Chubb Incorporated", + "city": { + "name": "Whitman", + "code": "NE", + "state": "Nebraska", + "county": "Grant", + "display": "Whitman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7254681776542875842-3384", + "name": "Farmers Corporation", + "city": { + "name": "Hyattville", + "code": "WY", + "state": "Wyoming", + "county": "Big Horn", + "display": "Hyattville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3955987362596472279-3385", + "name": "Thinknum Company", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Wilmington Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-203986857844851483-3386", + "name": "Bekins Corporation", + "city": { + "name": "Jadwin", + "code": "MO", + "state": "Missouri", + "county": "Dent", + "display": "Jadwin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4229981586805434476-3387", + "name": "PricewaterhouseCoopers Inc", + "city": { + "name": "Warda", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "Warda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2702555267282560073-3388", + "name": "Lending Club Corp", + "city": { + "name": "Blue Mound", + "code": "IL", + "state": "Illinois", + "county": "Macon", + "display": "Blue Mound" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-607758557856558831-3389", + "name": "Lawdragon Corporation", + "city": { + "name": "Kettle Island", + "code": "KY", + "state": "Kentucky", + "county": "Bell", + "display": "Kettle Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5052964670742831230-3390", + "name": "US Green Data Corporation", + "city": { + "name": "Mc Henry", + "code": "KY", + "state": "Kentucky", + "county": "Ohio", + "display": "Mc Henry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4348664045825208866-3391", + "name": "Level One Technologies Incorporated", + "city": { + "name": "Bingham", + "code": "ME", + "state": "Maine", + "county": "Somerset", + "display": "Moscow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4363516269022990246-3392", + "name": "CityScan Corporation", + "city": { + "name": "Needville", + "code": "TX", + "state": "Texas", + "county": "Fort Bend", + "display": "Needville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-924244216415928012-3393", + "name": "TrueCar Corp", + "city": { + "name": "Washburn", + "code": "ME", + "state": "Maine", + "county": "Aroostook", + "display": "Washburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2627521713009920741-3394", + "name": "GoodGuide Inc", + "city": { + "name": "Paradise Valley", + "code": "NV", + "state": "Nevada", + "county": "Humboldt", + "display": "Paradise Vly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-329839680557166866-3395", + "name": "Acxiom Corp", + "city": { + "name": "Nashville", + "code": "NC", + "state": "North Carolina", + "county": "Nash", + "display": "Momeyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6364270015985844290-3396", + "name": "Import.io Corporation", + "city": { + "name": "Camden", + "code": "SC", + "state": "South Carolina", + "county": "Kershaw", + "display": "Shamokin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8065803746763487878-3397", + "name": "SolarList LLC", + "city": { + "name": "Marysville", + "code": "CA", + "state": "California", + "county": "Yuba", + "display": "Hallwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3062238534764984039-3398", + "name": "Wolters Kluwer Company", + "city": { + "name": "Mocksville", + "code": "NC", + "state": "North Carolina", + "county": "Davie", + "display": "Mocksville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1627815987443598466-3399", + "name": "Morgan Stanley LLC", + "city": { + "name": "Belgrade", + "code": "NE", + "state": "Nebraska", + "county": "Boone", + "display": "Belgrade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2965851258284968178-3400", + "name": "Weather Underground LLC", + "city": { + "name": "Birch Tree", + "code": "MO", + "state": "Missouri", + "county": "Shannon", + "display": "Thomasville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2213090592737817108-3401", + "name": "Aidin Corporation", + "city": { + "name": "Elliston", + "code": "VA", + "state": "Virginia", + "county": "Montgomery", + "display": "Ironto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5612001449018192948-3402", + "name": "TowerData Corp", + "city": { + "name": "Nicollet", + "code": "MN", + "state": "Minnesota", + "county": "Nicollet", + "display": "Nicollet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8197368542336586846-3403", + "name": "VisualDoD, Corporation", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Ohio Dept Of Taxation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4388508581878322042-3404", + "name": "Analytica LLC", + "city": { + "name": "Warsaw", + "code": "KY", + "state": "Kentucky", + "county": "Gallatin", + "display": "Napoleon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7766587579162708062-3405", + "name": "Earthquake Alert Incorporated", + "city": { + "name": "Mount Sterling", + "code": "WI", + "state": "Wisconsin", + "county": "Crawford", + "display": "Mt Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3157353798025916833-3406", + "name": "Castle Biosciences Company", + "city": { + "name": "Beatrice", + "code": "AL", + "state": "Alabama", + "county": "Monroe", + "display": "Beatrice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4985411912842276544-3407", + "name": "CONNECT-DOT LLC", + "city": { + "name": "Marriottsville", + "code": "MD", + "state": "Maryland", + "county": "Carroll", + "display": "Marriottsvl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8998435203028350084-3408", + "name": "Jurispect Corporation", + "city": { + "name": "Osage", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Snellman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8432825883967999883-3409", + "name": "SolarList Corp", + "city": { + "name": "Emigrant Gap", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Emigrant Gap" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2452029603736171049-3410", + "name": "NonprofitMetrics LLC", + "city": { + "name": "Polacca", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "First Mesa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6230612321732645335-3411", + "name": "Impaq International Company", + "city": { + "name": "Crystal Bay", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Orono" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6005799943436333408-3412", + "name": "IPHIX Company", + "city": { + "name": "Drums", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Drums" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4721276235784386495-3413", + "name": "Equal Speed Inc", + "city": { + "name": "New Castle", + "code": "IN", + "state": "Indiana", + "county": "Henry", + "display": "Millville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8700369731861466797-3414", + "name": "Trintech Inc", + "city": { + "name": "Presho", + "code": "SD", + "state": "South Dakota", + "county": "Lyman", + "display": "Edna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-774375229088742405-3415", + "name": "LegiStorm Incorporated", + "city": { + "name": "Stewart", + "code": "TN", + "state": "Tennessee", + "county": "Houston", + "display": "Stewart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2705916654075462312-3416", + "name": "Altova Inc", + "city": { + "name": "Toms River", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Berkeley Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-721490348191045497-3417", + "name": "Ez-XBRL Corporation", + "city": { + "name": "Birch Tree", + "code": "MO", + "state": "Missouri", + "county": "Shannon", + "display": "Thomasville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2879043472021857888-3418", + "name": "NonprofitMetrics Company", + "city": { + "name": "Saint John", + "code": "WA", + "state": "Washington", + "county": "Whitman", + "display": "Saint John" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2229538198257214512-3419", + "name": "Vitals Inc", + "city": { + "name": "Havertown", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Lower Merion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5444759452523390736-3420", + "name": "Aidin LLC", + "city": { + "name": "Greenleaf", + "code": "ID", + "state": "Idaho", + "county": "Canyon", + "display": "Greenleaf" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-28862625577315199-3421", + "name": "YourMapper Corporation", + "city": { + "name": "Porter", + "code": "OK", + "state": "Oklahoma", + "county": "Wagoner", + "display": "Porter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2853195486625097571-3422", + "name": "Graebel Van Lines Company", + "city": { + "name": "Houghton", + "code": "IA", + "state": "Iowa", + "county": "Lee", + "display": "Houghton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4933639751207678980-3423", + "name": "Ernst \u0026 Young LLP LLC", + "city": { + "name": "Trout Creek", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Trout Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7604540751844496004-3424", + "name": "Intermap Technologies Incorporated", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "West Farmington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3730846895400777944-3425", + "name": "Solar Census Inc", + "city": { + "name": "Bryan", + "code": "TX", + "state": "Texas", + "county": "Brazos", + "display": "Steep Hollow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3142313999183010632-3426", + "name": "Xatori Corporation", + "city": { + "name": "Delta", + "code": "AL", + "state": "Alabama", + "county": "Clay", + "display": "Fishhead" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8576596010757183662-3427", + "name": "Keychain Logistics Corp", + "city": { + "name": "New Bloomfield", + "code": "MO", + "state": "Missouri", + "county": "Callaway", + "display": "Dixie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6040251735200318306-3428", + "name": "Inovalon Corp", + "city": { + "name": "Portland", + "code": "IN", + "state": "Indiana", + "county": "Jay", + "display": "Liber" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5330669724575804872-3429", + "name": "Votizen Corp", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Immig And Naturalization Ser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-957077010972810147-3430", + "name": "Zillow Incorporated", + "city": { + "name": "Littleton", + "code": "CO", + "state": "Colorado", + "county": "Arapahoe", + "display": "Centennial" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3397342128850741946-3431", + "name": "GovTribe LLC", + "city": { + "name": "New Virginia", + "code": "IA", + "state": "Iowa", + "county": "Warren", + "display": "Jamison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3908199427730757991-3432", + "name": "ClearStory Data Corporation", + "city": { + "name": "Long Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "East Long Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2010754948691343411-3433", + "name": "Zonability Corp", + "city": { + "name": "Dhs", + "code": "VA", + "state": "Virginia", + "county": "Loudoun", + "display": "Chantilly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4183271202707531353-3434", + "name": "48 Factoring LLC", + "city": { + "name": "International Falls", + "code": "MN", + "state": "Minnesota", + "county": "Koochiching", + "display": "International Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9069037152952367907-3435", + "name": "EarthObserver App LLC", + "city": { + "name": "Stratton", + "code": "NE", + "state": "Nebraska", + "county": "Hitchcock", + "display": "Stratton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-118267377609699931-3436", + "name": "H3 Biomedicine Inc", + "city": { + "name": "Newbury", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "Newbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3220199378165174872-3437", + "name": "Stamen Design LLC", + "city": { + "name": "Akron", + "code": "OH", + "state": "Ohio", + "county": "Summit", + "display": "Akron Business Reply" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-917586395976982954-3438", + "name": "The Advisory Board Company Company", + "city": { + "name": "Brandenburg", + "code": "KY", + "state": "Kentucky", + "county": "Meade", + "display": "Brandenburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1206616644029184922-3439", + "name": "CARFAX Corp", + "city": { + "name": "Little Mountain", + "code": "SC", + "state": "South Carolina", + "county": "Newberry", + "display": "Little Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2268446376731934175-3440", + "name": "SpeSo Health LLC", + "city": { + "name": "Mechanicsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Trindle Sprg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8021216641546788319-3441", + "name": "IFI CLAIMS Patent Services Incorporated", + "city": { + "name": "Tooele", + "code": "UT", + "state": "Utah", + "county": "Tooele", + "display": "Tooele Army Depot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1030922639961997724-3442", + "name": "Amida Technology Solutions Corp", + "city": { + "name": "Troup", + "code": "TX", + "state": "Texas", + "county": "Smith", + "display": "Griffin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4010035282420238824-3443", + "name": "Reed Elsevier Corp", + "city": { + "name": "Champlin", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Champlin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-220385056713567904-3444", + "name": "Merrill Lynch Corp", + "city": { + "name": "Eldorado Springs", + "code": "CO", + "state": "Colorado", + "county": "Boulder", + "display": "Eldorado Sprg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7325919076007067879-3445", + "name": "Rank and Filed Inc", + "city": { + "name": "Beltrami", + "code": "MN", + "state": "Minnesota", + "county": "Polk", + "display": "Beltrami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8211271861728474321-3446", + "name": "Atlas Van Lines LLC", + "city": { + "name": "Great Barrington", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "Great Barrington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-851578543456469765-3447", + "name": "Navico Corporation", + "city": { + "name": "Vanceburg", + "code": "KY", + "state": "Kentucky", + "county": "Lewis", + "display": "Carrs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7610400009714237781-3448", + "name": "The Advisory Board Company Corp", + "city": { + "name": "Mifflin", + "code": "PA", + "state": "Pennsylvania", + "county": "Juniata", + "display": "Mifflin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8213701540320414186-3449", + "name": "Abt Associates Corp", + "city": { + "name": "La Pine", + "code": "OR", + "state": "Oregon", + "county": "Deschutes", + "display": "E Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6035530760715844508-3450", + "name": "Social Health Insights Corp", + "city": { + "name": "Avon By The Sea", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Avon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2886767012095723479-3451", + "name": "Apextech Corp", + "city": { + "name": "Portola Valley", + "code": "CA", + "state": "California", + "county": "San Mateo", + "display": "Portola Vally" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6347198467968271085-3452", + "name": "Cloudmade Incorporated", + "city": { + "name": "Crumpler", + "code": "NC", + "state": "North Carolina", + "county": "Ashe", + "display": "Nathans Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2728446616483167507-3453", + "name": "Marlin \u0026 Associates Incorporated", + "city": { + "name": "Mc Cool Junction", + "code": "NE", + "state": "Nebraska", + "county": "York", + "display": "Mc Cool Jct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6478334923991347855-3454", + "name": "Google Public Data Explorer Corp", + "city": { + "name": "West Hatfield", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "W Hatfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5450052101967946954-3455", + "name": "Paxata Inc", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Action" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7083915196388698276-3456", + "name": "Think Computer Corp", + "city": { + "name": "LS", + "code": "MO", + "state": "Missouri", + "county": "Jackson", + "display": "Ls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2656477090640999867-3457", + "name": "Yahoo Corp", + "city": { + "name": "East Wenatchee", + "code": "WA", + "state": "Washington", + "county": "Douglas", + "display": "East Wenatchee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3342533091374047860-3458", + "name": "Webitects Inc", + "city": { + "name": "Anaconda", + "code": "MT", + "state": "Montana", + "county": "Deer Lodge", + "display": "Fairmont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2457998913242690373-3459", + "name": "Civic Impulse Company", + "city": { + "name": "Candor", + "code": "NY", + "state": "New York", + "county": "Tioga", + "display": "Candor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2640936365234918919-3460", + "name": "DataMarket LLC", + "city": { + "name": "Green", + "code": "KS", + "state": "Kansas", + "county": "Clay", + "display": "Green" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5571745329104162515-3461", + "name": "VisualDoD, Inc", + "city": { + "name": "Stevenson", + "code": "WA", + "state": "Washington", + "county": "Skamania", + "display": "Skamania" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8267649437275672717-3462", + "name": "SeeClickFix LLC", + "city": { + "name": "Leesville", + "code": "SC", + "state": "South Carolina", + "county": "Lexington", + "display": "Fairview Crossroads" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2492601187517007457-3463", + "name": "GoodGuide Corp", + "city": { + "name": "Saint Cloud", + "code": "FL", + "state": "Florida", + "county": "Osceola", + "display": "Harmony" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-855480029591018920-3464", + "name": "LOVELAND Technologies Inc", + "city": { + "name": "Holdrege", + "code": "NE", + "state": "Nebraska", + "county": "Phelps", + "display": "Sheridan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3800802931630833178-3465", + "name": "IVES Group LLC", + "city": { + "name": "New Madrid", + "code": "MO", + "state": "Missouri", + "county": "New Madrid", + "display": "Howardville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-615211338754110289-3466", + "name": "VisualDoD, LLC", + "city": { + "name": "Belden", + "code": "MS", + "state": "Mississippi", + "county": "Lee", + "display": "Belden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2753403956516377610-3467", + "name": "Remi Company", + "city": { + "name": "Lititz", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Fairland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2357826683060358326-3468", + "name": "Computer Packages Incorporated", + "city": { + "name": "Bloomfield", + "code": "KY", + "state": "Kentucky", + "county": "Nelson", + "display": "Bloomfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7841212114432690508-3469", + "name": "Municode Incorporated", + "city": { + "name": "Muncy Valley", + "code": "PA", + "state": "Pennsylvania", + "county": "Sullivan", + "display": "Beaver Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3096300728731430978-3470", + "name": "InnoCentive Company", + "city": { + "name": "Elon", + "code": "NC", + "state": "North Carolina", + "county": "Alamance", + "display": "Stonycreek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4802668539424454140-3471", + "name": "ClearHealthCosts Corp", + "city": { + "name": "Sanderson", + "code": "FL", + "state": "Florida", + "county": "Baker", + "display": "Sanderson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4353778064812058743-3472", + "name": "Cloudmade Incorporated", + "city": { + "name": "Surprise", + "code": "NE", + "state": "Nebraska", + "county": "Butler", + "display": "Ulysses" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3538580519221516453-3473", + "name": "Business Monitor International Corporation", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Marys Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2204748476206092199-3474", + "name": "Google Public Data Explorer Company", + "city": { + "name": "Acme", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Acme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3966849568590629840-3475", + "name": "MetLife Inc", + "city": { + "name": "Lancaster", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Meadia Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5857227654271148882-3476", + "name": "Xcential Incorporated", + "city": { + "name": "Offerle", + "code": "KS", + "state": "Kansas", + "county": "Edwards", + "display": "Offerle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2603948862512010127-3477", + "name": "S\u0026P Capital IQ Inc", + "city": { + "name": "Elmhurst", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Elmhurst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2774262960008831642-3478", + "name": "Legal Science Partners Corp", + "city": { + "name": "Machipongo", + "code": "VA", + "state": "Virginia", + "county": "Northampton", + "display": "Machipongo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3210154861483230113-3479", + "name": "CONNECT-DOT Corp", + "city": { + "name": "Terry", + "code": "MS", + "state": "Mississippi", + "county": "Hinds", + "display": "Terry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7111518790380373722-3480", + "name": "ClearHealthCosts Inc", + "city": { + "name": "Grampian", + "code": "PA", + "state": "Pennsylvania", + "county": "Clearfield", + "display": "Grampian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-162461267093765315-3481", + "name": "Careset.com Inc", + "city": { + "name": "Woodleaf", + "code": "NC", + "state": "North Carolina", + "county": "Rowan", + "display": "Woodleaf" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2873059241029049172-3482", + "name": "Loqate, Incorporated", + "city": { + "name": "Decatur", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Dunaire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3981275491206849720-3483", + "name": "Microsoft Windows Azure Marketplace Company", + "city": { + "name": "Paducah", + "code": "KY", + "state": "Kentucky", + "county": "Mccracken", + "display": "Saint Johns" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6226001354455232136-3484", + "name": "PlanetEcosystems Inc", + "city": { + "name": "Lee", + "code": "MA", + "state": "Massachusetts", + "county": "Berkshire", + "display": "W Becket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8613845812489716934-3485", + "name": "Canon Company", + "city": { + "name": "Yorkshire", + "code": "OH", + "state": "Ohio", + "county": "Darke", + "display": "Yorkshire" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6712001689616184290-3486", + "name": "Locavore Incorporated", + "city": { + "name": "Springfield", + "code": "VT", + "state": "Vermont", + "county": "Windsor", + "display": "Orchard Lane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3106839725606051477-3487", + "name": "Merrill LLC", + "city": { + "name": "Gainesville", + "code": "TX", + "state": "Texas", + "county": "Cooke", + "display": "Oak Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8495124762947599602-3488", + "name": "Ez-XBRL Corporation", + "city": { + "name": "Stillwater", + "code": "MN", + "state": "Minnesota", + "county": "Washington", + "display": "Grant Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2070569634893470079-3489", + "name": "Nautilytics Corp", + "city": { + "name": "Osage", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Snellman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6408186074878183596-3490", + "name": "Deloitte Corp", + "city": { + "name": "Candor", + "code": "NY", + "state": "New York", + "county": "Tioga", + "display": "Candor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6125184589084569293-3491", + "name": "Credit Karma Corporation", + "city": { + "name": "Bowling Green", + "code": "MO", + "state": "Missouri", + "county": "Pike", + "display": "Tarrants" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2020005913841548661-3492", + "name": "Arrive Labs Incorporated", + "city": { + "name": "Newfoundland", + "code": "NJ", + "state": "New Jersey", + "county": "Passaic", + "display": "Newfoundland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2179779899064304841-3493", + "name": "Walk Score Inc", + "city": { + "name": "Carbondale", + "code": "CO", + "state": "Colorado", + "county": "Garfield", + "display": "El Jebel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4148805901338502885-3494", + "name": "Government Transaction Services Inc", + "city": { + "name": "Winslow", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Winslow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-302712317762426641-3495", + "name": "Investormill LLC", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Los Angls AFB" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6349441210448851932-3496", + "name": "HopStop Corporation", + "city": { + "name": "Massapequa", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "North Massapequa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2413267129997213816-3497", + "name": "MuckRock.com Company", + "city": { + "name": "Hanamaulu", + "code": "HI", + "state": "Hawaii", + "county": "Kauai", + "display": "Lihue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-25264131871842598-3498", + "name": "Nielsen Inc", + "city": { + "name": "Oxford", + "code": "WI", + "state": "Wisconsin", + "county": "Marquette", + "display": "Brooks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6562080803130759705-3499", + "name": "Intermap Technologies Company", + "city": { + "name": "New Johnsonville", + "code": "TN", + "state": "Tennessee", + "county": "Humphreys", + "display": "New Johnsonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7717365025369443512-3500", + "name": "PlaceILive.com LLC", + "city": { + "name": "Dodgertown", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Los Angeles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2571714269525063149-3501", + "name": "Adaptive LLC", + "city": { + "name": "Surveyor", + "code": "WV", + "state": "West Virginia", + "county": "Raleigh", + "display": "Surveyor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4092392539106151360-3502", + "name": "Allied Van Lines Incorporated", + "city": { + "name": "Climax", + "code": "MI", + "state": "Michigan", + "county": "Kalamazoo", + "display": "Climax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7967819494074997754-3503", + "name": "R R Donnelley LLC", + "city": { + "name": "Palmyra", + "code": "PA", + "state": "Pennsylvania", + "county": "Lebanon", + "display": "Upper Lawn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3231403704895102284-3504", + "name": "iFactor Consulting LLC", + "city": { + "name": "Andalusia", + "code": "AL", + "state": "Alabama", + "county": "Covington", + "display": "Dixie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-449876056967710119-3505", + "name": "AllState Insurance Group Corporation", + "city": { + "name": "Bovard", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Bovard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3864664047071081727-3506", + "name": "Mint Incorporated", + "city": { + "name": "Florence", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Florence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4268410229267589359-3507", + "name": "ProgrammableWeb Corp", + "city": { + "name": "Mifflin", + "code": "PA", + "state": "Pennsylvania", + "county": "Juniata", + "display": "Mifflin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4940991396190565784-3508", + "name": "HDScores, Inc", + "city": { + "name": "Dannebrog", + "code": "NE", + "state": "Nebraska", + "county": "Howard", + "display": "Nysted" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-169050904293745363-3509", + "name": "PlotWatt Corp", + "city": { + "name": "Newport", + "code": "OR", + "state": "Oregon", + "county": "Lincoln", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1683377397103044528-3510", + "name": "Civinomics Incorporated", + "city": { + "name": "Newport", + "code": "AR", + "state": "Arkansas", + "county": "Jackson", + "display": "Weldon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6535725724605096732-3511", + "name": "Stormpulse Incorporated", + "city": { + "name": "Spring Valley", + "code": "NY", + "state": "New York", + "county": "Rockland", + "display": "New Hempstead" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1107081663470446030-3512", + "name": "Captricity Incorporated", + "city": { + "name": "East Hampton", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "E Hampton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3602528839246805779-3513", + "name": "Noesis Corporation", + "city": { + "name": "Henderson", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Woodville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3427267052394934428-3514", + "name": "New Media Parents LLC", + "city": { + "name": "Mooresboro", + "code": "NC", + "state": "North Carolina", + "county": "Cleveland", + "display": "Mooresboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6447527433782647231-3515", + "name": "Rank and Filed Company", + "city": { + "name": "Summersville", + "code": "MO", + "state": "Missouri", + "county": "Texas", + "display": "Summersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5058076817371398110-3516", + "name": "Keychain Logistics LLC", + "city": { + "name": "Port Hueneme", + "code": "CA", + "state": "California", + "county": "Ventura", + "display": "Port Hueneme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3012917921446872572-3517", + "name": "Mango Transit Corporation", + "city": { + "name": "Silverstreet", + "code": "SC", + "state": "South Carolina", + "county": "Newberry", + "display": "Silverstreet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6804233210336331370-3518", + "name": "T. Rowe Price Corporation", + "city": { + "name": "Manito", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Talbott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7872216776153390303-3519", + "name": "MicroBilt Incorporated", + "city": { + "name": "Julian", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Julian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-781962683134400424-3520", + "name": "STILLWATER SUPERCOMPUTING INC Company", + "city": { + "name": "Randolph", + "code": "AL", + "state": "Alabama", + "county": "Bibb", + "display": "Randolph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-327302995627931796-3521", + "name": "TowerData Company", + "city": { + "name": "Charles Town", + "code": "WV", + "state": "West Virginia", + "county": "Jefferson", + "display": "Charles Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7717955985871947408-3522", + "name": "STILLWATER SUPERCOMPUTING INC Incorporated", + "city": { + "name": "Bassett", + "code": "NE", + "state": "Nebraska", + "county": "Rock", + "display": "Rose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3054513048674298871-3523", + "name": "Embark Company", + "city": { + "name": "Olympia", + "code": "WA", + "state": "Washington", + "county": "Thurston", + "display": "Washington State Department" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1973328355552438391-3524", + "name": "The DocGraph Journal Company", + "city": { + "name": "Abercrombie", + "code": "ND", + "state": "North Dakota", + "county": "Richland", + "display": "Abercrombie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8553010216478893876-3525", + "name": "Dabo Health Incorporated", + "city": { + "name": "Monroe", + "code": "GA", + "state": "Georgia", + "county": "Walton", + "display": "Between" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4381914985988120772-3526", + "name": "Aunt Bertha, Inc", + "city": { + "name": "Scammon", + "code": "KS", + "state": "Kansas", + "county": "Cherokee", + "display": "Scammon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5755278160554079879-3527", + "name": "realtor.com Corp", + "city": { + "name": "Des Moines", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Visa Mastercard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2107245607629436967-3528", + "name": "Vizzuality Corporation", + "city": { + "name": "Wappapello", + "code": "MO", + "state": "Missouri", + "county": "Wayne", + "display": "Wappapello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-328344613669990564-3529", + "name": "Rivet Software LLC", + "city": { + "name": "Monroe", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "S Bloomng Grv" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1820427005041377872-3530", + "name": "eInstitutional LLC", + "city": { + "name": "Mc Clure", + "code": "OH", + "state": "Ohio", + "county": "Henry", + "display": "Grelton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9145628141297300157-3531", + "name": "T. Rowe Price Corp", + "city": { + "name": "Medway", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Medway" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2766491168659629698-3532", + "name": "Housefax Company", + "city": { + "name": "Newville", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Hays Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6204540284415127086-3533", + "name": "Inrix Traffic Corporation", + "city": { + "name": "Haynesville", + "code": "LA", + "state": "Louisiana", + "county": "Claiborne", + "display": "Blackburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6683755303047687154-3534", + "name": "Consumer Reports Inc", + "city": { + "name": "Fonda", + "code": "IA", + "state": "Iowa", + "county": "Pocahontas", + "display": "Industry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3043291278940104309-3535", + "name": "Cappex LLC", + "city": { + "name": "Rentz", + "code": "GA", + "state": "Georgia", + "county": "Laurens", + "display": "Rentz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6530636620846961170-3536", + "name": "Dun \u0026 Bradstreet Incorporated", + "city": { + "name": "Zephyr Cove", + "code": "NV", + "state": "Nevada", + "county": "Douglas", + "display": "Pinewild" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-613339883203135482-3537", + "name": "Zebu Compliance Solutions Inc", + "city": { + "name": "Camden On Gauley", + "code": "WV", + "state": "West Virginia", + "county": "Webster", + "display": "Camden On Gly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2298370415996819700-3538", + "name": "Everyday Health LLC", + "city": { + "name": "Clayton", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Murray Isle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1026462100140346453-3539", + "name": "Compendia Bioscience Life Technologies Corporation", + "city": { + "name": "Litchfield Park", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Litchfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5739521837862685485-3540", + "name": "Stamen Design LLC", + "city": { + "name": "Whiteside", + "code": "TN", + "state": "Tennessee", + "county": "Marion", + "display": "Whiteside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5963159834400270015-3541", + "name": "Mercaris Incorporated", + "city": { + "name": "Mount Pleasant", + "code": "TX", + "state": "Texas", + "county": "Titus", + "display": "Mt Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-525332641733530165-3542", + "name": "CoreLogic Corporation", + "city": { + "name": "Faulkton", + "code": "SD", + "state": "South Dakota", + "county": "Faulk", + "display": "Burkmere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4447779238446884927-3543", + "name": "Allied Van Lines LLC", + "city": { + "name": "Thorpe", + "code": "WV", + "state": "West Virginia", + "county": "Mcdowell", + "display": "Thorpe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5988256179519555850-3544", + "name": "NerdWallet Company", + "city": { + "name": "South International Falls", + "code": "MN", + "state": "Minnesota", + "county": "Koochiching", + "display": "South International Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-734095770428926531-3545", + "name": "Liberty Mutual Insurance Cos Inc", + "city": { + "name": "Grand Haven", + "code": "MI", + "state": "Michigan", + "county": "Ottawa", + "display": "Grand Haven" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7731919111569318016-3546", + "name": "Locavore Corporation", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Harris Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5382756750666658410-3547", + "name": "SocialEffort LLC", + "city": { + "name": "De Witt", + "code": "AR", + "state": "Arkansas", + "county": "Arkansas", + "display": "De Witt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2523708966455687187-3548", + "name": "Sage Bionetworks LLC", + "city": { + "name": "Graford", + "code": "TX", + "state": "Texas", + "county": "Palo Pinto", + "display": "Graford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2581808292385944413-3549", + "name": "Computer Packages Company", + "city": { + "name": "North Canton", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "North Canton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2417753152651671200-3550", + "name": "Inrix Traffic Inc", + "city": { + "name": "Corona", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Queens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8055243135294759597-3551", + "name": "Enigma.io Corp", + "city": { + "name": "Colts Neck", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Earle Naval Weapons Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4422452077670608910-3552", + "name": "Onvia Company", + "city": { + "name": "Austin", + "code": "TX", + "state": "Texas", + "county": "Travis", + "display": "State Comptroller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4524968873162498934-3553", + "name": "Loqate, Corp", + "city": { + "name": "Laramie", + "code": "WY", + "state": "Wyoming", + "county": "Albany", + "display": "Bosler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6444745865739105985-3554", + "name": "Accela Corp", + "city": { + "name": "Big Bend National Park", + "code": "TX", + "state": "Texas", + "county": "Brewster", + "display": "Big Bend National Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8060219120171489911-3555", + "name": "Compendia Bioscience Life Technologies LLC", + "city": { + "name": "Buffalo", + "code": "MN", + "state": "Minnesota", + "county": "Wright", + "display": "Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8102874049648993313-3556", + "name": "Mozio LLC", + "city": { + "name": "Park Hill", + "code": "OK", + "state": "Oklahoma", + "county": "Cherokee", + "display": "Park Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3223328006296906254-3557", + "name": "indoo.rs Inc", + "city": { + "name": "Jericho", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Uhc Berdon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6831948063007875390-3558", + "name": "State Farm Insurance Company", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Arsenal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7792433636981921562-3559", + "name": "Citigroup Incorporated", + "city": { + "name": "Bergland", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Bergland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2790623559459179883-3560", + "name": "Robinson + Yu Incorporated", + "city": { + "name": "Big Wells", + "code": "TX", + "state": "Texas", + "county": "Dimmit", + "display": "Big Wells" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2897393883849899064-3561", + "name": "CGI LLC", + "city": { + "name": "Bloomfield", + "code": "NY", + "state": "New York", + "county": "Ontario", + "display": "Holcomb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4610420982770580270-3562", + "name": "TopCoder Corp", + "city": { + "name": "Bremerton", + "code": "WA", + "state": "Washington", + "county": "Kitsap", + "display": "Brem" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2230741590053760369-3563", + "name": "BillGuard Incorporated", + "city": { + "name": "Comstock", + "code": "NE", + "state": "Nebraska", + "county": "Custer", + "display": "Comstock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8458858280201702678-3564", + "name": "Intermap Technologies LLC", + "city": { + "name": "Millwood", + "code": "KY", + "state": "Kentucky", + "county": "Grayson", + "display": "Millwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2179631856028217069-3565", + "name": "TagniFi Corporation", + "city": { + "name": "Gotham", + "code": "WI", + "state": "Wisconsin", + "county": "Richland", + "display": "Gotham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2012995401847137659-3566", + "name": "MetLife Inc", + "city": { + "name": "Mesa", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Mesa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7344681931143031502-3567", + "name": "Healthgrades Company", + "city": { + "name": "Ayr", + "code": "NE", + "state": "Nebraska", + "county": "Adams", + "display": "Ayr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8261041211922018470-3568", + "name": "StreetEasy Inc", + "city": { + "name": "Corona Del Mar", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Corona Dl Mar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8132163076754458227-3569", + "name": "Knoema LLC", + "city": { + "name": "West Warren", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "W Warren" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6062156021524124759-3570", + "name": "Russell Investments Incorporated", + "city": { + "name": "Big Wells", + "code": "TX", + "state": "Texas", + "county": "Dimmit", + "display": "Big Wells" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1931770449602599958-3571", + "name": "National Van Lines LLC", + "city": { + "name": "Kincheloe", + "code": "MI", + "state": "Michigan", + "county": "Chippewa", + "display": "Chippewa Temp Correction Fac" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2579254184881760363-3572", + "name": "Credit Sesame Company", + "city": { + "name": "Smartt", + "code": "TN", + "state": "Tennessee", + "county": "Warren", + "display": "Smartt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4024658604318584832-3573", + "name": "Personal, Inc", + "city": { + "name": "Poplarville", + "code": "MS", + "state": "Mississippi", + "county": "Pearl River", + "display": "Hillsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-990533952898607856-3574", + "name": "Healthgrades Inc", + "city": { + "name": "Occidental", + "code": "CA", + "state": "California", + "county": "Sonoma", + "display": "Occidental" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9119715690571242143-3575", + "name": "Rand McNally Corporation", + "city": { + "name": "Pretty Prairie", + "code": "KS", + "state": "Kansas", + "county": "Reno", + "display": "Pretty Pr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1065179303705876903-3576", + "name": "BlackRock Company", + "city": { + "name": "Vergennes", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Oraville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1611746511399339083-3577", + "name": "Consumer Reports LLC", + "city": { + "name": "Olympic Valley", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Alpine Mdws" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8043275748923831103-3578", + "name": "The Advisory Board Company Company", + "city": { + "name": "Kings Mountain", + "code": "KY", + "state": "Kentucky", + "county": "Lincoln", + "display": "Kings Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8365878688807573211-3579", + "name": "Adobe Digital Government Inc", + "city": { + "name": "Holcomb", + "code": "MS", + "state": "Mississippi", + "county": "Grenada", + "display": "Oxberry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2838070433007082342-3580", + "name": "WebMD Company", + "city": { + "name": "Tarlton", + "code": "OH", + "state": "Ohio", + "county": "Pickaway", + "display": "Tarlton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2233191748556472831-3581", + "name": "LOGIXDATA, Company", + "city": { + "name": "Marmaduke", + "code": "AR", + "state": "Arkansas", + "county": "Greene", + "display": "Marmaduke" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1488375881509410517-3582", + "name": "Socrata LLC", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Marys Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1308834719732707867-3583", + "name": "Panjiva Corp", + "city": { + "name": "Butler", + "code": "KY", + "state": "Kentucky", + "county": "Pendleton", + "display": "Butler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5249008296705156373-3584", + "name": "Whitby Group Company", + "city": { + "name": "Nuevo", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Nuevo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7991823077703457248-3585", + "name": "Locavore Corporation", + "city": { + "name": "Mannsville", + "code": "KY", + "state": "Kentucky", + "county": "Taylor", + "display": "Mannsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3363469990727347525-3586", + "name": "SpeSo Health Corporation", + "city": { + "name": "Rugby", + "code": "ND", + "state": "North Dakota", + "county": "Pierce", + "display": "Silva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6105128163647298298-3587", + "name": "MapQuest Corporation", + "city": { + "name": "Mc Crory", + "code": "AR", + "state": "Arkansas", + "county": "Woodruff", + "display": "Fair Oaks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5129090592596663521-3588", + "name": "GetRaised Corp", + "city": { + "name": "Cool", + "code": "CA", + "state": "California", + "county": "El Dorado", + "display": "Auburn Lake Trails" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2245684340837064512-3589", + "name": "GitHub Inc", + "city": { + "name": "Rockwell City", + "code": "IA", + "state": "Iowa", + "county": "Calhoun", + "display": "Richards" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9022507761568685218-3590", + "name": "TuvaLabs Corporation", + "city": { + "name": "Carterville", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Hafer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5100027461183834460-3591", + "name": "DataWeave Incorporated", + "city": { + "name": "Frankston", + "code": "TX", + "state": "Texas", + "county": "Anderson", + "display": "Berryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1557011890990218023-3592", + "name": "karmadata Company", + "city": { + "name": "Bridgeton", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Hazelwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-948388060255309171-3593", + "name": "Govzilla, Incorporated", + "city": { + "name": "Green Pond", + "code": "AL", + "state": "Alabama", + "county": "Bibb", + "display": "Green Pond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6315387320693990115-3594", + "name": "Suddath Incorporated", + "city": { + "name": "Franklin", + "code": "NC", + "state": "North Carolina", + "county": "Macon", + "display": "East Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3763517619016135936-3595", + "name": "HERE Corporation", + "city": { + "name": "East Palestine", + "code": "OH", + "state": "Ohio", + "county": "Columbiana", + "display": "East Palestine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1698275496011051157-3596", + "name": "WebMD LLC", + "city": { + "name": "Boonville", + "code": "IN", + "state": "Indiana", + "county": "Warrick", + "display": "Boonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9134231747257081220-3597", + "name": "SpotHero.com Corp", + "city": { + "name": "Brewster", + "code": "WA", + "state": "Washington", + "county": "Okanogan", + "display": "Brewster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9043199858065609878-3598", + "name": "ideas42 Incorporated", + "city": { + "name": "Montauk", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Montauk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7533857958533207817-3599", + "name": "Careset.com LLC", + "city": { + "name": "Letcher", + "code": "SD", + "state": "South Dakota", + "county": "Sanborn", + "display": "Letcher" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7786385283530385748-3600", + "name": "iMedicare Company", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "G W Univ" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5713362202168363215-3601", + "name": "Uber Inc", + "city": { + "name": "Gilson", + "code": "IL", + "state": "Illinois", + "county": "Knox", + "display": "Gilson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6126640745195227377-3602", + "name": "Department of Better Technology Inc", + "city": { + "name": "Wagner", + "code": "SD", + "state": "South Dakota", + "county": "Charles Mix", + "display": "Wagner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1057922246065209620-3603", + "name": "Bing Corporation", + "city": { + "name": "Willow City", + "code": "ND", + "state": "North Dakota", + "county": "Bottineau", + "display": "Ostby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1774486742988512820-3604", + "name": "Mint Corp", + "city": { + "name": "Marble", + "code": "MN", + "state": "Minnesota", + "county": "Itasca", + "display": "Marble" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-930449656293560250-3605", + "name": "Appallicious Incorporated", + "city": { + "name": "Morrilton", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Morrilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3026353507365228153-3606", + "name": "Vital Axiom | Niinja Corporation", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Ny Secretary Of State" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4681985928009170233-3607", + "name": "NERA Economic Consulting Corp", + "city": { + "name": "Bruneau", + "code": "ID", + "state": "Idaho", + "county": "Owyhee", + "display": "Riddle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-769920628399379460-3608", + "name": "Oversight Systems Corp", + "city": { + "name": "Coal City", + "code": "IL", + "state": "Illinois", + "county": "Grundy", + "display": "Eileen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1546095294571911516-3609", + "name": "Peterson's Incorporated", + "city": { + "name": "Fort Hall", + "code": "ID", + "state": "Idaho", + "county": "Bingham", + "display": "Fort Hall Indian Reservation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4138236600415210548-3610", + "name": "Legal Science Partners Corporation", + "city": { + "name": "Bradley", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Bradley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4197996983994485684-3611", + "name": "Evidera Incorporated", + "city": { + "name": "Windsor", + "code": "OH", + "state": "Ohio", + "county": "Ashtabula", + "display": "Windsor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7369466715107029308-3612", + "name": "GovTribe Corporation", + "city": { + "name": "Mammoth Lakes", + "code": "CA", + "state": "California", + "county": "Mono", + "display": "Toms Place" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7664422499330729067-3613", + "name": "CB Insights Corporation", + "city": { + "name": "Ingomar", + "code": "MT", + "state": "Montana", + "county": "Rosebud", + "display": "Ingomar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5919966607371893995-3614", + "name": "Liquid Robotics Corporation", + "city": { + "name": "Tippecanoe", + "code": "IN", + "state": "Indiana", + "county": "Marshall", + "display": "Tippecanoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7481213423248665986-3615", + "name": "Sterling Infosystems Inc", + "city": { + "name": "Kansas City", + "code": "KS", + "state": "Kansas", + "county": "Wyandotte", + "display": "Edwardsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3314472268429304268-3616", + "name": "MetLife Corporation", + "city": { + "name": "Gouldsboro", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "S Gouldsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-242529272781556193-3617", + "name": "Urban Mapping, Inc", + "city": { + "name": "Seminary", + "code": "MS", + "state": "Mississippi", + "county": "Covington", + "display": "Eminence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2909682128804498781-3618", + "name": "Pave Inc", + "city": { + "name": "Middle Amana", + "code": "IA", + "state": "Iowa", + "county": "Iowa", + "display": "Middle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2673076742905498436-3619", + "name": "Ernst \u0026 Young LLP Company", + "city": { + "name": "Avon By The Sea", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Avon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7734105670570655307-3620", + "name": "TransparaGov Corporation", + "city": { + "name": "Bridgewater", + "code": "MA", + "state": "Massachusetts", + "county": "Plymouth", + "display": "Bridgewater State College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6907275430497949405-3621", + "name": "Lawdragon LLC", + "city": { + "name": "Olympia", + "code": "WA", + "state": "Washington", + "county": "Thurston", + "display": "Washington State Department" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3989475500168681803-3622", + "name": "Caspio Inc", + "city": { + "name": "Fonda", + "code": "IA", + "state": "Iowa", + "county": "Pocahontas", + "display": "Industry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2186490994225225447-3623", + "name": "Noveda Technologies Corporation", + "city": { + "name": "Walcott", + "code": "AR", + "state": "Arkansas", + "county": "Greene", + "display": "Walcott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1464577115287532794-3624", + "name": "Jurispect LLC", + "city": { + "name": "Roberts", + "code": "MT", + "state": "Montana", + "county": "Carbon", + "display": "Fox" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-672122646754933228-3625", + "name": "CitySourced Corporation", + "city": { + "name": "Bishopville", + "code": "SC", + "state": "South Carolina", + "county": "Lee", + "display": "Manville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2528707437688610583-3626", + "name": "Bloomberg LLC", + "city": { + "name": "Le Roy", + "code": "WV", + "state": "West Virginia", + "county": "Jackson", + "display": "Duncan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8074727255526550657-3627", + "name": "OpportunitySpace, Corp", + "city": { + "name": "Conover", + "code": "NC", + "state": "North Carolina", + "county": "Catawba", + "display": "Conover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9097813297521260900-3628", + "name": "Boston Consulting Group Incorporated", + "city": { + "name": "New Orleans", + "code": "LA", + "state": "Louisiana", + "county": "Orleans", + "display": "University Of New Orleans" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4877398990927786089-3629", + "name": "Scale Unlimited Incorporated", + "city": { + "name": "Washington", + "code": "TX", + "state": "Texas", + "county": "Washington", + "display": "Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5672489135040095643-3630", + "name": "Everyday Health Corp", + "city": { + "name": "Gleason", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Parrish" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1580998945526455602-3631", + "name": "InCadence Company", + "city": { + "name": "Sweet Water", + "code": "AL", + "state": "Alabama", + "county": "Marengo", + "display": "Sweet Water" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2325835877374300510-3632", + "name": "Stormpulse Company", + "city": { + "name": "Gilman", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Gilman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7035629697226657407-3633", + "name": "CostQuest Company", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Richmond Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1649362882802356081-3634", + "name": "Mapbox Incorporated", + "city": { + "name": "Glen", + "code": "WV", + "state": "West Virginia", + "county": "Clay", + "display": "Glen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3626067766862851727-3635", + "name": "Farmers Corporation", + "city": { + "name": "Renton", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Cascade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3215694202016672029-3636", + "name": "Nationwide Mutual Insurance Company Company", + "city": { + "name": "Rodney", + "code": "MI", + "state": "Michigan", + "county": "Mecosta", + "display": "Rodney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6342761981344108066-3637", + "name": "Berkshire Hathaway Inc", + "city": { + "name": "Stockville", + "code": "NE", + "state": "Nebraska", + "county": "Frontier", + "display": "Stockville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3754657485809750511-3638", + "name": "IVES Group Corp", + "city": { + "name": "Springfield", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Mallet Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2212223458111544540-3639", + "name": "Navico Corp", + "city": { + "name": "Wenatchee", + "code": "WA", + "state": "Washington", + "county": "Chelan", + "display": "West Wenatchee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-455767191306625794-3640", + "name": "Walk Score Inc", + "city": { + "name": "Collins", + "code": "MS", + "state": "Mississippi", + "county": "Covington", + "display": "Mcraney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3166304114180440567-3641", + "name": "Food+Tech Connect Incorporated", + "city": { + "name": "Center Strafford", + "code": "NH", + "state": "New Hampshire", + "county": "Strafford", + "display": "Ctr Strafford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6506450602918020693-3642", + "name": "R R Donnelley Corporation", + "city": { + "name": "Flat", + "code": "TX", + "state": "Texas", + "county": "Coryell", + "display": "Flat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6253837353379502534-3643", + "name": "MapQuest Corp", + "city": { + "name": "Wolcottville", + "code": "IN", + "state": "Indiana", + "county": "Lagrange", + "display": "Pretty Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3823246008438610405-3644", + "name": "Morningstar, Company", + "city": { + "name": "Elliston", + "code": "VA", + "state": "Virginia", + "county": "Montgomery", + "display": "Ironto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6193548795736819086-3645", + "name": "SocialEffort LLC", + "city": { + "name": "Bergland", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Bergland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5274534112526578113-3646", + "name": "Chemical Abstracts Service Inc", + "city": { + "name": "Browns Summit", + "code": "NC", + "state": "North Carolina", + "county": "Guilford", + "display": "Osceola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-437997549940127942-3647", + "name": "Tableau Software Company", + "city": { + "name": "Cape Canaveral", + "code": "FL", + "state": "Florida", + "county": "Brevard", + "display": "Cpe Canaveral" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8639275787037927443-3648", + "name": "IW Financial Inc", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Woodland Hls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6436386700344800995-3649", + "name": "Intelius LLC", + "city": { + "name": "Florence", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Florence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7053720389291108222-3650", + "name": "Social Explorer LLC", + "city": { + "name": "Cobalt", + "code": "ID", + "state": "Idaho", + "county": "Lemhi", + "display": "Challis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5819534878125475571-3651", + "name": "Zonability LLC", + "city": { + "name": "Ashland", + "code": "MT", + "state": "Montana", + "county": "Rosebud", + "display": "Saint Labre Mission" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-515095103916067302-3652", + "name": "Lumesis, LLC", + "city": { + "name": "Coleman", + "code": "WI", + "state": "Wisconsin", + "county": "Marinette", + "display": "Coleman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7661993656433093591-3653", + "name": "Equifax Inc", + "city": { + "name": "Whatley", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Whatley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8447418489105021639-3654", + "name": "Vital Axiom | Niinja Company", + "city": { + "name": "Gnadenhutten", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Gnadenhutten" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8335093299202385153-3655", + "name": "Eat Shop Sleep Corporation", + "city": { + "name": "Mystic", + "code": "GA", + "state": "Georgia", + "county": "Irwin", + "display": "Mystic" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2056069426056717330-3656", + "name": "Parsons Brinckerhoff Inc", + "city": { + "name": "Leonard", + "code": "OK", + "state": "Oklahoma", + "county": "Tulsa", + "display": "Leonard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2126587857188469239-3657", + "name": "Smartronix Incorporated", + "city": { + "name": "Falkville", + "code": "AL", + "state": "Alabama", + "county": "Morgan", + "display": "Falkville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7528794608349712090-3658", + "name": "TowerData Corporation", + "city": { + "name": "Adrian", + "code": "MO", + "state": "Missouri", + "county": "Bates", + "display": "Adrian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7416029011066324050-3659", + "name": "Knowledge Agency Inc", + "city": { + "name": "Long Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "East Long Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3813627746834593546-3660", + "name": "Webitects Incorporated", + "city": { + "name": "Saint Michaels", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Saint Michaels" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7515723129396704457-3661", + "name": "KPMG Inc", + "city": { + "name": "Pueblo", + "code": "CO", + "state": "Colorado", + "county": "Pueblo", + "display": "Devine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3492531481875502964-3662", + "name": "LoseIt.com Company", + "city": { + "name": "Othello", + "code": "WA", + "state": "Washington", + "county": "Adams", + "display": "Othello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1867255424615340819-3663", + "name": "North American Van Lines Company", + "city": { + "name": "Middlesex", + "code": "NC", + "state": "North Carolina", + "county": "Nash", + "display": "Middlesex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3063013165340216691-3664", + "name": "IBM Corp", + "city": { + "name": "Mc Veytown", + "code": "PA", + "state": "Pennsylvania", + "county": "Mifflin", + "display": "Mc Veytown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2320062639314152567-3665", + "name": "Vital Axiom | Niinja Incorporated", + "city": { + "name": "Desert Hot Springs", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Desert Edge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8661875611794020794-3666", + "name": "Merrill LLC", + "city": { + "name": "Beaumont", + "code": "TX", + "state": "Texas", + "county": "Jefferson", + "display": "Taylor Landing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4382758031816761781-3667", + "name": "Civic Impulse Company", + "city": { + "name": "La Grange", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "Rutersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4551132569335965787-3668", + "name": "MarketSense Incorporated", + "city": { + "name": "Marysville", + "code": "CA", + "state": "California", + "county": "Yuba", + "display": "Hallwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-904512300282833795-3669", + "name": "NuCivic Incorporated", + "city": { + "name": "Rio Grande City", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "Santa Catarina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7615081996316769988-3670", + "name": "StreetEasy Corp", + "city": { + "name": "Arapahoe", + "code": "NC", + "state": "North Carolina", + "county": "Pamlico", + "display": "Minnesott Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3881595118010832330-3671", + "name": "GetRaised Corporation", + "city": { + "name": "Gilboa", + "code": "NY", + "state": "New York", + "county": "Schoharie", + "display": "Gilboa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2195862367116200586-3672", + "name": "Calcbench, Inc", + "city": { + "name": "Ridgefield", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Morsemere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6464329130469003766-3673", + "name": "StreetCred Software, Corporation", + "city": { + "name": "Markleeville", + "code": "CA", + "state": "California", + "county": "Alpine", + "display": "Woodfords" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-722921906216749111-3674", + "name": "The Advisory Board Company Corporation", + "city": { + "name": "Arapahoe", + "code": "NC", + "state": "North Carolina", + "county": "Pamlico", + "display": "Arapahoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5973488514547024270-3675", + "name": "Way Better Patents Corp", + "city": { + "name": "Highland", + "code": "MD", + "state": "Maryland", + "county": "Howard", + "display": "Highland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8332401759753538810-3676", + "name": "LegiNation, Corp", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Xerox" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3177394742464790318-3677", + "name": "Junar, Inc", + "city": { + "name": "De Kalb", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Siloam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4420124126481017340-3678", + "name": "CitySourced Inc", + "city": { + "name": "North Myrtle Beach", + "code": "SC", + "state": "South Carolina", + "county": "Horry", + "display": "North Myrtle Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2900815835428620528-3679", + "name": "Farmers Incorporated", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Miami Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2544056255460690146-3680", + "name": "Oversight Systems Incorporated", + "city": { + "name": "Lincoln", + "code": "NE", + "state": "Nebraska", + "county": "Lancaster", + "display": "Prairie Home" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4511424410175585257-3681", + "name": "MetLife Inc", + "city": { + "name": "Waitsfield", + "code": "VT", + "state": "Vermont", + "county": "Washington", + "display": "Irasville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3103302127319952479-3682", + "name": "LegiNation, LLC", + "city": { + "name": "Philadelphia", + "code": "PA", + "state": "Pennsylvania", + "county": "Philadelphia", + "display": "William Penn Annex West" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8252995949488641890-3683", + "name": "U.S. News Schools Corp", + "city": { + "name": "Verndale", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Wing River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-776732868504583109-3684", + "name": "Connotate Company", + "city": { + "name": "Martin", + "code": "PA", + "state": "Pennsylvania", + "county": "Fayette", + "display": "Martin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3507779882922852550-3685", + "name": "NonprofitMetrics Corp", + "city": { + "name": "Mechanicsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Trindle Sprg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2310525549623769007-3686", + "name": "MuckRock.com Corp", + "city": { + "name": "Weedsport", + "code": "NY", + "state": "New York", + "county": "Cayuga", + "display": "Weedsport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-794410457728744390-3687", + "name": "Azavea Corp", + "city": { + "name": "Jamestown", + "code": "PA", + "state": "Pennsylvania", + "county": "Mercer", + "display": "Westford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2744073002494980619-3688", + "name": "Yahoo LLC", + "city": { + "name": "Iron City", + "code": "GA", + "state": "Georgia", + "county": "Seminole", + "display": "Iron City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-419127362398505711-3689", + "name": "Ensco Inc", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Poplar Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7088647995174628972-3690", + "name": "ideas42 LLC", + "city": { + "name": "Cresson", + "code": "TX", + "state": "Texas", + "county": "Hood", + "display": "Cresson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9190106889043173843-3691", + "name": "Impact Forecasting Inc", + "city": { + "name": "Snoqualmie Pass", + "code": "WA", + "state": "Washington", + "county": "Kittitas", + "display": "Snoqualmie Ps" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6331503579686752508-3692", + "name": "AccuWeather LLC", + "city": { + "name": "Rose Hill", + "code": "KS", + "state": "Kansas", + "county": "Butler", + "display": "Rose Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9017297132623666903-3693", + "name": "CliniCast Incorporated", + "city": { + "name": "Waelder", + "code": "TX", + "state": "Texas", + "county": "Gonzales", + "display": "Waelder" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5376861142141505723-3694", + "name": "Vital Axiom | Niinja Corp", + "city": { + "name": "Green Pond", + "code": "SC", + "state": "South Carolina", + "county": "Colleton", + "display": "Green Pond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-151018009954345804-3695", + "name": "48 Factoring LLC", + "city": { + "name": "Lohman", + "code": "MO", + "state": "Missouri", + "county": "Cole", + "display": "Lohman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-411177675353413543-3696", + "name": "Genability Incorporated", + "city": { + "name": "Montauk", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Montauk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3801022982508743350-3697", + "name": "PYA Analytics Company", + "city": { + "name": "Cobalt", + "code": "ID", + "state": "Idaho", + "county": "Lemhi", + "display": "Challis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5255959591423774571-3698", + "name": "Webitects Inc", + "city": { + "name": "Midland", + "code": "SD", + "state": "South Dakota", + "county": "Haakon", + "display": "Kirley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9112158899115020073-3699", + "name": "Energy Points, Corp", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Crystal Lake Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3548970690270055985-3700", + "name": "Genability Inc", + "city": { + "name": "Bristol", + "code": "GA", + "state": "Georgia", + "county": "Pierce", + "display": "Bristol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-198037346395821396-3701", + "name": "TransparaGov Incorporated", + "city": { + "name": "Rachel", + "code": "WV", + "state": "West Virginia", + "county": "Marion", + "display": "Rachel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3721459588880298642-3702", + "name": "CARFAX Corp", + "city": { + "name": "Peachland", + "code": "NC", + "state": "North Carolina", + "county": "Anson", + "display": "White Store" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6376471846493369184-3703", + "name": "FlightView Inc", + "city": { + "name": "Manorville", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Manorville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3133990227829403728-3704", + "name": "iMedicare Company", + "city": { + "name": "Swanton", + "code": "NE", + "state": "Nebraska", + "county": "Saline", + "display": "Swanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4646194912925776255-3705", + "name": "VitalChek Company", + "city": { + "name": "Cookeville", + "code": "TN", + "state": "Tennessee", + "county": "Putnam", + "display": "Cookevle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-981374063614882496-3706", + "name": "Amida Technology Solutions Incorporated", + "city": { + "name": "Youngsville", + "code": "NM", + "state": "New Mexico", + "county": "Rio Arriba", + "display": "Rito De Las Sillas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7573299902151985144-3707", + "name": "Aquicore Incorporated", + "city": { + "name": "Arthur", + "code": "IA", + "state": "Iowa", + "county": "Ida", + "display": "Arthur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5238945385388422006-3708", + "name": "Locavore Corp", + "city": { + "name": "Harper", + "code": "IA", + "state": "Iowa", + "county": "Keokuk", + "display": "Harper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3286482678520686087-3709", + "name": "Mercaris Company", + "city": { + "name": "Lone Tree", + "code": "CO", + "state": "Colorado", + "county": "Douglas", + "display": "Lone Tree" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9139973532819014962-3710", + "name": "SmartProcure Corporation", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis City", + "display": "Courtesy Reply Mail Firms" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3204082744157202163-3711", + "name": "Kroll Bond Ratings Agency Corporation", + "city": { + "name": "Lovelock", + "code": "NV", + "state": "Nevada", + "county": "Pershing", + "display": "Rabbit Hole" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4909983069922563255-3712", + "name": "Compliance and Risks Corporation", + "city": { + "name": "Webbville", + "code": "KY", + "state": "Kentucky", + "county": "Lawrence", + "display": "Webbville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9193470149088806505-3713", + "name": "Child Care Desk Incorporated", + "city": { + "name": "Columbia", + "code": "MO", + "state": "Missouri", + "county": "Boone", + "display": "University Of Missouri" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2761961742310975614-3714", + "name": "PEV4me.com Corporation", + "city": { + "name": "Ocean Springs", + "code": "MS", + "state": "Mississippi", + "county": "Jackson", + "display": "Gulf Park Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7173309826834398921-3715", + "name": "Marinexplore, Incorporated", + "city": { + "name": "Wyalusing", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Wyalusing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3078969671076366668-3716", + "name": "PolicyMap Corp", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis City", + "display": "Courtesy Reply Mail Firms" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-214455328059452653-3717", + "name": "SpeSo Health Corporation", + "city": { + "name": "Kensett", + "code": "IA", + "state": "Iowa", + "county": "Worth", + "display": "Bolan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1238121511085353495-3718", + "name": "StreamLink Software Corporation", + "city": { + "name": "Cedaredge", + "code": "CO", + "state": "Colorado", + "county": "Delta", + "display": "Coalby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2700545808143504540-3719", + "name": "Citigroup Corporation", + "city": { + "name": "Ontario", + "code": "NY", + "state": "New York", + "county": "Wayne", + "display": "Ontario" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6161261170686215111-3720", + "name": "MetLife Corporation", + "city": { + "name": "Craftsbury", + "code": "VT", + "state": "Vermont", + "county": "Orleans", + "display": "Craftsbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5811154656255388481-3721", + "name": "Scale Unlimited Inc", + "city": { + "name": "Venetia", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Venetia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6829053339663212506-3722", + "name": "Rivet Software Incorporated", + "city": { + "name": "North Little Rock", + "code": "AR", + "state": "Arkansas", + "county": "Pulaski", + "display": "Veterans Administration Faci" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3983510026359381005-3723", + "name": "Morningstar, Corp", + "city": { + "name": "Dorothy", + "code": "WV", + "state": "West Virginia", + "county": "Raleigh", + "display": "Ameagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7555150645865648884-3724", + "name": "Funding Circle Inc", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Readers Digest" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8405106947761216760-3725", + "name": "H3 Biomedicine Corporation", + "city": { + "name": "Petersburg", + "code": "IL", + "state": "Illinois", + "county": "Menard", + "display": "Tice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-231921215596728249-3726", + "name": "Rivet Software Corp", + "city": { + "name": "Hamilton", + "code": "PA", + "state": "Pennsylvania", + "county": "Jefferson", + "display": "Hamilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5860209399130861366-3727", + "name": "GitHub LLC", + "city": { + "name": "Stoddard", + "code": "NH", + "state": "New Hampshire", + "county": "Cheshire", + "display": "Stoddard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4033127831350507754-3728", + "name": "Stevens Worldwide Van Lines LLC", + "city": { + "name": "New Century", + "code": "KS", + "state": "Kansas", + "county": "Johnson", + "display": "New Century" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4904851546738677023-3729", + "name": "Verdafero Inc", + "city": { + "name": "Glenmont", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Bethlehem Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5564606229004999177-3730", + "name": "Cambridge Information Group Inc", + "city": { + "name": "Syracuse", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Dewitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8167250947797293828-3731", + "name": "Consumer Reports Inc", + "city": { + "name": "Delavan", + "code": "MN", + "state": "Minnesota", + "county": "Faribault", + "display": "Delavan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6376465983023588199-3732", + "name": "Atlas Van Lines Corp", + "city": { + "name": "Marion", + "code": "AL", + "state": "Alabama", + "county": "Perry", + "display": "Sprott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6012487899154521712-3733", + "name": "Stevens Worldwide Van Lines LLC", + "city": { + "name": "Freeland", + "code": "WA", + "state": "Washington", + "county": "Island", + "display": "Freeland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-247662846102518295-3734", + "name": "nGAP orporated Inc", + "city": { + "name": "Lehi", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Eagle Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-230670625263107251-3735", + "name": "Aureus Sciences Company", + "city": { + "name": "Trabuco Canyon", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Trabuco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5684066010612811395-3736", + "name": "SpaceCurve Company", + "city": { + "name": "South Amboy", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "South Amboy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-953398874034859977-3737", + "name": "PlotWatt Corporation", + "city": { + "name": "Lynchburg", + "code": "VA", + "state": "Virginia", + "county": "Lynchburg City", + "display": "Fort Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8624992328808324827-3738", + "name": "Dabo Health Company", + "city": { + "name": "Menahga", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Blueberry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5242816070754757912-3739", + "name": "Way Better Patents Incorporated", + "city": { + "name": "Tarlton", + "code": "OH", + "state": "Ohio", + "county": "Pickaway", + "display": "Tarlton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4786425625306782624-3740", + "name": "Munetrix LLC", + "city": { + "name": "Rickreall", + "code": "OR", + "state": "Oregon", + "county": "Polk", + "display": "Rickreall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3610376762762506961-3741", + "name": "Dabo Health Incorporated", + "city": { + "name": "Sparks", + "code": "NV", + "state": "Nevada", + "county": "Washoe", + "display": "Lockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7596850694029607698-3742", + "name": "Roadify Transit Company", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Jackson", + "display": "Kans City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2632976405015530694-3743", + "name": "PlotWatt Corp", + "city": { + "name": "Gouldsboro", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "S Gouldsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-16528221192340511-3744", + "name": "DataMarket Company", + "city": { + "name": "Elrod", + "code": "AL", + "state": "Alabama", + "county": "Tuscaloosa", + "display": "Elrod" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8967155193500579178-3745", + "name": "Vimo LLC", + "city": { + "name": "Greencastle", + "code": "PA", + "state": "Pennsylvania", + "county": "Franklin", + "display": "Greencastle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4392450904833251037-3746", + "name": "Xatori Corporation", + "city": { + "name": "Bristol", + "code": "GA", + "state": "Georgia", + "county": "Pierce", + "display": "Bristol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6163527562975848533-3747", + "name": "TrialX Company", + "city": { + "name": "Elkader", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Mederville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8461478918923241445-3748", + "name": "Noesis Corp", + "city": { + "name": "Saginaw", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Brevator" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-589310370564069745-3749", + "name": "KPMG Inc", + "city": { + "name": "Wilson", + "code": "TX", + "state": "Texas", + "county": "Lynn", + "display": "New Home" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-115563761407701053-3750", + "name": "Kimono Labs LLC", + "city": { + "name": "Manchester", + "code": "IL", + "state": "Illinois", + "county": "Scott", + "display": "Manchester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2629352451838352107-3751", + "name": "Municode Corp", + "city": { + "name": "Luana", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Luana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7497717529886932168-3752", + "name": "Palantir Technologies Company", + "city": { + "name": "Beverly", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Beverly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6522397628056959834-3753", + "name": "REI Systems Corp", + "city": { + "name": "Jacksonville", + "code": "FL", + "state": "Florida", + "county": "Duval", + "display": "Jacksonville Nas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2369452140427811028-3754", + "name": "nGAP orporated Company", + "city": { + "name": "Logan", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Logan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2478680145567376984-3755", + "name": "GuideStar Corporation", + "city": { + "name": "Mount Freedom", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Mount Freedom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5424098840598598124-3756", + "name": "Scale Unlimited Inc", + "city": { + "name": "Forest Knolls", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Forest Knolls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3868935517736166565-3757", + "name": "WattzOn Corporation", + "city": { + "name": "Cedar Key", + "code": "FL", + "state": "Florida", + "county": "Levy", + "display": "Cedar Key" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4138186572357130748-3758", + "name": "People Power Corp", + "city": { + "name": "South New Berlin", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Lathams Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3188741612543411942-3759", + "name": "Earth Networks LLC", + "city": { + "name": "Lawndale", + "code": "NC", + "state": "North Carolina", + "county": "Cleveland", + "display": "Belwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7809448225142566785-3760", + "name": "MapQuest Company", + "city": { + "name": "Braceville", + "code": "IL", + "state": "Illinois", + "county": "Grundy", + "display": "Godley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5731887466260090836-3761", + "name": "Rand McNally Corporation", + "city": { + "name": "Occidental", + "code": "CA", + "state": "California", + "county": "Sonoma", + "display": "Occidental" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9068429648888242719-3762", + "name": "Qado Energy, LLC", + "city": { + "name": "Honaker", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Elk Garden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6340106731060949905-3763", + "name": "DataMade Corp", + "city": { + "name": "Pittsburg", + "code": "KS", + "state": "Kansas", + "county": "Crawford", + "display": "Pittsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7158950892671414632-3764", + "name": "The Advisory Board Company Corporation", + "city": { + "name": "Clermont", + "code": "KY", + "state": "Kentucky", + "county": "Bullitt", + "display": "Clermont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9170545447256609395-3765", + "name": "StreamLink Software Incorporated", + "city": { + "name": "Robinson Creek", + "code": "KY", + "state": "Kentucky", + "county": "Pike", + "display": "Robinson Crk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8260395668133953423-3766", + "name": "Jurispect Inc", + "city": { + "name": "Inverness", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Inverness" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3213518784639280943-3767", + "name": "Nationwide Mutual Insurance Company Corp", + "city": { + "name": "Derby", + "code": "IA", + "state": "Iowa", + "county": "Lucas", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1905928553295584863-3768", + "name": "Teradata Incorporated", + "city": { + "name": "Houlton", + "code": "ME", + "state": "Maine", + "county": "Aroostook", + "display": "Linneus" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7605721210136447548-3769", + "name": "The Bridgespan Group Corp", + "city": { + "name": "Dumas", + "code": "AR", + "state": "Arkansas", + "county": "Desha", + "display": "Reedville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4900025074049654405-3770", + "name": "Aunt Bertha, LLC", + "city": { + "name": "Kenedy", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Kenedy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4173867116912621915-3771", + "name": "PublicEngines Incorporated", + "city": { + "name": "Badger", + "code": "MN", + "state": "Minnesota", + "county": "Roseau", + "display": "Badger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7515085793826060184-3772", + "name": "Bridgewater LLC", + "city": { + "name": "Collinston", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Wheelon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-690443828619105151-3773", + "name": "Cambridge Semantics Company", + "city": { + "name": "Laneville", + "code": "TX", + "state": "Texas", + "county": "Rusk", + "display": "Laneville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3890676661430758286-3774", + "name": "Impaq International LLC", + "city": { + "name": "Amery", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Little Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7888285875483088928-3775", + "name": "CareSet Systems Incorporated", + "city": { + "name": "Bellevue", + "code": "MI", + "state": "Michigan", + "county": "Eaton", + "display": "Bellevue" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1290187145310163001-3776", + "name": "Panjiva Incorporated", + "city": { + "name": "Exeter", + "code": "RI", + "state": "Rhode Island", + "county": "Washington", + "display": "Exeter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2131585283296799567-3777", + "name": "GetRaised LLC", + "city": { + "name": "Westfield", + "code": "PA", + "state": "Pennsylvania", + "county": "Tioga", + "display": "Westfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-451403959666284254-3778", + "name": "LegiStorm Incorporated", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Arkansas Louisiana Gas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5706293997934588724-3779", + "name": "Garmin Incorporated", + "city": { + "name": "Crump", + "code": "TN", + "state": "Tennessee", + "county": "Hardin", + "display": "Crump" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7025312606157362731-3780", + "name": "MedWatcher Corp", + "city": { + "name": "Crump", + "code": "TN", + "state": "Tennessee", + "county": "Hardin", + "display": "Crump" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2382466380330998998-3781", + "name": "College Abacus, an ECMC initiative LLC", + "city": { + "name": "East Poland", + "code": "ME", + "state": "Maine", + "county": "Androscoggin", + "display": "East Poland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8336880437969706116-3782", + "name": "Zonability Company", + "city": { + "name": "Golconda", + "code": "IL", + "state": "Illinois", + "county": "Pope", + "display": "Temple Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1326584646306402845-3783", + "name": "Intelius Inc", + "city": { + "name": "Hallett", + "code": "OK", + "state": "Oklahoma", + "county": "Pawnee", + "display": "Hailey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6748354136650369850-3784", + "name": "T. Rowe Price Inc", + "city": { + "name": "Ganado", + "code": "AZ", + "state": "Arizona", + "county": "Apache", + "display": "Greasewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6115862762894845926-3785", + "name": "realtor.com Corp", + "city": { + "name": "Brewster", + "code": "KS", + "state": "Kansas", + "county": "Thomas", + "display": "Brewster" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4741147878664884033-3786", + "name": "DataLogix Inc", + "city": { + "name": "Hitchita", + "code": "OK", + "state": "Oklahoma", + "county": "Mcintosh", + "display": "Hitchita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3907715259834198815-3787", + "name": "Mapbox Corp", + "city": { + "name": "Everglades City", + "code": "FL", + "state": "Florida", + "county": "Collier", + "display": "Everglades City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7413061470387232778-3788", + "name": "CAN Capital Corporation", + "city": { + "name": "Bucyrus", + "code": "KS", + "state": "Kansas", + "county": "Miami", + "display": "Bucyrus" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8011577656275906262-3789", + "name": "Junar, LLC", + "city": { + "name": "Bacliff", + "code": "TX", + "state": "Texas", + "county": "Galveston", + "display": "Bacliff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6910391474305585133-3790", + "name": "Gallup Inc", + "city": { + "name": "Valley Springs", + "code": "SD", + "state": "South Dakota", + "county": "Minnehaha", + "display": "Valley Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-743896963189385316-3791", + "name": "Google Maps Incorporated", + "city": { + "name": "Northfield", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Thomaston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3820220690062292513-3792", + "name": "NerdWallet Inc", + "city": { + "name": "San Diego", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Nas North Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8319382322874388973-3793", + "name": "LOGIXDATA, Inc", + "city": { + "name": "Hawthorne", + "code": "NV", + "state": "Nevada", + "county": "Mineral", + "display": "Babbitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-455496293368387988-3794", + "name": "Govzilla, Company", + "city": { + "name": "Hanover", + "code": "MA", + "state": "Massachusetts", + "county": "Plymouth", + "display": "West Hanover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6556901074056251411-3795", + "name": "Mozio Corp", + "city": { + "name": "Lena", + "code": "WI", + "state": "Wisconsin", + "county": "Oconto", + "display": "Lena" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8500076457812533524-3796", + "name": "Ontodia, Inc", + "city": { + "name": "Haugen", + "code": "WI", + "state": "Wisconsin", + "county": "Barron", + "display": "Haugen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8947413879235160667-3797", + "name": "People Power Company", + "city": { + "name": "Buckhannon", + "code": "WV", + "state": "West Virginia", + "county": "Upshur", + "display": "Buckhannon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2525549209258273839-3798", + "name": "Archimedes Inc", + "city": { + "name": "Thompson", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Thompson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6085169622333512961-3799", + "name": "nGAP orporated Corporation", + "city": { + "name": "Clayton", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Murray Isle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8577350041423210016-3800", + "name": "Aidin Inc", + "city": { + "name": "Whatley", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Whatley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8943891940057406194-3801", + "name": "Energy Points, Corp", + "city": { + "name": "Carterville", + "code": "IL", + "state": "Illinois", + "county": "Williamson", + "display": "Hafer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3182995155758193231-3802", + "name": "Bloomberg Company", + "city": { + "name": "Ah Gwah Ching", + "code": "MN", + "state": "Minnesota", + "county": "Cass", + "display": "Ah Gwah Ching" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2240435046290300822-3803", + "name": "Credit Sesame Incorporated", + "city": { + "name": "Pottsboro", + "code": "TX", + "state": "Texas", + "county": "Grayson", + "display": "Pottsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1210172565154284759-3804", + "name": "Tendril Company", + "city": { + "name": "Pompano Beach", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Lighthouse Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1128534376065388581-3805", + "name": "Way Better Patents Inc", + "city": { + "name": "Pleasant Ridge", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Pleasant Rdg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3561710742188852198-3806", + "name": "LegiStorm Company", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Wilmington Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-418840876723361493-3807", + "name": "Level One Technologies Inc", + "city": { + "name": "Haugen", + "code": "WI", + "state": "Wisconsin", + "county": "Barron", + "display": "Haugen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2013929113343838856-3808", + "name": "Suddath Company", + "city": { + "name": "Ward Cove", + "code": "AK", + "state": "Alaska", + "county": "Ketchikan Gateway", + "display": "Ward Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7692201900113264996-3809", + "name": "PlaceILive.com Corporation", + "city": { + "name": "East Waterford", + "code": "PA", + "state": "Pennsylvania", + "county": "Juniata", + "display": "Scyoc" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3804400072437649427-3810", + "name": "Garmin Incorporated", + "city": { + "name": "Griffithville", + "code": "AR", + "state": "Arkansas", + "county": "White", + "display": "Griffithville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3249744660174584067-3811", + "name": "Weather Decision Technologies Incorporated", + "city": { + "name": "Alma", + "code": "AR", + "state": "Arkansas", + "county": "Crawford", + "display": "Alma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2382785992859540751-3812", + "name": "Amida Technology Solutions Incorporated", + "city": { + "name": "Media", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Franklin Mt Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8511662059310383108-3813", + "name": "Captricity LLC", + "city": { + "name": "Ashley", + "code": "IL", + "state": "Illinois", + "county": "Washington", + "display": "Bolo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-990183866741219227-3814", + "name": "SeeClickFix Company", + "city": { + "name": "Swanton", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Maquam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3342481977540079414-3815", + "name": "Garmin Company", + "city": { + "name": "Corning", + "code": "OH", + "state": "Ohio", + "county": "Perry", + "display": "Corning" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7557075915116810742-3816", + "name": "Credit Sesame Incorporated", + "city": { + "name": "Bronx", + "code": "NY", + "state": "New York", + "county": "Bronx", + "display": "Esplanade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8381861483399520566-3817", + "name": "Propeller Health Corp", + "city": { + "name": "Highland", + "code": "MD", + "state": "Maryland", + "county": "Howard", + "display": "Highland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5515331663155994106-3818", + "name": "Inrix Traffic Inc", + "city": { + "name": "Salem", + "code": "AL", + "state": "Alabama", + "county": "Lee", + "display": "Salem" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5039098531516307292-3819", + "name": "Trulia Corp", + "city": { + "name": "Saint Charles", + "code": "MO", + "state": "Missouri", + "county": "Saint Charles", + "display": "Weldon Spring Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2797883640084820147-3820", + "name": "Overture Technologies Corp", + "city": { + "name": "Avondale", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Avondale-Goodyear" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5465079606509385352-3821", + "name": "The Bridgespan Group LLC", + "city": { + "name": "Jacksonville", + "code": "FL", + "state": "Florida", + "county": "Duval", + "display": "Jacksonville Nas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7404588508528759691-3822", + "name": "Business and Legal Resources Incorporated", + "city": { + "name": "Binghamton", + "code": "NY", + "state": "New York", + "county": "Broome", + "display": "Nimmonsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9079665534521034137-3823", + "name": "FutureAdvisor Inc", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Marys Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3609486474637726678-3824", + "name": "Solar Census Company", + "city": { + "name": "Loxahatchee", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Vlg Wellingtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7226782115025652180-3825", + "name": "Abt Associates Company", + "city": { + "name": "Orland Park", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Orland Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-694765032000199853-3826", + "name": "Yahoo Inc", + "city": { + "name": "Beatrice", + "code": "AL", + "state": "Alabama", + "county": "Monroe", + "display": "Beatrice" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6408622978775380630-3827", + "name": "OpenGov Company", + "city": { + "name": "Mount Erie", + "code": "IL", + "state": "Illinois", + "county": "Wayne", + "display": "Mount Erie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8944921895739730817-3828", + "name": "LoopNet Corp", + "city": { + "name": "West Burlington", + "code": "IA", + "state": "Iowa", + "county": "Des Moines", + "display": "West Burlington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1576485553392033736-3829", + "name": "Recargo Company", + "city": { + "name": "Washington", + "code": "DC", + "state": "Washington, D.C.", + "county": "District Of Columbia", + "display": "Veterans Admin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1708591213288490220-3830", + "name": "AutoGrid Systems Company", + "city": { + "name": "Stennis Space Center", + "code": "MS", + "state": "Mississippi", + "county": "Hancock", + "display": "Stennis Sp Ct" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1682339886487955899-3831", + "name": "Quid Incorporated", + "city": { + "name": "Nevada", + "code": "MO", + "state": "Missouri", + "county": "Vernon", + "display": "Camp Clark" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9137094370852605413-3832", + "name": "Ensco LLC", + "city": { + "name": "Artesia Wells", + "code": "TX", + "state": "Texas", + "county": "La Salle", + "display": "Artesia Wells" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5077310232551189530-3833", + "name": "TagniFi Inc", + "city": { + "name": "Eminence", + "code": "KY", + "state": "Kentucky", + "county": "Henry", + "display": "Eminence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2552614340216845122-3834", + "name": "Geolytics Corporation", + "city": { + "name": "Williamsburg", + "code": "NM", + "state": "New Mexico", + "county": "Sierra", + "display": "Las Palomas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-248586444698775408-3835", + "name": "Geofeedia Corporation", + "city": { + "name": "Fairfield", + "code": "ID", + "state": "Idaho", + "county": "Camas", + "display": "Fairfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7476820364868634999-3836", + "name": "Everyday Health Inc", + "city": { + "name": "Poquonock", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Poquonock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3340249865416084418-3837", + "name": "CareSet Systems Company", + "city": { + "name": "Standish", + "code": "MI", + "state": "Michigan", + "county": "Arenac", + "display": "Standish" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3337399026239450239-3838", + "name": "FlightView Corporation", + "city": { + "name": "Northbrook", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Northbrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3473682438745239730-3839", + "name": "Mercaris Corporation", + "city": { + "name": "Bayport", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Bayport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4216137481421366829-3840", + "name": "Headlight Corporation", + "city": { + "name": "Irondale", + "code": "OH", + "state": "Ohio", + "county": "Jefferson", + "display": "Cream City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-69725329049146197-3841", + "name": "Mercaris Corporation", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Ny Agr And Mkts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8525783475456060893-3842", + "name": "Arpin Van Lines Incorporated", + "city": { + "name": "Chapmanville", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Chapmanville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-458984931394267541-3843", + "name": "People Power Incorporated", + "city": { + "name": "Pretty Prairie", + "code": "KS", + "state": "Kansas", + "county": "Reno", + "display": "Pretty Pr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5674009818707248206-3844", + "name": "Nationwide Mutual Insurance Company Corp", + "city": { + "name": "Deer Park", + "code": "AL", + "state": "Alabama", + "county": "Washington", + "display": "Seaboard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8766895438717462986-3845", + "name": "OSIsoft Inc", + "city": { + "name": "Harper", + "code": "OR", + "state": "Oregon", + "county": "Malheur", + "display": "Harper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6227153430058127470-3846", + "name": "Sterling Infosystems LLC", + "city": { + "name": "Ranchos De Taos", + "code": "NM", + "state": "New Mexico", + "county": "Taos", + "display": "Ranches Of Taos" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2546676448697599594-3847", + "name": "PossibilityU LLC", + "city": { + "name": "Hadley", + "code": "PA", + "state": "Pennsylvania", + "county": "Mercer", + "display": "Hadley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6346463038711206699-3848", + "name": "Aquicore Inc", + "city": { + "name": "Bath", + "code": "NY", + "state": "New York", + "county": "Steuben", + "display": "Bath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2651010527727886944-3849", + "name": "FlightView Company", + "city": { + "name": "Floydada", + "code": "TX", + "state": "Texas", + "county": "Floyd", + "display": "Floydada" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-512585072394888409-3850", + "name": "CityScan Corporation", + "city": { + "name": "Saint Michael", + "code": "ND", + "state": "North Dakota", + "county": "Benson", + "display": "St Michael" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6483753444866358335-3851", + "name": "ClearHealthCosts Company", + "city": { + "name": "I B M", + "code": "CA", + "state": "California", + "county": "Santa Clara", + "display": "I B M" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6744357589092627587-3852", + "name": "Smart Utility Systems Corporation", + "city": { + "name": "Peru", + "code": "IN", + "state": "Indiana", + "county": "Miami", + "display": "Peru" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6109396886875601180-3853", + "name": "Chubb Corp", + "city": { + "name": "Washington", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Washington Dt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8849340147312196606-3854", + "name": "Sophic Systems Alliance Incorporated", + "city": { + "name": "Edwards", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "South Edwards" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4203693314438358845-3855", + "name": "OSIsoft Company", + "city": { + "name": "Lynchburg", + "code": "VA", + "state": "Virginia", + "county": "Lynchburg City", + "display": "Rivermont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7409469616408610389-3856", + "name": "The Vanguard Group Corporation", + "city": { + "name": "Forest Junction", + "code": "WI", + "state": "Wisconsin", + "county": "Calumet", + "display": "Forest Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1413108808728798197-3857", + "name": "Standard and Poor's Corporation", + "city": { + "name": "Midland", + "code": "SD", + "state": "South Dakota", + "county": "Haakon", + "display": "Kirley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-461408621466507144-3858", + "name": "Urban Airship Company", + "city": { + "name": "Linch", + "code": "WY", + "state": "Wyoming", + "county": "Johnson", + "display": "Linch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5039381820194955157-3859", + "name": "Boundless Corporation", + "city": { + "name": "Loveland", + "code": "OK", + "state": "Oklahoma", + "county": "Tillman", + "display": "Loveland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6573687777896461478-3860", + "name": "Recargo Corporation", + "city": { + "name": "Eastview", + "code": "KY", + "state": "Kentucky", + "county": "Hardin", + "display": "E View" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6300948212158224847-3861", + "name": "WaterSmart Software Inc", + "city": { + "name": "South Newfane", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "South Newfane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2244554354249152607-3862", + "name": "Funding Circle Corp", + "city": { + "name": "Milton", + "code": "NC", + "state": "North Carolina", + "county": "Caswell", + "display": "Milton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4096581683232693255-3863", + "name": "Pave Inc", + "city": { + "name": "Washburn", + "code": "ND", + "state": "North Dakota", + "county": "Mclean", + "display": "Falkirk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3489414553491316457-3864", + "name": "SpotHero.com Inc", + "city": { + "name": "Mountain Rest", + "code": "SC", + "state": "South Carolina", + "county": "Oconee", + "display": "Mountain Rest" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6521985410106993631-3865", + "name": "Mercaris LLC", + "city": { + "name": "Petersburg", + "code": "NE", + "state": "Nebraska", + "county": "Boone", + "display": "Petersburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8680626708646850288-3866", + "name": "Department of Better Technology Inc", + "city": { + "name": "War", + "code": "WV", + "state": "West Virginia", + "county": "Mcdowell", + "display": "Yukon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8727275598733672727-3867", + "name": "Energy Solutions Forum Incorporated", + "city": { + "name": "Morven", + "code": "NC", + "state": "North Carolina", + "county": "Anson", + "display": "Morven" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2451492237784856450-3868", + "name": "Mint Company", + "city": { + "name": "Warsaw", + "code": "KY", + "state": "Kentucky", + "county": "Gallatin", + "display": "Warsaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4852885594859056312-3869", + "name": "Navico LLC", + "city": { + "name": "Blue Mound", + "code": "IL", + "state": "Illinois", + "county": "Macon", + "display": "Blue Mound" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6010954612028085241-3870", + "name": "48 Factoring LLC", + "city": { + "name": "Annada", + "code": "MO", + "state": "Missouri", + "county": "Pike", + "display": "Annada" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5325548756345713590-3871", + "name": "Equilar Incorporated", + "city": { + "name": "Thorn Hill", + "code": "TN", + "state": "Tennessee", + "county": "Grainger", + "display": "Treadway" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6683974972076228455-3872", + "name": "Ez-XBRL Company", + "city": { + "name": "Westfield", + "code": "PA", + "state": "Pennsylvania", + "county": "Tioga", + "display": "Elmer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3151395287729700863-3873", + "name": "Code-N Corporation", + "city": { + "name": "Anthony", + "code": "TX", + "state": "Texas", + "county": "El Paso", + "display": "Vinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4308240910351335700-3874", + "name": "Factset Incorporated", + "city": { + "name": "Elysian Fields", + "code": "TX", + "state": "Texas", + "county": "Harrison", + "display": "Elysian Fields" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1851748763678558570-3875", + "name": "AutoGrid Systems Corporation", + "city": { + "name": "Saint Johns", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Switzerland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3602228802095352296-3876", + "name": "Sophic Systems Alliance Company", + "city": { + "name": "Lycoming", + "code": "NY", + "state": "New York", + "county": "Oswego", + "display": "Lycoming" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3949030864995064815-3877", + "name": "WebMD Inc", + "city": { + "name": "Watertown", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Fort Drum" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8158210752473916960-3878", + "name": "karmadata LLC", + "city": { + "name": "Amissville", + "code": "VA", + "state": "Virginia", + "county": "Culpeper", + "display": "Amissville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4711975396113576808-3879", + "name": "Poncho App Corporation", + "city": { + "name": "Montgomery", + "code": "AL", + "state": "Alabama", + "county": "Montgomery", + "display": "Al State Govt Mail" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5679333830737468086-3880", + "name": "Inrix Traffic Incorporated", + "city": { + "name": "Burlison", + "code": "TN", + "state": "Tennessee", + "county": "Tipton", + "display": "Randolph" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2713339445662830328-3881", + "name": "Fitch Corporation", + "city": { + "name": "Mount Carmel", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Connersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8364208316677997929-3882", + "name": "Allianz Company", + "city": { + "name": "Ogden", + "code": "UT", + "state": "Utah", + "county": "Weber", + "display": "Marriott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5874305133351726699-3883", + "name": "Rapid Cycle Solutions Company", + "city": { + "name": "Mechanicville", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Malta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4863310671962796001-3884", + "name": "Urban Airship Corporation", + "city": { + "name": "West Mifflin", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Pittsburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1215233309386076649-3885", + "name": "Code for America Company", + "city": { + "name": "Aspers", + "code": "PA", + "state": "Pennsylvania", + "county": "Adams", + "display": "Aspers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6816100396941669381-3886", + "name": "Allianz LLC", + "city": { + "name": "Briceville", + "code": "TN", + "state": "Tennessee", + "county": "Anderson", + "display": "Devonia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4127597020935041081-3887", + "name": "indoo.rs Corp", + "city": { + "name": "King And Queen Court House", + "code": "VA", + "state": "Virginia", + "county": "King And Queen", + "display": "King And Qn C H" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4021718388813762599-3888", + "name": "Innovest Systems LLC", + "city": { + "name": "Minerva", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Pekin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-60081713297099976-3889", + "name": "Import.io Corp", + "city": { + "name": "Cambridge", + "code": "NY", + "state": "New York", + "county": "Washington", + "display": "Cambridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6507398112007720635-3890", + "name": "SAP Corporation", + "city": { + "name": "Robinson", + "code": "IL", + "state": "Illinois", + "county": "Crawford", + "display": "Hardinville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-778114795038899280-3891", + "name": "indoo.rs Corp", + "city": { + "name": "Stowell", + "code": "TX", + "state": "Texas", + "county": "Chambers", + "display": "Stowell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4314221709666526699-3892", + "name": "Chemical Abstracts Service Corporation", + "city": { + "name": "Lanagan", + "code": "MO", + "state": "Missouri", + "county": "Mcdonald", + "display": "Lanagan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7250549321014766877-3893", + "name": "Nautilytics Inc", + "city": { + "name": "Deer Park", + "code": "AL", + "state": "Alabama", + "county": "Washington", + "display": "Seaboard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6715479563351974386-3894", + "name": "48 Factoring Incorporated", + "city": { + "name": "Saint Rose", + "code": "LA", + "state": "Louisiana", + "county": "Saint Charles", + "display": "Saint Rose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3024124659749052596-3895", + "name": "Parsons Brinckerhoff Incorporated", + "city": { + "name": "Mountainair", + "code": "NM", + "state": "New Mexico", + "county": "Torrance", + "display": "Mountainair" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1268923756090444140-3896", + "name": "Splunk LLC", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Jefferson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1291227878824186354-3897", + "name": "TransparaGov Inc", + "city": { + "name": "Kimball", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Kimball" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6988277804663930410-3898", + "name": "Rank and Filed LLC", + "city": { + "name": "Bethel", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Bethel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2463200050560000932-3899", + "name": "Credit Sesame Corp", + "city": { + "name": "Morrisville", + "code": "VT", + "state": "Vermont", + "county": "Lamoille", + "display": "Lake Lamoille" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-758739387971976115-3900", + "name": "Bing Corp", + "city": { + "name": "Swedesboro", + "code": "NJ", + "state": "New Jersey", + "county": "Gloucester", + "display": "Logan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4675192321431929902-3901", + "name": "Panjiva Inc", + "city": { + "name": "Westfield", + "code": "ME", + "state": "Maine", + "county": "Aroostook", + "display": "Westfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6668270227439905012-3902", + "name": "Thomson Reuters Corporation", + "city": { + "name": "Plummer", + "code": "MN", + "state": "Minnesota", + "county": "Red Lake", + "display": "Plummer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4868669579381336602-3903", + "name": "Innovest Systems Corp", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Mehlville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3629418982980534232-3904", + "name": "48 Factoring Corporation", + "city": { + "name": "Le Roy", + "code": "NY", + "state": "New York", + "county": "Genesee", + "display": "Le Roy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6077546458551595633-3905", + "name": "Workhands Inc", + "city": { + "name": "Montclair", + "code": "NJ", + "state": "New Jersey", + "county": "Essex", + "display": "Montclair" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8231246286622902258-3906", + "name": "Ontodia, Inc", + "city": { + "name": "Glen Riddle Lima", + "code": "PA", + "state": "Pennsylvania", + "county": "Delaware", + "display": "Glen Rdl Lima" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-128542431056355819-3907", + "name": "Equilar LLC", + "city": { + "name": "Geddes", + "code": "SD", + "state": "South Dakota", + "county": "Charles Mix", + "display": "Geddes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9119924174040846984-3908", + "name": "USSearch Corp", + "city": { + "name": "Salisbury", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Salisbury Bch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5123264011231966758-3909", + "name": "Open Data Nation LLC", + "city": { + "name": "Mchenry", + "code": "ND", + "state": "North Dakota", + "county": "Foster", + "display": "Mchenry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7232378088939902277-3910", + "name": "SigFig Incorporated", + "city": { + "name": "Boise", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Intermountain Gas Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7099182945968213429-3911", + "name": "Berkery Noyes MandASoft Incorporated", + "city": { + "name": "Wood Lake", + "code": "MN", + "state": "Minnesota", + "county": "Yellow Medicine", + "display": "Wood Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7785067856828853471-3912", + "name": "MapQuest Company", + "city": { + "name": "Salem", + "code": "NY", + "state": "New York", + "county": "Washington", + "display": "East Greenwich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2496215362177350292-3913", + "name": "Relationship Science Company", + "city": { + "name": "Bayville", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Bayville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5027170788138371156-3914", + "name": "Housefax Inc", + "city": { + "name": "West Sand Lake", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "W Sand Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8743112242199315609-3915", + "name": "LegiNation, Corp", + "city": { + "name": "Santa Elena", + "code": "TX", + "state": "Texas", + "county": "Starr", + "display": "La Gloria" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3077992430300983499-3916", + "name": "SlashDB Company", + "city": { + "name": "Narrows", + "code": "VA", + "state": "Virginia", + "county": "Giles", + "display": "Narrows" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1797915063714416144-3917", + "name": "US Green Data LLC", + "city": { + "name": "Gibson", + "code": "PA", + "state": "Pennsylvania", + "county": "Susquehanna", + "display": "Gibson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1851579584943407473-3918", + "name": "Bridgewater Corporation", + "city": { + "name": "Boron", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Boron" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7723068231472434128-3919", + "name": "Barchart Incorporated", + "city": { + "name": "Pearl River", + "code": "LA", + "state": "Louisiana", + "county": "Saint Tammany", + "display": "Pearl River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8068281800984318548-3920", + "name": "Intermap Technologies Inc", + "city": { + "name": "Bronson", + "code": "TX", + "state": "Texas", + "county": "Sabine", + "display": "Bronson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-964565867299154432-3921", + "name": "StreetEasy LLC", + "city": { + "name": "Terre Haute", + "code": "IN", + "state": "Indiana", + "county": "Vigo", + "display": "Cemar Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-294905662227813972-3922", + "name": "Thomson Reuters Incorporated", + "city": { + "name": "Sanford", + "code": "NC", + "state": "North Carolina", + "county": "Lee", + "display": "Shallowell" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1700706814252004114-3923", + "name": "Science Exchange Corp", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Ohio Dept Of Taxation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7075673398122884741-3924", + "name": "indoo.rs Corp", + "city": { + "name": "Dover", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Davidsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6938581042181483399-3925", + "name": "Geofeedia LLC", + "city": { + "name": "Albany", + "code": "MO", + "state": "Missouri", + "county": "Gentry", + "display": "Gentryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1007277438139708896-3926", + "name": "Civic Impulse LLC", + "city": { + "name": "Canon City", + "code": "CO", + "state": "Colorado", + "county": "Fremont", + "display": "Canon City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6617073221913921795-3927", + "name": "Lenddo Inc", + "city": { + "name": "Villa Ridge", + "code": "MO", + "state": "Missouri", + "county": "Franklin", + "display": "Villa Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5272186311114694405-3928", + "name": "AllState Insurance Group Corporation", + "city": { + "name": "Coolidge", + "code": "KS", + "state": "Kansas", + "county": "Hamilton", + "display": "Coolidge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3125072393695327449-3929", + "name": "Gallup Incorporated", + "city": { + "name": "Sugarcreek", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Sugarcreek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4304945698623493530-3930", + "name": "Wheaton World Wide Moving Company", + "city": { + "name": "Torrance", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Torrance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-122220443022134140-3931", + "name": "Oversight Systems Company", + "city": { + "name": "Dover Foxcroft", + "code": "ME", + "state": "Maine", + "county": "Piscataquis", + "display": "Dovr Foxcroft" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3866027915838617797-3932", + "name": "Sage Bionetworks Corp", + "city": { + "name": "Round Mountain", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Round Mtn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7470329056678039043-3933", + "name": "FlightStats Incorporated", + "city": { + "name": "Gleneden Beach", + "code": "OR", + "state": "Oregon", + "county": "Lincoln", + "display": "Gleneden Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8484330637414215671-3934", + "name": "Locavore Corporation", + "city": { + "name": "Mount Lemmon", + "code": "AZ", + "state": "Arizona", + "county": "Pima", + "display": "Mount Lemmon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1109924353925833219-3935", + "name": "Predilytics LLC", + "city": { + "name": "Grand Ridge", + "code": "IL", + "state": "Illinois", + "county": "La Salle", + "display": "Grand Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2664808471463924114-3936", + "name": "Dow Jones \u0026 Co LLC", + "city": { + "name": "Seattle", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Tukwila" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1888905065053598064-3937", + "name": "Consumer Reports Company", + "city": { + "name": "Manhattan", + "code": "KS", + "state": "Kansas", + "county": "Riley", + "display": "Manhattan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2031768245481661634-3938", + "name": "BillGuard LLC", + "city": { + "name": "Murdock", + "code": "NE", + "state": "Nebraska", + "county": "Cass", + "display": "Wabash" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8940452251792521164-3939", + "name": "Adaptive LLC", + "city": { + "name": "Savage", + "code": "MD", + "state": "Maryland", + "county": "Howard", + "display": "Savage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4191570582289154646-3940", + "name": "KLD Research Company", + "city": { + "name": "Pentress", + "code": "WV", + "state": "West Virginia", + "county": "Monongalia", + "display": "Pentress" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5259426522700221464-3941", + "name": "Civis Analytics Inc", + "city": { + "name": "Sparks", + "code": "GA", + "state": "Georgia", + "county": "Cook", + "display": "Sparks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5553563279070173618-3942", + "name": "Xignite Inc", + "city": { + "name": "Piedmont", + "code": "SD", + "state": "South Dakota", + "county": "Meade", + "display": "Grashul" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4590317438417502585-3943", + "name": "Datamyne Corp", + "city": { + "name": "Smithers", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Smithers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9090345700020338135-3944", + "name": "Splunk LLC", + "city": { + "name": "Walsenburg", + "code": "CO", + "state": "Colorado", + "county": "Huerfano", + "display": "Farisita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4584789828550190863-3945", + "name": "Lumesis, Incorporated", + "city": { + "name": "New York Mills", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "New York Mls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3638905181377728375-3946", + "name": "Avvo Inc", + "city": { + "name": "New Lebanon", + "code": "NY", + "state": "New York", + "county": "Columbia", + "display": "New Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-999348639919199252-3947", + "name": "Avvo Incorporated", + "city": { + "name": "Fort Gratiot", + "code": "MI", + "state": "Michigan", + "county": "Saint Clair", + "display": "Burtchville Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8592490710691419040-3948", + "name": "WattzOn Incorporated", + "city": { + "name": "Indianapolis", + "code": "IN", + "state": "Indiana", + "county": "Marion", + "display": "Cumberland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8660044519806538443-3949", + "name": "Loqate, LLC", + "city": { + "name": "Watertown", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Wtown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2736712251477677449-3950", + "name": "RAND Incorporated", + "city": { + "name": "Middletown", + "code": "CT", + "state": "Connecticut", + "county": "Middlesex", + "display": "Middletown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2399932804875399394-3951", + "name": "StockSmart Incorporated", + "city": { + "name": "Gwynedd", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Gwynedd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6705925318877074331-3952", + "name": "Ranku Corp", + "city": { + "name": "Willard", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Willard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7561855314819003264-3953", + "name": "HopStop Company", + "city": { + "name": "Bethel", + "code": "ME", + "state": "Maine", + "county": "Oxford", + "display": "Mason Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1282822256498040156-3954", + "name": "Way Better Patents Corporation", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Arsenal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-809308561365550258-3955", + "name": "HERE Incorporated", + "city": { + "name": "Cleveland", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Cleveland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5245724483490785685-3956", + "name": "Loqate, Company", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Lincoln Hts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5020896786988810779-3957", + "name": "Reed Elsevier Inc", + "city": { + "name": "La Follette", + "code": "TN", + "state": "Tennessee", + "county": "Campbell", + "display": "La Follette" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7492800024610769832-3958", + "name": "Arrive Labs LLC", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Xerox" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-565247750831717866-3959", + "name": "The DocGraph Journal LLC", + "city": { + "name": "Moorestown", + "code": "NJ", + "state": "New Jersey", + "county": "Burlington", + "display": "Moorestown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4034670087882953360-3960", + "name": "CARFAX Company", + "city": { + "name": "Frackville", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "State Correctional Inst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5729438841856479488-3961", + "name": "New Media Parents Company", + "city": { + "name": "Roberts", + "code": "MT", + "state": "Montana", + "county": "Carbon", + "display": "Fox" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8246475774600964827-3962", + "name": "Estately Inc", + "city": { + "name": "Indianola", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Fairview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-161334824327146910-3963", + "name": "ProPublica Incorporated", + "city": { + "name": "Arlington", + "code": "VA", + "state": "Virginia", + "county": "Arlington", + "display": "Navy Sea Systems Command" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5502612072627636627-3964", + "name": "MedWatcher Inc", + "city": { + "name": "Marathon", + "code": "NY", + "state": "New York", + "county": "Cortland", + "display": "Hunts Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6168256125284266981-3965", + "name": "OTC Markets Inc", + "city": { + "name": "Ogunquit", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "Ogunquit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7429673734216341295-3966", + "name": "LegiNation, Incorporated", + "city": { + "name": "Van Buren Point", + "code": "NY", + "state": "New York", + "county": "Chautauqua", + "display": "Van Buren Pt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5361080912544486185-3967", + "name": "Personalis Corp", + "city": { + "name": "La Veta", + "code": "CO", + "state": "Colorado", + "county": "Huerfano", + "display": "Wahatoya" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1196898841084622294-3968", + "name": "Compendia Bioscience Life Technologies Company", + "city": { + "name": "East Palestine", + "code": "OH", + "state": "Ohio", + "county": "Columbiana", + "display": "East Palestine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3487222078418855265-3969", + "name": "LoopNet LLC", + "city": { + "name": "Netarts", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Netarts Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5815011985767660377-3970", + "name": "Lenddo Corporation", + "city": { + "name": "Watsontown", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Watsonville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2463730488575103267-3971", + "name": "Kimono Labs LLC", + "city": { + "name": "Newville", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Entlerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2154348361283113973-3972", + "name": "AllState Insurance Group LLC", + "city": { + "name": "Bellflower", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Bellflower" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8762923787445626365-3973", + "name": "Seabourne Company", + "city": { + "name": "Winslow", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Tolani" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8316414656009551859-3974", + "name": "Cappex Corporation", + "city": { + "name": "Morse", + "code": "TX", + "state": "Texas", + "county": "Hansford", + "display": "Morse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1925111420848327143-3975", + "name": "Housefax LLC", + "city": { + "name": "Lawndale", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Lawndale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-455102629150587201-3976", + "name": "ProPublica Incorporated", + "city": { + "name": "Manchester", + "code": "IL", + "state": "Illinois", + "county": "Scott", + "display": "Manchester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4586317931002872743-3977", + "name": "BaleFire Global Corp", + "city": { + "name": "Bremond", + "code": "TX", + "state": "Texas", + "county": "Robertson", + "display": "Bremond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2819119587597184737-3978", + "name": "Mint Corp", + "city": { + "name": "Waseca", + "code": "MN", + "state": "Minnesota", + "county": "Waseca", + "display": "Otisco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3585929577210151539-3979", + "name": "Science Exchange Inc", + "city": { + "name": "Riverside", + "code": "WA", + "state": "Washington", + "county": "Okanogan", + "display": "Riverside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4034642591825272188-3980", + "name": "Urban Mapping, Incorporated", + "city": { + "name": "Brandenburg", + "code": "KY", + "state": "Kentucky", + "county": "Meade", + "display": "Brandenburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3301816941390265294-3981", + "name": "Rapid Cycle Solutions Inc", + "city": { + "name": "Roscoe", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Roscoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2908803204991773178-3982", + "name": "Healthgrades Inc", + "city": { + "name": "Faucett", + "code": "MO", + "state": "Missouri", + "county": "Buchanan", + "display": "Faucett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8370009913820553858-3983", + "name": "Mint Incorporated", + "city": { + "name": "Carson", + "code": "NM", + "state": "New Mexico", + "county": "Taos", + "display": "Carson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3787439814022998463-3984", + "name": "Epsilon Company", + "city": { + "name": "Lebanon", + "code": "VA", + "state": "Virginia", + "county": "Russell", + "display": "Bolton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9074768324417901401-3985", + "name": "Smartronix Corp", + "city": { + "name": "Mount Arlington", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Mount Arlington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7389698350893965124-3986", + "name": "MedWatcher Corp", + "city": { + "name": "Lost Hills", + "code": "CA", + "state": "California", + "county": "Kern", + "display": "Lost Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6193580657698284896-3987", + "name": "Docket Alarm, LLC", + "city": { + "name": "Marion", + "code": "AL", + "state": "Alabama", + "county": "Perry", + "display": "Sprott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7701494941919412478-3988", + "name": "TrueCar Corp", + "city": { + "name": "Iron", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Iron Junction" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7330020844606414844-3989", + "name": "Orlin Research Corporation", + "city": { + "name": "Mount Lemmon", + "code": "AZ", + "state": "Arizona", + "county": "Pima", + "display": "Mount Lemmon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1563959151264014522-3990", + "name": "Canon Corp", + "city": { + "name": "Moodys", + "code": "OK", + "state": "Oklahoma", + "county": "Cherokee", + "display": "Moodys" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9077785484689197803-3991", + "name": "Evidera Incorporated", + "city": { + "name": "Braymer", + "code": "MO", + "state": "Missouri", + "county": "Caldwell", + "display": "Braymer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-201856080138672311-3992", + "name": "Accenture Corporation", + "city": { + "name": "Hannibal", + "code": "NY", + "state": "New York", + "county": "Oswego", + "display": "Hannibal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-77085596682489330-3993", + "name": "Energy Solutions Forum Inc", + "city": { + "name": "Elkader", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Clayton Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3490979120450868323-3994", + "name": "HDScores, Incorporated", + "city": { + "name": "Roscoe", + "code": "MO", + "state": "Missouri", + "county": "Saint Clair", + "display": "Roscoe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6517569794825596853-3995", + "name": "SnapSense LLC", + "city": { + "name": "Gainesville", + "code": "AL", + "state": "Alabama", + "county": "Sumter", + "display": "Gainesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2769641103013381022-3996", + "name": "Weather Underground Incorporated", + "city": { + "name": "Leonard", + "code": "OK", + "state": "Oklahoma", + "county": "Tulsa", + "display": "Leonard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5464428400347090066-3997", + "name": "iFactor Consulting Company", + "city": { + "name": "Montgomery", + "code": "AL", + "state": "Alabama", + "county": "Montgomery", + "display": "Al State Govt Mail" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-895490706235811862-3998", + "name": "Arpin Van Lines Corporation", + "city": { + "name": "Offutt A F B", + "code": "NE", + "state": "Nebraska", + "county": "Sarpy", + "display": "Offutt Air Force Base" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2612374165539454459-3999", + "name": "Compared Care LLC", + "city": { + "name": "King And Queen Court House", + "code": "VA", + "state": "Virginia", + "county": "King And Queen", + "display": "King And Qn C H" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1634340810693553112-4000", + "name": "CB Insights LLC", + "city": { + "name": "Kensett", + "code": "IA", + "state": "Iowa", + "county": "Worth", + "display": "Bolan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1172355261129850551-4001", + "name": "Kaiser Permanante Incorporated", + "city": { + "name": "Sterling", + "code": "IL", + "state": "Illinois", + "county": "Whiteside", + "display": "Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1691254903069180389-4002", + "name": "Vitals Company", + "city": { + "name": "Mount Olivet", + "code": "KY", + "state": "Kentucky", + "county": "Robertson", + "display": "Mount Olivet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3550359613254158301-4003", + "name": "Graematter, Company", + "city": { + "name": "Gobles", + "code": "MI", + "state": "Michigan", + "county": "Van Buren", + "display": "Gobles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7862010607049304134-4004", + "name": "WeMakeItSafer LLC", + "city": { + "name": "Jackhorn", + "code": "KY", + "state": "Kentucky", + "county": "Letcher", + "display": "Jackhorn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1872775746747194380-4005", + "name": "PEV4me.com Inc", + "city": { + "name": "Nuremberg", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Nuremberg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4132160523853829376-4006", + "name": "Social Health Insights Inc", + "city": { + "name": "Scranton", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Dickson City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4155011281438218729-4007", + "name": "United Mayflower Corporation", + "city": { + "name": "Newell", + "code": "SD", + "state": "South Dakota", + "county": "Butte", + "display": "Cedar Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6350552638851042723-4008", + "name": "Aureus Sciences Company", + "city": { + "name": "Augusta", + "code": "GA", + "state": "Georgia", + "county": "Richmond", + "display": "Railroad Retirement Board" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8631307857516161321-4009", + "name": "Open Data Nation Inc", + "city": { + "name": "Mcalester", + "code": "OK", + "state": "Oklahoma", + "county": "Pittsburg", + "display": "Haywood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6221277196835986221-4010", + "name": "Asset4 Corp", + "city": { + "name": "Cold Brook", + "code": "NY", + "state": "New York", + "county": "Herkimer", + "display": "Morehouse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2902175827384212409-4011", + "name": "CitySourced Corporation", + "city": { + "name": "Leonard", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Addison Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4685033966693563684-4012", + "name": "Rank and Filed Incorporated", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Wilmington Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5501875395628758261-4013", + "name": "Earth Networks Corp", + "city": { + "name": "Center Line", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Center Line" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8436705943281119745-4014", + "name": "Marlin Alter and Associates Incorporated", + "city": { + "name": "Banner", + "code": "WY", + "state": "Wyoming", + "county": "Sheridan", + "display": "Story" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6136714738430927524-4015", + "name": "PlanetEcosystems Company", + "city": { + "name": "Hamburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Edenburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6042261365402807635-4016", + "name": "IBM Corp", + "city": { + "name": "Savanna", + "code": "IL", + "state": "Illinois", + "county": "Carroll", + "display": "Savanna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7364604208506148638-4017", + "name": "Predilytics Incorporated", + "city": { + "name": "Newland", + "code": "NC", + "state": "North Carolina", + "county": "Avery", + "display": "Stamey Branch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9213412854418657663-4018", + "name": "National Van Lines Company", + "city": { + "name": "Farmland", + "code": "IN", + "state": "Indiana", + "county": "Randolph", + "display": "Farmland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8783799923133714059-4019", + "name": "Accela Incorporated", + "city": { + "name": "Littleton", + "code": "IL", + "state": "Illinois", + "county": "Schuyler", + "display": "Littleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2624574951019807176-4020", + "name": "FlightView Incorporated", + "city": { + "name": "Maple Plain", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Minnetrista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2354172729627508316-4021", + "name": "FlightStats Company", + "city": { + "name": "Bedford", + "code": "OH", + "state": "Ohio", + "county": "Cuyahoga", + "display": "Oakwood Vlg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1895542422811988232-4022", + "name": "Reed Elsevier Incorporated", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Commercial National Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9165551161178950919-4023", + "name": "TransparaGov LLC", + "city": { + "name": "Greenbrier", + "code": "TN", + "state": "Tennessee", + "county": "Robertson", + "display": "Greenbrier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6916888504090999702-4024", + "name": "OpenGov LLC", + "city": { + "name": "Sullivan", + "code": "IL", + "state": "Illinois", + "county": "Moultrie", + "display": "Sullivan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8130624387618205692-4025", + "name": "Spokeo LLC", + "city": { + "name": "Walterboro", + "code": "SC", + "state": "South Carolina", + "county": "Colleton", + "display": "Walterboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7048466776760112280-4026", + "name": "Barchart Inc", + "city": { + "name": "Airville", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Airville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6502690809404826948-4027", + "name": "Science Exchange Inc", + "city": { + "name": "Machesney Park", + "code": "IL", + "state": "Illinois", + "county": "Winnebago", + "display": "Machesney Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-305078039326720565-4028", + "name": "The Govtech Fund Corporation", + "city": { + "name": "Nottingham", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Nottingham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6884617135438299231-4029", + "name": "HDScores, Corporation", + "city": { + "name": "Perry", + "code": "IA", + "state": "Iowa", + "county": "Dallas", + "display": "Berkley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5975160035557072817-4030", + "name": "Construction Monitor Corporation", + "city": { + "name": "Wilson", + "code": "AR", + "state": "Arkansas", + "county": "Mississippi", + "display": "Wilson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5318279005677518292-4031", + "name": "Palantir Technologies Corp", + "city": { + "name": "Duluth", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Proctor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4113336660547141036-4032", + "name": "Stormpulse Corp", + "city": { + "name": "South Seaville", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "South Seaville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6208146193637388275-4033", + "name": "People Power Inc", + "city": { + "name": "Aspers", + "code": "PA", + "state": "Pennsylvania", + "county": "Adams", + "display": "Aspers" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5638444302594171176-4034", + "name": "Earthquake Alert Corp", + "city": { + "name": "Eastland", + "code": "TX", + "state": "Texas", + "county": "Eastland", + "display": "Eastland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2504829982507055193-4035", + "name": "Geofeedia Corp", + "city": { + "name": "Wabasso", + "code": "MN", + "state": "Minnesota", + "county": "Redwood", + "display": "Wabasso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1609040976662792199-4036", + "name": "Relationship Science Inc", + "city": { + "name": "Chester", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Chester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4928266269018592987-4037", + "name": "PeerJ Company", + "city": { + "name": "Markle", + "code": "IN", + "state": "Indiana", + "county": "Wells", + "display": "Markle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7319442475745332201-4038", + "name": "GuideStar Incorporated", + "city": { + "name": "Wanette", + "code": "OK", + "state": "Oklahoma", + "county": "Pottawatomie", + "display": "Wanette" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8033901268008749140-4039", + "name": "Healthgrades Corporation", + "city": { + "name": "Belle Plaine", + "code": "KS", + "state": "Kansas", + "county": "Sumner", + "display": "Belle Plaine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-843037726609133446-4040", + "name": "Forrester Research Company", + "city": { + "name": "Apopka", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Apopka" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7299421740849155386-4041", + "name": "Gallup Company", + "city": { + "name": "Sesser", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Goode" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6369714796249072041-4042", + "name": "Trintech Corporation", + "city": { + "name": "North Stratford", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Columbia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2327621950193968412-4043", + "name": "Optensity Company", + "city": { + "name": "Woodrow", + "code": "CO", + "state": "Colorado", + "county": "Washington", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9059666870796902051-4044", + "name": "The Advisory Board Company Inc", + "city": { + "name": "Reidsville", + "code": "NC", + "state": "North Carolina", + "county": "Rockingham", + "display": "Monroeton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7808785226754203934-4045", + "name": "Practice Fusion LLC", + "city": { + "name": "Avoca", + "code": "NY", + "state": "New York", + "county": "Steuben", + "display": "Avoca" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7846785622773408987-4046", + "name": "USSearch Corporation", + "city": { + "name": "Pleasant Shade", + "code": "TN", + "state": "Tennessee", + "county": "Smith", + "display": "Pleasant Shade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3982899023536322899-4047", + "name": "Zebu Compliance Solutions Corporation", + "city": { + "name": "Lebanon", + "code": "SD", + "state": "South Dakota", + "county": "Potter", + "display": "Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4032488658916162555-4048", + "name": "Weather Underground LLC", + "city": { + "name": "Deptford", + "code": "NJ", + "state": "New Jersey", + "county": "Gloucester", + "display": "Jericho" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5534861409696472637-4049", + "name": "Fidelity Investments LLC", + "city": { + "name": "Bastian", + "code": "VA", + "state": "Virginia", + "county": "Bland", + "display": "Cove Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4699512218040578175-4050", + "name": "Wolfram Research Corporation", + "city": { + "name": "Gravity", + "code": "IA", + "state": "Iowa", + "county": "Taylor", + "display": "Gravity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8228526631197480194-4051", + "name": "Compared Care LLC", + "city": { + "name": "Stone Mountain", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "St Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7171541016573692215-4052", + "name": "OpportunitySpace, Corp", + "city": { + "name": "Tylertown", + "code": "MS", + "state": "Mississippi", + "county": "Walthall", + "display": "Tylertown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1770236325719585422-4053", + "name": "Municode Company", + "city": { + "name": "Gilmer", + "code": "TX", + "state": "Texas", + "county": "Upshur", + "display": "Soules Chapel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1604569069911061261-4054", + "name": "Civic Impulse LLC", + "city": { + "name": "Allen", + "code": "KS", + "state": "Kansas", + "county": "Lyon", + "display": "Bushong" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1979199379981713557-4055", + "name": "SlashDB Company", + "city": { + "name": "Ovett", + "code": "MS", + "state": "Mississippi", + "county": "Jones", + "display": "Ouetti" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5148506998678421067-4056", + "name": "Factset Corporation", + "city": { + "name": "Memphis", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "International Paper Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7213081739757888028-4057", + "name": "Wheaton World Wide Moving Incorporated", + "city": { + "name": "West Hartford", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "W Htfd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7309489585484596991-4058", + "name": "Wheaton World Wide Moving Company", + "city": { + "name": "Monroe", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Monroe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1190178542093565550-4059", + "name": "EMC LLC", + "city": { + "name": "Estero", + "code": "FL", + "state": "Florida", + "county": "Lee", + "display": "Estero" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8032500460861523024-4060", + "name": "BetterLesson Corp", + "city": { + "name": "Marble Falls", + "code": "AR", + "state": "Arkansas", + "county": "Newton", + "display": "Dogpatch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-355746849579266611-4061", + "name": "Cambridge Semantics Incorporated", + "city": { + "name": "Athens", + "code": "IL", + "state": "Illinois", + "county": "Menard", + "display": "Athens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2692324512311629950-4062", + "name": "StreetCred Software, LLC", + "city": { + "name": "Marbury", + "code": "MD", + "state": "Maryland", + "county": "Charles", + "display": "Rison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2233892370966126871-4063", + "name": "Boundless Inc", + "city": { + "name": "Lucerne", + "code": "IN", + "state": "Indiana", + "county": "Cass", + "display": "Lucerne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4720515024374760803-4064", + "name": "WaterSmart Software LLC", + "city": { + "name": "Greenacres", + "code": "WA", + "state": "Washington", + "county": "Spokane", + "display": "Spo Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3992602095377222629-4065", + "name": "College Abacus, an ECMC initiative Inc", + "city": { + "name": "Holdingford", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Holdingford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2958463970408040636-4066", + "name": "Palantir Technologies Inc", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Westwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6357055979195379777-4067", + "name": "CitySourced Corporation", + "city": { + "name": "Riegelwood", + "code": "NC", + "state": "North Carolina", + "county": "Columbus", + "display": "Acme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-872127889253167306-4068", + "name": "Environmental Data Resources Corp", + "city": { + "name": "Millston", + "code": "WI", + "state": "Wisconsin", + "county": "Jackson", + "display": "Millston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8393597987289406031-4069", + "name": "Microsoft Windows Azure Marketplace LLC", + "city": { + "name": "Cambridge", + "code": "VT", + "state": "Vermont", + "county": "Chittenden", + "display": "Cambridgeboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2145377086251530474-4070", + "name": "Ez-XBRL LLC", + "city": { + "name": "Oakwood", + "code": "GA", + "state": "Georgia", + "county": "Hall", + "display": "Oakwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7707301053552263279-4071", + "name": "Connotate LLC", + "city": { + "name": "West Rutland", + "code": "VT", + "state": "Vermont", + "county": "Rutland", + "display": "Clarendn Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4541615045021928043-4072", + "name": "Wolfram Research Inc", + "city": { + "name": "Courtland", + "code": "VA", + "state": "Virginia", + "county": "Southampton", + "display": "Courtland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1112145459516858595-4073", + "name": "Child Care Desk Company", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "Knickerbocker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6902442572798754834-4074", + "name": "iFactor Consulting Corp", + "city": { + "name": "Edenville", + "code": "MI", + "state": "Michigan", + "county": "Midland", + "display": "Edenville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5880087525991507675-4075", + "name": "Embark Inc", + "city": { + "name": "New Lebanon", + "code": "NY", + "state": "New York", + "county": "Columbia", + "display": "Lebanon Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5618021111759761404-4076", + "name": "Mercaris Incorporated", + "city": { + "name": "Whatley", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Gosport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6496756602967468201-4077", + "name": "Legal Science Partners Corp", + "city": { + "name": "Saint Michael", + "code": "ND", + "state": "North Dakota", + "county": "Benson", + "display": "St Michael" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-267522429736370275-4078", + "name": "iTriage LLC", + "city": { + "name": "Lanagan", + "code": "MO", + "state": "Missouri", + "county": "Mcdonald", + "display": "Lanagan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5201825097848090873-4079", + "name": "Locavore LLC", + "city": { + "name": "Mount Lookout", + "code": "WV", + "state": "West Virginia", + "county": "Nicholas", + "display": "Mount Lookout" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1670522014353144846-4080", + "name": "Loqate, Inc", + "city": { + "name": "Coal Township", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Excelsior" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4643118136112397693-4081", + "name": "Votizen Corp", + "city": { + "name": "Meigs", + "code": "GA", + "state": "Georgia", + "county": "Thomas", + "display": "Hinsonton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7624367679864463878-4082", + "name": "VisualDoD, LLC", + "city": { + "name": "Westville", + "code": "OH", + "state": "Ohio", + "county": "Champaign", + "display": "Westville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4316907716025790453-4083", + "name": "Factual Corp", + "city": { + "name": "Apopka", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Apopka" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2941487682919863404-4084", + "name": "Weather Underground Corp", + "city": { + "name": "Edwards", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "South Edwards" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-411148928113157129-4085", + "name": "realtor.com Incorporated", + "city": { + "name": "Madison", + "code": "VA", + "state": "Virginia", + "county": "Madison", + "display": "Banco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8225139419763530723-4086", + "name": "SigFig LLC", + "city": { + "name": "Huntsville", + "code": "MO", + "state": "Missouri", + "county": "Randolph", + "display": "Huntsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5241321804756924741-4087", + "name": "Liberty Mutual Insurance Cos Corporation", + "city": { + "name": "Summerland Key", + "code": "FL", + "state": "Florida", + "county": "Monroe", + "display": "Sugarloaf Key" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5255732658552191451-4088", + "name": "DataWeave Company", + "city": { + "name": "Townsend", + "code": "TN", + "state": "Tennessee", + "county": "Blount", + "display": "Townsend" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7745532098037707364-4089", + "name": "AccuWeather Company", + "city": { + "name": "Union", + "code": "NE", + "state": "Nebraska", + "county": "Cass", + "display": "Union" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3852770570426943190-4090", + "name": "BaleFire Global LLC", + "city": { + "name": "Senatobia", + "code": "MS", + "state": "Mississippi", + "county": "Tate", + "display": "Northwest Junior College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2957714213033577844-4091", + "name": "BetterLesson Corporation", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Ny Agr And Mkts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2465165877059700210-4092", + "name": "mHealthCoach Corp", + "city": { + "name": "Estherville", + "code": "IA", + "state": "Iowa", + "county": "Emmet", + "display": "Estherville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6791479167753620707-4093", + "name": "Workhands Inc", + "city": { + "name": "Beecher City", + "code": "IL", + "state": "Illinois", + "county": "Effingham", + "display": "Wrights Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8910045995310736351-4094", + "name": "Climate Inc", + "city": { + "name": "Water Valley", + "code": "MS", + "state": "Mississippi", + "county": "Yalobusha", + "display": "Pine Flat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6636521727785823267-4095", + "name": "REI Systems LLC", + "city": { + "name": "Moab", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Castleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3000267451972927124-4096", + "name": "Personalis Corporation", + "city": { + "name": "Cleveland", + "code": "TN", + "state": "Tennessee", + "county": "Bradley", + "display": "Clevelnd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3113876221409679440-4097", + "name": "TopCoder Incorporated", + "city": { + "name": "Haynesville", + "code": "LA", + "state": "Louisiana", + "county": "Claiborne", + "display": "Blackburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3257104386742137709-4098", + "name": "MicroBilt Company", + "city": { + "name": "North Little Rock", + "code": "AR", + "state": "Arkansas", + "county": "Pulaski", + "display": "Veterans Administration Faci" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6730614508163407646-4099", + "name": "Inovalon LLC", + "city": { + "name": "Starkville", + "code": "MS", + "state": "Mississippi", + "county": "Oktibbeha", + "display": "Osborn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5231738633410819107-4100", + "name": "Overture Technologies Inc", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "N Kansas City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8915639320936146100-4101", + "name": "ConnectEDU Company", + "city": { + "name": "Stockbridge", + "code": "GA", + "state": "Georgia", + "county": "Henry", + "display": "Stockbridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-680852063551118741-4102", + "name": "Splunk Inc", + "city": { + "name": "Putney", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "E Dummerston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-150625997349239886-4103", + "name": "IFI CLAIMS Patent Services Incorporated", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Arden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8199451336801144529-4104", + "name": "realtor.com Inc", + "city": { + "name": "Saint Matthews", + "code": "SC", + "state": "South Carolina", + "county": "Calhoun", + "display": "Fort Motte" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-159794424785673665-4105", + "name": "Whitby Group Corporation", + "city": { + "name": "Water Mill", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Watermill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3133297326151033555-4106", + "name": "KLD Research Inc", + "city": { + "name": "Koyukuk", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Koyukuk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8791479348838153588-4107", + "name": "Docket Alarm, Inc", + "city": { + "name": "Thompson", + "code": "UT", + "state": "Utah", + "county": "Grand", + "display": "Thompson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-581537093952181571-4108", + "name": "StreetEasy LLC", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Fleet" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-777143119742742865-4109", + "name": "ConnectEDU Company", + "city": { + "name": "Catharpin", + "code": "VA", + "state": "Virginia", + "county": "Prince William", + "display": "Catharpin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3660753741178873120-4110", + "name": "Junyo Corporation", + "city": { + "name": "Maitland", + "code": "MO", + "state": "Missouri", + "county": "Holt", + "display": "Maitland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1918071675268484983-4111", + "name": "Workhands LLC", + "city": { + "name": "Andrews", + "code": "TX", + "state": "Texas", + "county": "Andrews", + "display": "Andrews" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7565348563291879665-4112", + "name": "xDayta Corp", + "city": { + "name": "Miller", + "code": "MO", + "state": "Missouri", + "county": "Lawrence", + "display": "Miller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5707596477903956916-4113", + "name": "Onvia Inc", + "city": { + "name": "Beaver Creek", + "code": "MN", + "state": "Minnesota", + "county": "Rock", + "display": "Beaver Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2084093888726807454-4114", + "name": "FlightView Inc", + "city": { + "name": "Ovett", + "code": "MS", + "state": "Mississippi", + "county": "Jones", + "display": "Ouetti" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4392924444694012713-4115", + "name": "Graebel Van Lines Inc", + "city": { + "name": "Shepherd", + "code": "MT", + "state": "Montana", + "county": "Yellowstone", + "display": "Shepherd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7485671414252263460-4116", + "name": "Paxata Inc", + "city": { + "name": "Alameda", + "code": "CA", + "state": "California", + "county": "Alameda", + "display": "Alameda Pt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6167509246177457514-4117", + "name": "Zillow Corp", + "city": { + "name": "Lansing", + "code": "MI", + "state": "Michigan", + "county": "Ingham", + "display": "Secretary Of State" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6745368018451919254-4118", + "name": "TuvaLabs Company", + "city": { + "name": "Danville", + "code": "KS", + "state": "Kansas", + "county": "Harper", + "display": "Danville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2162031588056560364-4119", + "name": "Innovest Systems LLC", + "city": { + "name": "Dripping Springs", + "code": "TX", + "state": "Texas", + "county": "Hays", + "display": "Dripping Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4096050328910929541-4120", + "name": "MetLife Corp", + "city": { + "name": "Maywood", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Broadview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1004906482773138605-4121", + "name": "Rapid Cycle Solutions LLC", + "city": { + "name": "Verndale", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Wing River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1894898506065921841-4122", + "name": "Oliver Wyman Incorporated", + "city": { + "name": "Charleston", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Charleston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8539348308314349147-4123", + "name": "Cloudspyre Corp", + "city": { + "name": "Boncarbo", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Boncarbo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4014137487516650001-4124", + "name": "Legal Science Partners Company", + "city": { + "name": "Freistatt", + "code": "MO", + "state": "Missouri", + "county": "Lawrence", + "display": "Freistatt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3173100757225308965-4125", + "name": "Gallup Company", + "city": { + "name": "Winona", + "code": "MN", + "state": "Minnesota", + "county": "Winona", + "display": "Pickwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5392059562853959269-4126", + "name": "Pave Inc", + "city": { + "name": "Gainesville", + "code": "TX", + "state": "Texas", + "county": "Cooke", + "display": "Oak Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8556651639214531526-4127", + "name": "PatientsLikeMe Company", + "city": { + "name": "Whiting", + "code": "KS", + "state": "Kansas", + "county": "Jackson", + "display": "Whiting" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7852430890675389915-4128", + "name": "The Bridgespan Group Incorporated", + "city": { + "name": "Youngsville", + "code": "NM", + "state": "New Mexico", + "county": "Rio Arriba", + "display": "Rito De Las Sillas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7112110811847085983-4129", + "name": "Equifax Corporation", + "city": { + "name": "Schenley", + "code": "PA", + "state": "Pennsylvania", + "county": "Armstrong", + "display": "Schenley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-773094149103896616-4130", + "name": "Allianz Corporation", + "city": { + "name": "Lane City", + "code": "TX", + "state": "Texas", + "county": "Wharton", + "display": "Lane City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3227882945950675757-4131", + "name": "Telenav Incorporated", + "city": { + "name": "Long Lake", + "code": "WI", + "state": "Wisconsin", + "county": "Florence", + "display": "Nelma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4399540194051430477-4132", + "name": "Kaiser Permanante Incorporated", + "city": { + "name": "Eastland", + "code": "TX", + "state": "Texas", + "county": "Eastland", + "display": "Eastland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2905869947346649612-4133", + "name": "karmadata Corporation", + "city": { + "name": "Kingston Mines", + "code": "IL", + "state": "Illinois", + "county": "Peoria", + "display": "Kingston Mine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2964443167273226288-4134", + "name": "People Power Inc", + "city": { + "name": "Lincoln", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Lincoln Cntr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2128724763348057170-4135", + "name": "BetterLesson Incorporated", + "city": { + "name": "Elkader", + "code": "IA", + "state": "Iowa", + "county": "Clayton", + "display": "Osborne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6691168630545014921-4136", + "name": "Locavore Corp", + "city": { + "name": "Granville Summit", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Granville Smt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4899455848372872205-4137", + "name": "Canon Inc", + "city": { + "name": "Tres Piedras", + "code": "NM", + "state": "New Mexico", + "county": "Taos", + "display": "Tres Piedras" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3338640671475598730-4138", + "name": "Locavore LLC", + "city": { + "name": "Riverhead", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Riverhead" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5668328931256624736-4139", + "name": "Copyright Clearance Center LLC", + "city": { + "name": "Millston", + "code": "WI", + "state": "Wisconsin", + "county": "Jackson", + "display": "Millston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3213513559126858803-4140", + "name": "Informatica Company", + "city": { + "name": "Ladysmith", + "code": "WI", + "state": "Wisconsin", + "county": "Rusk", + "display": "Ladysmith" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3374064280382742732-4141", + "name": "Housefax Inc", + "city": { + "name": "Melba", + "code": "ID", + "state": "Idaho", + "county": "Canyon", + "display": "Stoddard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1632880344949819225-4142", + "name": "Compared Care Inc", + "city": { + "name": "Wagner", + "code": "SD", + "state": "South Dakota", + "county": "Charles Mix", + "display": "Wagner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6591474796896324499-4143", + "name": "Vimo Company", + "city": { + "name": "Pleasant Shade", + "code": "TN", + "state": "Tennessee", + "county": "Smith", + "display": "Pleasant Shade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-303485665817253156-4144", + "name": "Golden Helix Inc", + "city": { + "name": "Viola", + "code": "AR", + "state": "Arkansas", + "county": "Fulton", + "display": "Viola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8997535657237877625-4145", + "name": "Ceiba Solutions LLC", + "city": { + "name": "Madison", + "code": "IN", + "state": "Indiana", + "county": "Jefferson", + "display": "Madison" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6244219013199117908-4146", + "name": "NERA Economic Consulting Company", + "city": { + "name": "Amana", + "code": "IA", + "state": "Iowa", + "county": "Iowa", + "display": "Amana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2922711757856186461-4147", + "name": "BlackRock Company", + "city": { + "name": "Smarr", + "code": "GA", + "state": "Georgia", + "county": "Monroe", + "display": "Smarr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9202391034905986385-4148", + "name": "Berkery Noyes MandASoft Company", + "city": { + "name": "Howes", + "code": "SD", + "state": "South Dakota", + "county": "Meade", + "display": "Bridger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-831513624714044275-4149", + "name": "BizVizz Inc", + "city": { + "name": "Blue Ball", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Blue Ball" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7336645832297893938-4150", + "name": "STILLWATER SUPERCOMPUTING INC LLC", + "city": { + "name": "Nimitz", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Nimitz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8227183215767605044-4151", + "name": "Equifax Corp", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Mtn Green" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1866844653197072209-4152", + "name": "Business Monitor International Company", + "city": { + "name": "Waco", + "code": "KY", + "state": "Kentucky", + "county": "Madison", + "display": "College Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6458884797131777648-4153", + "name": "Google Maps Company", + "city": { + "name": "Rockland", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "Rockland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8839379150800072770-4154", + "name": "Arpin Van Lines Incorporated", + "city": { + "name": "Topeka", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Goofy Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-980995045168220150-4155", + "name": "Charles Schwab Corporation", + "city": { + "name": "Newark", + "code": "NJ", + "state": "New Jersey", + "county": "Essex", + "display": "Bank Of New York" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3734035932585858424-4156", + "name": "WattzOn LLC", + "city": { + "name": "Chambersburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Franklin", + "display": "Sunbeam" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5184401391855178343-4157", + "name": "Civis Analytics Corp", + "city": { + "name": "Jericho", + "code": "VT", + "state": "Vermont", + "county": "Chittenden", + "display": "Jericho" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5697934367581999984-4158", + "name": "ProgrammableWeb Company", + "city": { + "name": "Hampden", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Newburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4705781718076250635-4159", + "name": "MuckRock.com Corp", + "city": { + "name": "Middleburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Snyder", + "display": "Meiser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3872953845026952569-4160", + "name": "Simple Energy Company", + "city": { + "name": "Brainard", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Brainard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1435116959133425862-4161", + "name": "Climate Corp", + "city": { + "name": "Lincolnton", + "code": "GA", + "state": "Georgia", + "county": "Lincoln", + "display": "Leathersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7453075233568083539-4162", + "name": "CoolClimate Inc", + "city": { + "name": "Fields Landing", + "code": "CA", + "state": "California", + "county": "Humboldt", + "display": "Fields Landing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6557777788898410662-4163", + "name": "CGI LLC", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Stoddard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6805780235976308690-4164", + "name": "Unigo LLC", + "city": { + "name": "El Paso", + "code": "TX", + "state": "Texas", + "county": "El Paso", + "display": "El Paso Water Utilities" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3451743154497956213-4165", + "name": "Marlin \u0026 Associates Company", + "city": { + "name": "Brookhaven", + "code": "MS", + "state": "Mississippi", + "county": "Lincoln", + "display": "West Lincoln" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1464645141749818017-4166", + "name": "BillGuard Incorporated", + "city": { + "name": "Thayne", + "code": "WY", + "state": "Wyoming", + "county": "Lincoln", + "display": "Star Vly Rnch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1783078884226228545-4167", + "name": "Propeller Health Incorporated", + "city": { + "name": "Stockville", + "code": "NE", + "state": "Nebraska", + "county": "Frontier", + "display": "Stockville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4555109613099284888-4168", + "name": "BuildZoom Corp", + "city": { + "name": "New Canaan", + "code": "CT", + "state": "Connecticut", + "county": "Fairfield", + "display": "New Canaan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3039703614045496712-4169", + "name": "Civic Insight LLC", + "city": { + "name": "Kings Canyon National Pk", + "code": "CA", + "state": "California", + "county": "Tulare", + "display": "Kings Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3339606016778658165-4170", + "name": "Equilar Corporation", + "city": { + "name": "Houston", + "code": "DE", + "state": "Delaware", + "county": "Kent", + "display": "Houston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8712365408772643008-4171", + "name": "Charles River Associates LLC", + "city": { + "name": "Chittenango", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Sullivan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-266857142339787311-4172", + "name": "Castle Biosciences Corp", + "city": { + "name": "Averill Park", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Burden Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2547436177076531790-4173", + "name": "Solar Census LLC", + "city": { + "name": "Helotes", + "code": "TX", + "state": "Texas", + "county": "Bexar", + "display": "Grey Forest" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7432465549507309630-4174", + "name": "Outline Corp", + "city": { + "name": "Chester", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Chester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8481832397443134204-4175", + "name": "Arpin Van Lines Inc", + "city": { + "name": "Balta", + "code": "ND", + "state": "North Dakota", + "county": "Pierce", + "display": "Balta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4168854495163763163-4176", + "name": "Healthline LLC", + "city": { + "name": "Gilberts", + "code": "IL", + "state": "Illinois", + "county": "Kane", + "display": "Gilberts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-198248293825854729-4177", + "name": "Housefax LLC", + "city": { + "name": "Bear River City", + "code": "UT", + "state": "Utah", + "county": "Box Elder", + "display": "Bear River City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2283788275271073649-4178", + "name": "Unigo LLC", + "city": { + "name": "West Wardsboro", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "Stratton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2585859333322018261-4179", + "name": "IVES Group LLC", + "city": { + "name": "Middle Point", + "code": "OH", + "state": "Ohio", + "county": "Van Wert", + "display": "Middle Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1495658099438413035-4180", + "name": "Vizzuality LLC", + "city": { + "name": "Faulkton", + "code": "SD", + "state": "South Dakota", + "county": "Faulk", + "display": "Burkmere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7360715895130807254-4181", + "name": "Ecodesk Inc", + "city": { + "name": "Saint Paul", + "code": "AR", + "state": "Arkansas", + "county": "Madison", + "display": "Saint Paul" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4365065301583525389-4182", + "name": "Code for America Inc", + "city": { + "name": "Sadsburyville", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Sadsburyville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3676943879923305432-4183", + "name": "Morningstar, Corporation", + "city": { + "name": "Lackland A F B", + "code": "TX", + "state": "Texas", + "county": "Bexar", + "display": "Kelly Usa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3018205194929090574-4184", + "name": "DemystData Corp", + "city": { + "name": "Delphi Falls", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Delphi Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4120313646179042526-4185", + "name": "Funding Circle Inc", + "city": { + "name": "Crane", + "code": "IN", + "state": "Indiana", + "county": "Martin", + "display": "Crane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4125771067619459185-4186", + "name": "Innovest Systems Incorporated", + "city": { + "name": "Parkers Lake", + "code": "KY", + "state": "Kentucky", + "county": "Mccreary", + "display": "Parkers Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7759137708516925364-4187", + "name": "Ez-XBRL Corp", + "city": { + "name": "Howard Lake", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Howard Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8064313554102570534-4188", + "name": "Consumer Reports Incorporated", + "city": { + "name": "Long Beach", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "East Long Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8113263847502899778-4189", + "name": "Quertle Company", + "city": { + "name": "Half Way", + "code": "MO", + "state": "Missouri", + "county": "Polk", + "display": "Goodson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7688926129992811797-4190", + "name": "indoo.rs Corp", + "city": { + "name": "Kenton", + "code": "OH", + "state": "Ohio", + "county": "Hardin", + "display": "Kenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2473432895417496892-4191", + "name": "Stormpulse Company", + "city": { + "name": "Middle Amana", + "code": "IA", + "state": "Iowa", + "county": "Iowa", + "display": "Middle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-113477657679707124-4192", + "name": "National Van Lines Inc", + "city": { + "name": "Sunbury", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Mile Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5768535574815924441-4193", + "name": "Level One Technologies LLC", + "city": { + "name": "El Mirage", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "El Mirage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7926332263564710686-4194", + "name": "TrialX Inc", + "city": { + "name": "Bolckow", + "code": "MO", + "state": "Missouri", + "county": "Andrew", + "display": "Bolckow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8167081647083032097-4195", + "name": "FlightAware LLC", + "city": { + "name": "Noxen", + "code": "PA", + "state": "Pennsylvania", + "county": "Wyoming", + "display": "Forkston Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4141976027348996990-4196", + "name": "Palantir Technologies Company", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Castle Shannon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8258837774521176185-4197", + "name": "Reed Elsevier LLC", + "city": { + "name": "Lomira", + "code": "WI", + "state": "Wisconsin", + "county": "Dodge", + "display": "Knowles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5815341672185019503-4198", + "name": "FlightView Corporation", + "city": { + "name": "Grenville", + "code": "NM", + "state": "New Mexico", + "county": "Union", + "display": "Grenville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1307152376028933383-4199", + "name": "Equal Speed Company", + "city": { + "name": "Gilbert", + "code": "IA", + "state": "Iowa", + "county": "Story", + "display": "Gilbert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8085135199185186148-4200", + "name": "KidAdmit, Corp", + "city": { + "name": "Covington", + "code": "OH", + "state": "Ohio", + "county": "Miami", + "display": "Covington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4107694427994788216-4201", + "name": "Clean Power Finance Inc", + "city": { + "name": "Sacramento", + "code": "CA", + "state": "California", + "county": "Sacramento", + "display": "Ca Dept Motor Vehicle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-386943534902070659-4202", + "name": "Kyruus LLC", + "city": { + "name": "Port Hadlock", + "code": "WA", + "state": "Washington", + "county": "Jefferson", + "display": "Irondale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8356303314085308693-4203", + "name": "realtor.com Corp", + "city": { + "name": "Virginia City", + "code": "NV", + "state": "Nevada", + "county": "Storey", + "display": "Virginia City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-864937624173604140-4204", + "name": "Atlas Van Lines Company", + "city": { + "name": "Chelsea", + "code": "MI", + "state": "Michigan", + "county": "Washtenaw", + "display": "Sylvan Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3197094066498287065-4205", + "name": "LegiStorm Inc", + "city": { + "name": "De Kalb", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Hodgson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-372072971954873086-4206", + "name": "USAA Group LLC", + "city": { + "name": "East Andover", + "code": "NH", + "state": "New Hampshire", + "county": "Merrimack", + "display": "E Andover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6947884871894851693-4207", + "name": "Civic Impulse Corporation", + "city": { + "name": "Langlois", + "code": "OR", + "state": "Oregon", + "county": "Curry", + "display": "Langlois" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6147293106616349196-4208", + "name": "PlotWatt Inc", + "city": { + "name": "Saint Louis", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Westwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4453346101102364155-4209", + "name": "United Mayflower LLC", + "city": { + "name": "Nuevo", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Nuevo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8625985804930332770-4210", + "name": "Equal Speed LLC", + "city": { + "name": "Eagle", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Eagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4099546582837394412-4211", + "name": "Healthline Company", + "city": { + "name": "Mapleton", + "code": "IL", + "state": "Illinois", + "county": "Peoria", + "display": "Mapleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4871526677843426098-4212", + "name": "BetterLesson Corp", + "city": { + "name": "Franklin", + "code": "TN", + "state": "Tennessee", + "county": "Williamson", + "display": "Kingfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6145378819146129817-4213", + "name": "IPHIX Inc", + "city": { + "name": "Half Way", + "code": "MO", + "state": "Missouri", + "county": "Polk", + "display": "Goodson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6900603572796572609-4214", + "name": "PEV4me.com Inc", + "city": { + "name": "Bellbrook", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Beavercrk Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7393819298950986826-4215", + "name": "ZocDoc Inc", + "city": { + "name": "Elgin", + "code": "TN", + "state": "Tennessee", + "county": "Scott", + "display": "Elgin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5411230817567836379-4216", + "name": "CoreLogic Corp", + "city": { + "name": "Lindale", + "code": "GA", + "state": "Georgia", + "county": "Floyd", + "display": "Lindale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3153009224665982389-4217", + "name": "Experian Corp", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Parsons" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2238569681300579679-4218", + "name": "Connotate Company", + "city": { + "name": "Jal", + "code": "NM", + "state": "New Mexico", + "county": "Lea", + "display": "Bennett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-821908525918622263-4219", + "name": "Marinexplore, Corp", + "city": { + "name": "Maidens", + "code": "VA", + "state": "Virginia", + "county": "Goochland", + "display": "Dabneys" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1150509169709415305-4220", + "name": "iTriage Corporation", + "city": { + "name": "Goldendale", + "code": "WA", + "state": "Washington", + "county": "Klickitat", + "display": "Maryhill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5213573565065941435-4221", + "name": "Navico Inc", + "city": { + "name": "Galva", + "code": "IL", + "state": "Illinois", + "county": "Henry", + "display": "Galva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6232516679392513753-4222", + "name": "CareSet Systems Incorporated", + "city": { + "name": "Northbrook", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Northbrook" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8376081643456033423-4223", + "name": "LOVELAND Technologies Inc", + "city": { + "name": "Azalea", + "code": "OR", + "state": "Oregon", + "county": "Douglas", + "display": "Azalea" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2147052158843880807-4224", + "name": "TrialX Inc", + "city": { + "name": "Lanham", + "code": "MD", + "state": "Maryland", + "county": "Prince Georges", + "display": "Glenarden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4874984908880658780-4225", + "name": "StreamLink Software Corp", + "city": { + "name": "West Grove", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "West Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8057906358955275330-4226", + "name": "Bekins Corp", + "city": { + "name": "Spanish Fork", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Lake Shore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8598170496298396941-4227", + "name": "Import.io Corporation", + "city": { + "name": "Marlborough", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Marlborough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9069299569638429191-4228", + "name": "Uber Incorporated", + "city": { + "name": "Rockland", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "Rockland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-67159990607972824-4229", + "name": "Impaq International Company", + "city": { + "name": "Chelsea", + "code": "MI", + "state": "Michigan", + "county": "Washtenaw", + "display": "Sylvan Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9048341583092035036-4230", + "name": "Kroll Bond Ratings Agency Incorporated", + "city": { + "name": "Beaumont", + "code": "KY", + "state": "Kentucky", + "county": "Metcalfe", + "display": "Beaumont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-631542449346830014-4231", + "name": "Dun \u0026 Bradstreet Inc", + "city": { + "name": "Oakland", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Oakland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3113692847381544996-4232", + "name": "Abt Associates Incorporated", + "city": { + "name": "Fort Wayne", + "code": "IN", + "state": "Indiana", + "county": "Allen", + "display": "Southtown Mall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2708742425483043233-4233", + "name": "Smart Utility Systems Corporation", + "city": { + "name": "Sterling", + "code": "IL", + "state": "Illinois", + "county": "Whiteside", + "display": "Sterling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-523137099496854109-4234", + "name": "Epsilon Incorporated", + "city": { + "name": "Pasadena", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Shared Firm Zip Code" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1107229767169105577-4235", + "name": "NERA Economic Consulting Corp", + "city": { + "name": "Baytown", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Mont Belvieu" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2984254324386320683-4236", + "name": "Cambridge Semantics LLC", + "city": { + "name": "Kersey", + "code": "CO", + "state": "Colorado", + "county": "Weld", + "display": "Kersey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4291946209512453872-4237", + "name": "WattzOn Inc", + "city": { + "name": "Kenna", + "code": "WV", + "state": "West Virginia", + "county": "Jackson", + "display": "Kentuck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2658319922549702325-4238", + "name": "VitalChek Corporation", + "city": { + "name": "Nashville", + "code": "NC", + "state": "North Carolina", + "county": "Nash", + "display": "Momeyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5050253948894144695-4239", + "name": "Scale Unlimited LLC", + "city": { + "name": "Houghton", + "code": "IA", + "state": "Iowa", + "county": "Lee", + "display": "Houghton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5740310331003952264-4240", + "name": "Municode Incorporated", + "city": { + "name": "Tullahoma", + "code": "TN", + "state": "Tennessee", + "county": "Coffee", + "display": "Dickel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3598540799136975059-4241", + "name": "Predilytics Incorporated", + "city": { + "name": "Memphis", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "International Paper Co" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8329469225013273458-4242", + "name": "PatientsLikeMe Corp", + "city": { + "name": "Oak Grove", + "code": "LA", + "state": "Louisiana", + "county": "West Carroll", + "display": "Chickasaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4318552592500431206-4243", + "name": "Dabo Health Corp", + "city": { + "name": "Keyport", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Cliffwood Bch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6383585245410313199-4244", + "name": "Cerner Corporation", + "city": { + "name": "Grinnell", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Newburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8504318534870582666-4245", + "name": "Exversion Corp", + "city": { + "name": "Randolph Center", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "Randolph Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4375476757655588205-4246", + "name": "IVES Group Incorporated", + "city": { + "name": "NSL", + "code": "UT", + "state": "Utah", + "county": "Davis", + "display": "Nsl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6275147220924435035-4247", + "name": "Science Exchange Inc", + "city": { + "name": "Sutter Creek", + "code": "CA", + "state": "California", + "county": "Amador", + "display": "Sutter Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2283869465647972258-4248", + "name": "Weather Underground LLC", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Ohio Dept Of Taxation" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-668873899885723210-4249", + "name": "Earthquake Alert Corp", + "city": { + "name": "Guyton", + "code": "GA", + "state": "Georgia", + "county": "Effingham", + "display": "Pineora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8685251208025816075-4250", + "name": "Wheaton World Wide Moving Corp", + "city": { + "name": "Mohnton", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Alleghenyville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2969248224687148560-4251", + "name": "AutoGrid Systems Company", + "city": { + "name": "Norwich", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "Woods Corners" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3020508955706901651-4252", + "name": "Lilly Open Innovation Drug Discovery Inc", + "city": { + "name": "Brattleboro", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "Brattleboro Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7895065323425861377-4253", + "name": "Brightscope Incorporated", + "city": { + "name": "Boomer", + "code": "WV", + "state": "West Virginia", + "county": "Fayette", + "display": "Boomer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5866479894515087870-4254", + "name": "StreetEasy Corp", + "city": { + "name": "Inverness", + "code": "MS", + "state": "Mississippi", + "county": "Sunflower", + "display": "Inverness" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5659062930122986757-4255", + "name": "Munetrix Company", + "city": { + "name": "Grinnell", + "code": "IA", + "state": "Iowa", + "county": "Poweshiek", + "display": "Newburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6128408690582902165-4256", + "name": "Zonability Incorporated", + "city": { + "name": "Newhall", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Newhall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4567130275734661693-4257", + "name": "Vitals Incorporated", + "city": { + "name": "San Juan", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Lopezville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5471293668648390140-4258", + "name": "Iodine Corp", + "city": { + "name": "Anderson", + "code": "AK", + "state": "Alaska", + "county": "Denali", + "display": "Anderson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2292085353248086978-4259", + "name": "karmadata Corporation", + "city": { + "name": "Conneaut Lake", + "code": "PA", + "state": "Pennsylvania", + "county": "Crawford", + "display": "Conneaut Lake Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2408585903543496169-4260", + "name": "Charles River Associates Corp", + "city": { + "name": "Machesney Park", + "code": "IL", + "state": "Illinois", + "county": "Winnebago", + "display": "Machesney Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6746325070837957533-4261", + "name": "Tendril Company", + "city": { + "name": "Winthrop", + "code": "AR", + "state": "Arkansas", + "county": "Little River", + "display": "Winthrop" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7888052238038017163-4262", + "name": "BaleFire Global LLC", + "city": { + "name": "Highgate Springs", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Highgate Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3994557345909313034-4263", + "name": "Innography Inc", + "city": { + "name": "Elliott", + "code": "IA", + "state": "Iowa", + "county": "Montgomery", + "display": "Elliott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3330579728370718658-4264", + "name": "Child Care Desk Corp", + "city": { + "name": "Julian", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Julian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6065483291744344161-4265", + "name": "Quid Corp", + "city": { + "name": "Craley", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Craley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-597238887422946390-4266", + "name": "PolicyMap Inc", + "city": { + "name": "Lehi", + "code": "UT", + "state": "Utah", + "county": "Utah", + "display": "Saratoga Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1195584967025216397-4267", + "name": "Amida Technology Solutions Incorporated", + "city": { + "name": "Garrison", + "code": "NY", + "state": "New York", + "county": "Putnam", + "display": "Manitou" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3050031731552714088-4268", + "name": "PayScale, Corp", + "city": { + "name": "Monroe", + "code": "GA", + "state": "Georgia", + "county": "Walton", + "display": "Monroe" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6801903043181155446-4269", + "name": "ASC Partners LLC", + "city": { + "name": "Frankston", + "code": "TX", + "state": "Texas", + "county": "Anderson", + "display": "Berryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4265806196838211529-4270", + "name": "Seabourne Incorporated", + "city": { + "name": "Mulberry Grove", + "code": "IL", + "state": "Illinois", + "county": "Bond", + "display": "Mulberry Grv" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5837814512825710107-4271", + "name": "SmartProcure Corporation", + "city": { + "name": "West Terre Haute", + "code": "IN", + "state": "Indiana", + "county": "Vigo", + "display": "Sandford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6121040092588389252-4272", + "name": "PYA Analytics Company", + "city": { + "name": "Davenport", + "code": "NY", + "state": "New York", + "county": "Delaware", + "display": "Sturges Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7222541260263536534-4273", + "name": "TuvaLabs Incorporated", + "city": { + "name": "Yap", + "code": "FM", + "state": "Federated States of Micronesia", + "county": "Federated States Of Micro", + "display": "Yap Caroline Islands" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6868160892157167132-4274", + "name": "ConnectEDU LLC", + "city": { + "name": "Littleton", + "code": "CO", + "state": "Colorado", + "county": "Jefferson", + "display": "Columbine Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4438640066079673780-4275", + "name": "mHealthCoach LLC", + "city": { + "name": "Shippensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Pinola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-871887141658630558-4276", + "name": "DataMade Inc", + "city": { + "name": "Oshkosh", + "code": "NE", + "state": "Nebraska", + "county": "Garden", + "display": "Oshkosh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-755431684146354166-4277", + "name": "Adaptive Inc", + "city": { + "name": "Sebastian", + "code": "FL", + "state": "Florida", + "county": "Brevard", + "display": "Micco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-647415043653186772-4278", + "name": "Earth Networks Incorporated", + "city": { + "name": "Savanna", + "code": "IL", + "state": "Illinois", + "county": "Carroll", + "display": "Savanna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4141372181853812702-4279", + "name": "Think Computer Corporation", + "city": { + "name": "Marlin", + "code": "WA", + "state": "Washington", + "county": "Grant", + "display": "Krupp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6646951181946253509-4280", + "name": "Fidelity Investments Corporation", + "city": { + "name": "Williamsburg", + "code": "KY", + "state": "Kentucky", + "county": "Whitley", + "display": "Cumberlnd Clg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8357011285286565884-4281", + "name": "Practice Fusion Company", + "city": { + "name": "Abbeville", + "code": "LA", + "state": "Louisiana", + "county": "Vermilion", + "display": "Meaux" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8322527470397583605-4282", + "name": "PEV4me.com LLC", + "city": { + "name": "Fairview", + "code": "OK", + "state": "Oklahoma", + "county": "Major", + "display": "Orienta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4124534503955945817-4283", + "name": "How's My Offer? Company", + "city": { + "name": "Fresno", + "code": "OH", + "state": "Ohio", + "county": "Coshocton", + "display": "New Bedford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4390238993078773719-4284", + "name": "Apextech Corp", + "city": { + "name": "Trout Creek", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Trout Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7541775597248545568-4285", + "name": "SlashDB Incorporated", + "city": { + "name": "Medina", + "code": "ND", + "state": "North Dakota", + "county": "Stutsman", + "display": "Crystal Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7782240252573286393-4286", + "name": "LegiNation, Corporation", + "city": { + "name": "Harrold", + "code": "SD", + "state": "South Dakota", + "county": "Hughes", + "display": "Harrold" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3645517107563802387-4287", + "name": "Stormpulse Company", + "city": { + "name": "Normal", + "code": "AL", + "state": "Alabama", + "county": "Madison", + "display": "Normal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1443724628196768607-4288", + "name": "Junyo Company", + "city": { + "name": "Kokomo", + "code": "MS", + "state": "Mississippi", + "county": "Marion", + "display": "Darbun" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-524446239005507118-4289", + "name": "Rank and Filed Corporation", + "city": { + "name": "West Point", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "West Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4727194284501583990-4290", + "name": "PublicEngines Company", + "city": { + "name": "Murphysboro", + "code": "IL", + "state": "Illinois", + "county": "Jackson", + "display": "Somerset" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-181726936835249794-4291", + "name": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7745952771104247799-4292", + "name": "Esri Company", + "city": { + "name": "Patuxent River", + "code": "MD", + "state": "Maryland", + "county": "Saint Marys", + "display": "Patuxent River Naval Air Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6388260601814584011-4293", + "name": "Adobe Digital Government Corporation", + "city": { + "name": "Waterloo", + "code": "IA", + "state": "Iowa", + "county": "Black Hawk", + "display": "Washburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3836301147072103022-4294", + "name": "Outline Inc", + "city": { + "name": "Saint Rose", + "code": "LA", + "state": "Louisiana", + "county": "Saint Charles", + "display": "Saint Rose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1305834826686730245-4295", + "name": "Experian Corporation", + "city": { + "name": "Marthaville", + "code": "LA", + "state": "Louisiana", + "county": "Natchitoches", + "display": "Ajax" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8014451700944505660-4296", + "name": "Datamyne Company", + "city": { + "name": "Olympia Fields", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Olympia Flds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-272857146258801852-4297", + "name": "Google Maps Company", + "city": { + "name": "New Castle", + "code": "PA", + "state": "Pennsylvania", + "county": "Lawrence", + "display": "Castle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8244631715819070539-4298", + "name": "Avvo Corp", + "city": { + "name": "Koyukuk", + "code": "AK", + "state": "Alaska", + "county": "Yukon Koyukuk", + "display": "Koyukuk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5661763033739766350-4299", + "name": "Revaluate Corporation", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Pgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9054700443648150279-4300", + "name": "GovTribe Corporation", + "city": { + "name": "Philadelphia", + "code": "PA", + "state": "Pennsylvania", + "county": "Philadelphia", + "display": "Mid City East" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2429143264746591558-4301", + "name": "eScholar Corporation", + "city": { + "name": "Saline", + "code": "LA", + "state": "Louisiana", + "county": "Bienville", + "display": "Chestnut" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5373881045787867909-4302", + "name": "Intermap Technologies Inc", + "city": { + "name": "Troy", + "code": "MT", + "state": "Montana", + "county": "Lincoln", + "display": "Troy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6237433171693485854-4303", + "name": "Eat Shop Sleep Company", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Thunderbolt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4683051576028306536-4304", + "name": "CareSet Systems Company", + "city": { + "name": "Webb", + "code": "MS", + "state": "Mississippi", + "county": "Tallahatchie", + "display": "Webb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7193293181064332669-4305", + "name": "Persint Corp", + "city": { + "name": "San Juan", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Lopezville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3189493243948503240-4306", + "name": "NuCivic Company", + "city": { + "name": "Cadiz", + "code": "KY", + "state": "Kentucky", + "county": "Trigg", + "display": "Linton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3474778977569804863-4307", + "name": "CareSet Systems Inc", + "city": { + "name": "North Bloomfield", + "code": "OH", + "state": "Ohio", + "county": "Trumbull", + "display": "Lockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-376069413832377877-4308", + "name": "Earth Networks Corporation", + "city": { + "name": "Nimitz", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Nimitz" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8160113694266256057-4309", + "name": "Remi Company", + "city": { + "name": "Middleburgh", + "code": "NY", + "state": "New York", + "county": "Schoharie", + "display": "Breakabeen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5470539136308788641-4310", + "name": "Estately Inc", + "city": { + "name": "Berthoud", + "code": "CO", + "state": "Colorado", + "county": "Larimer", + "display": "Berthoud" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2409820006162844317-4311", + "name": "Graematter, LLC", + "city": { + "name": "Gloster", + "code": "MS", + "state": "Mississippi", + "county": "Amite", + "display": "Bewelcome" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9172809745020869325-4312", + "name": "Cloudmade Corp", + "city": { + "name": "Long Grove", + "code": "IA", + "state": "Iowa", + "county": "Scott", + "display": "Wildwood Camp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4240793812069545428-4313", + "name": "The Govtech Fund Inc", + "city": { + "name": "Athens", + "code": "WI", + "state": "Wisconsin", + "county": "Marathon", + "display": "Milan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5002935656122311302-4314", + "name": "Porch Inc", + "city": { + "name": "Nahant", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Nahant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6781133454859342551-4315", + "name": "BuildZoom Corporation", + "city": { + "name": "Smithland", + "code": "KY", + "state": "Kentucky", + "county": "Livingston", + "display": "Carrsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1187344795560882595-4316", + "name": "The Schork Report Corp", + "city": { + "name": "Catoosa", + "code": "OK", + "state": "Oklahoma", + "county": "Rogers", + "display": "Fair Oaks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4310339485554953527-4317", + "name": "Level One Technologies Corp", + "city": { + "name": "Chapmanville", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Chapmanville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7724864012932123013-4318", + "name": "Exversion Company", + "city": { + "name": "Hansen", + "code": "ID", + "state": "Idaho", + "county": "Twin Falls", + "display": "Rock Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2585159822558121786-4319", + "name": "Vimo Company", + "city": { + "name": "Porcupine", + "code": "SD", + "state": "South Dakota", + "county": "Shannon", + "display": "Rockyford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4297911971083918044-4320", + "name": "Intermap Technologies Inc", + "city": { + "name": "Cedar Grove", + "code": "NC", + "state": "North Carolina", + "county": "Orange", + "display": "Cedar Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-136840646226958681-4321", + "name": "iMedicare Inc", + "city": { + "name": "Lincoln", + "code": "MO", + "state": "Missouri", + "county": "Benton", + "display": "Lincoln" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7926534894234126472-4322", + "name": "LOGIXDATA, Corp", + "city": { + "name": "Laramie", + "code": "WY", + "state": "Wyoming", + "county": "Albany", + "display": "Bosler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5855747648665226797-4323", + "name": "Ensco Corporation", + "city": { + "name": "Whatley", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Gosport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3844049851971591537-4324", + "name": "Civic Insight Company", + "city": { + "name": "Emigrant Gap", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Emigrant Gap" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6618373608029587072-4325", + "name": "Robinson + Yu Company", + "city": { + "name": "Emerson", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Emerson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3371770644583885420-4326", + "name": "StreamLink Software Corporation", + "city": { + "name": "Canaan", + "code": "VT", + "state": "Vermont", + "county": "Essex", + "display": "Canaan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7006437483515481138-4327", + "name": "StreetCred Software, Company", + "city": { + "name": "Stone Creek", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Stone Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2073065634418303124-4328", + "name": "LexisNexis Corporation", + "city": { + "name": "Fergus Falls", + "code": "MN", + "state": "Minnesota", + "county": "Otter Tail", + "display": "Fergus Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5742597353863629273-4329", + "name": "Inrix Traffic LLC", + "city": { + "name": "Baltimore", + "code": "MD", + "state": "Maryland", + "county": "Baltimore City", + "display": "Social Security Administrat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3601438469962544435-4330", + "name": "Think Computer Corporation", + "city": { + "name": "Scottdale", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "Scottdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2533953268636835631-4331", + "name": "USSearch Corporation", + "city": { + "name": "Pollok", + "code": "TX", + "state": "Texas", + "county": "Angelina", + "display": "Redtown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3558120213124920148-4332", + "name": "ASC Partners Corp", + "city": { + "name": "Stockholm", + "code": "SD", + "state": "South Dakota", + "county": "Grant", + "display": "Stockholm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7370336909189769375-4333", + "name": "GovTribe Inc", + "city": { + "name": "West Point", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "West Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1121372676913409021-4334", + "name": "SimpleTuition Incorporated", + "city": { + "name": "Sikeston", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Sikeston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9025528766085307556-4335", + "name": "Legal Science Partners Company", + "city": { + "name": "Wenona", + "code": "IL", + "state": "Illinois", + "county": "Marshall", + "display": "Garfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6873465951968642030-4336", + "name": "indoo.rs Company", + "city": { + "name": "Bloomington", + "code": "IL", + "state": "Illinois", + "county": "Mclean", + "display": "Bloomington Normal Airport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4702586369876889904-4337", + "name": "Amazon Web Services Incorporated", + "city": { + "name": "Young America", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Young America" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6718025433944781037-4338", + "name": "Microsoft Windows Azure Marketplace Inc", + "city": { + "name": "Monroe", + "code": "LA", + "state": "Louisiana", + "county": "Ouachita", + "display": "Bosco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3833284167683092619-4339", + "name": "Outline Corp", + "city": { + "name": "Summitville", + "code": "OH", + "state": "Ohio", + "county": "Columbiana", + "display": "Summitville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8789522344340115807-4340", + "name": "Equifax LLC", + "city": { + "name": "Rancho Cucamonga", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Cucamonga" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5012404060439156025-4341", + "name": "Rand McNally Incorporated", + "city": { + "name": "Avondale", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Avondale-Goodyear" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2867322181936390622-4342", + "name": "PublicEngines Company", + "city": { + "name": "Conover", + "code": "NC", + "state": "North Carolina", + "county": "Catawba", + "display": "Conover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4579381060794737829-4343", + "name": "Sage Bionetworks Inc", + "city": { + "name": "Shidler", + "code": "OK", + "state": "Oklahoma", + "county": "Osage", + "display": "Foraker" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8235039874837878988-4344", + "name": "Politify LLC", + "city": { + "name": "South Whitley", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Luther" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4480545448773521656-4345", + "name": "S\u0026P Capital IQ Inc", + "city": { + "name": "Bath", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Lynchburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2237335171586873259-4346", + "name": "Cambridge Information Group Corp", + "city": { + "name": "Bruno", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Bruno" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8764901745431848692-4347", + "name": "PIXIA Corp", + "city": { + "name": "East Livermore", + "code": "ME", + "state": "Maine", + "county": "Androscoggin", + "display": "E Livermore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4213595429664328712-4348", + "name": "FutureAdvisor Company", + "city": { + "name": "Chehalis", + "code": "WA", + "state": "Washington", + "county": "Lewis", + "display": "Marys Corner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3746670920149452094-4349", + "name": "Social Health Insights Company", + "city": { + "name": "Belt", + "code": "MT", + "state": "Montana", + "county": "Cascade", + "display": "Armington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6980725463373556613-4350", + "name": "TrueCar Corp", + "city": { + "name": "Gold Creek", + "code": "MT", + "state": "Montana", + "county": "Powell", + "display": "Gold Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8220588579649762764-4351", + "name": "SlashDB Corporation", + "city": { + "name": "Marquette", + "code": "MI", + "state": "Michigan", + "county": "Marquette", + "display": "Marquette" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6973633317041909209-4352", + "name": "Think Computer Company", + "city": { + "name": "Coal City", + "code": "IL", + "state": "Illinois", + "county": "Grundy", + "display": "Eileen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3470649947363517939-4353", + "name": "Politify Corporation", + "city": { + "name": "Lillian", + "code": "AL", + "state": "Alabama", + "county": "Baldwin", + "display": "Lillian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3386704755049633258-4354", + "name": "Predilytics Company", + "city": { + "name": "Hannawa Falls", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "Hannawa Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7114521167781302785-4355", + "name": "Avvo Inc", + "city": { + "name": "Wooton", + "code": "KY", + "state": "Kentucky", + "county": "Leslie", + "display": "Frew" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7068163674458401268-4356", + "name": "BillGuard Corp", + "city": { + "name": "Painesville", + "code": "OH", + "state": "Ohio", + "county": "Lake", + "display": "Painesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-612300636680669373-4357", + "name": "POPVOX Inc", + "city": { + "name": "El Paso", + "code": "TX", + "state": "Texas", + "county": "El Paso", + "display": "El Paso" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3468532859112313402-4358", + "name": "Connotate Corporation", + "city": { + "name": "Hot Springs National Park", + "code": "AR", + "state": "Arkansas", + "county": "Garland", + "display": "Pleasant Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4503292138022541963-4359", + "name": "Civic Impulse Inc", + "city": { + "name": "Bristol", + "code": "VT", + "state": "Vermont", + "county": "Addison", + "display": "Downingville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8481210067352682691-4360", + "name": "FlightAware Incorporated", + "city": { + "name": "Thorp", + "code": "WI", + "state": "Wisconsin", + "county": "Clark", + "display": "Thorp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-745566112203112927-4361", + "name": "YourMapper Inc", + "city": { + "name": "Newport", + "code": "KY", + "state": "Kentucky", + "county": "Campbell", + "display": "Newport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6942550262093957496-4362", + "name": "S\u0026P Capital IQ Corporation", + "city": { + "name": "Cape Coral", + "code": "FL", + "state": "Florida", + "county": "Lee", + "display": "Cape Coral S" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4571238859542503658-4363", + "name": "AccuWeather Incorporated", + "city": { + "name": "Squaw Valley", + "code": "CA", + "state": "California", + "county": "Fresno", + "display": "Squaw Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3112617634647763359-4364", + "name": "Solar Census Corporation", + "city": { + "name": "New Lebanon", + "code": "NY", + "state": "New York", + "county": "Columbia", + "display": "Lebanon Spg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1046216883441047236-4365", + "name": "Brightscope LLC", + "city": { + "name": "West Monroe", + "code": "LA", + "state": "Louisiana", + "county": "Ouachita", + "display": "Olinkraft" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5272425846249759065-4366", + "name": "Atlas Van Lines Incorporated", + "city": { + "name": "Julian", + "code": "NE", + "state": "Nebraska", + "county": "Nemaha", + "display": "Johnson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5952822771195429582-4367", + "name": "PlaceILive.com Corp", + "city": { + "name": "Natchitoches", + "code": "LA", + "state": "Louisiana", + "county": "Natchitoches", + "display": "Northwestern" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1740112564021367601-4368", + "name": "Glassy Media Company", + "city": { + "name": "Eustis", + "code": "NE", + "state": "Nebraska", + "county": "Frontier", + "display": "Eustis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9144606812326692045-4369", + "name": "Lawdragon Corporation", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Pgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2520558773850890613-4370", + "name": "Moody's Corp", + "city": { + "name": "Starkweather", + "code": "ND", + "state": "North Dakota", + "county": "Ramsey", + "display": "Starkweather" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6186859109020601005-4371", + "name": "JJ Keller Corp", + "city": { + "name": "Winchester", + "code": "TN", + "state": "Tennessee", + "county": "Franklin", + "display": "Winchester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6413110699676294475-4372", + "name": "Noveda Technologies Corp", + "city": { + "name": "Annapolis", + "code": "MD", + "state": "Maryland", + "county": "Anne Arundel", + "display": "Sherwood Frst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5940271303006253420-4373", + "name": "Recargo LLC", + "city": { + "name": "Safety Harbor", + "code": "FL", + "state": "Florida", + "county": "Pinellas", + "display": "Safety Harbor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2847897323382959357-4374", + "name": "Recargo Corporation", + "city": { + "name": "Mathis", + "code": "TX", + "state": "Texas", + "county": "San Patricio", + "display": "San Patricio" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4290912089667917766-4375", + "name": "TrialTrove Corporation", + "city": { + "name": "Windsor", + "code": "OH", + "state": "Ohio", + "county": "Ashtabula", + "display": "Windsor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8139501958046497094-4376", + "name": "Science Exchange Incorporated", + "city": { + "name": "Crossville", + "code": "IL", + "state": "Illinois", + "county": "White", + "display": "Phillipstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2389155737599988754-4377", + "name": "People Power Corp", + "city": { + "name": "Muskegon", + "code": "MI", + "state": "Michigan", + "county": "Muskegon", + "display": "Muskegon Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4615118447353420632-4378", + "name": "CitySourced LLC", + "city": { + "name": "Florence", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Florence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2367233451842278143-4379", + "name": "KidAdmit, Inc", + "city": { + "name": "Enterprise", + "code": "KS", + "state": "Kansas", + "county": "Dickinson", + "display": "Enterprise" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7367225356131983915-4380", + "name": "Geolytics LLC", + "city": { + "name": "Bluffton", + "code": "SC", + "state": "South Carolina", + "county": "Beaufort", + "display": "Pritchardville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8917200583370976185-4381", + "name": "iRecycle LLC", + "city": { + "name": "Troup", + "code": "TX", + "state": "Texas", + "county": "Smith", + "display": "Griffin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8923859297648267097-4382", + "name": "Standard and Poor's Corp", + "city": { + "name": "Olyphant", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Sturges" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3554673091538121983-4383", + "name": "Aunt Bertha, LLC", + "city": { + "name": "Riegelwood", + "code": "NC", + "state": "North Carolina", + "county": "Columbus", + "display": "Acme" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3868714465575067232-4384", + "name": "Foursquare Corp", + "city": { + "name": "Wheeler", + "code": "IL", + "state": "Illinois", + "county": "Jasper", + "display": "Wheeler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3430773446994831237-4385", + "name": "ConnectEDU Company", + "city": { + "name": "Bridgeton", + "code": "NJ", + "state": "New Jersey", + "county": "Cumberland", + "display": "Upper Deerfield Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-771288643227585150-4386", + "name": "Granicus Corp", + "city": { + "name": "Mcdaniel", + "code": "MD", + "state": "Maryland", + "county": "Talbot", + "display": "Mcdaniel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5019652715095910053-4387", + "name": "CoreLogic Inc", + "city": { + "name": "Mc Clellanville", + "code": "SC", + "state": "South Carolina", + "county": "Charleston", + "display": "Mc Clellanville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7810847856039313183-4388", + "name": "CareSet Systems Inc", + "city": { + "name": "Putney", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "Putney" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1437905231936103730-4389", + "name": "Estately LLC", + "city": { + "name": "Dover", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Dover" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6155721419788362313-4390", + "name": "TuvaLabs Corp", + "city": { + "name": "Mcdaniel", + "code": "MD", + "state": "Maryland", + "county": "Talbot", + "display": "Mcdaniel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6649830033022959116-4391", + "name": "KLD Research Corporation", + "city": { + "name": "Woodrow", + "code": "CO", + "state": "Colorado", + "county": "Washington", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5156844319411182680-4392", + "name": "IVES Group Incorporated", + "city": { + "name": "Harleton", + "code": "TX", + "state": "Texas", + "county": "Harrison", + "display": "Harleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3903232286243934206-4393", + "name": "SpeSo Health LLC", + "city": { + "name": "Fork", + "code": "MD", + "state": "Maryland", + "county": "Baltimore", + "display": "Fork" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4406723317076168204-4394", + "name": "Munetrix Corporation", + "city": { + "name": "Leesburg", + "code": "OH", + "state": "Ohio", + "county": "Highland", + "display": "Samantha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4723184296075487687-4395", + "name": "Fastcase LLC", + "city": { + "name": "Washburn", + "code": "IL", + "state": "Illinois", + "county": "Marshall", + "display": "Washburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4288150904554185075-4396", + "name": "Honest Buildings Company", + "city": { + "name": "Dushore", + "code": "PA", + "state": "Pennsylvania", + "county": "Sullivan", + "display": "Wilmot Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1675728563148032492-4397", + "name": "Code for America Corporation", + "city": { + "name": "Shippensburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Mowersville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7289922809132225021-4398", + "name": "Synthicity Corporation", + "city": { + "name": "Rockville", + "code": "NE", + "state": "Nebraska", + "county": "Sherman", + "display": "Bristol" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9201850047686113286-4399", + "name": "Chemical Abstracts Service Incorporated", + "city": { + "name": "Columbia", + "code": "SC", + "state": "South Carolina", + "county": "Richland", + "display": "Farrow Terrace" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5565954147221890111-4400", + "name": "People Power LLC", + "city": { + "name": "Carson City", + "code": "NV", + "state": "Nevada", + "county": "Carson City", + "display": "Carson City Mall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7845169007144496327-4401", + "name": "Poncho App Inc", + "city": { + "name": "Elyria", + "code": "OH", + "state": "Ohio", + "county": "Lorain", + "display": "Elyria" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5412949506180733488-4402", + "name": "InnoCentive Incorporated", + "city": { + "name": "Northampton", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "Northampton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5211532404245806432-4403", + "name": "Predilytics LLC", + "city": { + "name": "Montpelier Station", + "code": "VA", + "state": "Virginia", + "county": "Orange", + "display": "Montpelier Station" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4019521422792149658-4404", + "name": "College Board Corporation", + "city": { + "name": "Plymouth", + "code": "OH", + "state": "Ohio", + "county": "Huron", + "display": "New Pittsburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1846459700602564650-4405", + "name": "SAS Corp", + "city": { + "name": "Orland Park", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Orland Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1411404334870540915-4406", + "name": "Atlas Van Lines Company", + "city": { + "name": "Savannah", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Wilmington Is" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4186066107110837966-4407", + "name": "Rapid Cycle Solutions Inc", + "city": { + "name": "Wellsville", + "code": "KS", + "state": "Kansas", + "county": "Franklin", + "display": "Wellsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4042585090227397680-4408", + "name": "NextBus LLC", + "city": { + "name": "Page", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Lake Powell Mart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7682658908912769310-4409", + "name": "Epsilon Incorporated", + "city": { + "name": "Biddeford Pool", + "code": "ME", + "state": "Maine", + "county": "York", + "display": "Biddeford Pl" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7818827369389547845-4410", + "name": "Personal, Company", + "city": { + "name": "Atwater", + "code": "OH", + "state": "Ohio", + "county": "Portage", + "display": "Atwater" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-291711804294888715-4411", + "name": "Sophic Systems Alliance Corporation", + "city": { + "name": "Plummer", + "code": "MN", + "state": "Minnesota", + "county": "Red Lake", + "display": "Plummer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2942077215474613867-4412", + "name": "Palantir Technologies Incorporated", + "city": { + "name": "Newbury", + "code": "MA", + "state": "Massachusetts", + "county": "Essex", + "display": "Newburyport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3100146988833380227-4413", + "name": "iMedicare Corp", + "city": { + "name": "Cambridge", + "code": "NY", + "state": "New York", + "county": "Washington", + "display": "Cambridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-418660825636291635-4414", + "name": "Enigma.io Corporation", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "So Pole" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4794797094364804759-4415", + "name": "PYA Analytics LLC", + "city": { + "name": "Green Mountain", + "code": "NC", + "state": "North Carolina", + "county": "Yancey", + "display": "Green Mt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2271259437540075629-4416", + "name": "SnapSense LLC", + "city": { + "name": "Florence", + "code": "AL", + "state": "Alabama", + "county": "Lauderdale", + "display": "Univ Of North Ala" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-300484863769534413-4417", + "name": "Sage Bionetworks LLC", + "city": { + "name": "Fort Necessity", + "code": "LA", + "state": "Louisiana", + "county": "Franklin", + "display": "Fort Necessity" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2200291720393842806-4418", + "name": "TagniFi Incorporated", + "city": { + "name": "Center Ridge", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Center Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6683755355754089113-4419", + "name": "Science Exchange Corporation", + "city": { + "name": "Terry", + "code": "MS", + "state": "Mississippi", + "county": "Hinds", + "display": "Terry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8035513319692442361-4420", + "name": "Lilly Open Innovation Drug Discovery Company", + "city": { + "name": "Winona", + "code": "MN", + "state": "Minnesota", + "county": "Winona", + "display": "Pickwick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1572974657136276272-4421", + "name": "BillGuard Corporation", + "city": { + "name": "Burnham", + "code": "PA", + "state": "Pennsylvania", + "county": "Mifflin", + "display": "Burnham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9127535368733635777-4422", + "name": "Impaq International Incorporated", + "city": { + "name": "Stone Mountain", + "code": "GA", + "state": "Georgia", + "county": "Dekalb", + "display": "St Mountain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3908799065550504312-4423", + "name": "Brightscope Company", + "city": { + "name": "Jenison", + "code": "MI", + "state": "Michigan", + "county": "Ottawa", + "display": "Georgetown Tp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3270543530960769436-4424", + "name": "Energy Solutions Forum Inc", + "city": { + "name": "Newville", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Lower Mifflin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2021015933510411773-4425", + "name": "Sage Bionetworks LLC", + "city": { + "name": "Las Vegas", + "code": "NV", + "state": "Nevada", + "county": "Clark", + "display": "Nevada Power" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7430250551534422844-4426", + "name": "T. Rowe Price Corporation", + "city": { + "name": "Salem", + "code": "NY", + "state": "New York", + "county": "Washington", + "display": "East Greenwich" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8594896889358178281-4427", + "name": "TagniFi LLC", + "city": { + "name": "Essex Junction", + "code": "VT", + "state": "Vermont", + "county": "Chittenden", + "display": "Brookside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6408885157449401522-4428", + "name": "Nationwide Mutual Insurance Company Corp", + "city": { + "name": "Upton", + "code": "WY", + "state": "Wyoming", + "county": "Weston", + "display": "Upton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5068595119456469239-4429", + "name": "OpenGov Incorporated", + "city": { + "name": "Port William", + "code": "OH", + "state": "Ohio", + "county": "Clinton", + "display": "Port William" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8746603696150411284-4430", + "name": "Zillow Incorporated", + "city": { + "name": "Valley Stream", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Valley Stream" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7550036204190908704-4431", + "name": "Vital Axiom | Niinja Corp", + "city": { + "name": "Lindale", + "code": "GA", + "state": "Georgia", + "county": "Floyd", + "display": "Lindale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3344842273633935161-4432", + "name": "Boundless Corporation", + "city": { + "name": "Pride", + "code": "LA", + "state": "Louisiana", + "county": "East Baton Rouge", + "display": "Pride" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1324946849682365606-4433", + "name": "Barchart LLC", + "city": { + "name": "Gotha", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Gotha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-794079877629032858-4434", + "name": "Rezolve Group LLC", + "city": { + "name": "Emerson", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Emerson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5268018624896240530-4435", + "name": "Bridgewater Company", + "city": { + "name": "Vancourt", + "code": "TX", + "state": "Texas", + "county": "Tom Green", + "display": "Vancourt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5793160332825476254-4436", + "name": "Patently-O LLC", + "city": { + "name": "Ballwin", + "code": "MO", + "state": "Missouri", + "county": "Saint Louis", + "display": "Sherman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-974179510379772526-4437", + "name": "Food+Tech Connect Corp", + "city": { + "name": "Hernando", + "code": "MS", + "state": "Mississippi", + "county": "Desoto", + "display": "Hernando" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3074008316861831296-4438", + "name": "OnStar Corporation", + "city": { + "name": "Beltrami", + "code": "MN", + "state": "Minnesota", + "county": "Polk", + "display": "Beltrami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8664625285198003564-4439", + "name": "FutureAdvisor Corporation", + "city": { + "name": "Newark", + "code": "NJ", + "state": "New Jersey", + "county": "Essex", + "display": "Bank Of New York" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8193744174227973071-4440", + "name": "Certara Incorporated", + "city": { + "name": "Hiawatha", + "code": "KS", + "state": "Kansas", + "county": "Brown", + "display": "Hamlin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7170563617610643032-4441", + "name": "Think Computer Company", + "city": { + "name": "Moundville", + "code": "AL", + "state": "Alabama", + "county": "Hale", + "display": "Havana" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6389102896466414738-4442", + "name": "GovTribe Inc", + "city": { + "name": "Canajoharie", + "code": "NY", + "state": "New York", + "county": "Montgomery", + "display": "Browns Hollow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-326545581544007022-4443", + "name": "Mango Transit Inc", + "city": { + "name": "Tyronza", + "code": "AR", + "state": "Arkansas", + "county": "Poinsett", + "display": "Tyronza" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4916802695465642386-4444", + "name": "Chemical Abstracts Service Inc", + "city": { + "name": "South Seaville", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "South Seaville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-911900236897932294-4445", + "name": "Expert Health Data Programming, Incorporated", + "city": { + "name": "Pueblo", + "code": "CO", + "state": "Colorado", + "county": "Pueblo", + "display": "Devine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2318306893370886664-4446", + "name": "BaleFire Global Inc", + "city": { + "name": "Leeper", + "code": "PA", + "state": "Pennsylvania", + "county": "Clarion", + "display": "Leeper" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-837774305826723533-4447", + "name": "FlightView Corporation", + "city": { + "name": "Desert Hot Springs", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Desert Edge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4457534616779584295-4448", + "name": "Locavore Corp", + "city": { + "name": "Solana Beach", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Solana Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4924034254874168518-4449", + "name": "Uber Corporation", + "city": { + "name": "Eden", + "code": "TX", + "state": "Texas", + "county": "Concho", + "display": "Eden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5961301090206738356-4450", + "name": "Child Care Desk Company", + "city": { + "name": "Delphi Falls", + "code": "NY", + "state": "New York", + "county": "Onondaga", + "display": "Delphi Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4679616236597217093-4451", + "name": "Xignite Inc", + "city": { + "name": "Carbon", + "code": "IA", + "state": "Iowa", + "county": "Adams", + "display": "Carbon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5214086191323758055-4452", + "name": "Intelius Corporation", + "city": { + "name": "Glenmont", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Bethlehem Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7554030440171196915-4453", + "name": "Suddath Corporation", + "city": { + "name": "Kellyton", + "code": "AL", + "state": "Alabama", + "county": "Coosa", + "display": "Kellyton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4349900892108359602-4454", + "name": "CliniCast Company", + "city": { + "name": "Salyersville", + "code": "KY", + "state": "Kentucky", + "county": "Magoffin", + "display": "Edna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2867017932109299348-4455", + "name": "DataLogix LLC", + "city": { + "name": "Nemours", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Nemours" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6180448974390859838-4456", + "name": "REI Systems LLC", + "city": { + "name": "Pinewood", + "code": "SC", + "state": "South Carolina", + "county": "Sumter", + "display": "Panola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5969366688361497195-4457", + "name": "Google Public Data Explorer Company", + "city": { + "name": "Aragon", + "code": "GA", + "state": "Georgia", + "county": "Polk", + "display": "Aragon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2810521072406894835-4458", + "name": "PlaceILive.com LLC", + "city": { + "name": "Spencer", + "code": "ID", + "state": "Idaho", + "county": "Clark", + "display": "Dubois" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4280172569166461626-4459", + "name": "Revaluate Corporation", + "city": { + "name": "Elizabethtown", + "code": "KY", + "state": "Kentucky", + "county": "Hardin", + "display": "E Town" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3910509906804393824-4460", + "name": "FutureAdvisor Company", + "city": { + "name": "Petoskey", + "code": "MI", + "state": "Michigan", + "county": "Emmet", + "display": "Petoskey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8152727364998099128-4461", + "name": "Housefax LLC", + "city": { + "name": "Broad Brook", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Melrose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4950261068951272759-4462", + "name": "FarmLogs Corporation", + "city": { + "name": "Henderson", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Woodville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4818131757190469364-4463", + "name": "OTC Markets Incorporated", + "city": { + "name": "Saxis", + "code": "VA", + "state": "Virginia", + "county": "Accomack", + "display": "Saxis" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6363733640750772673-4464", + "name": "iFactor Consulting Corp", + "city": { + "name": "Manito", + "code": "IL", + "state": "Illinois", + "county": "Mason", + "display": "Talbott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9107539606537357740-4465", + "name": "Docket Alarm, Company", + "city": { + "name": "Laguna Hills", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Aliso Viejo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4989518835258232050-4466", + "name": "Urban Mapping, Corporation", + "city": { + "name": "Pueblo", + "code": "CO", + "state": "Colorado", + "county": "Pueblo", + "display": "Devine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8148483232639706792-4467", + "name": "Sophic Systems Alliance Corp", + "city": { + "name": "Grove Hill", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Grove Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4546607569470153230-4468", + "name": "CAN Capital Incorporated", + "city": { + "name": "North Grafton", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "North Grafton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4516163747119219783-4469", + "name": "IMS Health Inc", + "city": { + "name": "Minneapolis", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Medicine Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7475988108178660682-4470", + "name": "T. Rowe Price Corp", + "city": { + "name": "Aurora", + "code": "IL", + "state": "Illinois", + "county": "Dupage", + "display": "Aurora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1321819076215117808-4471", + "name": "Exversion Corporation", + "city": { + "name": "Tyronza", + "code": "AR", + "state": "Arkansas", + "county": "Poinsett", + "display": "Tyronza" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2461128251014475738-4472", + "name": "AccuWeather Incorporated", + "city": { + "name": "Esparto", + "code": "CA", + "state": "California", + "county": "Yolo", + "display": "Esparto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8259614703696377970-4473", + "name": "Next Step Living Company", + "city": { + "name": "Palestine", + "code": "AR", + "state": "Arkansas", + "county": "Saint Francis", + "display": "Palestine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6577256925890918455-4474", + "name": "Marinexplore, Company", + "city": { + "name": "Gilmer", + "code": "TX", + "state": "Texas", + "county": "Upshur", + "display": "Soules Chapel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2018283454455212135-4475", + "name": "TopCoder Inc", + "city": { + "name": "Richmond", + "code": "VA", + "state": "Virginia", + "county": "Henrico", + "display": "Rich Int Ap" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6834625607386061843-4476", + "name": "Smart Utility Systems Corporation", + "city": { + "name": "Lumberton", + "code": "NJ", + "state": "New Jersey", + "county": "Burlington", + "display": "Lumberton Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6064508764248374371-4477", + "name": "eInstitutional Company", + "city": { + "name": "Franklin", + "code": "NC", + "state": "North Carolina", + "county": "Macon", + "display": "Franklin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6545560509092121005-4478", + "name": "Optensity Company", + "city": { + "name": "Check", + "code": "VA", + "state": "Virginia", + "county": "Floyd", + "display": "Check" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-156586821005951173-4479", + "name": "MapQuest Incorporated", + "city": { + "name": "Sesser", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Goode" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8824176283725494532-4480", + "name": "Fastcase Company", + "city": { + "name": "Menlo", + "code": "GA", + "state": "Georgia", + "county": "Chattooga", + "display": "Menlo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4395246744911652640-4481", + "name": "H3 Biomedicine Inc", + "city": { + "name": "Newark", + "code": "NJ", + "state": "New Jersey", + "county": "Essex", + "display": "Bank Of New York" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6671130150725295679-4482", + "name": "Barchart Company", + "city": { + "name": "Little River Academy", + "code": "TX", + "state": "Texas", + "county": "Bell", + "display": "Little River Academy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5104456016565448762-4483", + "name": "CONNECT-DOT Corp", + "city": { + "name": "New Preston Marble Dale", + "code": "CT", + "state": "Connecticut", + "county": "Litchfield", + "display": "Washington Dt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3251562619721529757-4484", + "name": "StreetCred Software, Company", + "city": { + "name": "Jackson", + "code": "WY", + "state": "Wyoming", + "county": "Teton", + "display": "Jackson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3227356070076760218-4485", + "name": "iTriage Inc", + "city": { + "name": "Brazil", + "code": "IN", + "state": "Indiana", + "county": "Clay", + "display": "Hoosierville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6776110556259450019-4486", + "name": "Bing Corp", + "city": { + "name": "Paden", + "code": "OK", + "state": "Oklahoma", + "county": "Okfuskee", + "display": "Paden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-173107187707484677-4487", + "name": "Factual Corporation", + "city": { + "name": "Dundee", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Dundee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5018936316137572588-4488", + "name": "Epsilon LLC", + "city": { + "name": "Emigrant Gap", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Emigrant Gap" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2243212377013183394-4489", + "name": "Credit Sesame Company", + "city": { + "name": "Elephant Butte", + "code": "NM", + "state": "New Mexico", + "county": "Sierra", + "display": "Engle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7468142672434623046-4490", + "name": "Stevens Worldwide Van Lines Incorporated", + "city": { + "name": "Maysel", + "code": "WV", + "state": "West Virginia", + "county": "Clay", + "display": "Maysel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4772713105316479912-4491", + "name": "Lumesis, Inc", + "city": { + "name": "Andalusia", + "code": "AL", + "state": "Alabama", + "county": "Covington", + "display": "Dixie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2954848135656095682-4492", + "name": "McKinsey Company", + "city": { + "name": "Castleton", + "code": "VT", + "state": "Vermont", + "county": "Rutland", + "display": "Castleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5646185845701732554-4493", + "name": "Weather Underground Company", + "city": { + "name": "Southport", + "code": "NC", + "state": "North Carolina", + "county": "Brunswick", + "display": "Southport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5934559904243201098-4494", + "name": "First Fuel Software Corporation", + "city": { + "name": "Irvine", + "code": "KY", + "state": "Kentucky", + "county": "Estill", + "display": "Crystal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5603652498851992742-4495", + "name": "Innography LLC", + "city": { + "name": "Pleasanton", + "code": "NE", + "state": "Nebraska", + "county": "Buffalo", + "display": "Pleasanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1626697926030813497-4496", + "name": "Junyo Company", + "city": { + "name": "Amery", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Little Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6473385564776017858-4497", + "name": "HERE Incorporated", + "city": { + "name": "Mill Hall", + "code": "PA", + "state": "Pennsylvania", + "county": "Clinton", + "display": "Bald Eagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2847152744417886974-4498", + "name": "Whitby Group Company", + "city": { + "name": "Center Ridge", + "code": "AR", + "state": "Arkansas", + "county": "Conway", + "display": "Center Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8110515638140370121-4499", + "name": "DemystData Corp", + "city": { + "name": "Jensen Beach", + "code": "FL", + "state": "Florida", + "county": "Martin", + "display": "Ocean Brz Pk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7924779549665580190-4500", + "name": "Progressive Insurance Group Incorporated", + "city": { + "name": "Isola", + "code": "MS", + "state": "Mississippi", + "county": "Humphreys", + "display": "Caile" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2384470390704254851-4501", + "name": "TrialTrove Company", + "city": { + "name": "Angola", + "code": "IN", + "state": "Indiana", + "county": "Steuben", + "display": "Angola" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3326629396759772516-4502", + "name": "Propeller Health Corp", + "city": { + "name": "Blodgett Mills", + "code": "NY", + "state": "New York", + "county": "Cortland", + "display": "Blodgett Mills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3900874539364457086-4503", + "name": "Granicus Inc", + "city": { + "name": "Kingstree", + "code": "SC", + "state": "South Carolina", + "county": "Williamsburg", + "display": "Kingstree" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-819324214881813830-4504", + "name": "Acxiom Company", + "city": { + "name": "Airville", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Airville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4613752739720884996-4505", + "name": "Funding Circle Incorporated", + "city": { + "name": "Grand Isle", + "code": "VT", + "state": "Vermont", + "county": "Grand Isle", + "display": "Grand Isle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2713859434955781041-4506", + "name": "CAN Capital Inc", + "city": { + "name": "Tonopah", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Tonopah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3149832959333280218-4507", + "name": "Import.io Incorporated", + "city": { + "name": "New York", + "code": "NY", + "state": "New York", + "county": "New York", + "display": "Triborough" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-589692786026999487-4508", + "name": "Next Step Living Corp", + "city": { + "name": "Rincon", + "code": "GA", + "state": "Georgia", + "county": "Effingham", + "display": "Rincon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4186485570124217913-4509", + "name": "Alltuition Company", + "city": { + "name": "Mc Intyre", + "code": "PA", + "state": "Pennsylvania", + "county": "Indiana", + "display": "Mcintyre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5331894680687513870-4510", + "name": "People Power Corp", + "city": { + "name": "Tamiment", + "code": "PA", + "state": "Pennsylvania", + "county": "Pike", + "display": "Bushkill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-823416582621484983-4511", + "name": "Standard and Poor's LLC", + "city": { + "name": "Rockland", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "Rockland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5358265291254548014-4512", + "name": "SeeClickFix Company", + "city": { + "name": "Chicago", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Peoples Gas And Light" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-406819958432370144-4513", + "name": "Webitects Company", + "city": { + "name": "Woodrow", + "code": "CO", + "state": "Colorado", + "county": "Washington", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5267402672884233298-4514", + "name": "Votizen Corporation", + "city": { + "name": "Bellflower", + "code": "MO", + "state": "Missouri", + "county": "Montgomery", + "display": "Gamma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1689185616963250264-4515", + "name": "Inrix Traffic Corp", + "city": { + "name": "Mount Lemmon", + "code": "AZ", + "state": "Arizona", + "county": "Pima", + "display": "Mount Lemmon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2593465073426570372-4516", + "name": "eScholar Inc", + "city": { + "name": "Port Murray", + "code": "NJ", + "state": "New Jersey", + "county": "Warren", + "display": "Port Murray" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1713878713450486482-4517", + "name": "IBM Company", + "city": { + "name": "Greenville", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Smithfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1930123300368458661-4518", + "name": "USSearch Incorporated", + "city": { + "name": "Swanton", + "code": "VT", + "state": "Vermont", + "county": "Franklin", + "display": "Fonda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5957202480037773714-4519", + "name": "iMedicare Corporation", + "city": { + "name": "South Chatham", + "code": "MA", + "state": "Massachusetts", + "county": "Barnstable", + "display": "South Chatham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4755632181568993519-4520", + "name": "HealthMap Company", + "city": { + "name": "Brownsville", + "code": "KY", + "state": "Kentucky", + "county": "Edmonson", + "display": "Huff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7741377040547914260-4521", + "name": "Sterling Infosystems Corporation", + "city": { + "name": "Lee Center", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "West Lee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6435402928652806891-4522", + "name": "Bridgewater LLC", + "city": { + "name": "Hannawa Falls", + "code": "NY", + "state": "New York", + "county": "Saint Lawrence", + "display": "Hannawa Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-409044782484834660-4523", + "name": "Xcential Incorporated", + "city": { + "name": "Trimble", + "code": "TN", + "state": "Tennessee", + "county": "Dyer", + "display": "Trimble" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8393022189820288232-4524", + "name": "Headlight Inc", + "city": { + "name": "Gillett", + "code": "AR", + "state": "Arkansas", + "county": "Arkansas", + "display": "Gillett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5152847298116998118-4525", + "name": "Alltuition Corp", + "city": { + "name": "Karnes City", + "code": "TX", + "state": "Texas", + "county": "Karnes", + "display": "Karnes City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2702455654310471211-4526", + "name": "Ecodesk Corp", + "city": { + "name": "Mather", + "code": "PA", + "state": "Pennsylvania", + "county": "Greene", + "display": "Mather" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8127861959410000580-4527", + "name": "HealthPocket, Corporation", + "city": { + "name": "New Paris", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "New Paris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6839813172502045603-4528", + "name": "Morningstar, Corporation", + "city": { + "name": "Mckeesport", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "White Oak" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5125960860090774021-4529", + "name": "Legal Science Partners Corporation", + "city": { + "name": "Taberg", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Point Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1997708420658382375-4530", + "name": "MapQuest Corporation", + "city": { + "name": "Upper Sandusky", + "code": "OH", + "state": "Ohio", + "county": "Wyandot", + "display": "Upper Sandusky" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7047446628500720653-4531", + "name": "Patently-O Corporation", + "city": { + "name": "Bovard", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Bovard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4098085473974544025-4532", + "name": "OSIsoft LLC", + "city": { + "name": "Towaco", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Towaco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6796080254454145363-4533", + "name": "Kroll Bond Ratings Agency Company", + "city": { + "name": "North Turner", + "code": "ME", + "state": "Maine", + "county": "Androscoggin", + "display": "North Turner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6331676889764876026-4534", + "name": "IFI CLAIMS Patent Services LLC", + "city": { + "name": "Alexandria", + "code": "LA", + "state": "Louisiana", + "county": "Rapides", + "display": "Alex" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8564984839308883622-4535", + "name": "Appallicious LLC", + "city": { + "name": "Riverside", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Box Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5868474017902316615-4536", + "name": "Ceiba Solutions Inc", + "city": { + "name": "Tignall", + "code": "GA", + "state": "Georgia", + "county": "Wilkes", + "display": "Tignall" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-202386852685115800-4537", + "name": "Cloudmade Corp", + "city": { + "name": "Whitewater", + "code": "WI", + "state": "Wisconsin", + "county": "Walworth", + "display": "Whitewater" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2902834902446367511-4538", + "name": "iTriage Corporation", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Lyndon B Johnson Space Cen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1342677077167236039-4539", + "name": "PlaceILive.com Company", + "city": { + "name": "Cassadaga", + "code": "FL", + "state": "Florida", + "county": "Volusia", + "display": "Cassadaga" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6170712604362513594-4540", + "name": "BaleFire Global Corporation", + "city": { + "name": "Cheraw", + "code": "CO", + "state": "Colorado", + "county": "Otero", + "display": "Cheraw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3473818348857248091-4541", + "name": "BaleFire Global Incorporated", + "city": { + "name": "Bullville", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Bullville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1362774699522153839-4542", + "name": "Healthgrades Corp", + "city": { + "name": "Frankfort", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Frankfort" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2382237157700235635-4543", + "name": "Kroll Bond Ratings Agency LLC", + "city": { + "name": "Black Hawk", + "code": "CO", + "state": "Colorado", + "county": "Gilpin", + "display": "Black Hawk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6704016312163385261-4544", + "name": "5PSolutions Incorporated", + "city": { + "name": "Baltimore", + "code": "MD", + "state": "Maryland", + "county": "Baltimore City", + "display": "Social Security Administrat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6636597810052724420-4545", + "name": "Sage Bionetworks LLC", + "city": { + "name": "Fairview", + "code": "OK", + "state": "Oklahoma", + "county": "Major", + "display": "Orienta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4936737364379980652-4546", + "name": "Geolytics Corporation", + "city": { + "name": "Hull", + "code": "IA", + "state": "Iowa", + "county": "Sioux", + "display": "Hull" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3055778637122387538-4547", + "name": "HealthMap Corporation", + "city": { + "name": "Cannelton", + "code": "IN", + "state": "Indiana", + "county": "Perry", + "display": "Tobinsport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7603882901693968790-4548", + "name": "PEV4me.com Corporation", + "city": { + "name": "Gleason", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Parrish" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-171437486133508114-4549", + "name": "HDScores, Company", + "city": { + "name": "Breckenridge", + "code": "CO", + "state": "Colorado", + "county": "Summit", + "display": "Blue River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3206623483201512443-4550", + "name": "Apextech LLC", + "city": { + "name": "Byrnedale", + "code": "PA", + "state": "Pennsylvania", + "county": "Elk", + "display": "Byrnedale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6814058430829121657-4551", + "name": "OpenPlans Incorporated", + "city": { + "name": "Second Mesa", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Toreva" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7827945736319924827-4552", + "name": "Berkery Noyes MandASoft Corp", + "city": { + "name": "Larkspur", + "code": "CA", + "state": "California", + "county": "Marin", + "display": "Larkspur" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-681894933710818128-4553", + "name": "Archimedes Incorporated", + "city": { + "name": "Burney", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Johnson Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-450290818551010504-4554", + "name": "Bing Inc", + "city": { + "name": "Bellwood", + "code": "IL", + "state": "Illinois", + "county": "Cook", + "display": "Bellwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7337796208623104211-4555", + "name": "Jurispect LLC", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Naval Base" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6860355929422973844-4556", + "name": "Revaluate Incorporated", + "city": { + "name": "Burgettstown", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "Burgettstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4378906194854319948-4557", + "name": "Cambridge Semantics Corp", + "city": { + "name": "San Francisco", + "code": "CA", + "state": "California", + "county": "San Francisco", + "display": "Union Bank Of California" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4876330027289678986-4558", + "name": "Exversion LLC", + "city": { + "name": "Myra", + "code": "KY", + "state": "Kentucky", + "county": "Pike", + "display": "Myra" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7050494992360058856-4559", + "name": "MarketSense Incorporated", + "city": { + "name": "Hamilton", + "code": "MS", + "state": "Mississippi", + "county": "Monroe", + "display": "Hamilton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1279872994502306565-4560", + "name": "IVES Group Corp", + "city": { + "name": "Cardin", + "code": "OK", + "state": "Oklahoma", + "county": "Ottawa", + "display": "Cardin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2319606087195604037-4561", + "name": "Personal Democracy Media Corporation", + "city": { + "name": "Ruffin", + "code": "NC", + "state": "North Carolina", + "county": "Rockingham", + "display": "Powells Store" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9013246515984776182-4562", + "name": "Smartronix Company", + "city": { + "name": "South Fork", + "code": "MO", + "state": "Missouri", + "county": "Howell", + "display": "West Plains" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1988374357687846889-4563", + "name": "YourMapper Company", + "city": { + "name": "Ardmore", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Ardmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2444392137577949099-4564", + "name": "IFI CLAIMS Patent Services Inc", + "city": { + "name": "Louisville", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Louisville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8367989002648934709-4565", + "name": "Vizzuality Corporation", + "city": { + "name": "East Bernard", + "code": "TX", + "state": "Texas", + "county": "Wharton", + "display": "Tavener" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5118729913285876375-4566", + "name": "optiGov LLC", + "city": { + "name": "Chesapeake City", + "code": "MD", + "state": "Maryland", + "county": "Cecil", + "display": "Chesapeake City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7370530864543836482-4567", + "name": "Zonability Incorporated", + "city": { + "name": "Little Compton", + "code": "RI", + "state": "Rhode Island", + "county": "Newport", + "display": "Little Compton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8184793605849744751-4568", + "name": "Porch Company", + "city": { + "name": "Kenton", + "code": "OH", + "state": "Ohio", + "county": "Hardin", + "display": "Kenton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7800017495594331089-4569", + "name": "NERA Economic Consulting Company", + "city": { + "name": "Excelsior Springs", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "Mosby" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8364161452162830366-4570", + "name": "Intermap Technologies Inc", + "city": { + "name": "Banner Elk", + "code": "NC", + "state": "North Carolina", + "county": "Avery", + "display": "Elk Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3280344067725303476-4571", + "name": "Persint Corporation", + "city": { + "name": "Voorhees", + "code": "NJ", + "state": "New Jersey", + "county": "Camden", + "display": "Echelon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3255355928524481789-4572", + "name": "Cloudspyre Incorporated", + "city": { + "name": "Boydton", + "code": "VA", + "state": "Virginia", + "county": "Mecklenburg", + "display": "Palmersprings" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6108489998915712490-4573", + "name": "Uber Incorporated", + "city": { + "name": "Knoxville", + "code": "TN", + "state": "Tennessee", + "county": "Knox", + "display": "University Of Tenn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6184784826088382391-4574", + "name": "Paxata Corp", + "city": { + "name": "Yorktown", + "code": "VA", + "state": "Virginia", + "county": "York", + "display": "Nav Wpns Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3101298920737259579-4575", + "name": "Geoscape Company", + "city": { + "name": "Gilbert", + "code": "IA", + "state": "Iowa", + "county": "Story", + "display": "Gilbert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6168228613146364733-4576", + "name": "PlotWatt LLC", + "city": { + "name": "Lansing", + "code": "MI", + "state": "Michigan", + "county": "Ingham", + "display": "State Of Mich Dept Treasury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3148354411772899995-4577", + "name": "Zillow Corp", + "city": { + "name": "Bullville", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Bullville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7630501726282716276-4578", + "name": "Galorath orporated Inc", + "city": { + "name": "SF", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Sf" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2796980257953759785-4579", + "name": "Kaiser Permanante Corporation", + "city": { + "name": "Ranchita", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Warner Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2842027768753341154-4580", + "name": "Fujitsu Corporation", + "city": { + "name": "Englewood", + "code": "CO", + "state": "Colorado", + "county": "Arapahoe", + "display": "Cherry Hills" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4926619957888895980-4581", + "name": "Ez-XBRL Corp", + "city": { + "name": "Huron", + "code": "OH", + "state": "Ohio", + "county": "Erie", + "display": "Ceylon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6919549363026447310-4582", + "name": "Suddath Corporation", + "city": { + "name": "Wheeler", + "code": "IL", + "state": "Illinois", + "county": "Jasper", + "display": "Wheeler" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1804275572981965668-4583", + "name": "SlashDB Corp", + "city": { + "name": "Hinton", + "code": "WV", + "state": "West Virginia", + "county": "Summers", + "display": "Hinton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-392893070412712568-4584", + "name": "YourMapper Corp", + "city": { + "name": "Newington", + "code": "VA", + "state": "Virginia", + "county": "Fairfax", + "display": "Newington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7405097588761263564-4585", + "name": "Ernst \u0026 Young LLP Corporation", + "city": { + "name": "Lockwood", + "code": "CA", + "state": "California", + "county": "Monterey", + "display": "Lockwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7204616711025721603-4586", + "name": "Exversion Inc", + "city": { + "name": "Le Roy", + "code": "WV", + "state": "West Virginia", + "county": "Jackson", + "display": "Duncan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8556701743307377280-4587", + "name": "Moody's Corp", + "city": { + "name": "Avoca", + "code": "NY", + "state": "New York", + "county": "Steuben", + "display": "Avoca" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7861990619377881287-4588", + "name": "Gallup Corp", + "city": { + "name": "Tigerton", + "code": "WI", + "state": "Wisconsin", + "county": "Shawano", + "display": "Morris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2118059853012232171-4589", + "name": "PlanetEcosystems LLC", + "city": { + "name": "Savanna", + "code": "IL", + "state": "Illinois", + "county": "Carroll", + "display": "Savanna" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8089292830183281961-4590", + "name": "karmadata Corporation", + "city": { + "name": "Penn", + "code": "ND", + "state": "North Dakota", + "county": "Ramsey", + "display": "Penn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1358629757792763792-4591", + "name": "BlackRock Corp", + "city": { + "name": "Bunceton", + "code": "MO", + "state": "Missouri", + "county": "Cooper", + "display": "Lone Elm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5908565528722729245-4592", + "name": "Garmin Corp", + "city": { + "name": "Frackville", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "State Correctional Inst" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4084181866029789936-4593", + "name": "Arpin Van Lines Company", + "city": { + "name": "Deltona", + "code": "FL", + "state": "Florida", + "county": "Volusia", + "display": "Deltona" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-43252295856935465-4594", + "name": "CityScan Company", + "city": { + "name": "Newellton", + "code": "LA", + "state": "Louisiana", + "county": "Tensas", + "display": "Newlight" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3159571993924442290-4595", + "name": "Boston Consulting Group Company", + "city": { + "name": "Needville", + "code": "TX", + "state": "Texas", + "county": "Fort Bend", + "display": "Fairchilds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1382216312866809937-4596", + "name": "CityScan Inc", + "city": { + "name": "Belvidere", + "code": "NE", + "state": "Nebraska", + "county": "Thayer", + "display": "Belvidere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4595829169925204389-4597", + "name": "DemystData Corp", + "city": { + "name": "El Dorado Hills", + "code": "CA", + "state": "California", + "county": "El Dorado", + "display": "Folsom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4314020073258915819-4598", + "name": "Factual Corp", + "city": { + "name": "Belden", + "code": "MS", + "state": "Mississippi", + "county": "Lee", + "display": "Belden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3630997095939169033-4599", + "name": "Import.io Inc", + "city": { + "name": "Wiergate", + "code": "TX", + "state": "Texas", + "county": "Newton", + "display": "Indian Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1136400704107673566-4600", + "name": "MetLife LLC", + "city": { + "name": "Mc Clure", + "code": "OH", + "state": "Ohio", + "county": "Henry", + "display": "Grelton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1469125022667121231-4601", + "name": "Simple Energy Incorporated", + "city": { + "name": "Riverside", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Box Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5379337761581800012-4602", + "name": "Sage Bionetworks Company", + "city": { + "name": "Zuni", + "code": "NM", + "state": "New Mexico", + "county": "Mckinley", + "display": "Ramah Community" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7474216361331592065-4603", + "name": "Cloudmade Incorporated", + "city": { + "name": "O Brien", + "code": "TX", + "state": "Texas", + "county": "Haskell", + "display": "O Brien" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-638307022476801437-4604", + "name": "Overture Technologies LLC", + "city": { + "name": "Larwill", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Larwill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2049846361489368724-4605", + "name": "American Red Ball Movers Incorporated", + "city": { + "name": "Woodrow", + "code": "CO", + "state": "Colorado", + "county": "Washington", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-915203327285152592-4606", + "name": "Marinexplore, LLC", + "city": { + "name": "Hamtramck", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Detroit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-821422505828593639-4607", + "name": "Xatori Corp", + "city": { + "name": "East Wenatchee", + "code": "WA", + "state": "Washington", + "county": "Douglas", + "display": "East Wenatchee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4660940114609513639-4608", + "name": "karmadata Incorporated", + "city": { + "name": "Atlanta", + "code": "GA", + "state": "Georgia", + "county": "Fulton", + "display": "Lenox Square Finance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8236934554691243915-4609", + "name": "Zurich Insurance Corporation", + "city": { + "name": "Xenia", + "code": "OH", + "state": "Ohio", + "county": "Greene", + "display": "Sugarcreek Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7749875555017629511-4610", + "name": "KLD Research Corporation", + "city": { + "name": "Wyalusing", + "code": "PA", + "state": "Pennsylvania", + "county": "Bradford", + "display": "Wyalusing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5307881281831084003-4611", + "name": "Govini Inc", + "city": { + "name": "Columbia", + "code": "LA", + "state": "Louisiana", + "county": "Caldwell", + "display": "Burroughs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7352978833685891481-4612", + "name": "LexisNexis Corp", + "city": { + "name": "Tupper Lake", + "code": "NY", + "state": "New York", + "county": "Franklin", + "display": "Tupper Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4992995585307066811-4613", + "name": "Glassy Media Corp", + "city": { + "name": "Donnelsville", + "code": "OH", + "state": "Ohio", + "county": "Clark", + "display": "Donnelsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2706005474312652502-4614", + "name": "Jurispect Corp", + "city": { + "name": "El Mirage", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "El Mirage" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1923575173348339877-4615", + "name": "WattzOn Inc", + "city": { + "name": "Holdingford", + "code": "MN", + "state": "Minnesota", + "county": "Stearns", + "display": "Holdingford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3578839472490561508-4616", + "name": "OSIsoft Inc", + "city": { + "name": "West Topsham", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "Waits River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2315990662904734103-4617", + "name": "Epsilon Corp", + "city": { + "name": "Laredo", + "code": "TX", + "state": "Texas", + "county": "Webb", + "display": "Rio Bravo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4304719851580159427-4618", + "name": "H3 Biomedicine LLC", + "city": { + "name": "Washington", + "code": "CA", + "state": "California", + "county": "Nevada", + "display": "Washington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1664562514961750333-4619", + "name": "WebMD Corp", + "city": { + "name": "Bangor", + "code": "WI", + "state": "Wisconsin", + "county": "La Crosse", + "display": "Middle Ridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5869161420507013903-4620", + "name": "Ceiba Solutions Inc", + "city": { + "name": "Troy", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Albia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1639429500697491833-4621", + "name": "Whitby Group Corp", + "city": { + "name": "Palmdale", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Quartz Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4358309006426711176-4622", + "name": "Peterson's Company", + "city": { + "name": "Fonda", + "code": "IA", + "state": "Iowa", + "county": "Pocahontas", + "display": "Industry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8068484612203427496-4623", + "name": "Social Explorer Incorporated", + "city": { + "name": "South Newfane", + "code": "VT", + "state": "Vermont", + "county": "Windham", + "display": "South Newfane" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7180124015756777270-4624", + "name": "Consumer Reports LLC", + "city": { + "name": "Buena Vista", + "code": "VA", + "state": "Virginia", + "county": "Buena Vista City", + "display": "Buena Vista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6108885644657964612-4625", + "name": "Lilly Open Innovation Drug Discovery Corp", + "city": { + "name": "Fergus Falls", + "code": "MN", + "state": "Minnesota", + "county": "Otter Tail", + "display": "Fergus Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-425153037885701480-4626", + "name": "Stamen Design Company", + "city": { + "name": "Bloomville", + "code": "OH", + "state": "Ohio", + "county": "Seneca", + "display": "Bloomville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7237268717478941570-4627", + "name": "Social Health Insights LLC", + "city": { + "name": "Chapman Ranch", + "code": "TX", + "state": "Texas", + "county": "Nueces", + "display": "Chapman Ranch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-287035113258484945-4628", + "name": "Govzilla, Corporation", + "city": { + "name": "Baytown", + "code": "TX", + "state": "Texas", + "county": "Chambers", + "display": "Beach City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5021069964206115568-4629", + "name": "Boston Consulting Group LLC", + "city": { + "name": "Sharon", + "code": "SC", + "state": "South Carolina", + "county": "York", + "display": "Sharon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7228564941722636462-4630", + "name": "Dabo Health Inc", + "city": { + "name": "West Hartford", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "W Htfd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6605402789547874180-4631", + "name": "Consumer Reports Corporation", + "city": { + "name": "Beltrami", + "code": "MN", + "state": "Minnesota", + "county": "Polk", + "display": "Beltrami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5728525998470237259-4632", + "name": "Development Seed LLC", + "city": { + "name": "Bonnieville", + "code": "KY", + "state": "Kentucky", + "county": "Hart", + "display": "Bonnieville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7169821612959691189-4633", + "name": "Environmental Data Resources Corporation", + "city": { + "name": "Mount Morris", + "code": "PA", + "state": "Pennsylvania", + "county": "Greene", + "display": "Mt Morris" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2293607733878460851-4634", + "name": "Telenav Incorporated", + "city": { + "name": "Frankston", + "code": "TX", + "state": "Texas", + "county": "Anderson", + "display": "Berryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-869281347859057095-4635", + "name": "WaterSmart Software Corporation", + "city": { + "name": "Bulpitt", + "code": "IL", + "state": "Illinois", + "county": "Christian", + "display": "Bulpitt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3033569653588335617-4636", + "name": "BuildZoom Corp", + "city": { + "name": "Fayetteville", + "code": "NC", + "state": "North Carolina", + "county": "Cumberland", + "display": "Eutaw" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2995413613095397266-4637", + "name": "OpenCounter Inc", + "city": { + "name": "New Holland", + "code": "SD", + "state": "South Dakota", + "county": "Douglas", + "display": "Joubert" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3534979426323897746-4638", + "name": "Golden Helix Corp", + "city": { + "name": "Gotha", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Gotha" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5836363067191062363-4639", + "name": "Kimono Labs Corp", + "city": { + "name": "Cincinnati", + "code": "OH", + "state": "Ohio", + "county": "Hamilton", + "display": "Price Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-462635734667887581-4640", + "name": "AutoGrid Systems Incorporated", + "city": { + "name": "Afton", + "code": "OK", + "state": "Oklahoma", + "county": "Ottawa", + "display": "Cleora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5455066639171067433-4641", + "name": "How's My Offer? LLC", + "city": { + "name": "Wilmington", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Custer Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1268831015690269988-4642", + "name": "Civic Insight Corporation", + "city": { + "name": "Collyer", + "code": "KS", + "state": "Kansas", + "county": "Trego", + "display": "Collyer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3052189384545082674-4643", + "name": "Aureus Sciences Corp", + "city": { + "name": "Carson City", + "code": "MI", + "state": "Michigan", + "county": "Montcalm", + "display": "Carson City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4020680179825511840-4644", + "name": "Exversion LLC", + "city": { + "name": "Franklin Springs", + "code": "NY", + "state": "New York", + "county": "Oneida", + "display": "Franklin Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6199056739611923830-4645", + "name": "Legal Science Partners Corp", + "city": { + "name": "Hemphill", + "code": "TX", + "state": "Texas", + "county": "Sabine", + "display": "East Mayfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6057540685823844532-4646", + "name": "Maponics LLC", + "city": { + "name": "Bath", + "code": "NY", + "state": "New York", + "county": "Steuben", + "display": "Bath" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5728008789925550925-4647", + "name": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6484544173372429232-4648", + "name": "Honest Buildings Company", + "city": { + "name": "Oklahoma City", + "code": "OK", + "state": "Oklahoma", + "county": "Oklahoma", + "display": "Smith Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7430160956207166165-4649", + "name": "Xcential LLC", + "city": { + "name": "Church Hill", + "code": "MD", + "state": "Maryland", + "county": "Queen Annes", + "display": "Church Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4004476788825385146-4650", + "name": "TuvaLabs Incorporated", + "city": { + "name": "Anamoose", + "code": "ND", + "state": "North Dakota", + "county": "Mchenry", + "display": "Aylmer" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8005720858674841251-4651", + "name": "Civic Impulse Company", + "city": { + "name": "Lakeland", + "code": "LA", + "state": "Louisiana", + "county": "Pointe Coupee", + "display": "Lakeland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4588962380590594717-4652", + "name": "Import.io Inc", + "city": { + "name": "Jenison", + "code": "MI", + "state": "Michigan", + "county": "Ottawa", + "display": "Georgetown Tp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8223040739342595692-4653", + "name": "EMC Corporation", + "city": { + "name": "Pawtucket", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Pawtucket" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2275211971830285298-4654", + "name": "Galorath orporated Company", + "city": { + "name": "Hestand", + "code": "KY", + "state": "Kentucky", + "county": "Monroe", + "display": "Hestand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-794039784537866504-4655", + "name": "ideas42 Inc", + "city": { + "name": "Bradley", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Bradley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2992970123691275262-4656", + "name": "Cloudspyre Company", + "city": { + "name": "Ardmore", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Ardmore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6158926275802770733-4657", + "name": "Spikes Cavell Analytic Corp", + "city": { + "name": "Talihina", + "code": "OK", + "state": "Oklahoma", + "county": "Latimer", + "display": "Talihina" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1031449909328925641-4658", + "name": "Azavea Corporation", + "city": { + "name": "Live Oak", + "code": "FL", + "state": "Florida", + "county": "Suwannee", + "display": "Dowling Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4064025601336943863-4659", + "name": "TransUnion Company", + "city": { + "name": "Robbinsville", + "code": "NC", + "state": "North Carolina", + "county": "Graham", + "display": "Robbinsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-370359250889453917-4660", + "name": "Enigma.io Inc", + "city": { + "name": "Ragland", + "code": "WV", + "state": "West Virginia", + "county": "Mingo", + "display": "Ragland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-408155696736278-4661", + "name": "Inrix Traffic Company", + "city": { + "name": "Frenchburg", + "code": "KY", + "state": "Kentucky", + "county": "Menifee", + "display": "Frenchburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7285110802143672925-4662", + "name": "Quid LLC", + "city": { + "name": "Hazard", + "code": "KY", + "state": "Kentucky", + "county": "Perry", + "display": "Walkertown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5081619494585520430-4663", + "name": "Legal Science Partners Inc", + "city": { + "name": "Kelford", + "code": "NC", + "state": "North Carolina", + "county": "Bertie", + "display": "Kelford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1565902126391327650-4664", + "name": "Persint Corporation", + "city": { + "name": "Holland", + "code": "MA", + "state": "Massachusetts", + "county": "Hampden", + "display": "Holland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6363965034726191287-4665", + "name": "LoseIt.com Corporation", + "city": { + "name": "Driscoll", + "code": "TX", + "state": "Texas", + "county": "Nueces", + "display": "Driscoll" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7474197720765271560-4666", + "name": "Oliver Wyman Corporation", + "city": { + "name": "Anamosa", + "code": "IA", + "state": "Iowa", + "county": "Jones", + "display": "Amber" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7817352045502567286-4667", + "name": "Propeller Health LLC", + "city": { + "name": "North Granville", + "code": "NY", + "state": "New York", + "county": "Washington", + "display": "North Granville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4770470473496233096-4668", + "name": "POPVOX LLC", + "city": { + "name": "Bastrop", + "code": "TX", + "state": "Texas", + "county": "Bastrop", + "display": "Bastrop" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8095548381436991833-4669", + "name": "Stevens Worldwide Van Lines Inc", + "city": { + "name": "Farley", + "code": "MO", + "state": "Missouri", + "county": "Platte", + "display": "Farley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-434770091902266907-4670", + "name": "Cappex Inc", + "city": { + "name": "Hanover", + "code": "IN", + "state": "Indiana", + "county": "Jefferson", + "display": "Paynesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1795701770637866744-4671", + "name": "CoolClimate Corporation", + "city": { + "name": "Franklin", + "code": "NE", + "state": "Nebraska", + "county": "Franklin", + "display": "Macon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-153295103030950719-4672", + "name": "ReciPal Company", + "city": { + "name": "Fall River Mills", + "code": "CA", + "state": "California", + "county": "Shasta", + "display": "Fl River Mls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5652938916784304517-4673", + "name": "Citigroup Corporation", + "city": { + "name": "De Witt", + "code": "AR", + "state": "Arkansas", + "county": "Arkansas", + "display": "De Witt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2885438245215278870-4674", + "name": "Orlin Research Incorporated", + "city": { + "name": "Seattle", + "code": "WA", + "state": "Washington", + "county": "King", + "display": "Safeco Plaza" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6315317552678111224-4675", + "name": "Overture Technologies Company", + "city": { + "name": "Minneapolis", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Wells Fargo Bank" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4688301529761683025-4676", + "name": "EarthObserver App Corp", + "city": { + "name": "Hazard", + "code": "KY", + "state": "Kentucky", + "county": "Perry", + "display": "Hazard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3011728769755209552-4677", + "name": "Thomson Reuters LLC", + "city": { + "name": "Swanton", + "code": "NE", + "state": "Nebraska", + "county": "Saline", + "display": "Swanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6255833161828226811-4678", + "name": "Junyo Corporation", + "city": { + "name": "San Benito", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Laureles" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3749829721915250264-4679", + "name": "Uber LLC", + "city": { + "name": "Eagleville", + "code": "CA", + "state": "California", + "county": "Modoc", + "display": "Eagleville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-236258494982591521-4680", + "name": "Everyday Health Corp", + "city": { + "name": "Broadview", + "code": "NM", + "state": "New Mexico", + "county": "Curry", + "display": "Bellview" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8688739414180271484-4681", + "name": "eInstitutional Corp", + "city": { + "name": "Maidens", + "code": "VA", + "state": "Virginia", + "county": "Goochland", + "display": "Dabneys" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7481480223828045297-4682", + "name": "JJ Keller Corp", + "city": { + "name": "Keyport", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Cliffwood Bch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5625526251200772677-4683", + "name": "Reed Elsevier Incorporated", + "city": { + "name": "Terre Haute", + "code": "IN", + "state": "Indiana", + "county": "Vigo", + "display": "Lakewood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1029488405735269594-4684", + "name": "Boundless LLC", + "city": { + "name": "Jameson", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Jameson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4184376927909698154-4685", + "name": "Buildingeye Inc", + "city": { + "name": "Williamsburg", + "code": "WV", + "state": "West Virginia", + "county": "Greenbrier", + "display": "Trout" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1062349838693671274-4686", + "name": "Kimono Labs LLC", + "city": { + "name": "Pentress", + "code": "WV", + "state": "West Virginia", + "county": "Monongalia", + "display": "Pentress" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3686077254989841963-4687", + "name": "POPVOX Inc", + "city": { + "name": "Puposky", + "code": "MN", + "state": "Minnesota", + "county": "Beltrami", + "display": "Durand" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4609862503352319240-4688", + "name": "StreamLink Software Corporation", + "city": { + "name": "High Rolls Mountain Park", + "code": "NM", + "state": "New Mexico", + "county": "Otero", + "display": "Mountain Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8175790232400420603-4689", + "name": "Weather Underground Company", + "city": { + "name": "North Tonawanda", + "code": "NY", + "state": "New York", + "county": "Niagara", + "display": "No Tonawanda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7927470559603559636-4690", + "name": "Computer Packages Corporation", + "city": { + "name": "Bear Creek", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Bear Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4490559258799880322-4691", + "name": "Trulia Corporation", + "city": { + "name": "Pigeon", + "code": "MI", + "state": "Michigan", + "county": "Huron", + "display": "Pigeon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1675027339656570084-4692", + "name": "Maponics Inc", + "city": { + "name": "Bly", + "code": "OR", + "state": "Oregon", + "county": "Klamath", + "display": "Bly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5838864796825434786-4693", + "name": "Trintech Incorporated", + "city": { + "name": "Crystal Bay", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Orono" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2943620302717147477-4694", + "name": "Keychain Logistics LLC", + "city": { + "name": "Laporte", + "code": "MN", + "state": "Minnesota", + "county": "Hubbard", + "display": "Guthrie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1914903948005926446-4695", + "name": "Ecodesk Company", + "city": { + "name": "Glenwood", + "code": "FL", + "state": "Florida", + "county": "Volusia", + "display": "Deland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8289272138257103102-4696", + "name": "USAA Group Inc", + "city": { + "name": "Tooele", + "code": "UT", + "state": "Utah", + "county": "Tooele", + "display": "Tooele Army Depot" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3800344533202335108-4697", + "name": "Locavore Company", + "city": { + "name": "Binghamton", + "code": "NY", + "state": "New York", + "county": "Broome", + "display": "Nimmonsburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1771640771906141741-4698", + "name": "BlackRock Corp", + "city": { + "name": "Arkadelphia", + "code": "AR", + "state": "Arkansas", + "county": "Clark", + "display": "Joan" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5937593006121753790-4699", + "name": "OptumInsight Incorporated", + "city": { + "name": "Derby", + "code": "IA", + "state": "Iowa", + "county": "Lucas", + "display": "Last Chance" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8972421237507681546-4700", + "name": "Yahoo Company", + "city": { + "name": "Saulsbury", + "code": "TN", + "state": "Tennessee", + "county": "Hardeman", + "display": "Saulsbury" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-960523917021281751-4701", + "name": "GreatSchools Corporation", + "city": { + "name": "Watson", + "code": "AR", + "state": "Arkansas", + "county": "Desha", + "display": "Yancopin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4166788900357889280-4702", + "name": "Caspio Incorporated", + "city": { + "name": "Reading", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Saint Lawrence" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5728836448856955772-4703", + "name": "HealthPocket, Company", + "city": { + "name": "Mullett Lake", + "code": "MI", + "state": "Michigan", + "county": "Cheboygan", + "display": "Mullett Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7785631410890494048-4704", + "name": "PricewaterhouseCoopers Company", + "city": { + "name": "Ocean Beach", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Corneil Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7380404357194425420-4705", + "name": "Aunt Bertha, Incorporated", + "city": { + "name": "Walnut Ridge", + "code": "AR", + "state": "Arkansas", + "county": "Lawrence", + "display": "Wms College" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6295409697473353124-4706", + "name": "The Vanguard Group Incorporated", + "city": { + "name": "Dinero", + "code": "TX", + "state": "Texas", + "county": "Live Oak", + "display": "Mount Lucas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4327077327819357879-4707", + "name": "SAS Company", + "city": { + "name": "Simms", + "code": "TX", + "state": "Texas", + "county": "Bowie", + "display": "Simms" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-489223636712921382-4708", + "name": "Plus-U Incorporated", + "city": { + "name": "Othello", + "code": "WA", + "state": "Washington", + "county": "Adams", + "display": "Othello" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1843055818067017679-4709", + "name": "Personal, Inc", + "city": { + "name": "Albrightsville", + "code": "PA", + "state": "Pennsylvania", + "county": "Carbon", + "display": "Albrightsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4019019730081529922-4710", + "name": "Genability Company", + "city": { + "name": "Glenallen", + "code": "MO", + "state": "Missouri", + "county": "Bollinger", + "display": "Grassy" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-241938975567923643-4711", + "name": "Politify LLC", + "city": { + "name": "Midvale", + "code": "UT", + "state": "Utah", + "county": "Salt Lake", + "display": "Midvale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8401732067431281453-4712", + "name": "Environmental Data Resources Inc", + "city": { + "name": "Rumely", + "code": "MI", + "state": "Michigan", + "county": "Alger", + "display": "Rumely" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1019958288949312158-4713", + "name": "OpenCounter Corp", + "city": { + "name": "Derby", + "code": "IN", + "state": "Indiana", + "county": "Perry", + "display": "Dexter" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7517216725397715132-4714", + "name": "NERA Economic Consulting Inc", + "city": { + "name": "Jerome", + "code": "ID", + "state": "Idaho", + "county": "Jerome", + "display": "Appleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2061225779957668101-4715", + "name": "The Govtech Fund Inc", + "city": { + "name": "Westport", + "code": "SD", + "state": "South Dakota", + "county": "Brown", + "display": "Westport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5866706122092742759-4716", + "name": "gRadiant Research Company", + "city": { + "name": "Gainesville", + "code": "AL", + "state": "Alabama", + "county": "Sumter", + "display": "Gainesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5290119216891551182-4717", + "name": "Amazon Web Services LLC", + "city": { + "name": "Excelsior Springs", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "Wood Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3700380765676815821-4718", + "name": "State Farm Insurance Incorporated", + "city": { + "name": "Pohnpei", + "code": "FM", + "state": "Federated States of Micronesia", + "county": "Federated States Of Micro", + "display": "Pohnpei" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6372857534952293985-4719", + "name": "Orlin Research Incorporated", + "city": { + "name": "Litchfield Park", + "code": "AZ", + "state": "Arizona", + "county": "Maricopa", + "display": "Litchfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6503842544790942575-4720", + "name": "Yelp Corp", + "city": { + "name": "Eldred", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Eldred" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8588859534605055193-4721", + "name": "Alltuition LLC", + "city": { + "name": "Gotham", + "code": "WI", + "state": "Wisconsin", + "county": "Richland", + "display": "Gotham" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5978421345812104085-4722", + "name": "Healthgrades Corporation", + "city": { + "name": "Holland", + "code": "TX", + "state": "Texas", + "county": "Bell", + "display": "Vilas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2354657580295386910-4723", + "name": "Verdafero Company", + "city": { + "name": "Leavenworth", + "code": "WA", + "state": "Washington", + "county": "Chelan", + "display": "Blewett" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5343944356144382489-4724", + "name": "Rank and Filed Incorporated", + "city": { + "name": "Gwynedd", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Gwynedd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6107541937307350349-4725", + "name": "FindTheBest.com Company", + "city": { + "name": "Moscow", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Covington Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5007019262904308657-4726", + "name": "Collective IP LLC", + "city": { + "name": "Austin", + "code": "TX", + "state": "Texas", + "county": "Travis", + "display": "State Comptroller" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4530876806370029433-4727", + "name": "GovTribe Inc", + "city": { + "name": "Brunswick", + "code": "TN", + "state": "Tennessee", + "county": "Shelby", + "display": "Brunswick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3343246302596898687-4728", + "name": "OnDeck Company", + "city": { + "name": "Virgie", + "code": "KY", + "state": "Kentucky", + "county": "Pike", + "display": "Virgie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5325653209233087479-4729", + "name": "CONNECT-DOT Company", + "city": { + "name": "Hitchita", + "code": "OK", + "state": "Oklahoma", + "county": "Mcintosh", + "display": "Hitchita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7935161076713182226-4730", + "name": "HERE LLC", + "city": { + "name": "Dolgeville", + "code": "NY", + "state": "New York", + "county": "Herkimer", + "display": "Manheim" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-531498979884209372-4731", + "name": "SAP Inc", + "city": { + "name": "Gwynedd", + "code": "PA", + "state": "Pennsylvania", + "county": "Montgomery", + "display": "Gwynedd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4171056912346691241-4732", + "name": "Ayasdi Incorporated", + "city": { + "name": "Logan", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Hanaford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7376700136613441455-4733", + "name": "NextBus LLC", + "city": { + "name": "Newburgh", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Town Branch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2436271291041030378-4734", + "name": "Cerner Corp", + "city": { + "name": "Des Moines", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Visa Mastercard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7724392737251427432-4735", + "name": "SlashDB Incorporated", + "city": { + "name": "East Setauket", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Poquott" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6275199460854825515-4736", + "name": "Construction Monitor Incorporated", + "city": { + "name": "Wilkesville", + "code": "OH", + "state": "Ohio", + "county": "Vinton", + "display": "Wilkesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4223256314284235705-4737", + "name": "gRadiant Research Incorporated", + "city": { + "name": "Houston", + "code": "TX", + "state": "Texas", + "county": "Harris", + "display": "Jersey Village" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3566652322323727063-4738", + "name": "eScholar Corp", + "city": { + "name": "Seminole", + "code": "AL", + "state": "Alabama", + "county": "Baldwin", + "display": "Robertsdale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3447598808271673067-4739", + "name": "Civic Impulse Corp", + "city": { + "name": "Covington", + "code": "LA", + "state": "Louisiana", + "county": "Saint Tammany", + "display": "Riverwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2744108982111254114-4740", + "name": "REI Systems Corp", + "city": { + "name": "Souris", + "code": "ND", + "state": "North Dakota", + "county": "Bottineau", + "display": "Roth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5948156258877526018-4741", + "name": "SAS Inc", + "city": { + "name": "Dudley", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Dudley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3191994059793217083-4742", + "name": "CrowdANALYTIX LLC", + "city": { + "name": "Riesel", + "code": "TX", + "state": "Texas", + "county": "Mclennan", + "display": "Otto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3328469525276042535-4743", + "name": "Climate LLC", + "city": { + "name": "New Portland", + "code": "ME", + "state": "Maine", + "county": "Somerset", + "display": "New Portland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2757144421248202445-4744", + "name": "Reed Elsevier Corporation", + "city": { + "name": "Cuyahoga Falls", + "code": "OH", + "state": "Ohio", + "county": "Summit", + "display": "Cuyahoga Fls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2801199715974625794-4745", + "name": "Evidera Corp", + "city": { + "name": "Kathryn", + "code": "ND", + "state": "North Dakota", + "county": "Barnes", + "display": "Kathryn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9135407727443105262-4746", + "name": "DataLogix Inc", + "city": { + "name": "Taylor Springs", + "code": "IL", + "state": "Illinois", + "county": "Montgomery", + "display": "Taylor Spgs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7682544256953842428-4747", + "name": "Fuzion Apps, Inc", + "city": { + "name": "Enterprise", + "code": "WV", + "state": "West Virginia", + "county": "Harrison", + "display": "Enterprise" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4329345486617054101-4748", + "name": "Expert Health Data Programming, Inc", + "city": { + "name": "Anton Chico", + "code": "NM", + "state": "New Mexico", + "county": "Guadalupe", + "display": "Upper Anton Chico" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3427749967311689230-4749", + "name": "Kaiser Permanante Company", + "city": { + "name": "New Eagle", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "New Eagle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-482366934305875280-4750", + "name": "Workhands LLC", + "city": { + "name": "Atlanta", + "code": "GA", + "state": "Georgia", + "county": "Fulton", + "display": "Ft Mcpherson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2549076566022240715-4751", + "name": "Berkshire Hathaway Corp", + "city": { + "name": "Mallard", + "code": "IA", + "state": "Iowa", + "county": "Palo Alto", + "display": "Mallard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7200844884100266248-4752", + "name": "Expert Health Data Programming, Incorporated", + "city": { + "name": "Condon", + "code": "MT", + "state": "Montana", + "county": "Missoula", + "display": "Condon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6101012580037775612-4753", + "name": "FlightAware Corp", + "city": { + "name": "North Granville", + "code": "NY", + "state": "New York", + "county": "Washington", + "display": "North Granville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4192050675873168985-4754", + "name": "Govzilla, LLC", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Arkansas Louisiana Gas" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8901077522583804026-4755", + "name": "Boundless LLC", + "city": { + "name": "Barhamsville", + "code": "VA", + "state": "Virginia", + "county": "New Kent", + "display": "Barhamsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8588432048057442691-4756", + "name": "ProgrammableWeb Corp", + "city": { + "name": "Bement", + "code": "IL", + "state": "Illinois", + "county": "Piatt", + "display": "Bement" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2777076891649979841-4757", + "name": "Adaptive Incorporated", + "city": { + "name": "Columbus", + "code": "MS", + "state": "Mississippi", + "county": "Lowndes", + "display": "Golden Triangle Regional Air" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7616150869765589280-4758", + "name": "Seabourne LLC", + "city": { + "name": "Sherwood", + "code": "AR", + "state": "Arkansas", + "county": "Pulaski", + "display": "North Little Rock" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8843343873009222812-4759", + "name": "Booz Allen Hamilton Company", + "city": { + "name": "Eagle Bridge", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "White Creek" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4272274386411928997-4760", + "name": "Eat Shop Sleep Inc", + "city": { + "name": "Bayport", + "code": "NY", + "state": "New York", + "county": "Suffolk", + "display": "Bayport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9033163496203168744-4761", + "name": "GovTribe Corporation", + "city": { + "name": "Pulaski", + "code": "WI", + "state": "Wisconsin", + "county": "Brown", + "display": "Pulaski" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2045608468656541764-4762", + "name": "CAN Capital Incorporated", + "city": { + "name": "Trumbull", + "code": "CT", + "state": "Connecticut", + "county": "Fairfield", + "display": "Trumbull" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9019631938490970416-4763", + "name": "Accenture Corp", + "city": { + "name": "Chester", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Chester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1414963931317688801-4764", + "name": "Munetrix Corp", + "city": { + "name": "Bronson", + "code": "TX", + "state": "Texas", + "county": "Sabine", + "display": "Bronson" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3515682453680267586-4765", + "name": "Credit Karma Incorporated", + "city": { + "name": "Nahunta", + "code": "GA", + "state": "Georgia", + "county": "Brantley", + "display": "Raybon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4908631658420583341-4766", + "name": "Intermap Technologies Incorporated", + "city": { + "name": "Arnold", + "code": "CA", + "state": "California", + "county": "Calaveras", + "display": "Arnold" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8017753330728741543-4767", + "name": "SolarList Incorporated", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Quail Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5638053685360360092-4768", + "name": "Lumesis, Corp", + "city": { + "name": "Ocean City", + "code": "MD", + "state": "Maryland", + "county": "Worcester", + "display": "Ocean City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7503700433260446754-4769", + "name": "Citigroup Corp", + "city": { + "name": "Sylvania", + "code": "AL", + "state": "Alabama", + "county": "De Kalb", + "display": "Sylvania" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-208036272845837806-4770", + "name": "realtor.com Corporation", + "city": { + "name": "Alton", + "code": "VA", + "state": "Virginia", + "county": "Halifax", + "display": "Alton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4171144055872683606-4771", + "name": "Whitby Group Corp", + "city": { + "name": "Rock Hill", + "code": "SC", + "state": "South Carolina", + "county": "York", + "display": "Winthrop University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8087685201103857922-4772", + "name": "Smartronix Corporation", + "city": { + "name": "Letcher", + "code": "SD", + "state": "South Dakota", + "county": "Sanborn", + "display": "Letcher" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6599702644733907777-4773", + "name": "Impaq International Incorporated", + "city": { + "name": "Homer Glen", + "code": "IL", + "state": "Illinois", + "county": "Will", + "display": "Lockport" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3725967195307707370-4774", + "name": "Zebu Compliance Solutions Corporation", + "city": { + "name": "Louisville", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Creekside" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-735122238471307520-4775", + "name": "Capital Cube Corp", + "city": { + "name": "North Stratford", + "code": "NH", + "state": "New Hampshire", + "county": "Coos", + "display": "Stratford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2188325893455013498-4776", + "name": "VitalChek Company", + "city": { + "name": "Port Wentworth", + "code": "GA", + "state": "Georgia", + "county": "Chatham", + "display": "Savannah" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3046010234469196171-4777", + "name": "LexisNexis LLC", + "city": { + "name": "Carnelian Bay", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Carnelian Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-948643316053130258-4778", + "name": "Geofeedia Company", + "city": { + "name": "Gastonia", + "code": "NC", + "state": "North Carolina", + "county": "Gaston", + "display": "Smyre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5069384137660066922-4779", + "name": "Marinexplore, Inc", + "city": { + "name": "Kenner", + "code": "LA", + "state": "Louisiana", + "county": "Jefferson", + "display": "Kenner" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2461088462593582462-4780", + "name": "Caspio Company", + "city": { + "name": "Morgan", + "code": "UT", + "state": "Utah", + "county": "Morgan", + "display": "Littleton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7275774563438413215-4781", + "name": "BetterLesson Incorporated", + "city": { + "name": "Columbia City", + "code": "IN", + "state": "Indiana", + "county": "Whitley", + "display": "Collins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6093171520214572369-4782", + "name": "Archimedes Incorporated", + "city": { + "name": "Holland", + "code": "MA", + "state": "Massachusetts", + "county": "Hampden", + "display": "Holland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8295484485013188931-4783", + "name": "Azavea LLC", + "city": { + "name": "Hundred", + "code": "WV", + "state": "West Virginia", + "county": "Wetzel", + "display": "Hundred" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3552525713938153940-4784", + "name": "Garmin Incorporated", + "city": { + "name": "De Witt", + "code": "AR", + "state": "Arkansas", + "county": "Arkansas", + "display": "De Witt" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4482802569009989763-4785", + "name": "Noveda Technologies Corporation", + "city": { + "name": "Edisto Island", + "code": "SC", + "state": "South Carolina", + "county": "Colleton", + "display": "Edisto Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-546184528014595771-4786", + "name": "Mapbox Corp", + "city": { + "name": "Dayton", + "code": "OH", + "state": "Ohio", + "county": "Montgomery", + "display": "Sugarcreek Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-268636665924743261-4787", + "name": "PIXIA Incorporated", + "city": { + "name": "Marble Rock", + "code": "IA", + "state": "Iowa", + "county": "Floyd", + "display": "Oakwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5691768965600051674-4788", + "name": "Informatica Corporation", + "city": { + "name": "South Thomaston", + "code": "ME", + "state": "Maine", + "county": "Knox", + "display": "S Thomaston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2995142406524188505-4789", + "name": "DataWeave Inc", + "city": { + "name": "Pottsville", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Phoenix Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6439273401568448536-4790", + "name": "48 Factoring Incorporated", + "city": { + "name": "Graceville", + "code": "FL", + "state": "Florida", + "county": "Jackson", + "display": "Graceville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1628527606899237611-4791", + "name": "Azavea Corp", + "city": { + "name": "Cleveland", + "code": "TN", + "state": "Tennessee", + "county": "Bradley", + "display": "Clevelnd" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9151673206230924978-4792", + "name": "Mango Transit Company", + "city": { + "name": "Bethel", + "code": "MN", + "state": "Minnesota", + "county": "Anoka", + "display": "Linwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7927319276414715170-4793", + "name": "Cyte LLC", + "city": { + "name": "Troy", + "code": "NC", + "state": "North Carolina", + "county": "Montgomery", + "display": "Uwharie" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5796128432754775248-4794", + "name": "ZocDoc Corp", + "city": { + "name": "Huntley", + "code": "IL", + "state": "Illinois", + "county": "Mchenry", + "display": "Huntley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3452497793287034363-4795", + "name": "Social Explorer Incorporated", + "city": { + "name": "Dunkirk", + "code": "IN", + "state": "Indiana", + "county": "Jay", + "display": "Dunkirk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-612151659946839218-4796", + "name": "Expert Health Data Programming, Corporation", + "city": { + "name": "Fields Landing", + "code": "CA", + "state": "California", + "county": "Humboldt", + "display": "Fields Landing" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9004020619833809647-4797", + "name": "Nautilytics Company", + "city": { + "name": "Pittstown", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Pittstown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3541105269876405886-4798", + "name": "StockSmart Corporation", + "city": { + "name": "Franklin", + "code": "TN", + "state": "Tennessee", + "county": "Williamson", + "display": "Kingfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4997270067760133549-4799", + "name": "OnDeck Corp", + "city": { + "name": "West Point", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "West Point" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8302088474533924255-4800", + "name": "HERE Corporation", + "city": { + "name": "Wood Lake", + "code": "MN", + "state": "Minnesota", + "county": "Yellow Medicine", + "display": "Wood Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5311376932651786931-4801", + "name": "ProPublica Corporation", + "city": { + "name": "Eastanollee", + "code": "GA", + "state": "Georgia", + "county": "Stephens", + "display": "Eastanollee" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8639395361382128750-4802", + "name": "NuCivic Company", + "city": { + "name": "Pansey", + "code": "AL", + "state": "Alabama", + "county": "Houston", + "display": "Pansey" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4214309020850234721-4803", + "name": "MedWatcher Company", + "city": { + "name": "Lancaster", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Meadia Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1429249378522444584-4804", + "name": "Fuzion Apps, Corp", + "city": { + "name": "Mountainburg", + "code": "AR", + "state": "Arkansas", + "county": "Crawford", + "display": "Mountainburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-547895586903420080-4805", + "name": "Buildingeye Corporation", + "city": { + "name": "Merrill", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Merrill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7930103708376895412-4806", + "name": "The Govtech Fund Corporation", + "city": { + "name": "Wood River", + "code": "NE", + "state": "Nebraska", + "county": "Hall", + "display": "Prosser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9067857409224384706-4807", + "name": "Spikes Cavell Analytic Inc", + "city": { + "name": "Chamisal", + "code": "NM", + "state": "New Mexico", + "county": "Taos", + "display": "Chamisal" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3746928469353358552-4808", + "name": "IVES Group Company", + "city": { + "name": "Grenville", + "code": "NM", + "state": "New Mexico", + "county": "Union", + "display": "Mt Dora" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5661815377054707676-4809", + "name": "Abt Associates Inc", + "city": { + "name": "West Frankfort", + "code": "IL", + "state": "Illinois", + "county": "Franklin", + "display": "Denning" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8204627829237443687-4810", + "name": "PossibilityU Inc", + "city": { + "name": "Antwerp", + "code": "OH", + "state": "Ohio", + "county": "Paulding", + "display": "Antwerp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6051945376604600617-4811", + "name": "Charles River Associates Company", + "city": { + "name": "Stevenson", + "code": "WA", + "state": "Washington", + "county": "Skamania", + "display": "Skamania" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6124439822349075326-4812", + "name": "MedWatcher Inc", + "city": { + "name": "Genoa", + "code": "WV", + "state": "West Virginia", + "county": "Wayne", + "display": "Radnor" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1775598397569263776-4813", + "name": "Ez-XBRL Incorporated", + "city": { + "name": "Zachow", + "code": "WI", + "state": "Wisconsin", + "county": "Shawano", + "display": "Bonduel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4898917757413922930-4814", + "name": "College Abacus, an ECMC initiative Inc", + "city": { + "name": "Galesville", + "code": "MD", + "state": "Maryland", + "county": "Anne Arundel", + "display": "Galesville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2343159565645660855-4815", + "name": "Everyday Health Corporation", + "city": { + "name": "Stillwater", + "code": "NY", + "state": "New York", + "county": "Saratoga", + "display": "Stillwater" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5308816631031621158-4816", + "name": "Estately Company", + "city": { + "name": "Chester", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Chester" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1264891211030230655-4817", + "name": "Bridgewater Company", + "city": { + "name": "Bonita", + "code": "LA", + "state": "Louisiana", + "county": "Morehouse", + "display": "Bonita" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-315243717509389228-4818", + "name": "Junyo Inc", + "city": { + "name": "Amelia", + "code": "LA", + "state": "Louisiana", + "county": "Saint Mary", + "display": "Amelia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1151041448585974980-4819", + "name": "Harris Company", + "city": { + "name": "Mount Pleasant", + "code": "AR", + "state": "Arkansas", + "county": "Izard", + "display": "Mount Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8235681597290019597-4820", + "name": "HealthPocket, Corporation", + "city": { + "name": "Allenwood", + "code": "PA", + "state": "Pennsylvania", + "county": "Union", + "display": "Gregg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2546585398417073953-4821", + "name": "Socrata Incorporated", + "city": { + "name": "Needville", + "code": "TX", + "state": "Texas", + "county": "Fort Bend", + "display": "Needville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2011517199260384986-4822", + "name": "Adobe Digital Government Company", + "city": { + "name": "Smoot", + "code": "WV", + "state": "West Virginia", + "county": "Greenbrier", + "display": "Meadow Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3735257452455145692-4823", + "name": "Personal Democracy Media LLC", + "city": { + "name": "Pomfret Center", + "code": "CT", + "state": "Connecticut", + "county": "Windham", + "display": "Pomfret Center" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4782866814252175330-4824", + "name": "Junar, Corporation", + "city": { + "name": "Plymouth", + "code": "FL", + "state": "Florida", + "county": "Orange", + "display": "Plymouth" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2180981932733541120-4825", + "name": "Noveda Technologies Corp", + "city": { + "name": "Colfax", + "code": "CA", + "state": "California", + "county": "Placer", + "display": "Eden Valley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3622039482314880459-4826", + "name": "NERA Economic Consulting Corporation", + "city": { + "name": "Eau Claire", + "code": "WI", + "state": "Wisconsin", + "county": "Eau Claire", + "display": "Caryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4070556618237756067-4827", + "name": "HelloWallet Company", + "city": { + "name": "Frenchtown", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Frenchtown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6350062483193698028-4828", + "name": "FlightStats Inc", + "city": { + "name": "Union City", + "code": "PA", + "state": "Pennsylvania", + "county": "Erie", + "display": "Union City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6271312216289152565-4829", + "name": "TrustedID Company", + "city": { + "name": "Hampden", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Newburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3772931108239819365-4830", + "name": "xDayta Corp", + "city": { + "name": "Markle", + "code": "IN", + "state": "Indiana", + "county": "Wells", + "display": "Markle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5731875210557201765-4831", + "name": "CareSet Systems Inc", + "city": { + "name": "Green Pond", + "code": "AL", + "state": "Alabama", + "county": "Bibb", + "display": "Green Pond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3353590486597590776-4832", + "name": "LoopNet Inc", + "city": { + "name": "Emden", + "code": "IL", + "state": "Illinois", + "county": "Logan", + "display": "Emden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3056553048488429111-4833", + "name": "Garmin LLC", + "city": { + "name": "Monetta", + "code": "SC", + "state": "South Carolina", + "county": "Aiken", + "display": "Hibernia" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3704979809737498770-4834", + "name": "StreamLink Software LLC", + "city": { + "name": "North Miami Beach", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Miami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7107106150010813699-4835", + "name": "Azavea Corporation", + "city": { + "name": "South Ozone Park", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "South Ozone Park" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7794590429149695595-4836", + "name": "Microsoft Windows Azure Marketplace Company", + "city": { + "name": "Big Oak Flat", + "code": "CA", + "state": "California", + "county": "Tuolumne", + "display": "Big Oak Flat" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8181867209138079755-4837", + "name": "Symcat LLC", + "city": { + "name": "Spring Grove", + "code": "PA", + "state": "Pennsylvania", + "county": "York", + "display": "Spring Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2415193203197176581-4838", + "name": "DataWeave Inc", + "city": { + "name": "Columbus", + "code": "OH", + "state": "Ohio", + "county": "Franklin", + "display": "Columbus" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5710344761996971939-4839", + "name": "Microsoft Windows Azure Marketplace LLC", + "city": { + "name": "Flushing", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Linden Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3977266603901603489-4840", + "name": "Allianz Corporation", + "city": { + "name": "Huntsville", + "code": "MO", + "state": "Missouri", + "county": "Randolph", + "display": "Huntsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8798682730702349346-4841", + "name": "ASC Partners Corp", + "city": { + "name": "Catoosa", + "code": "OK", + "state": "Oklahoma", + "county": "Rogers", + "display": "Fair Oaks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6291212239254038586-4842", + "name": "DataLogix Corporation", + "city": { + "name": "Laguna Hills", + "code": "CA", + "state": "California", + "county": "Orange", + "display": "Aliso Viejo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5529173306306920745-4843", + "name": "Seabourne Incorporated", + "city": { + "name": "Loraine", + "code": "IL", + "state": "Illinois", + "county": "Adams", + "display": "Bigneck" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-583627384116239688-4844", + "name": "Junyo Inc", + "city": { + "name": "High Rolls Mountain Park", + "code": "NM", + "state": "New Mexico", + "county": "Otero", + "display": "Hi Rls Mtn Pk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8209554954791361646-4845", + "name": "DataLogix LLC", + "city": { + "name": "Audubon", + "code": "IA", + "state": "Iowa", + "county": "Audubon", + "display": "Audubon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-813175392756805467-4846", + "name": "Calcbench, Inc", + "city": { + "name": "Highland", + "code": "MD", + "state": "Maryland", + "county": "Howard", + "display": "Highland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4831921702222097579-4847", + "name": "Smart Utility Systems Company", + "city": { + "name": "Cape Vincent", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Cape Vincent" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8986182029308154866-4848", + "name": "Civis Analytics LLC", + "city": { + "name": "Mercury", + "code": "NV", + "state": "Nevada", + "county": "Nye", + "display": "Jackass Flats" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-769915803449010227-4849", + "name": "Compliance and Risks Corp", + "city": { + "name": "Basom", + "code": "NY", + "state": "New York", + "county": "Genesee", + "display": "Basom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2296767958675229743-4850", + "name": "Science Exchange Corporation", + "city": { + "name": "Alvin", + "code": "IL", + "state": "Illinois", + "county": "Vermilion", + "display": "Alvin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2958786373875645533-4851", + "name": "LegiNation, Corporation", + "city": { + "name": "Piseco", + "code": "NY", + "state": "New York", + "county": "Hamilton", + "display": "Arietta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-661132245191736329-4852", + "name": "StreetEasy Incorporated", + "city": { + "name": "Milladore", + "code": "WI", + "state": "Wisconsin", + "county": "Wood", + "display": "Sherry" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2026380890016606237-4853", + "name": "Earthquake Alert Corporation", + "city": { + "name": "South Seaville", + "code": "NJ", + "state": "New Jersey", + "county": "Cape May", + "display": "South Seaville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1092132389345039533-4854", + "name": "Acxiom LLC", + "city": { + "name": "Dubois", + "code": "ID", + "state": "Idaho", + "county": "Clark", + "display": "Kilgore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3090950031381038430-4855", + "name": "CGI Corporation", + "city": { + "name": "Pueblo Of Acoma", + "code": "NM", + "state": "New Mexico", + "county": "Valencia", + "display": "Pblo Of Acoma" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-841537175286104280-4856", + "name": "BillGuard Corp", + "city": { + "name": "Miami", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Univ Of Miami" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2012084929571497265-4857", + "name": "Predilytics Company", + "city": { + "name": "Buckland", + "code": "OH", + "state": "Ohio", + "county": "Auglaize", + "display": "Buckland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1666936004246765880-4858", + "name": "Personal Democracy Media Inc", + "city": { + "name": "Adrian", + "code": "MO", + "state": "Missouri", + "county": "Bates", + "display": "Adrian" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1756323150279142864-4859", + "name": "Zillow Company", + "city": { + "name": "King Cove", + "code": "AK", + "state": "Alaska", + "county": "Aleutians East", + "display": "King Cove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2231283366019904259-4860", + "name": "Booz Allen Hamilton LLC", + "city": { + "name": "Vermillion", + "code": "SD", + "state": "South Dakota", + "county": "Clay", + "display": "Westerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4732671645740358921-4861", + "name": "The Vanguard Group Incorporated", + "city": { + "name": "Malverne", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Malverne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3820748145283803134-4862", + "name": "Legal Science Partners Company", + "city": { + "name": "Orwigsburg", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "West Brunswick" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-162116854135954582-4863", + "name": "Practice Fusion Company", + "city": { + "name": "Fiddletown", + "code": "CA", + "state": "California", + "county": "Amador", + "display": "Fiddletown" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6244021654053158165-4864", + "name": "Lawdragon Corporation", + "city": { + "name": "Bucksport", + "code": "ME", + "state": "Maine", + "county": "Hancock", + "display": "Verona Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4463938178233663735-4865", + "name": "Development Seed Corporation", + "city": { + "name": "King And Queen Court House", + "code": "VA", + "state": "Virginia", + "county": "King And Queen", + "display": "King And Qn C H" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6522556822649633546-4866", + "name": "Wolters Kluwer Incorporated", + "city": { + "name": "Moosic", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Scranton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8174079580386278772-4867", + "name": "IFI CLAIMS Patent Services Incorporated", + "city": { + "name": "Redwood", + "code": "VA", + "state": "Virginia", + "county": "Franklin", + "display": "Redwood" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4579559369643762091-4868", + "name": "CrowdANALYTIX Corporation", + "city": { + "name": "Winnsboro", + "code": "SC", + "state": "South Carolina", + "county": "Fairfield", + "display": "Winnsboro" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1183606026256225858-4869", + "name": "Peterson's Company", + "city": { + "name": "Potts Camp", + "code": "MS", + "state": "Mississippi", + "county": "Marshall", + "display": "Lebanon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7115086278835235439-4870", + "name": "Mapbox Corporation", + "city": { + "name": "Basom", + "code": "NY", + "state": "New York", + "county": "Genesee", + "display": "Basom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6120666754237630457-4871", + "name": "The Advisory Board Company LLC", + "city": { + "name": "Hampton", + "code": "AR", + "state": "Arkansas", + "county": "Calhoun", + "display": "Hampton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2915901289068470124-4872", + "name": "Be Informed Incorporated", + "city": { + "name": "Hundred", + "code": "WV", + "state": "West Virginia", + "county": "Wetzel", + "display": "Hundred" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4305792738971944088-4873", + "name": "Civinomics Corporation", + "city": { + "name": "North Grosvenordale", + "code": "CT", + "state": "Connecticut", + "county": "Windham", + "display": "North Grosvenordale" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-954026084900637296-4874", + "name": "Environmental Data Resources Corp", + "city": { + "name": "Grand Chain", + "code": "IL", + "state": "Illinois", + "county": "Pulaski", + "display": "Grand Chain" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1069491381493499056-4875", + "name": "Liberty Mutual Insurance Cos Corp", + "city": { + "name": "Jamaica", + "code": "NY", + "state": "New York", + "county": "Queens", + "display": "Addisleigh Pk" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5438307196772120243-4876", + "name": "PatientsLikeMe LLC", + "city": { + "name": "Edgerton", + "code": "MN", + "state": "Minnesota", + "county": "Pipestone", + "display": "Edgerton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9144715228056999230-4877", + "name": "Peterson's Inc", + "city": { + "name": "Bradley", + "code": "ME", + "state": "Maine", + "county": "Penobscot", + "display": "Bradley" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5865443877907118803-4878", + "name": "karmadata Inc", + "city": { + "name": "Minford", + "code": "OH", + "state": "Ohio", + "county": "Scioto", + "display": "Minford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5963095254825310168-4879", + "name": "Rezolve Group Incorporated", + "city": { + "name": "Grapevine", + "code": "AR", + "state": "Arkansas", + "county": "Grant", + "display": "Grapevine" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2361284458048775507-4880", + "name": "Personal, Incorporated", + "city": { + "name": "West Sacramento", + "code": "CA", + "state": "California", + "county": "Yolo", + "display": "West Sacramento" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6412978431187115627-4881", + "name": "Urban Airship Corp", + "city": { + "name": "Fort Myers", + "code": "FL", + "state": "Florida", + "county": "Lee", + "display": "Florida Gulf Coast Univ" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1367695925848452495-4882", + "name": "Careset.com Corporation", + "city": { + "name": "Murray", + "code": "KY", + "state": "Kentucky", + "county": "Calloway", + "display": "University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-625033401366000321-4883", + "name": "Innography Corporation", + "city": { + "name": "Mount Pleasant", + "code": "NC", + "state": "North Carolina", + "county": "Cabarrus", + "display": "Mt Pleasant" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2493316080611463997-4884", + "name": "SAP Incorporated", + "city": { + "name": "Castleton On Hudson", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "South Schodack" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3962337431883651389-4885", + "name": "KidAdmit, LLC", + "city": { + "name": "Wood River", + "code": "NE", + "state": "Nebraska", + "county": "Hall", + "display": "Prosser" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6724428752915865001-4886", + "name": "gRadiant Research Inc", + "city": { + "name": "Pohnpei", + "code": "FM", + "state": "Federated States of Micronesia", + "county": "Federated States Of Micro", + "display": "Pohnpei" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2053328079196624857-4887", + "name": "Noveda Technologies Company", + "city": { + "name": "Newport", + "code": "AR", + "state": "Arkansas", + "county": "Jackson", + "display": "Weldon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2000655045351117939-4888", + "name": "Aidin Incorporated", + "city": { + "name": "Rensselaerville", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Rensselaerville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6765375848323447985-4889", + "name": "Jurispect LLC", + "city": { + "name": "Sparks Glencoe", + "code": "MD", + "state": "Maryland", + "county": "Baltimore", + "display": "Sparks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5480375390911046644-4890", + "name": "TrialX Inc", + "city": { + "name": "Saint Elmo", + "code": "IL", + "state": "Illinois", + "county": "Fayette", + "display": "Saint Elmo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6518533454015965936-4891", + "name": "Fujitsu Company", + "city": { + "name": "Summit", + "code": "MS", + "state": "Mississippi", + "county": "Pike", + "display": "Summit" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8614718178541358475-4892", + "name": "OptumInsight LLC", + "city": { + "name": "Bassett", + "code": "NE", + "state": "Nebraska", + "county": "Rock", + "display": "Rose" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2708352386165572918-4893", + "name": "Scale Unlimited Company", + "city": { + "name": "Schulenburg", + "code": "TX", + "state": "Texas", + "county": "Fayette", + "display": "Engle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8126897804905690496-4894", + "name": "CoolClimate Incorporated", + "city": { + "name": "Benjamin", + "code": "TX", + "state": "Texas", + "county": "Knox", + "display": "Benjamin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6882523907407774367-4895", + "name": "Politify Company", + "city": { + "name": "Naples", + "code": "NY", + "state": "New York", + "county": "Ontario", + "display": "Naples" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5761866984619171230-4896", + "name": "Earthquake Alert Corporation", + "city": { + "name": "Whittier", + "code": "NC", + "state": "North Carolina", + "county": "Jackson", + "display": "Whittier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2792127965701429270-4897", + "name": "Genability Company", + "city": { + "name": "Clarendon", + "code": "AR", + "state": "Arkansas", + "county": "Monroe", + "display": "Clarendon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7246159010282780364-4898", + "name": "PricewaterhouseCoopers LLC", + "city": { + "name": "Carrollton", + "code": "OH", + "state": "Ohio", + "county": "Carroll", + "display": "Kilgore" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5386707521463251275-4899", + "name": "State Farm Insurance Corporation", + "city": { + "name": "Atlanta", + "code": "NE", + "state": "Nebraska", + "county": "Phelps", + "display": "Rock Falls" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6749543485615104017-4900", + "name": "U.S. News Schools Inc", + "city": { + "name": "Buffalo", + "code": "NY", + "state": "New York", + "county": "Erie", + "display": "University Buffalo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4126095113345924031-4901", + "name": "AreaVibes Company", + "city": { + "name": "Lynchburg", + "code": "SC", + "state": "South Carolina", + "county": "Lee", + "display": "South Lynchburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7905559474592929867-4902", + "name": "Dun \u0026 Bradstreet Corp", + "city": { + "name": "Trout Run", + "code": "PA", + "state": "Pennsylvania", + "county": "Lycoming", + "display": "Fields Sta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-438742022524966678-4903", + "name": "Simple Energy Inc", + "city": { + "name": "Mayville", + "code": "MI", + "state": "Michigan", + "county": "Tuscola", + "display": "Mayville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7492118314100984870-4904", + "name": "Certara LLC", + "city": { + "name": "Georgetown", + "code": "LA", + "state": "Louisiana", + "county": "Grant", + "display": "Mudville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3272214175998609126-4905", + "name": "StreetEasy Corporation", + "city": { + "name": "Masonic Home", + "code": "KY", + "state": "Kentucky", + "county": "Jefferson", + "display": "Masonic Home" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7101946330957678535-4906", + "name": "RedLaser Company", + "city": { + "name": "Johnson City", + "code": "TX", + "state": "Texas", + "county": "Blanco", + "display": "Cypress Mill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-572278695351789590-4907", + "name": "How's My Offer? Inc", + "city": { + "name": "Dhs", + "code": "VA", + "state": "Virginia", + "county": "Loudoun", + "display": "Chantilly" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3421287450219843345-4908", + "name": "Navico Company", + "city": { + "name": "Westbrookville", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Westbrookvlle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4408168024175118948-4909", + "name": "Fastcase Inc", + "city": { + "name": "Newell", + "code": "SD", + "state": "South Dakota", + "county": "Butte", + "display": "Cedar Canyon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7544008733136248684-4910", + "name": "Whitby Group Company", + "city": { + "name": "Omaha", + "code": "NE", + "state": "Nebraska", + "county": "Sarpy", + "display": "La Vista" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5089885811411938338-4911", + "name": "PricewaterhouseCoopers Inc", + "city": { + "name": "Sharon", + "code": "GA", + "state": "Georgia", + "county": "Taliaferro", + "display": "Sharon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5584137067997948084-4912", + "name": "Lawdragon LLC", + "city": { + "name": "Los Angeles", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Farmer Market" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1264986721670598217-4913", + "name": "Kaiser Permanante Corp", + "city": { + "name": "Brielle", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Brielle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7549812975827625294-4914", + "name": "SAP Incorporated", + "city": { + "name": "Shreveport", + "code": "LA", + "state": "Louisiana", + "county": "Caddo", + "display": "Swepco" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5267949312635929379-4915", + "name": "Equilar Company", + "city": { + "name": "Kemp", + "code": "TX", + "state": "Texas", + "county": "Kaufman", + "display": "Seven Points" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3030024306503300029-4916", + "name": "LOGIXDATA, Inc", + "city": { + "name": "Windsor Heights", + "code": "IA", + "state": "Iowa", + "county": "Polk", + "display": "Windsor Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3340207883592116363-4917", + "name": "Geofeedia Corp", + "city": { + "name": "Needham Heights", + "code": "MA", + "state": "Massachusetts", + "county": "Norfolk", + "display": "Needham Hgts" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2604318815215093101-4918", + "name": "Nautilytics Company", + "city": { + "name": "San Diego", + "code": "CA", + "state": "California", + "county": "San Diego", + "display": "Nas North Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1774060665900723439-4919", + "name": "5PSolutions Corporation", + "city": { + "name": "Toronto", + "code": "KS", + "state": "Kansas", + "county": "Woodson", + "display": "Toronto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-540018874010506049-4920", + "name": "Zillow Company", + "city": { + "name": "Starkville", + "code": "MS", + "state": "Mississippi", + "county": "Oktibbeha", + "display": "Starkville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6539082007756562258-4921", + "name": "Barchart LLC", + "city": { + "name": "Bainbridge Island", + "code": "WA", + "state": "Washington", + "county": "Kitsap", + "display": "Bainbridge Island" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8312817674192698670-4922", + "name": "Biovia Inc", + "city": { + "name": "Eldorado", + "code": "IL", + "state": "Illinois", + "county": "Saline", + "display": "College Heights" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8674883309828417497-4923", + "name": "NERA Economic Consulting Incorporated", + "city": { + "name": "Goetzville", + "code": "MI", + "state": "Michigan", + "county": "Chippewa", + "display": "Stalwart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-61972600929608224-4924", + "name": "Aidin Incorporated", + "city": { + "name": "West Millgrove", + "code": "OH", + "state": "Ohio", + "county": "Wood", + "display": "W Millgrove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7710615571582571550-4925", + "name": "StockSmart Incorporated", + "city": { + "name": "Filion", + "code": "MI", + "state": "Michigan", + "county": "Huron", + "display": "Filion" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3990874165565678320-4926", + "name": "WebFilings LLC", + "city": { + "name": "Dover", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Victory Gardens" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5088474805067113888-4927", + "name": "Trulia Corporation", + "city": { + "name": "New Woodstock", + "code": "NY", + "state": "New York", + "county": "Madison", + "display": "Sheds" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2073274382196141345-4928", + "name": "AutoGrid Systems Company", + "city": { + "name": "Melrude", + "code": "MN", + "state": "Minnesota", + "county": "Saint Louis", + "display": "Whiteface" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4581931499312329854-4929", + "name": "Civis Analytics LLC", + "city": { + "name": "Flat Rock", + "code": "MI", + "state": "Michigan", + "county": "Wayne", + "display": "Brownstwn Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3931095463070095318-4930", + "name": "ideas42 Corp", + "city": { + "name": "Bernalillo", + "code": "NM", + "state": "New Mexico", + "county": "Sandoval", + "display": "Sandia Pueblo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5521201489794027734-4931", + "name": "MetLife Incorporated", + "city": { + "name": "Whittier", + "code": "CA", + "state": "California", + "county": "Los Angeles", + "display": "Pico Rivera" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1486143060360362151-4932", + "name": "Energy Solutions Forum Company", + "city": { + "name": "Millington", + "code": "MD", + "state": "Maryland", + "county": "Kent", + "display": "Millington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5752963396721898669-4933", + "name": "Rank and Filed Inc", + "city": { + "name": "Mountainburg", + "code": "AR", + "state": "Arkansas", + "county": "Crawford", + "display": "Mountainburg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6759848658607124132-4934", + "name": "Appallicious Inc", + "city": { + "name": "Montesano", + "code": "WA", + "state": "Washington", + "county": "Grays Harbor", + "display": "Melbourne" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6395774558688662969-4935", + "name": "Paxata Corp", + "city": { + "name": "Cold Brook", + "code": "NY", + "state": "New York", + "county": "Herkimer", + "display": "Morehouse" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3367529374194166321-4936", + "name": "Progressive Insurance Group Inc", + "city": { + "name": "Dubuque", + "code": "IA", + "state": "Iowa", + "county": "Dubuque", + "display": "Center Grove" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4157674297513265289-4937", + "name": "J.P. Morgan Chase LLC", + "city": { + "name": "Juneau", + "code": "AK", + "state": "Alaska", + "county": "Juneau", + "display": "State Of Alaska Brm" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8781763840379740446-4938", + "name": "Junyo Inc", + "city": { + "name": "Mount Freedom", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Mount Freedom" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1855972723709075790-4939", + "name": "GetRaised Corporation", + "city": { + "name": "Whiting", + "code": "VT", + "state": "Vermont", + "county": "Addison", + "display": "Whiting" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6906755960815394965-4940", + "name": "Smartronix LLC", + "city": { + "name": "Green Pond", + "code": "SC", + "state": "South Carolina", + "county": "Colleton", + "display": "Green Pond" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7808224396857025763-4941", + "name": "Honest Buildings Corp", + "city": { + "name": "Edinburgh", + "code": "IN", + "state": "Indiana", + "county": "Johnson", + "display": "Edinburgh" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6711387626686843273-4942", + "name": "Everyday Health Corporation", + "city": { + "name": "Keego Harbor", + "code": "MI", + "state": "Michigan", + "county": "Oakland", + "display": "Sylvan Lake" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8925117286323542405-4943", + "name": "Unigo Company", + "city": { + "name": "Piermont", + "code": "NH", + "state": "New Hampshire", + "county": "Grafton", + "display": "Piermont" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7788673061619107328-4944", + "name": "gRadiant Research Inc", + "city": { + "name": "Willow Street", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Willow" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3627238733053811544-4945", + "name": "BuildFax LLC", + "city": { + "name": "Sikeston", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Sikeston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5639837192463518066-4946", + "name": "Vitals LLC", + "city": { + "name": "Albany", + "code": "NY", + "state": "New York", + "county": "Albany", + "display": "Nys Tax Processing Ctr" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5052057822659400357-4947", + "name": "WebFilings Corp", + "city": { + "name": "Esparto", + "code": "CA", + "state": "California", + "county": "Yolo", + "display": "Esparto" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5074577177741311407-4948", + "name": "Telenav Company", + "city": { + "name": "Macomb", + "code": "OK", + "state": "Oklahoma", + "county": "Pottawatomie", + "display": "Macomb" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2038521334672436121-4949", + "name": "Recargo Company", + "city": { + "name": "Milbridge", + "code": "ME", + "state": "Maine", + "county": "Washington", + "display": "Milbridge" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-997848665463321121-4950", + "name": "Recargo LLC", + "city": { + "name": "Hollins", + "code": "AL", + "state": "Alabama", + "county": "Clay", + "display": "Hollins" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5746663754105197513-4951", + "name": "Connotate Inc", + "city": { + "name": "Sandston", + "code": "VA", + "state": "Virginia", + "county": "Henrico", + "display": "Sandston" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4974700200711665048-4952", + "name": "Informatica LLC", + "city": { + "name": "Ringoes", + "code": "NJ", + "state": "New Jersey", + "county": "Hunterdon", + "display": "Ringoes" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3496638185594162888-4953", + "name": "TrustedID LLC", + "city": { + "name": "Audubon", + "code": "IA", + "state": "Iowa", + "county": "Audubon", + "display": "Audubon" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7440548941152999284-4954", + "name": "Arrive Labs Corporation", + "city": { + "name": "Graford", + "code": "TX", + "state": "Texas", + "county": "Palo Pinto", + "display": "Graford" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2320787221152479977-4955", + "name": "BlackRock Incorporated", + "city": { + "name": "Noxen", + "code": "PA", + "state": "Pennsylvania", + "county": "Wyoming", + "display": "Forkston Township" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1615948757352058663-4956", + "name": "Import.io Company", + "city": { + "name": "Weslaco", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Progreso Lks" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3028737625635244447-4957", + "name": "Berkery Noyes MandASoft Company", + "city": { + "name": "Verndale", + "code": "MN", + "state": "Minnesota", + "county": "Wadena", + "display": "Wing River" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4364584122407900232-4958", + "name": "ConnectEDU Corporation", + "city": { + "name": "Silver Springs", + "code": "NV", + "state": "Nevada", + "county": "Lyon", + "display": "Silver Springs" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-688601391891949515-4959", + "name": "College Abacus, an ECMC initiative Corp", + "city": { + "name": "Augusta", + "code": "WV", + "state": "West Virginia", + "county": "Hampshire", + "display": "Augusta" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8621898767660389320-4960", + "name": "SolarList Incorporated", + "city": { + "name": "Jersey Shore", + "code": "PA", + "state": "Pennsylvania", + "county": "Lycoming", + "display": "Larryville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7083066175961452242-4961", + "name": "SlashDB LLC", + "city": { + "name": "Ridgefield", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Morsemere" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5964109745194202130-4962", + "name": "Propeller Health LLC", + "city": { + "name": "Crystal Bay", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Crystal Bay" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9044678696486910108-4963", + "name": "Eat Shop Sleep Corp", + "city": { + "name": "Yucaipa", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Oak Glen" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8568765237687558819-4964", + "name": "SpaceCurve Incorporated", + "city": { + "name": "Howard", + "code": "OH", + "state": "Ohio", + "county": "Knox", + "display": "Howard" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6042664466433390426-4965", + "name": "Keychain Logistics Corp", + "city": { + "name": "Groveland", + "code": "FL", + "state": "Florida", + "county": "Lake", + "display": "Groveland" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4585388388580352143-4966", + "name": "Ayasdi Corporation", + "city": { + "name": "Fort Wainwright", + "code": "AK", + "state": "Alaska", + "county": "Fairbanks North Star", + "display": "Ft Wainwright" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7452539405355647104-4967", + "name": "CityScan LLC", + "city": { + "name": "Pittsfield", + "code": "PA", + "state": "Pennsylvania", + "county": "Warren", + "display": "Pittsfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6298225661673164571-4968", + "name": "Factset Incorporated", + "city": { + "name": "Saint Clairsville", + "code": "OH", + "state": "Ohio", + "county": "Belmont", + "display": "Saint Clairsville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-244156475706717860-4969", + "name": "Intermap Technologies Corporation", + "city": { + "name": "Ligonier", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Ligonier" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6305634288651575136-4970", + "name": "realtor.com Company", + "city": { + "name": "Elephant Butte", + "code": "NM", + "state": "New Mexico", + "county": "Sierra", + "display": "Engle" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-985671413641426654-4971", + "name": "Urban Airship LLC", + "city": { + "name": "Narvon", + "code": "PA", + "state": "Pennsylvania", + "county": "Lancaster", + "display": "Fetterville" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9144274404305226352-4972", + "name": "Eat Shop Sleep LLC", + "city": { + "name": "Osage", + "code": "MN", + "state": "Minnesota", + "county": "Becker", + "display": "Snellman" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6609992821290700717-4973", + "name": "WattzOn Inc", + "city": { + "name": "Gleason", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Parrish" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1794823575324859413-4974", + "name": "FutureAdvisor LLC", + "city": { + "name": "Midland", + "code": "SD", + "state": "South Dakota", + "county": "Haakon", + "display": "England Ranch" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5934497802387154125-4975", + "name": "Alarm.com Inc", + "city": { + "name": "Pine Bluff", + "code": "AR", + "state": "Arkansas", + "county": "Jefferson", + "display": "Pine Bluff" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-596735270189682119-4976", + "name": "Kaiser Permanante Corporation", + "city": { + "name": "Mc Intyre", + "code": "PA", + "state": "Pennsylvania", + "county": "Indiana", + "display": "Mcintyre" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2562979972261520809-4977", + "name": "Xignite Corporation", + "city": { + "name": "Fort Plain", + "code": "NY", + "state": "New York", + "county": "Montgomery", + "display": "Sand Hill" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1332708992965545291-4978", + "name": "MarketSense Company", + "city": { + "name": "Howell", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Wall Twp" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8503053587432963537-4979", + "name": "Business Monitor International Corporation", + "city": { + "name": "Loma Linda", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Loma Linda University" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5791648930893524291-4980", + "name": "IBM Corporation", + "city": { + "name": "Benjamin", + "code": "TX", + "state": "Texas", + "county": "Knox", + "display": "Benjamin" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4852022136629732109-4981", + "name": "Code-N LLC", + "city": { + "name": "Union City", + "code": "PA", + "state": "Pennsylvania", + "county": "Erie", + "display": "Union City" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2367480346462019015-4982", + "name": "AutoGrid Systems Corporation", + "city": { + "name": "Belmar", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "West Belmar" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6579086979272334178-4983", + "name": "CliniCast Corporation", + "city": { + "name": "Pleasanton", + "code": "NE", + "state": "Nebraska", + "county": "Buffalo", + "display": "Pleasanton" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4106289850966672887-4984", + "name": "Ernst \u0026 Young LLP LLC", + "city": { + "name": "Badger", + "code": "MN", + "state": "Minnesota", + "county": "Roseau", + "display": "Badger" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4583012672545547781-4985", + "name": "Xcential Corporation", + "city": { + "name": "West Hatfield", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "W Hatfield" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3924871608859186553-4986", + "name": "How's My Offer? LLC", + "city": { + "name": "New Lebanon", + "code": "NY", + "state": "New York", + "county": "Columbia", + "display": "Lebanon Spg" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3950409982780786911-4987", + "name": "Acxiom Incorporated", + "city": { + "name": "Avenel", + "code": "NJ", + "state": "New Jersey", + "county": "Middlesex", + "display": "Avenel" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9099503264527371266-4988", + "name": "Factual Incorporated", + "city": { + "name": "Ocean Springs", + "code": "MS", + "state": "Mississippi", + "county": "Jackson", + "display": "Gulf Park Estates" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7569004033096677412-4989", + "name": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-3263690433409999503-4990", + "name": "Navico Company", + "city": { + "name": "Stamford", + "code": "NE", + "state": "Nebraska", + "county": "Harlan", + "display": "Sappa" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-1402182556229598355-4991", + "name": "Morgan Stanley LLC", + "city": { + "name": "Columbus Junction", + "code": "IA", + "state": "Iowa", + "county": "Louisa", + "display": "Cairo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8051736240013155640-4992", + "name": "Bloomberg LLC", + "city": { + "name": "Haynesville", + "code": "LA", + "state": "Louisiana", + "county": "Claiborne", + "display": "Blackburn" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-4640035788968195153-4993", + "name": "Simple Energy Corp", + "city": { + "name": "West Burlington", + "code": "IA", + "state": "Iowa", + "county": "Des Moines", + "display": "West Burlington" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-9165055320120222102-4994", + "name": "Nielsen Corporation", + "city": { + "name": "Akron", + "code": "AL", + "state": "Alabama", + "county": "Hale", + "display": "Stewart" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-2054165738490438926-4995", + "name": "KLD Research Corp", + "city": { + "name": "Kenesaw", + "code": "NE", + "state": "Nebraska", + "county": "Adams", + "display": "Wanda" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-8048526564060372752-4996", + "name": "Dabo Health Company", + "city": { + "name": "Boncarbo", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Boncarbo" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5702522287246113782-4997", + "name": "iTriage Company", + "city": { + "name": "Middle Bass", + "code": "OH", + "state": "Ohio", + "county": "Ottawa", + "display": "Middle Bass" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-6799285179963472525-4998", + "name": "Oliver Wyman Inc", + "city": { + "name": "Kipling", + "code": "OH", + "state": "Ohio", + "county": "Guernsey", + "display": "Kipling" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-7117038111380865505-4999", + "name": "Cerner Corp", + "city": { + "name": "Pleasant Shade", + "code": "TN", + "state": "Tennessee", + "county": "Smith", + "display": "Pleasant Shade" + } +} +, +{ + "type": "merchant", + "merchantid": "merchant-5117638116383865201-5000", + "name": "Apple Regent Street", + "city": { + "name": "London", + "code": "W1B 2EL", + "county": "Westminster", + "display": "London Westminster" + } +} +] diff --git a/modules/eventing/assets/attachments/examples/high_risk/txns.json b/modules/eventing/assets/attachments/examples/high_risk/txns.json new file mode 100644 index 000000000..1cb49cf0d --- /dev/null +++ b/modules/eventing/assets/attachments/examples/high_risk/txns.json @@ -0,0 +1,7076 @@ +[ + { + "type": "transaction", + "txnid": "tx-1531149691-001", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-07-09T20:51:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526311379-002", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "GoodGuide Inc", + "city": { + "name": "Waseca", + "code": "MN", + "state": "Minnesota", + "county": "Waseca", + "display": "Otisco" + }, + "date": "2018-05-14T20:52:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524495646-003", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "Chubb Company", + "city": { + "name": "Lynchburg", + "code": "VA", + "state": "Virginia", + "county": "Lynchburg City", + "display": "Fort Hill" + }, + "date": "2018-04-23T20:30:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515512568-004", + "amount": 5000, + "product": "Consultant Contract For Acquisition And", + "card": "4273-6623-8686-4599", + "merchant": "Ayasdi LLC", + "city": { + "name": "Acme", + "code": "PA", + "state": "Pennsylvania", + "county": "Westmoreland", + "display": "Acme" + }, + "date": "2018-01-09T21:12:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514474890-005", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Merrill Corporation", + "city": { + "name": "Netarts", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Netarts Bay" + }, + "date": "2017-12-28T20:58:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526655858-006", + "amount": 16.79, + "product": "12a0910 Washer, Flat Stl, Zinc Pltd. 5/8", + "card": "4273-6623-8686-4599", + "merchant": "Govzilla, Corporation", + "city": { + "name": "Baytown", + "code": "TX", + "state": "Texas", + "county": "Chambers", + "display": "Beach City" + }, + "date": "2018-05-18T20:34:18+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534086962-007", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-08-12T20:46:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510328559-008", + "amount": 41.77, + "product": "3/4\" Emt Concrete Tight D Catalog # 251dc2", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-10T21:12:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511709792-009", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-26T20:53:12+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522856386-010", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-04-04T21:09:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534950221-011", + "amount": 384, + "product": "Repair Of Autocite Ticket Writer, Serial #76087", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-08-22T20:33:41+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524496846-012", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "Archimedes Incorporated", + "city": { + "name": "Holland", + "code": "MA", + "state": "Massachusetts", + "county": "Hampden", + "display": "Holland" + }, + "date": "2018-04-23T20:50:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514994625-013", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-01-03T21:20:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514386857-014", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "Collective IP Company", + "city": { + "name": "Gibson", + "code": "PA", + "state": "Pennsylvania", + "county": "Susquehanna", + "display": "Gibson" + }, + "date": "2017-12-27T20:30:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521128830-015", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-03-15T21:17:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527866004-016", + "amount": 113.99, + "product": "Toner Cartridge, Q5949a For Hp 1320", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-06-01T20:43:24+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530113963-017", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-06-27T21:09:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525966045-018", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-05-10T20:57:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524929769-019", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "Ernst & Young LLP LLC", + "city": { + "name": "Trout Creek", + "code": "MI", + "state": "Michigan", + "county": "Ontonagon", + "display": "Trout Creek" + }, + "date": "2018-04-28T21:06:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516980862-020", + "amount": 11550, + "product": "Abstracting Services For The Group Project 1b", + "card": "4273-6623-8686-4599", + "merchant": "Appallicious Inc", + "city": { + "name": "Bloomville", + "code": "OH", + "state": "Ohio", + "county": "Seneca", + "display": "Bloomville" + }, + "date": "2018-01-26T21:04:22+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535727288-021", + "amount": 5423, + "product": "Sony 1080p Hd 20x Camera, Mfg. Part #Snc-Ep580", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-08-31T20:24:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530632013-022", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "Cambridge Information Group Corp", + "city": { + "name": "Bruno", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Bruno" + }, + "date": "2018-07-03T21:03:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515858697-023", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "Sterling Infosystems Incorporated", + "city": { + "name": "Ferguson", + "code": "NC", + "state": "North Carolina", + "county": "Wilkes", + "display": "Darby" + }, + "date": "2018-01-13T21:21:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510672129-024", + "amount": 2400, + "product": "Whelen Siren, #295slsa6", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-14T20:38:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507477788-025", + "amount": 4373, + "product": "Provide Assistance To The Step Program As Per", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-08T21:19:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522597502-026", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-04-01T21:15:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511365082-027", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-22T21:08:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521645355-028", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-03-21T20:45:55+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519225543-029", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-02-21T20:35:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523546031-030", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Lumesis, Corporation", + "city": { + "name": "Vermillion", + "code": "SD", + "state": "South Dakota", + "county": "Clay", + "display": "Westerville" + }, + "date": "2018-04-12T20:43:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526311208-031", + "amount": 456.62, + "product": "Dominator 6, Item #D6bbbbbb,For 2012 Chevrolet", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-05-14T20:50:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512574773-032", + "amount": 19480, + "product": "Chevrolet Traverse Suv, 2016", + "card": "4273-6623-8686-4599", + "merchant": "IFI CLAIMS Patent Services Corp", + "city": { + "name": "Benezett", + "code": "PA", + "state": "Pennsylvania", + "county": "Elk", + "display": "Benezette" + }, + "date": "2017-12-06T21:09:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525880146-033", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-05-09T21:05:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517411866-034", + "amount": 649.10, + "product": "Replacement Eurodrive Clear Box", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-01-31T20:47:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508686119-035", + "amount": 2.59, + "product": "Suction Gasket,P/N Pvd719", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-22T20:58:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513869380-036", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "SAP Corporation", + "city": { + "name": "Empire", + "code": "CA", + "state": "California", + "county": "Stanislaus", + "display": "Empire" + }, + "date": "2017-12-21T20:46:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523372959-037", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-04-10T20:39:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507476204-038", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-08T20:53:24+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510327095-039", + "amount": 12130, + "product": "Downtown Tree Well & Sidewalk Beautification", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-10T20:48:15+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514820010-040", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-01-01T20:50:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511625126-041", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "Parsons Brinckerhoff Corp", + "city": { + "name": "Middletown", + "code": "CA", + "state": "California", + "county": "Lake", + "display": "Loch Lomond" + }, + "date": "2017-11-25T21:22:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516808835-042", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-01-24T21:17:15+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524322973-043", + "amount": 463.74, + "product": "Hon-Gsa Nucleus Mid Back Work Chair, Adjustable", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-04-21T20:32:53+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521560802-044", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-03-20T21:16:42+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534866260-045", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-08-21T21:14:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513352659-046", + "amount": 5, + "product": "Small Black Patch With \"Police\" In Gray Lettering 6\" X 2\"", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-12-15T21:14:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507561338-047", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-09T20:32:18+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519746014-048", + "amount": 8250, + "product": "Installation, Termination And Testing Of Cabling", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-02-27T21:10:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521731684-049", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "Earth Networks LLC", + "city": { + "name": "Lawndale", + "code": "NC", + "state": "North Carolina", + "county": "Cleveland", + "display": "Belwood" + }, + "date": "2018-03-22T20:44:44+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516892874-050", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-01-25T20:37:54+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509980936-051", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-06T20:38:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508426321-052", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Urban Airship Company", + "city": { + "name": "Merrill", + "code": "WI", + "state": "Wisconsin", + "county": "Lincoln", + "display": "Merrill" + }, + "date": "2017-10-19T20:48:41+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511537405-053", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-24T21:00:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527605951-054", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Optensity Corporation", + "city": { + "name": "Sugarcreek", + "code": "OH", + "state": "Ohio", + "county": "Tuscarawas", + "display": "Shanesville" + }, + "date": "2018-05-29T20:29:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512917833-055", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-12-10T20:27:13+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506613201-056", + "amount": 439, + "product": "Dell Optiplex 980 Small Form Factor For Standard", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-09-28T21:10:01+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526571296-057", + "amount": 12500, + "product": "Evidence Building, 2905 Evangeline St., Baton", + "card": "4273-6623-8686-4599", + "merchant": "H3 Biomedicine Inc", + "city": { + "name": "Newbury", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "Newbury" + }, + "date": "2018-05-17T21:04:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528904450-058", + "amount": 29.99, + "product": "Item# 112999-L Dri-Mesh V-Neck Sport Shirt Ladies Size - 4 Xl", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-06-13T21:10:50+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512748438-059", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "Onvia Incorporated", + "city": { + "name": "Chapmanville", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Chapmanville" + }, + "date": "2017-12-08T21:23:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527520956-060", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "TransUnion LLC", + "city": { + "name": "Nottingham", + "code": "PA", + "state": "Pennsylvania", + "county": "Chester", + "display": "Nottingham" + }, + "date": "2018-05-28T20:52:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521473851-061", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "Simple Energy Corporation", + "city": { + "name": "Newport", + "code": "VA", + "state": "Virginia", + "county": "Giles", + "display": "Newport" + }, + "date": "2018-03-19T21:07:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506180965-062", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "Personalis Corporation", + "city": { + "name": "Forestburgh", + "code": "NY", + "state": "New York", + "county": "Sullivan", + "display": "Forestburgh" + }, + "date": "2017-09-23T21:06:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516721257-063", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-01-23T20:57:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511276860-064", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "Panjiva Incorporated", + "city": { + "name": "Exeter", + "code": "RI", + "state": "Rhode Island", + "county": "Washington", + "display": "Exeter" + }, + "date": "2017-11-21T20:37:40+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510153917-065", + "amount": 18.99, + "product": "Dell Mini Display Port To Vga Conversion Dongle", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-08T20:41:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510067194-066", + "amount": 638.76, + "product": "Top End Load Carrier", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-07T20:36:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517325592-067", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "Innovest Systems Corp", + "city": { + "name": "Woodville", + "code": "WI", + "state": "Wisconsin", + "county": "Saint Croix", + "display": "Woodville" + }, + "date": "2018-01-30T20:49:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524842791-068", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-04-27T20:56:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507736796-069", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "Intelius Inc", + "city": { + "name": "Wellington", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "West Palm Beach" + }, + "date": "2017-10-11T21:16:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529249942-070", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "Cyte LLC", + "city": { + "name": "Troy", + "code": "NC", + "state": "North Carolina", + "county": "Montgomery", + "display": "Uwharie" + }, + "date": "2018-06-17T21:09:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526051174-071", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-05-11T20:36:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530287497-072", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-06-29T21:21:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528124305-073", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Arpin Van Lines Corporation", + "city": { + "name": "Elgin", + "code": "TX", + "state": "Texas", + "county": "Bastrop", + "display": "Elgin" + }, + "date": "2018-06-04T20:28:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505402809-074", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-09-14T20:56:49+05:30", + "currency": "EUR" + }, + { + "type": "transaction", + "txnid": "tx-1524236342-075", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "PYA Analytics Incorporated", + "city": { + "name": "Mount Carmel", + "code": "PA", + "state": "Pennsylvania", + "county": "Northumberland", + "display": "Connersville" + }, + "date": "2018-04-20T20:29:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507909437-076", + "amount": 8995, + "product": "2010 Ford E-150 Cargo Van 4dr Cargo, 1/2 Ton", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-13T21:13:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522768281-077", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-04-03T20:41:21+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522249060-078", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-03-28T20:27:40+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519139127-079", + "amount": 2225, + "product": "Southern University Head Start, Building 131", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-02-20T20:35:27+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507131297-080", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-04T21:04:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507995943-081", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-14T21:15:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507388159-082", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-07T20:25:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508857203-083", + "amount": 30.99, + "product": "Ff1101, Filter Fuel John Deere Equipment", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-10-24T20:30:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518447337-084", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "SAS LLC", + "city": { + "name": "High Point", + "code": "NC", + "state": "North Carolina", + "county": "Guilford", + "display": "Glenola" + }, + "date": "2018-02-12T20:25:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519743896-085", + "amount": 388, + "product": "Pro Guard Partition, Plastic Half Metal Mesh", + "card": "4273-6623-8686-4599", + "merchant": "Lawdragon Corporation", + "city": { + "name": "Pittsburgh", + "code": "PA", + "state": "Pennsylvania", + "county": "Allegheny", + "display": "Pgh" + }, + "date": "2018-02-27T20:34:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530459286-086", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-07-01T21:04:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525189735-087", + "amount": 352, + "product": "Red/White Light Fixtures, Part Code M6d", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-05-01T21:18:55+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530111896-088", + "amount": 875, + "product": "To Provide Design Services For Mosquito", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-06-27T20:34:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530025019-089", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Sterling Infosystems Incorporated", + "city": { + "name": "Ferguson", + "code": "NC", + "state": "North Carolina", + "county": "Wilkes", + "display": "Darby" + }, + "date": "2018-06-26T20:26:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525447852-090", + "amount": 1775, + "product": "Advising The Library Board Of Control On", + "card": "4273-6623-8686-4599", + "merchant": "Zebu Compliance Solutions Corp", + "city": { + "name": "Mc Cool Junction", + "code": "NE", + "state": "Nebraska", + "county": "York", + "display": "Mc Cool Jct" + }, + "date": "2018-05-04T21:00:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1536505378-091", + "amount": 80, + "product": "3/4\" Pa Rgdglv Str Strap Catalog # B2009pa34", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-09-09T20:32:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521559100-092", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-03-20T20:48:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532358524-093", + "amount": 299, + "product": "Vla Office Pro Plus 2012 (A6591288) Software", + "card": "4273-6623-8686-4599", + "merchant": "Kaiser Permanante Corporation", + "city": { + "name": "Hagatna", + "code": "GU", + "state": "Guam", + "county": "Guam", + "display": "Agana" + }, + "date": "2018-07-23T20:38:44+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533224448-094", + "amount": 1111.39, + "product": "40 Inch Professional Lcd Display", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-08-02T21:10:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530459573-095", + "amount": 242, + "product": "Printing The Covers For The 2014 Cafr, The 2014", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-07-01T21:09:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531583630-096", + "amount": 4676, + "product": "Copier, Lease, Xerox, Segment 7", + "card": "4273-6623-8686-4599", + "merchant": "InCadence Company", + "city": { + "name": "Sweet Water", + "code": "AL", + "state": "Alabama", + "county": "Marengo", + "display": "Sweet Water" + }, + "date": "2018-07-14T21:23:50+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526483166-097", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "CB Insights LLC", + "city": { + "name": "Kensett", + "code": "IA", + "state": "Iowa", + "county": "Worth", + "display": "Bolan" + }, + "date": "2018-05-16T20:36:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1536853994-098", + "amount": 850, + "product": "Janitorial Services In Accordance With Contract", + "card": "4273-6623-8686-4599", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2018-09-13T21:23:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509724249-099", + "amount": 899, + "product": "La Tech Spike Wide Lane Alpr 492 Camera With", + "card": "4273-6623-8686-4599", + "merchant": "Aidin Inc", + "city": { + "name": "Whatley", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Whatley" + }, + "date": "2017-11-03T21:20:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533570127-100", + "amount": 1792, + "product": "Back Enclosure For 72\"W Stack On Storage", + "card": "4273-6623-8686-4599", + "merchant": "Rand McNally Corporation", + "city": { + "name": "Pretty Prairie", + "code": "KS", + "state": "Kansas", + "county": "Reno", + "display": "Pretty Pr" + }, + "date": "2018-08-06T21:12:07+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520089159-101", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-03-03T20:29:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530285241-102", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "S&P Capital IQ LLC", + "city": { + "name": "San Benito", + "code": "TX", + "state": "Texas", + "county": "Cameron", + "display": "Laureles" + }, + "date": "2018-06-29T20:44:01+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528471060-103", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-06-08T20:47:40+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528818518-104", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-06-12T21:18:38+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535986505-105", + "amount": 21.88, + "product": "Qorpak Trigger Sprayer, White, Pk 12", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-09-03T20:25:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532876374-106", + "amount": 1553, + "product": "Overhead 78\" With Glass, Mahogany", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-07-29T20:29:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530978103-107", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Boston Consulting Group Company", + "city": { + "name": "Needville", + "code": "TX", + "state": "Texas", + "county": "Fort Bend", + "display": "Fairchilds" + }, + "date": "2018-07-07T21:11:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535730315-108", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Simple Energy Corp", + "city": { + "name": "West Burlington", + "code": "IA", + "state": "Iowa", + "county": "Des Moines", + "display": "West Burlington" + }, + "date": "2018-08-31T21:15:15+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521299600-109", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "iRecycle LLC", + "city": { + "name": "White Heath", + "code": "IL", + "state": "Illinois", + "county": "Piatt", + "display": "White Heath" + }, + "date": "2018-03-17T20:43:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513351170-110", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-12-15T20:49:30+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528386528-111", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "WebFilings Incorporated", + "city": { + "name": "Faulkton", + "code": "SD", + "state": "South Dakota", + "county": "Faulk", + "display": "Burkmere" + }, + "date": "2018-06-07T21:18:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529248331-112", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Import.io Company", + "city": { + "name": "Weslaco", + "code": "TX", + "state": "Texas", + "county": "Hidalgo", + "display": "Progreso Lks" + }, + "date": "2018-06-17T20:42:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519484754-113", + "amount": 179.20, + "product": "Zo3c0062 Wrist Pin, Ks/Kss", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-02-24T20:35:54+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534175122-114", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-08-13T21:15:22+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507044289-115", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-10-03T20:54:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528471351-116", + "amount": 749.99, + "product": "Controller; Tester, Nt-12 Nema, For Testing", + "card": "4163-4174-9281-3991", + "merchant": "Whitby Group LLC", + "city": { + "name": "New Cumberland", + "code": "PA", + "state": "Pennsylvania", + "county": "Cumberland", + "display": "Fair Acres" + }, + "date": "2018-06-08T20:52:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528384673-117", + "amount": 1349.00, + "product": "Wxga 5500 Ansi Lumens Projector", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-06-07T20:47:53+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526658171-118", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-05-18T21:12:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518449688-119", + "amount": 1050.50, + "product": "Copperhead 3-D Printer Kit; Components Are Wired", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-02-12T21:04:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524929535-120", + "amount": 28, + "product": "School Smart Multi-Purpose Butcher Kraft Paper", + "card": "4163-4174-9281-3991", + "merchant": "Moody's Company", + "city": { + "name": "Saint Joseph", + "code": "MI", + "state": "Michigan", + "county": "Berrien", + "display": "Saint Joseph" + }, + "date": "2018-04-28T21:02:15+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523891487-121", + "amount": 8146, + "product": "Wear Liner Type C - Hardox 400 Brinell Wear Bars", + "card": "4163-4174-9281-3991", + "merchant": "Standard and Poor's Inc", + "city": { + "name": "Cornwall On Hudson", + "code": "NY", + "state": "New York", + "county": "Orange", + "display": "Cornwall Hud" + }, + "date": "2018-04-16T20:41:27+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515858734-122", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Equal Speed Inc", + "city": { + "name": "Washington", + "code": "MI", + "state": "Michigan", + "county": "Macomb", + "display": "Washington" + }, + "date": "2018-01-13T21:22:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521903714-123", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-03-24T20:31:54+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522336208-124", + "amount": 18.99, + "product": "Uniform Pants; Color: Navy Blue, Redkap Durakap", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-03-29T20:40:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510067917-125", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-11-07T20:48:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521126022-126", + "amount": 21793, + "product": "Demilition Of Building, Slab, And Parking Area", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-03-15T20:30:22+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519055003-127", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-02-19T21:13:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510673905-128", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-11-14T21:08:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1504799249-129", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Inovalon Company", + "city": { + "name": "West Palm Beach", + "code": "FL", + "state": "Florida", + "county": "Palm Beach", + "display": "Royal Palm Beach" + }, + "date": "2017-09-07T21:17:29+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509548970-130", + "amount": 15000, + "product": "Professional Services Agreement To", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-11-01T20:39:30+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506784952-131", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-09-30T20:52:32+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526743354-132", + "amount": 15.25, + "product": "Insignia: Lt. Bar, Large, Blackington J-62", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-05-19T20:52:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508686837-133", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-10-22T21:10:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512486964-134", + "amount": 7500, + "product": "Supplemental Agreement No 9 For Engineering", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-12-05T20:46:04+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529766489-135", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Govini Inc", + "city": { + "name": "Columbia", + "code": "LA", + "state": "Louisiana", + "county": "Caldwell", + "display": "Burroughs" + }, + "date": "2018-06-23T20:38:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1536160080-136", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-09-05T20:38:00+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511883666-137", + "amount": 772, + "product": "Odns-Goldspv-1yr-1-Terms 12/9/17-12/9/18", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-11-28T21:11:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509983326-138", + "amount": 19.99, + "product": "Speaker Bracket For 2010 Camero, #Sak", + "card": "4163-4174-9281-3991", + "merchant": "Trintech Incorporated", + "city": { + "name": "Crystal Bay", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Orono" + }, + "date": "2017-11-06T21:18:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517413239-139", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Relationship Science Incorporated", + "city": { + "name": "Maquoketa", + "code": "IA", + "state": "Iowa", + "county": "Jackson", + "display": "Ironhills" + }, + "date": "2018-01-31T21:10:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514388425-140", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-12-27T20:57:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532617988-141", + "amount": 17.79, + "product": "Fadeless Art Paper 48\" X 50', Color: Black", + "card": "4163-4174-9281-3991", + "merchant": "POPVOX Inc", + "city": { + "name": "Summit", + "code": "MS", + "state": "Mississippi", + "county": "Pike", + "display": "Summit" + }, + "date": "2018-07-26T20:43:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524325069-142", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Paxata Corp", + "city": { + "name": "Howes", + "code": "SD", + "state": "South Dakota", + "county": "Meade", + "display": "Bridger" + }, + "date": "2018-04-21T21:07:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527261822-143", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-05-25T20:53:42+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507909357-144", + "amount": 387, + "product": "Tackboard: H90034 Hon-Gsa", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-10-13T21:12:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519918460-145", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "BuildFax LLC", + "city": { + "name": "Sikeston", + "code": "MO", + "state": "Missouri", + "county": "Scott", + "display": "Sikeston" + }, + "date": "2018-03-01T21:04:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515079182-146", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-01-04T20:49:42+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526485320-147", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-05-16T21:12:00+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514388968-148", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-12-27T21:06:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513868745-149", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-12-21T20:35:45+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524324581-150", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-04-21T20:59:41+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528472338-151", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-06-08T21:08:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509118938-152", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-10-27T21:12:18+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516461258-153", + "amount": 9475, + "product": "Renewal Of End User Silver Maintenance & Support", + "card": "4163-4174-9281-3991", + "merchant": "PatientsLikeMe Company", + "city": { + "name": "Buckland", + "code": "OH", + "state": "Ohio", + "county": "Auglaize", + "display": "Buckland" + }, + "date": "2018-01-20T20:44:18+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520521502-154", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-03-08T20:35:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513871164-155", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-12-21T21:16:04+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520091651-156", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "gRadiant Research Incorporated", + "city": { + "name": "Bainbridge", + "code": "NY", + "state": "New York", + "county": "Chenango", + "display": "West Bainbridge" + }, + "date": "2018-03-03T21:10:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510328883-157", + "amount": 239, + "product": "4hw2174d-36-H-4l-P.Inwoodof Bravo 2100 Series", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Company", + "city": { + "name": "New Eagle", + "code": "PA", + "state": "Pennsylvania", + "county": "Washington", + "display": "New Eagle" + }, + "date": "2017-11-10T21:18:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512919897-158", + "amount": 40, + "product": "Etc Selrn-7.5 7.5\" Narrow Lens (Round Field)", + "card": "4163-4174-9281-3991", + "merchant": "Chemical Abstracts Service Corporation", + "city": { + "name": "Lanagan", + "code": "MO", + "state": "Missouri", + "county": "Mcdonald", + "display": "Lanagan" + }, + "date": "2017-12-10T21:01:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510327262-159", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Avvo Incorporated", + "city": { + "name": "Fort Gratiot", + "code": "MI", + "state": "Michigan", + "county": "Saint Clair", + "display": "Burtchville Township" + }, + "date": "2017-11-10T20:51:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505919729-160", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-09-20T20:32:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534518404-161", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-08-17T20:36:44+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515251993-162", + "amount": 279.95, + "product": "Return Shell, Sl4224r-R Is Sl4224r", + "card": "4163-4174-9281-3991", + "merchant": "CitySourced Company", + "city": { + "name": "Rancho Cucamonga", + "code": "CA", + "state": "California", + "county": "San Bernardino", + "display": "Cucamonga" + }, + "date": "2018-01-06T20:49:53+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510154654-163", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-11-08T20:54:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508686893-164", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "MetLife Inc", + "city": { + "name": "Peterson", + "code": "MN", + "state": "Minnesota", + "county": "Fillmore", + "display": "Rushford Vlg" + }, + "date": "2017-10-22T21:11:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529161578-165", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "OpenCounter Company", + "city": { + "name": "Rossville", + "code": "TN", + "state": "Tennessee", + "county": "Fayette", + "display": "Rossville" + }, + "date": "2018-06-16T20:36:18+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514648212-166", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Intermap Technologies Incorporated", + "city": { + "name": "West Farmington", + "code": "ME", + "state": "Maine", + "county": "Franklin", + "display": "West Farmington" + }, + "date": "2017-12-30T21:06:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529423328-167", + "amount": 249.99, + "product": "Speaker, Black Plastic, Sa315p, Dodge Charger", + "card": "4163-4174-9281-3991", + "merchant": "Seabourne Company", + "city": { + "name": "Winslow", + "code": "AZ", + "state": "Arizona", + "county": "Navajo", + "display": "Tolani" + }, + "date": "2018-06-19T21:18:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518881974-168", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-02-17T21:09:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527175081-169", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "PlaceILive.com LLC", + "city": { + "name": "Spencer", + "code": "ID", + "state": "Idaho", + "county": "Clark", + "display": "Dubois" + }, + "date": "2018-05-24T20:48:01+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532705940-170", + "amount": 9271.15, + "product": "Hazmatid Elite Command Package-Dual Diamond", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-07-27T21:09:00+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519311549-171", + "amount": 128, + "product": "Fairbanks Morse Model 5\" B5423k End Suction", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-02-22T20:29:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512054355-172", + "amount": 18.99, + "product": "Uniform Pants; Color: Navy Blue, Redkap Durakap", + "card": "4163-4174-9281-3991", + "merchant": "Iodine Company", + "city": { + "name": "Cushing", + "code": "OK", + "state": "Oklahoma", + "county": "Payne", + "display": "Schlegal" + }, + "date": "2017-11-30T20:35:55+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524670708-173", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-04-25T21:08:28+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527261207-174", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-05-25T20:43:27+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513352507-175", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-12-15T21:11:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515512944-176", + "amount": 2150, + "product": "Onsite Destruction/Shredding Of 80-100 Banker'S", + "card": "4163-4174-9281-3991", + "merchant": "Honest Buildings Company", + "city": { + "name": "Dushore", + "code": "PA", + "state": "Pennsylvania", + "county": "Sullivan", + "display": "Wilmot Township" + }, + "date": "2018-01-09T21:19:04+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529506978-177", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-06-20T20:32:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518190453-178", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-02-09T21:04:13+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532274816-179", + "amount": 9326, + "product": "Line Added In Error", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-07-22T21:23:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515079955-180", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "LOGIXDATA, Company", + "city": { + "name": "Lighthouse Point", + "code": "FL", + "state": "Florida", + "county": "Broward", + "display": "Lighthouse Pt" + }, + "date": "2018-01-04T21:02:35+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508255264-181", + "amount": 2300, + "product": "Lease Of Property Located At:", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-10-17T21:17:44+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511710690-182", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-11-26T21:08:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507045656-183", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-10-03T21:17:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532186809-184", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-07-21T20:56:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515251806-185", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-01-06T20:46:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533741856-186", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-08-08T20:54:16+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515941844-187", + "amount": 699, + "product": "Replace Malfunctioning Brivo Acs50000-S", + "card": "4163-4174-9281-3991", + "merchant": "Funding Circle Inc", + "city": { + "name": "North Miami Beach", + "code": "FL", + "state": "Florida", + "county": "Miami-Dade", + "display": "Miami" + }, + "date": "2018-01-14T20:27:24+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508081578-188", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-10-15T21:02:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511105122-189", + "amount": 10364, + "product": "Second Line Added For Accounting Number And Money Amount Of $20,617.50", + "card": "4163-4174-9281-3991", + "merchant": "Merrill Corporation", + "city": { + "name": "Netarts", + "code": "OR", + "state": "Oregon", + "county": "Tillamook", + "display": "Netarts Bay" + }, + "date": "2017-11-19T20:55:22+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520436250-190", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-03-07T20:54:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517066452-191", + "amount": 3800, + "product": "Consulting Service: Provide Professional Skills", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-01-27T20:50:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507564267-192", + "amount": 301.99, + "product": "S-Fddsdv36 Type D Flipper Unit Sold Face 36w", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-10-09T21:21:07+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526398637-193", + "amount": 5292, + "product": "Cisco Catalyst 3650 48 Port Full Poe Module", + "card": "4163-4174-9281-3991", + "merchant": "Relationship Science Company", + "city": { + "name": "Bayville", + "code": "NJ", + "state": "New Jersey", + "county": "Ocean", + "display": "Bayville" + }, + "date": "2018-05-15T21:07:17+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524151608-194", + "amount": 79.99, + "product": "Cyan Eco-Solvent Ink, 440ml - #29952258", + "card": "4163-4174-9281-3991", + "merchant": "FlightView Inc", + "city": { + "name": "Lashmeet", + "code": "WV", + "state": "West Virginia", + "county": "Mercer", + "display": "Lashmeet" + }, + "date": "2018-04-19T20:56:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520696895-195", + "amount": 45, + "product": "#Albrgmshou Ambmshou Gms", + "card": "4163-4174-9281-3991", + "merchant": "Simple Energy Incorporated", + "city": { + "name": "Riverside", + "code": "CA", + "state": "California", + "county": "Riverside", + "display": "Box Springs" + }, + "date": "2018-03-10T21:18:15+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507391586-196", + "amount": 875, + "product": "Contract Number 4400008332, Line Number 22b", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2017-10-07T21:23:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532532096-197", + "amount": 1550, + "product": "Smartnet 8x5xnbd Catalyst 2960x", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2018-07-25T20:51:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517583691-198", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Patently-O LLC", + "city": { + "name": "Marion", + "code": "IN", + "state": "Indiana", + "county": "Grant", + "display": "Marion" + }, + "date": "2018-02-02T20:31:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521904978-199", + "amount": 3850.17, + "product": "Reimbursable Expenses, Travel And Transportation", + "card": "4163-4174-9281-3991", + "merchant": "Thomson Reuters Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Skillman" + }, + "date": "2018-03-24T20:52:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513263650-200", + "amount": 12506, + "product": "Must Have Metered Truck; 3,000 Gallons Of Mineral Oil", + "card": "4163-4174-9281-3991", + "merchant": "Kaiser Permanante Corp", + "city": { + "name": "Skillman", + "code": "NJ", + "state": "New Jersey", + "county": "Somerset", + "display": "Montgomery" + }, + "date": "2017-12-14T20:30:50+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510153476-201", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-11-08T20:34:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505403785-202", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Geofeedia Corp", + "city": { + "name": "Wabasso", + "code": "MN", + "state": "Minnesota", + "county": "Redwood", + "display": "Wabasso" + }, + "date": "2017-09-14T21:13:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517066346-203", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-27T20:49:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533568250-204", + "amount": 145.04, + "product": "Hp Laserjet 500 Sheet Feeder Tray", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-08-06T20:40:50+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506957544-205", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Cloudmade Incorporated", + "city": { + "name": "Surprise", + "code": "NE", + "state": "Nebraska", + "county": "Butler", + "display": "Ulysses" + }, + "date": "2017-10-02T20:49:04+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532188230-206", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-07-21T21:20:30+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535989743-207", + "amount": 3855, + "product": "Gis Support", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-09-03T21:19:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522855362-208", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-04-04T20:52:42+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517239450-209", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-29T20:54:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531324023-210", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-07-11T21:17:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516720312-211", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "SimpleTuition Inc", + "city": { + "name": "Rochester", + "code": "NY", + "state": "New York", + "county": "Monroe", + "display": "Ridgemont" + }, + "date": "2018-01-23T20:41:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511621808-212", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Cloudspyre Corp", + "city": { + "name": "Boncarbo", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Boncarbo" + }, + "date": "2017-11-25T20:26:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522509528-213", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Zurich Insurance Corporation", + "city": { + "name": "Lone Tree", + "code": "CO", + "state": "Colorado", + "county": "Douglas", + "display": "Lone Tree" + }, + "date": "2018-03-31T20:48:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507216318-214", + "amount": 131.64, + "product": "Blanket Order For Replacement Parts And Services", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-05T20:41:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505919308-215", + "amount": 200, + "product": "44a6225/4", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-09-20T20:25:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525880176-216", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Onvia LLC", + "city": { + "name": "Castor", + "code": "LA", + "state": "Louisiana", + "county": "Bienville", + "display": "Roy" + }, + "date": "2018-05-09T21:06:16+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533569748-217", + "amount": 709.44, + "product": "Pelican Ds-Pan-211 Docking Station For 19 Mk4/", + "card": "5677-7414-8288-4326", + "merchant": "GovTribe Incorporated", + "city": { + "name": "Sarah Ann", + "code": "WV", + "state": "West Virginia", + "county": "Logan", + "display": "Sarah Ann" + }, + "date": "2018-08-06T21:05:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519313974-218", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Remi Corporation", + "city": { + "name": "Peru", + "code": "IA", + "state": "Iowa", + "county": "Madison", + "display": "East Peru" + }, + "date": "2018-02-22T21:09:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532187416-219", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "How's My Offer? Company", + "city": { + "name": "Boonton", + "code": "NJ", + "state": "New Jersey", + "county": "Morris", + "display": "Powerville" + }, + "date": "2018-07-21T21:06:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508598393-220", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "OSIsoft Corp", + "city": { + "name": "Jackson", + "code": "TN", + "state": "Tennessee", + "county": "Madison", + "display": "Bemis" + }, + "date": "2017-10-21T20:36:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534258547-221", + "amount": 112.31, + "product": "Lower 87\" X 45'", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-08-14T20:25:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512226864-222", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-02T20:31:04+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524928259-223", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-04-28T20:40:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508772455-224", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "H3 Biomedicine Inc", + "city": { + "name": "Newbury", + "code": "VT", + "state": "Vermont", + "county": "Orange", + "display": "Newbury" + }, + "date": "2017-10-23T20:57:35+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506093232-225", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "CoolClimate LLC", + "city": { + "name": "Pawtucket", + "code": "RI", + "state": "Rhode Island", + "county": "Providence", + "display": "Pawtucket" + }, + "date": "2017-09-22T20:43:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522336796-226", + "amount": 345, + "product": "Build A Better World Small Youth Vinyl Banner", + "card": "5677-7414-8288-4326", + "merchant": "FarmLogs LLC", + "city": { + "name": "Yakima", + "code": "WA", + "state": "Washington", + "county": "Yakima", + "display": "Tampico" + }, + "date": "2018-03-29T20:49:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506093034-227", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "SeeClickFix Inc", + "city": { + "name": "Louisburg", + "code": "KS", + "state": "Kansas", + "county": "Miami", + "display": "Louisburg" + }, + "date": "2017-09-22T20:40:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527174873-228", + "amount": 11015, + "product": "Freeman-Matthews Head Start, 1383 Napoleon Street, Baton Rouge, La 70802", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-05-24T20:44:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505575037-229", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "College Board Incorporated", + "city": { + "name": "Paramus", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Paramus" + }, + "date": "2017-09-16T20:47:17+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517240303-230", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "PatientsLikeMe Corp", + "city": { + "name": "Newark", + "code": "DE", + "state": "Delaware", + "county": "New Castle", + "display": "Christiana" + }, + "date": "2018-01-29T21:08:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526312645-231", + "amount": 71.75, + "product": "Performance Of Fabulous Big Band Orchestra With", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-05-14T21:14:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511279084-232", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-11-21T21:14:44+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523113231-233", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-04-07T20:30:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528816545-234", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-06-12T20:45:45+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517584616-235", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-02-02T20:46:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516117680-236", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-16T21:18:00+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533308249-237", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-08-03T20:27:29+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510067143-238", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-11-07T20:35:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510412870-239", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Rivet Software Incorporated", + "city": { + "name": "North Little Rock", + "code": "AR", + "state": "Arkansas", + "county": "Pulaski", + "display": "Veterans Administration Faci" + }, + "date": "2017-11-11T20:37:50+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525101208-240", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "NextBus Incorporated", + "city": { + "name": "Wewahitchka", + "code": "FL", + "state": "Florida", + "county": "Calhoun", + "display": "Kinard" + }, + "date": "2018-04-30T20:43:28+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532013829-241", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-07-19T20:53:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507388236-242", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-07T20:27:16+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527434939-243", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-05-27T20:58:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530632421-244", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Barchart Corp", + "city": { + "name": "Stanley", + "code": "NM", + "state": "New Mexico", + "county": "Santa Fe", + "display": "Stanley" + }, + "date": "2018-07-03T21:10:21+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505660161-245", + "amount": 558, + "product": "Headlamps, Daytime Runner Lamps & Automatic", + "card": "5677-7414-8288-4326", + "merchant": "SpotHero.com Inc", + "city": { + "name": "Calhoun", + "code": "IL", + "state": "Illinois", + "county": "Richland", + "display": "Berryville" + }, + "date": "2017-09-17T20:26:01+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521212891-246", + "amount": 580, + "product": "Speed Hump - 14' L X 15' X 3\"H", + "card": "5677-7414-8288-4326", + "merchant": "McKinsey Inc", + "city": { + "name": "Hamilton", + "code": "OH", + "state": "Ohio", + "county": "Butler", + "display": "City View Heights" + }, + "date": "2018-03-16T20:38:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519485269-247", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Golden Helix Incorporated", + "city": { + "name": "East Hickory", + "code": "PA", + "state": "Pennsylvania", + "county": "Forest", + "display": "Endeavor" + }, + "date": "2018-02-24T20:44:29+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510154179-248", + "amount": 2201, + "product": "Airfield Sweeper System: 8 Foot, Single Mat", + "card": "5677-7414-8288-4326", + "merchant": "Nautilytics Corporation", + "city": { + "name": "Louisville", + "code": "OH", + "state": "Ohio", + "county": "Stark", + "display": "Fairhope" + }, + "date": "2017-11-08T20:46:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518103917-249", + "amount": 10930, + "product": "On-Site Installation Is Limited To The Initial", + "card": "5677-7414-8288-4326", + "merchant": "Apextech Incorporated", + "city": { + "name": "Rio Dell", + "code": "CA", + "state": "California", + "county": "Humboldt", + "display": "Rio Dell" + }, + "date": "2018-02-08T21:01:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518015860-250", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-02-07T20:34:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508081101-251", + "amount": 472.20, + "product": "Yokes, Custom", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-15T20:55:01+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512832070-252", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-09T20:37:50+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529766959-253", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-06-23T20:45:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516635142-254", + "amount": 478, + "product": "Item# Hoi Hf-4165; Bench, Fid", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-22T21:02:22+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529596429-255", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-06-21T21:23:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526656000-256", + "amount": 300, + "product": "Routine Maintenance Of Fire Alarms", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-05-18T20:36:40+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524754867-257", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "FutureAdvisor LLC", + "city": { + "name": "Midland", + "code": "SD", + "state": "South Dakota", + "county": "Haakon", + "display": "England Ranch" + }, + "date": "2018-04-26T20:31:07+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506266803-258", + "amount": 299.99, + "product": "Item #1.22 Tpc Gun Vault (Small), Custom Built", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-09-24T20:56:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519400337-259", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-02-23T21:08:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523375578-260", + "amount": 500.99, + "product": "Mc2000 Advanced Deskset Manual, Model 6880309k85, Line 126, Apc 454", + "card": "5677-7414-8288-4326", + "merchant": "Cloudspyre Corp", + "city": { + "name": "Boncarbo", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Boncarbo" + }, + "date": "2018-04-10T21:22:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509119097-261", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-27T21:14:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528213579-262", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-06-05T21:16:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513868905-263", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-21T20:38:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510931351-264", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "ClearStory Data Corp", + "city": { + "name": "Eagle", + "code": "ID", + "state": "Idaho", + "county": "Ada", + "display": "Eagle" + }, + "date": "2017-11-17T20:39:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534778627-265", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-08-20T20:53:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525014829-266", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-04-29T20:43:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535814048-267", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-09-01T20:30:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533828349-268", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-08-09T20:55:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533915445-269", + "amount": 11610, + "product": "Baker Branch Grounds Maintenance As Per The", + "card": "5677-7414-8288-4326", + "merchant": "Boundless LLC", + "city": { + "name": "Jameson", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Jameson" + }, + "date": "2018-08-10T21:07:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516029308-270", + "amount": 21.60, + "product": "Cincon Dc-Dc Volt Convertor 9-18vdc To 5vdc", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-15T20:45:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512316025-271", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-03T21:17:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506697491-272", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-09-29T20:34:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531667817-273", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Loqate, LLC", + "city": { + "name": "Watertown", + "code": "NY", + "state": "New York", + "county": "Jefferson", + "display": "Wtown" + }, + "date": "2018-07-15T20:46:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516895108-274", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-25T21:15:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509981855-275", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-11-06T20:54:15+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513438887-276", + "amount": 427.76, + "product": "Storage Box Clear-View Stackable -", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-16T21:11:27+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516720780-277", + "amount": 10500, + "product": "Design And Delivery Of Production Ready Artwork", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-01-23T20:49:40+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506958558-278", + "amount": 24879, + "product": "Truck: Ford F250 Crew Cab", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-02T21:05:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524670884-279", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "IBM Company", + "city": { + "name": "Happy Valley", + "code": "OR", + "state": "Oregon", + "county": "Clackamas", + "display": "Happy Valley" + }, + "date": "2018-04-25T21:11:24+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529420908-280", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "FindTheBest.com Corporation", + "city": { + "name": "Earlville", + "code": "PA", + "state": "Pennsylvania", + "county": "Berks", + "display": "Earlville" + }, + "date": "2018-06-19T20:38:28+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505920435-281", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-09-20T20:43:55+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514043576-282", + "amount": 214.95, + "product": "Teknion-Tos - Pedestal, Box, Box File Config", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-23T21:09:36+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509205439-283", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "Liquid Robotics LLC", + "city": { + "name": "Mackinac Island", + "code": "MI", + "state": "Michigan", + "county": "Mackinac", + "display": "Mackinac Island" + }, + "date": "2017-10-28T21:13:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506009103-284", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-09-21T21:21:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535900706-285", + "amount": 88, + "product": "35a0455 - Sign Tx For Style 5, 1-Step", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-09-02T20:35:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516375597-286", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "Food+Tech Connect Incorporated", + "city": { + "name": "Center Strafford", + "code": "NH", + "state": "New Hampshire", + "county": "Strafford", + "display": "Ctr Strafford" + }, + "date": "2018-01-19T20:56:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527868383-287", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-06-01T21:23:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518622505-288", + "amount": 150, + "product": "Provide Credit Reporting Services Per Written", + "card": "5677-7414-8288-4326", + "merchant": "Brightscope Incorporated", + "city": { + "name": "Davis Junction", + "code": "IL", + "state": "Illinois", + "county": "Ogle", + "display": "Davis Junction" + }, + "date": "2018-02-14T21:05:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535208924-289", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Cloudspyre Corp", + "city": { + "name": "Boncarbo", + "code": "CO", + "state": "Colorado", + "county": "Las Animas", + "display": "Boncarbo" + }, + "date": "2018-08-25T20:25:24+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510673015-290", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-11-14T20:53:35+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526397607-291", + "amount": 1639, + "product": "Dell Latitude E6410", + "card": "5677-7414-8288-4326", + "merchant": "PlanetEcosystems Incorporated", + "city": { + "name": "Monticello", + "code": "MS", + "state": "Mississippi", + "county": "Lawrence", + "display": "Robinwood" + }, + "date": "2018-05-15T20:50:07+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520608738-292", + "amount": 40, + "product": "Racpro Software, Manual And Usb Cable", + "card": "5677-7414-8288-4326", + "merchant": "U.S. News Schools Company", + "city": { + "name": "Mahanoy City", + "code": "PA", + "state": "Pennsylvania", + "county": "Schuylkill", + "display": "Morea Colliery" + }, + "date": "2018-03-09T20:48:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525015285-293", + "amount": 2507, + "product": "Chaise Recliner-Rocker, Catnapper Sku #20162258", + "card": "5677-7414-8288-4326", + "merchant": "Locavore Corp", + "city": { + "name": "Harper", + "code": "IA", + "state": "Iowa", + "county": "Keokuk", + "display": "Harper" + }, + "date": "2018-04-29T20:51:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508512617-294", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-20T20:46:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524325339-295", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "Standard and Poor's Corp", + "city": { + "name": "Olyphant", + "code": "PA", + "state": "Pennsylvania", + "county": "Lackawanna", + "display": "Sturges" + }, + "date": "2018-04-21T21:12:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535554855-296", + "amount": 41.19, + "product": "Dell Km632 Wireless Ms & Keyboard", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-08-29T20:30:55+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523116258-297", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-04-07T21:20:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509464872-298", + "amount": 9.99, + "product": "#1175c, Blue, Electronic Cuttable", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-10-31T21:17:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1512574208-299", + "amount": 586.99, + "product": "Inner Edge Xlp-10-Lt Charger W/Takedowns", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2017-12-06T21:00:08+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532706275-300", + "amount": 1845, + "product": "Telephone System: Toshiba Cix40 Ip", + "card": "5677-7414-8288-4326", + "merchant": "Berkery Noyes MandASoft Corporation", + "city": { + "name": "Meriden", + "code": "IA", + "state": "Iowa", + "county": "Cherokee", + "display": "Meriden" + }, + "date": "2018-07-27T21:14:35+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513265054-301", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-12-14T20:54:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506527625-302", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "Everyday Health LLC", + "city": { + "name": "Wanette", + "code": "OK", + "state": "Oklahoma", + "county": "Pottawatomie", + "display": "Wanette" + }, + "date": "2017-09-27T21:23:45+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528038051-303", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-03T20:30:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533656983-304", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-08-07T21:19:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505748928-305", + "amount": 33.49, + "product": "Havis Computer Adapter Bracket, C-Hdm-303", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-09-18T21:05:28+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516895539-306", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-01-25T21:22:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526225747-307", + "amount": 5144, + "product": "Fairbanks Morse Model 4\" D5433mkv Submersible", + "card": "5920-7728-6813-5867", + "merchant": "Xatori Corporation", + "city": { + "name": "Bristol", + "code": "GA", + "state": "Georgia", + "county": "Pierce", + "display": "Bristol" + }, + "date": "2018-05-13T21:05:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513178519-308", + "amount": 208, + "product": "Nec Ux5000 Remote Telephone System & Cabling", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-12-13T20:51:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513868628-309", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "College Board Corporation", + "city": { + "name": "Andover", + "code": "NJ", + "state": "New Jersey", + "county": "Sussex", + "display": "Byram Twp" + }, + "date": "2017-12-21T20:33:48+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513611373-310", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-12-18T21:06:13+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514734862-311", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "xDayta Company", + "city": { + "name": "Richmond", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Richmond" + }, + "date": "2017-12-31T21:11:02+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531754423-312", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "Deloitte Corporation", + "city": { + "name": "Butler", + "code": "KY", + "state": "Kentucky", + "county": "Pendleton", + "display": "Butler" + }, + "date": "2018-07-16T20:50:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532099188-313", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "SnapSense Corporation", + "city": { + "name": "Gillett", + "code": "WI", + "state": "Wisconsin", + "county": "Oconto", + "display": "Pulcifer" + }, + "date": "2018-07-20T20:36:28+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508080630-314", + "amount": 896.45, + "product": "Catalog#: Ec26tc3600", + "card": "5920-7728-6813-5867", + "merchant": "TowerData LLC", + "city": { + "name": "Bellemont", + "code": "AZ", + "state": "Arizona", + "county": "Coconino", + "display": "Flagstaff" + }, + "date": "2017-10-15T20:47:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521300752-315", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "Outline Inc", + "city": { + "name": "Young America", + "code": "MN", + "state": "Minnesota", + "county": "Hennepin", + "display": "Young America" + }, + "date": "2018-03-17T21:02:32+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520867396-316", + "amount": 350, + "product": "Articles Of Agreement - Changes To Utility", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-12T20:39:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527780319-317", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-05-31T20:55:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533311669-318", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-08-03T21:24:29+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533568643-319", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "SeeClickFix Corp", + "city": { + "name": "Milroy", + "code": "MN", + "state": "Minnesota", + "county": "Redwood", + "display": "Milroy" + }, + "date": "2018-08-06T20:47:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1504713011-320", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "Dun & Bradstreet Corp", + "city": { + "name": "Hartford", + "code": "CT", + "state": "Connecticut", + "county": "Hartford", + "display": "Central" + }, + "date": "2017-09-06T21:20:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514476120-321", + "amount": 8337, + "product": "Annual Licensing Fee For Infoworks Icm-Sewer", + "card": "5920-7728-6813-5867", + "merchant": "Overture Technologies Inc", + "city": { + "name": "Kansas City", + "code": "MO", + "state": "Missouri", + "county": "Clay", + "display": "N Kansas City" + }, + "date": "2017-12-28T21:18:40+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1522164925-322", + "amount": 7443.99, + "product": "Bomb Suit Ensemble, X-Large, Navy, Eod 10", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-27T21:05:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1534606422-323", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-08-18T21:03:42+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535124412-324", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-08-24T20:56:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1536418479-325", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-09-08T20:24:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510847672-326", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "FindTheBest.com Incorporated", + "city": { + "name": "Clinton Corners", + "code": "NY", + "state": "New York", + "county": "Dutchess", + "display": "Clinton Crn" + }, + "date": "2017-11-16T21:24:32+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513350267-327", + "amount": 53500, + "product": "Construction Contract For City Of Baton Rouge", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-12-15T20:34:27+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521385669-328", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-18T20:37:49+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510846391-329", + "amount": 71.75, + "product": "Performance Of Fabulous Big Band Orchestra With", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-11-16T21:03:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528038365-330", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "Ayasdi LLC", + "city": { + "name": "Mexia", + "code": "TX", + "state": "Texas", + "county": "Limestone", + "display": "Prairie Grove" + }, + "date": "2018-06-03T20:36:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1509031283-331", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-26T20:51:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531061829-332", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-07-08T20:27:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508857878-333", + "amount": 485, + "product": "Extended Maintenance Agreement For Software", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-24T20:41:18+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511710907-334", + "amount": 52.29, + "product": "Sign Base, 2-Bolt Sig Series", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-11-26T21:11:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1516981256-335", + "amount": 248.50, + "product": "Dual Avenger Windshield Lighthead, #Avn2bb For", + "card": "5920-7728-6813-5867", + "merchant": "Peterson's Corporation", + "city": { + "name": "New Paris", + "code": "OH", + "state": "Ohio", + "county": "Preble", + "display": "New Paris" + }, + "date": "2018-01-26T21:10:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523287258-336", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-04-09T20:50:58+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533569833-337", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "Honest Buildings Company", + "city": { + "name": "Oklahoma City", + "code": "OK", + "state": "Oklahoma", + "county": "Oklahoma", + "display": "Smith Village" + }, + "date": "2018-08-06T21:07:13+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508079297-338", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "Ontodia, Corp", + "city": { + "name": "Valley Stream", + "code": "NY", + "state": "New York", + "county": "Nassau", + "display": "Valley Stream" + }, + "date": "2017-10-15T20:24:57+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528041233-339", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "iMedicare Corp", + "city": { + "name": "Wilkes Barre", + "code": "PA", + "state": "Pennsylvania", + "county": "Luzerne", + "display": "Miners Mill" + }, + "date": "2018-06-03T21:23:53+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521560903-340", + "amount": 31.99, + "product": "Rein, Large 10\" Length, Black", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-20T21:18:23+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518967837-341", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "US Green Data LLC", + "city": { + "name": "Bridgman", + "code": "MI", + "state": "Michigan", + "county": "Berrien", + "display": "Bridgman" + }, + "date": "2018-02-18T21:00:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535209499-342", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-08-25T20:34:59+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1518104290-343", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-02-08T21:08:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508167577-344", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-16T20:56:17+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529421783-345", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-19T20:53:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529765677-346", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-23T20:24:37+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535729994-347", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "GuideStar Incorporated", + "city": { + "name": "Wanette", + "code": "OK", + "state": "Oklahoma", + "county": "Pottawatomie", + "display": "Wanette" + }, + "date": "2018-08-31T21:09:54+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513437356-348", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "PublicEngines Inc", + "city": { + "name": "Norfolk", + "code": "VA", + "state": "Virginia", + "county": "Norfolk City", + "display": "Cinclantflt" + }, + "date": "2017-12-16T20:45:56+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1514993125-349", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-01-03T20:55:25+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531236663-350", + "amount": 399.99, + "product": "Laptop, Panasonic Toughbook 52, Core I5 520m 2.4", + "card": "5920-7728-6813-5867", + "merchant": "Microsoft Windows Azure Marketplace Corp", + "city": { + "name": "Georgetown", + "code": "ME", + "state": "Maine", + "county": "Sagadahoc", + "display": "Georgetown" + }, + "date": "2018-07-10T21:01:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523201811-351", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "Castle Biosciences Inc", + "city": { + "name": "Cushing", + "code": "WI", + "state": "Wisconsin", + "county": "Polk", + "display": "Sterling" + }, + "date": "2018-04-08T21:06:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506353493-352", + "amount": 15.25, + "product": "Cslp 2017 Youth English/Spanish Bookmarks; 7\" X", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-09-25T21:01:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532532466-353", + "amount": 1190.28, + "product": "Drive Assemblies", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-07-25T20:57:46+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532446607-354", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-07-24T21:06:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532100052-355", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-07-20T20:50:52+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527865996-356", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "Exversion Company", + "city": { + "name": "Horseshoe Bend", + "code": "ID", + "state": "Idaho", + "county": "Boise", + "display": "Gardena" + }, + "date": "2018-06-01T20:43:16+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523373666-357", + "amount": 169.99, + "product": "New Mountain Nm 150 Weather Station; Wind Speed", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-04-10T20:51:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528385643-358", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-07T21:04:03+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529593907-359", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-21T20:41:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506956910-360", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-02T20:38:30+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1535814453-361", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-09-01T20:37:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1529250339-362", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-17T21:15:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1510757859-363", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-11-15T20:27:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513523498-364", + "amount": 5710, + "product": "Fiber Optics: Provide And Install The Following", + "card": "5920-7728-6813-5867", + "merchant": "Dun & Bradstreet Inc", + "city": { + "name": "Oakland", + "code": "NJ", + "state": "New Jersey", + "county": "Bergen", + "display": "Oakland" + }, + "date": "2017-12-17T20:41:38+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1506612012-365", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "SpeSo Health Corporation", + "city": { + "name": "Kensett", + "code": "IA", + "state": "Iowa", + "county": "Worth", + "display": "Bolan" + }, + "date": "2017-09-28T20:50:12+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1519313050-366", + "amount": 984, + "product": "Desk - Hon Company - Desking, 94000 Series 4-Dr", + "card": "5920-7728-6813-5867", + "merchant": "Weather Decision Technologies Incorporated", + "city": { + "name": "Amherst", + "code": "MA", + "state": "Massachusetts", + "county": "Hampshire", + "display": "Cushman" + }, + "date": "2018-02-22T20:54:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531063816-367", + "amount": 2239, + "product": "Installation Of Cage In The Welding Shop", + "card": "5920-7728-6813-5867", + "merchant": "Merrill LLC", + "city": { + "name": "Beaumont", + "code": "TX", + "state": "Texas", + "county": "Jefferson", + "display": "Taylor Landing" + }, + "date": "2018-07-08T21:00:16+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528299011-368", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-06T21:00:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521041351-369", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-14T20:59:11+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533051086-370", + "amount": 11136, + "product": "Assistance With Emergency Shelter, Homeless And", + "card": "5920-7728-6813-5867", + "merchant": "Relationship Science Company", + "city": { + "name": "Arlington Heights", + "code": "MA", + "state": "Massachusetts", + "county": "Middlesex", + "display": "Arlington" + }, + "date": "2018-07-31T21:01:26+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511711213-371", + "amount": 599, + "product": "Computer, Dell Optiplex 780, Qte 537030974", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-11-26T21:16:53+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525533986-372", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-05-05T20:56:26+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528731747-373", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-11T21:12:27+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1527694911-374", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "BetterLesson LLC", + "city": { + "name": "Wedderburn", + "code": "OR", + "state": "Oregon", + "county": "Curry", + "display": "Wedderburn" + }, + "date": "2018-05-30T21:11:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507474869-375", + "amount": 1141, + "product": "Asa 9.2.2 Software Image For Asa 5500-X Series", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-08T20:31:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1526914483-376", + "amount": 875, + "product": "Baton Rouge River Center Additions And", + "card": "5920-7728-6813-5867", + "merchant": "Locavore LLC", + "city": { + "name": "Sinton", + "code": "TX", + "state": "Texas", + "county": "San Patricio", + "display": "Papalote" + }, + "date": "2018-05-21T20:24:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508426275-377", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-19T20:47:55+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515251716-378", + "amount": 5575, + "product": "Professional Services Acquisition/New", + "card": "5920-7728-6813-5867", + "merchant": "Castle Biosciences Corp", + "city": { + "name": "Averill Park", + "code": "NY", + "state": "New York", + "county": "Rensselaer", + "display": "Burden Lake" + }, + "date": "2018-01-06T20:45:16+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513264869-379", + "amount": 11787, + "product": "Universal Headlight Flasher, 4 Outlet, Item #Ulf44 State Contract #408186", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-12-14T20:51:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515858155-380", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "Rivet Software Incorporated", + "city": { + "name": "Georgetown", + "code": "TX", + "state": "Texas", + "county": "Williamson", + "display": "Sun City" + }, + "date": "2018-01-13T21:12:35+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1525362845-381", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-05-03T21:24:05+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530456986-382", + "amount": 52, + "product": "Hgrmtac Hon-Gsa 4-Trac Electrical Power Hub 3\"", + "card": "5920-7728-6813-5867", + "merchant": "How's My Offer? Corp", + "city": { + "name": "Loveland", + "code": "OK", + "state": "Oklahoma", + "county": "Tillman", + "display": "Loveland" + }, + "date": "2018-07-01T20:26:26+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1520955513-383", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-13T21:08:33+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1513522882-384", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-12-17T20:31:22+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1530458904-385", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "Trintech Inc", + "city": { + "name": "Presho", + "code": "SD", + "state": "South Dakota", + "county": "Lyman", + "display": "Edna" + }, + "date": "2018-07-01T20:58:24+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1511709291-386", + "amount": 16.50, + "product": "10\" Roller Assy, Drive Size Kp3, 2-9/6\" Shaft", + "card": "5920-7728-6813-5867", + "merchant": "Geoscape Corp", + "city": { + "name": "Spring Lake", + "code": "NJ", + "state": "New Jersey", + "county": "Monmouth", + "display": "Spring Lake" + }, + "date": "2017-11-26T20:44:51+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1523374771-387", + "amount": 2508, + "product": "Computer", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-04-10T21:09:31+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1533568339-388", + "amount": 2491, + "product": "Copier Rental - Segment 5 Sharp Mx-M503n B&W", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-08-06T20:42:19+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1521992412-389", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-03-25T21:10:12+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528816634-390", + "amount": 150, + "product": "Minimal Janitorial Services, Two Days Per Week", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-12T20:47:14+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1515683012-391", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-01-11T20:33:32+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1524582343-392", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "Equifax Company", + "city": { + "name": "Mossy Head", + "code": "FL", + "state": "Florida", + "county": "Walton", + "display": "Defuniak Spgs" + }, + "date": "2018-04-24T20:35:43+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1531235861-393", + "amount": 9572, + "product": "To Provide Assistance To Homeless Under The 2015", + "card": "5920-7728-6813-5867", + "merchant": "Adaptive LLC", + "city": { + "name": "Winston", + "code": "MO", + "state": "Missouri", + "county": "Daviess", + "display": "Winston" + }, + "date": "2018-07-10T20:47:41+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1507823046-394", + "amount": 230.40, + "product": "Tasklight, Cord/Vertical Wire, A-Dvvwmtl16", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-10-12T21:14:06+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1508165728-395", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "Ensco Corporation", + "city": { + "name": "Whatley", + "code": "AL", + "state": "Alabama", + "county": "Clarke", + "display": "Gosport" + }, + "date": "2017-10-16T20:25:28+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1532617547-396", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-07-26T20:35:47+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517671414-397", + "amount": 1500, + "product": "Contract For Apprentice Acquisition And", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-02-03T20:53:34+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1528297509-398", + "amount": 175.5, + "product": "Software Parts And Accessories, Apc Code 785", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-06-06T20:35:09+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1517151920-399", + "amount": 202.99, + "product": "Halligan Forcible Entry Tool 36\"", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2018-01-28T20:35:20+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-400", + "amount": 275, + "product": "Computer, 2-Year Applecare+ For Ipad", + "card": "5920-7728-6813-5867", + "merchant": "North American Van Lines Incorporated", + "city": { + "name": "Ponte Vedra Beach", + "code": "FL", + "state": "Florida", + "county": "Saint Johns", + "display": "Ponte Vedra Beach" + }, + "date": "2017-09-13T20:44:10+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-401", + "amount": 2691.25, + "product": "Computer, Macbook Pro 32GB 1TB Nvme", + "card": "4885-1834-8271-9888", + "merchant": "Apple Regent Street", + "city": { + "name": "London", + "code": "W1B 2EL", + "county": "Westminster", + "display": "London Westminster" + }, + "date": "2018-06-15T20:44:10+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-402", + "amount": 41.77, + "product": "3/4\" Emt Concrete Tight D Catalog # 251dc2", + "card": "4885-1834-8271-9888", + "merchant": "BetterLesson Corp", + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "date": "2017-11-10T21:12:39+05:30", + "currency": "USD" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-403", + "amount": 5383.35, + "product": "Computer, iMac 64GB 4TB Nvme", + "card": "4273-6623-8686-4599", + "merchant": "Apple Regent Street", + "city": { + "name": "London", + "code": "W1B 2EL", + "county": "Westminster", + "display": "London Westminster" + }, + "date": "2018-09-14T20:46:10+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-404", + "amount": 78, + "product": "Misc., Apple Pen", + "card": "4273-6623-8686-4599", + "merchant": "Apple Regent Street", + "city": { + "name": "London", + "code": "W1B 2EL", + "county": "Westminster", + "display": "London Westminster" + }, + "date": "2018-09-18T14:48:11+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-405", + "amount": 4878.58, + "product": "Computer, iMac 64GB 2TB Nvme", + "card": "4273-6623-8686-4599", + "merchant": "Apple Regent Street", + "city": { + "name": "London", + "code": "W1B 2EL", + "county": "Westminster", + "display": "London Westminster" + }, + "date": "2018-09-20T14:48:11+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1505315650-406", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2017-09-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1547615650-407", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2017-10-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1598735650-408", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2017-11-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1565315650-409", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2017-12-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1505345650-410", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-01-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1545615650-411", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-02-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1515315650-412", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-03-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1518315650-413", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-04-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1519346550-414", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-05-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1520344550-415", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-06-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1520344750-416", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-07-15T12:48:15+05:30", + "currency": "GBP" + }, + { + "type": "transaction", + "txnid": "tx-1520387868-416", + "amount": 23, + "product": "British Journal for the History of Science", + "card": "3205-9894-1221-0005", + "merchant": "Cambridge University Press", + "city": { + "name": "Cambridge", + "code": "CB2 8BS", + "county": "Westminster", + "display": "Cambridge Cambridgeshire" + }, + "date": "2018-08-15T12:48:15+05:30", + "currency": "GBP" + } +] + diff --git a/modules/eventing/assets/images/N1QL-Query.png b/modules/eventing/assets/images/N1QL-Query.png new file mode 100644 index 000000000..e28eeaf3f Binary files /dev/null and b/modules/eventing/assets/images/N1QL-Query.png differ diff --git a/modules/eventing/assets/images/add_functions_code_exp2.png b/modules/eventing/assets/images/add_functions_code_exp2.png new file mode 100644 index 000000000..e55b3a2ea Binary files /dev/null and b/modules/eventing/assets/images/add_functions_code_exp2.png differ diff --git a/modules/eventing/assets/images/addfunc_00_prerq_bkts.png b/modules/eventing/assets/images/addfunc_00_prerq_bkts.png new file mode 100644 index 000000000..cb77e1b3e Binary files /dev/null and b/modules/eventing/assets/images/addfunc_00_prerq_bkts.png differ diff --git a/modules/eventing/assets/images/addfunc_00_prerq_bkts_s_c.png b/modules/eventing/assets/images/addfunc_00_prerq_bkts_s_c.png new file mode 100644 index 000000000..902249ce1 Binary files /dev/null and b/modules/eventing/assets/images/addfunc_00_prerq_bkts_s_c.png differ diff --git a/modules/eventing/assets/images/addfunc_01_empty_settings.png b/modules/eventing/assets/images/addfunc_01_empty_settings.png new file mode 100644 index 000000000..c8ccd6e9f Binary files /dev/null and b/modules/eventing/assets/images/addfunc_01_empty_settings.png differ diff --git a/modules/eventing/assets/images/addfunc_02_adv_settings.png b/modules/eventing/assets/images/addfunc_02_adv_settings.png new file mode 100644 index 000000000..20fcf4295 Binary files /dev/null and b/modules/eventing/assets/images/addfunc_02_adv_settings.png differ diff --git a/modules/eventing/assets/images/addfunc_02_settings.png b/modules/eventing/assets/images/addfunc_02_settings.png new file mode 100644 index 000000000..3ba0d3031 Binary files /dev/null and b/modules/eventing/assets/images/addfunc_02_settings.png differ diff --git a/modules/eventing/assets/images/addfunc_03_editor_with_default.png b/modules/eventing/assets/images/addfunc_03_editor_with_default.png new file mode 100644 index 000000000..3fa6cef6c Binary files /dev/null and b/modules/eventing/assets/images/addfunc_03_editor_with_default.png differ diff --git a/modules/eventing/assets/images/addfunc_04_newundeployed.png b/modules/eventing/assets/images/addfunc_04_newundeployed.png new file mode 100644 index 000000000..62329660b Binary files /dev/null and b/modules/eventing/assets/images/addfunc_04_newundeployed.png differ diff --git a/modules/eventing/assets/images/addfunc_04a_deploy.png b/modules/eventing/assets/images/addfunc_04a_deploy.png new file mode 100644 index 000000000..ffdd572eb Binary files /dev/null and b/modules/eventing/assets/images/addfunc_04a_deploy.png differ diff --git a/modules/eventing/assets/images/addfunc_05_deployed_done.png b/modules/eventing/assets/images/addfunc_05_deployed_done.png new file mode 100644 index 000000000..b50d76cd3 Binary files /dev/null and b/modules/eventing/assets/images/addfunc_05_deployed_done.png differ diff --git a/modules/eventing/assets/images/addfunc_05_logs_emitted.png b/modules/eventing/assets/images/addfunc_05_logs_emitted.png new file mode 100644 index 000000000..0233e24b9 Binary files /dev/null and b/modules/eventing/assets/images/addfunc_05_logs_emitted.png differ diff --git a/modules/eventing/assets/images/addfunc_06_logs_emitted.png b/modules/eventing/assets/images/addfunc_06_logs_emitted.png new file mode 100644 index 000000000..66e82a80d Binary files /dev/null and b/modules/eventing/assets/images/addfunc_06_logs_emitted.png differ diff --git a/modules/eventing/assets/images/addfunc_07_pause.png b/modules/eventing/assets/images/addfunc_07_pause.png new file mode 100644 index 000000000..18eec362c Binary files /dev/null and b/modules/eventing/assets/images/addfunc_07_pause.png differ diff --git a/modules/eventing/assets/images/addfunc_07_resume.png b/modules/eventing/assets/images/addfunc_07_resume.png new file mode 100644 index 000000000..0f31c3e51 Binary files /dev/null and b/modules/eventing/assets/images/addfunc_07_resume.png differ diff --git a/modules/eventing/assets/images/addfunc_07_undeploy.png b/modules/eventing/assets/images/addfunc_07_undeploy.png new file mode 100644 index 000000000..4d3c7751f Binary files /dev/null and b/modules/eventing/assets/images/addfunc_07_undeploy.png differ diff --git a/modules/eventing/assets/images/addfunc_08_delete.png b/modules/eventing/assets/images/addfunc_08_delete.png new file mode 100644 index 000000000..72c140b7c Binary files /dev/null and b/modules/eventing/assets/images/addfunc_08_delete.png differ diff --git a/modules/eventing/assets/images/addfunctions-code_exp3.png b/modules/eventing/assets/images/addfunctions-code_exp3.png new file mode 100644 index 000000000..718e7ddc7 Binary files /dev/null and b/modules/eventing/assets/images/addfunctions-code_exp3.png differ diff --git a/modules/eventing/assets/images/addfunctions_ex1.png b/modules/eventing/assets/images/addfunctions_ex1.png new file mode 100644 index 000000000..bb6348ab0 Binary files /dev/null and b/modules/eventing/assets/images/addfunctions_ex1.png differ diff --git a/modules/eventing/assets/images/buckets.png b/modules/eventing/assets/images/buckets.png new file mode 100644 index 000000000..4b550e26a Binary files /dev/null and b/modules/eventing/assets/images/buckets.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_01_add_document.png b/modules/eventing/assets/images/cancel_overwrite_timer_01_add_document.png new file mode 100644 index 000000000..535c6e498 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_01_add_document.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_01_buckets.png b/modules/eventing/assets/images/cancel_overwrite_timer_01_buckets.png new file mode 100644 index 000000000..bd5f2553a Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_01_buckets.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_01_data_in_scope.png b/modules/eventing/assets/images/cancel_overwrite_timer_01_data_in_scope.png new file mode 100644 index 000000000..dcdfeea86 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_01_data_in_scope.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_01_docdata.png b/modules/eventing/assets/images/cancel_overwrite_timer_01_docdata.png new file mode 100644 index 000000000..b5a83d399 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_01_docdata.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_01_documents.png b/modules/eventing/assets/images/cancel_overwrite_timer_01_documents.png new file mode 100644 index 000000000..9d4bbeb93 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_01_documents.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_01_settings.png b/modules/eventing/assets/images/cancel_overwrite_timer_01_settings.png new file mode 100644 index 000000000..71089f727 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_01_settings.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_02_editor_with_default.png b/modules/eventing/assets/images/cancel_overwrite_timer_02_editor_with_default.png new file mode 100644 index 000000000..acfb1d701 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_03_editor_with_code.png b/modules/eventing/assets/images/cancel_overwrite_timer_03_editor_with_code.png new file mode 100644 index 000000000..52fb5ef08 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_03a_deploy.png b/modules/eventing/assets/images/cancel_overwrite_timer_03a_deploy.png new file mode 100644 index 000000000..8d318d470 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_03a_deploy.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_04_log_active1.png b/modules/eventing/assets/images/cancel_overwrite_timer_04_log_active1.png new file mode 100644 index 000000000..ff7629f43 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_04_log_active1.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_04_log_fired1.png b/modules/eventing/assets/images/cancel_overwrite_timer_04_log_fired1.png new file mode 100644 index 000000000..a2fb7e146 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_04_log_fired1.png differ diff --git a/modules/eventing/assets/images/cancel_overwrite_timer_04_look_target.png b/modules/eventing/assets/images/cancel_overwrite_timer_04_look_target.png new file mode 100644 index 000000000..bae25a708 Binary files /dev/null and b/modules/eventing/assets/images/cancel_overwrite_timer_04_look_target.png differ diff --git a/modules/eventing/assets/images/casacade_del_withcode.png b/modules/eventing/assets/images/casacade_del_withcode.png new file mode 100644 index 000000000..103441645 Binary files /dev/null and b/modules/eventing/assets/images/casacade_del_withcode.png differ diff --git a/modules/eventing/assets/images/cascade_delete_buckets.png b/modules/eventing/assets/images/cascade_delete_buckets.png new file mode 100644 index 000000000..ceb0783e5 Binary files /dev/null and b/modules/eventing/assets/images/cascade_delete_buckets.png differ diff --git a/modules/eventing/assets/images/cascadedel_01_settings.png b/modules/eventing/assets/images/cascadedel_01_settings.png new file mode 100644 index 000000000..35722039b Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_01_settings.png differ diff --git a/modules/eventing/assets/images/cascadedel_02_editor_with_default.png b/modules/eventing/assets/images/cascadedel_02_editor_with_default.png new file mode 100644 index 000000000..1249bcf83 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/cascadedel_03_editor_with_code.png b/modules/eventing/assets/images/cascadedel_03_editor_with_code.png new file mode 100644 index 000000000..ec6ffddb9 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/cascadedel_03a_deploy.png b/modules/eventing/assets/images/cascadedel_03a_deploy.png new file mode 100644 index 000000000..092641d1f Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_03a_deploy.png differ diff --git a/modules/eventing/assets/images/cascadedel_04_qryusers.png b/modules/eventing/assets/images/cascadedel_04_qryusers.png new file mode 100644 index 000000000..0903ec136 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_04_qryusers.png differ diff --git a/modules/eventing/assets/images/cascadedel_05_qrytrans.png b/modules/eventing/assets/images/cascadedel_05_qrytrans.png new file mode 100644 index 000000000..3f0977e36 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_05_qrytrans.png differ diff --git a/modules/eventing/assets/images/cascadedel_05a_counts.png b/modules/eventing/assets/images/cascadedel_05a_counts.png new file mode 100644 index 000000000..86c81950d Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_05a_counts.png differ diff --git a/modules/eventing/assets/images/cascadedel_06_usersdocs.png b/modules/eventing/assets/images/cascadedel_06_usersdocs.png new file mode 100644 index 000000000..d41c2b9e7 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_06_usersdocs.png differ diff --git a/modules/eventing/assets/images/cascadedel_07_del_100_usersdocs.png b/modules/eventing/assets/images/cascadedel_07_del_100_usersdocs.png new file mode 100644 index 000000000..8ee2f2801 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_07_del_100_usersdocs.png differ diff --git a/modules/eventing/assets/images/cascadedel_08_remainingcounts.png b/modules/eventing/assets/images/cascadedel_08_remainingcounts.png new file mode 100644 index 000000000..19d3342ac Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_08_remainingcounts.png differ diff --git a/modules/eventing/assets/images/cascadedel_08_reminingcounts.png b/modules/eventing/assets/images/cascadedel_08_reminingcounts.png new file mode 100644 index 000000000..1ef0e42eb Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_08_reminingcounts.png differ diff --git a/modules/eventing/assets/images/cascadedel_09_kepttrans.png b/modules/eventing/assets/images/cascadedel_09_kepttrans.png new file mode 100644 index 000000000..09d21b321 Binary files /dev/null and b/modules/eventing/assets/images/cascadedel_09_kepttrans.png differ diff --git a/modules/eventing/assets/images/cascasde_delete.png b/modules/eventing/assets/images/cascasde_delete.png new file mode 100644 index 000000000..df4f4888a Binary files /dev/null and b/modules/eventing/assets/images/cascasde_delete.png differ diff --git a/modules/eventing/assets/images/debug_1.png b/modules/eventing/assets/images/debug_1.png new file mode 100644 index 000000000..136d16878 Binary files /dev/null and b/modules/eventing/assets/images/debug_1.png differ diff --git a/modules/eventing/assets/images/debug_2.png b/modules/eventing/assets/images/debug_2.png new file mode 100644 index 000000000..23545024b Binary files /dev/null and b/modules/eventing/assets/images/debug_2.png differ diff --git a/modules/eventing/assets/images/debug_3.png b/modules/eventing/assets/images/debug_3.png new file mode 100644 index 000000000..e9eabf9ce Binary files /dev/null and b/modules/eventing/assets/images/debug_3.png differ diff --git a/modules/eventing/assets/images/debug_4.png b/modules/eventing/assets/images/debug_4.png new file mode 100644 index 000000000..66081316e Binary files /dev/null and b/modules/eventing/assets/images/debug_4.png differ diff --git a/modules/eventing/assets/images/debug_5_log_level.png b/modules/eventing/assets/images/debug_5_log_level.png new file mode 100644 index 000000000..f8d05133d Binary files /dev/null and b/modules/eventing/assets/images/debug_5_log_level.png differ diff --git a/modules/eventing/assets/images/debug_websocket_disconnected.png b/modules/eventing/assets/images/debug_websocket_disconnected.png new file mode 100644 index 000000000..37aed3796 Binary files /dev/null and b/modules/eventing/assets/images/debug_websocket_disconnected.png differ diff --git a/modules/eventing/assets/images/debugger_01_eventing_page.png b/modules/eventing/assets/images/debugger_01_eventing_page.png new file mode 100644 index 000000000..0a2b0921d Binary files /dev/null and b/modules/eventing/assets/images/debugger_01_eventing_page.png differ diff --git a/modules/eventing/assets/images/debugger_02_eventing_settings.png b/modules/eventing/assets/images/debugger_02_eventing_settings.png new file mode 100644 index 000000000..48f4db103 Binary files /dev/null and b/modules/eventing/assets/images/debugger_02_eventing_settings.png differ diff --git a/modules/eventing/assets/images/debugger_03_deployed_function.png b/modules/eventing/assets/images/debugger_03_deployed_function.png new file mode 100644 index 000000000..a16938f18 Binary files /dev/null and b/modules/eventing/assets/images/debugger_03_deployed_function.png differ diff --git a/modules/eventing/assets/images/debugger_04_function_editor.png b/modules/eventing/assets/images/debugger_04_function_editor.png new file mode 100644 index 000000000..702fd8a15 Binary files /dev/null and b/modules/eventing/assets/images/debugger_04_function_editor.png differ diff --git a/modules/eventing/assets/images/debugger_05_debugger_waiting.png b/modules/eventing/assets/images/debugger_05_debugger_waiting.png new file mode 100644 index 000000000..3edf1344b Binary files /dev/null and b/modules/eventing/assets/images/debugger_05_debugger_waiting.png differ diff --git a/modules/eventing/assets/images/debugger_06a_make_event.png b/modules/eventing/assets/images/debugger_06a_make_event.png new file mode 100644 index 000000000..49a07b4b6 Binary files /dev/null and b/modules/eventing/assets/images/debugger_06a_make_event.png differ diff --git a/modules/eventing/assets/images/debugger_06b_make_event.png b/modules/eventing/assets/images/debugger_06b_make_event.png new file mode 100644 index 000000000..b8677063a Binary files /dev/null and b/modules/eventing/assets/images/debugger_06b_make_event.png differ diff --git a/modules/eventing/assets/images/debugger_07_debugger_have_url.png b/modules/eventing/assets/images/debugger_07_debugger_have_url.png new file mode 100644 index 000000000..352fc02df Binary files /dev/null and b/modules/eventing/assets/images/debugger_07_debugger_have_url.png differ diff --git a/modules/eventing/assets/images/debugger_08_new_tab_paste_url.png b/modules/eventing/assets/images/debugger_08_new_tab_paste_url.png new file mode 100644 index 000000000..bb641adf2 Binary files /dev/null and b/modules/eventing/assets/images/debugger_08_new_tab_paste_url.png differ diff --git a/modules/eventing/assets/images/debugger_09_chrome_step.png b/modules/eventing/assets/images/debugger_09_chrome_step.png new file mode 100644 index 000000000..a6eaf267c Binary files /dev/null and b/modules/eventing/assets/images/debugger_09_chrome_step.png differ diff --git a/modules/eventing/assets/images/debugger_10_chrome_breakpoint.png b/modules/eventing/assets/images/debugger_10_chrome_breakpoint.png new file mode 100644 index 000000000..a3994a66f Binary files /dev/null and b/modules/eventing/assets/images/debugger_10_chrome_breakpoint.png differ diff --git a/modules/eventing/assets/images/debugger_11_chrome_run_to_bp.png b/modules/eventing/assets/images/debugger_11_chrome_run_to_bp.png new file mode 100644 index 000000000..174fe85d4 Binary files /dev/null and b/modules/eventing/assets/images/debugger_11_chrome_run_to_bp.png differ diff --git a/modules/eventing/assets/images/debugger_12_chrome_run_at_bp.png b/modules/eventing/assets/images/debugger_12_chrome_run_at_bp.png new file mode 100644 index 000000000..ad5f49382 Binary files /dev/null and b/modules/eventing/assets/images/debugger_12_chrome_run_at_bp.png differ diff --git a/modules/eventing/assets/images/debugger_13_chrome_stop_debugging.png b/modules/eventing/assets/images/debugger_13_chrome_stop_debugging.png new file mode 100644 index 000000000..c8546ea3b Binary files /dev/null and b/modules/eventing/assets/images/debugger_13_chrome_stop_debugging.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_01_settings.png b/modules/eventing/assets/images/del_v_expiry_01_settings.png new file mode 100644 index 000000000..bbd5a086a Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_01_settings.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_02_editor_with_default.png b/modules/eventing/assets/images/del_v_expiry_02_editor_with_default.png new file mode 100644 index 000000000..fcb67b499 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_03_editor_with_code.png b/modules/eventing/assets/images/del_v_expiry_03_editor_with_code.png new file mode 100644 index 000000000..757289536 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_03a_deploy.png b/modules/eventing/assets/images/del_v_expiry_03a_deploy.png new file mode 100644 index 000000000..bd510169b Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_03a_deploy.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_04_expiration.png b/modules/eventing/assets/images/del_v_expiry_04_expiration.png new file mode 100644 index 000000000..eff08d6e9 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_04_expiration.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_04_view_bkt.png b/modules/eventing/assets/images/del_v_expiry_04_view_bkt.png new file mode 100644 index 000000000..841897485 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_04_view_bkt.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_04b_view_bkt.png b/modules/eventing/assets/images/del_v_expiry_04b_view_bkt.png new file mode 100644 index 000000000..199690401 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_04b_view_bkt.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_04b_view_doc.png b/modules/eventing/assets/images/del_v_expiry_04b_view_doc.png new file mode 100644 index 000000000..4dc20b706 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_04b_view_doc.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_05_buckets.png b/modules/eventing/assets/images/del_v_expiry_05_buckets.png new file mode 100644 index 000000000..8f0d09d13 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_05_buckets.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_05_log_expired.png b/modules/eventing/assets/images/del_v_expiry_05_log_expired.png new file mode 100644 index 000000000..9e4162347 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_05_log_expired.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_06_deletion.png b/modules/eventing/assets/images/del_v_expiry_06_deletion.png new file mode 100644 index 000000000..3cc7a8967 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_06_deletion.png differ diff --git a/modules/eventing/assets/images/del_v_expiry_06_log_deleted.png b/modules/eventing/assets/images/del_v_expiry_06_log_deleted.png new file mode 100644 index 000000000..4eda2ba98 Binary files /dev/null and b/modules/eventing/assets/images/del_v_expiry_06_log_deleted.png differ diff --git a/modules/eventing/assets/images/deploy_enrich_ip_nums.png b/modules/eventing/assets/images/deploy_enrich_ip_nums.png new file mode 100644 index 000000000..d49bd89f4 Binary files /dev/null and b/modules/eventing/assets/images/deploy_enrich_ip_nums.png differ diff --git a/modules/eventing/assets/images/docarchive_00_bsettings.png b/modules/eventing/assets/images/docarchive_00_bsettings.png new file mode 100644 index 000000000..5ad498cfd Binary files /dev/null and b/modules/eventing/assets/images/docarchive_00_bsettings.png differ diff --git a/modules/eventing/assets/images/docarchive_01_bsettings.png b/modules/eventing/assets/images/docarchive_01_bsettings.png new file mode 100644 index 000000000..44eabcf5e Binary files /dev/null and b/modules/eventing/assets/images/docarchive_01_bsettings.png differ diff --git a/modules/eventing/assets/images/docarchive_01_fsettings.png b/modules/eventing/assets/images/docarchive_01_fsettings.png new file mode 100644 index 000000000..7a97db8bf Binary files /dev/null and b/modules/eventing/assets/images/docarchive_01_fsettings.png differ diff --git a/modules/eventing/assets/images/docarchive_01_fsettings_a.png b/modules/eventing/assets/images/docarchive_01_fsettings_a.png new file mode 100644 index 000000000..52cfe37eb Binary files /dev/null and b/modules/eventing/assets/images/docarchive_01_fsettings_a.png differ diff --git a/modules/eventing/assets/images/docarchive_01_fsettings_b.png b/modules/eventing/assets/images/docarchive_01_fsettings_b.png new file mode 100644 index 000000000..f66e701de Binary files /dev/null and b/modules/eventing/assets/images/docarchive_01_fsettings_b.png differ diff --git a/modules/eventing/assets/images/docarchive_01_source_ttl.png b/modules/eventing/assets/images/docarchive_01_source_ttl.png new file mode 100644 index 000000000..76edc9378 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_01_source_ttl.png differ diff --git a/modules/eventing/assets/images/docarchive_02_editor_with_default.png b/modules/eventing/assets/images/docarchive_02_editor_with_default.png new file mode 100644 index 000000000..2820ff4e8 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/docarchive_03_editor_with_code.png b/modules/eventing/assets/images/docarchive_03_editor_with_code.png new file mode 100644 index 000000000..483b33fec Binary files /dev/null and b/modules/eventing/assets/images/docarchive_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/docarchive_03a_deploy.png b/modules/eventing/assets/images/docarchive_03a_deploy.png new file mode 100644 index 000000000..76c0030eb Binary files /dev/null and b/modules/eventing/assets/images/docarchive_03a_deploy.png differ diff --git a/modules/eventing/assets/images/docarchive_04_buckets.png b/modules/eventing/assets/images/docarchive_04_buckets.png new file mode 100644 index 000000000..ba8406e33 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_04_buckets.png differ diff --git a/modules/eventing/assets/images/docarchive_05_buckets.png b/modules/eventing/assets/images/docarchive_05_buckets.png new file mode 100644 index 000000000..c01a2dcf9 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_05_buckets.png differ diff --git a/modules/eventing/assets/images/docarchive_06_buckets.png b/modules/eventing/assets/images/docarchive_06_buckets.png new file mode 100644 index 000000000..7e5beb58e Binary files /dev/null and b/modules/eventing/assets/images/docarchive_06_buckets.png differ diff --git a/modules/eventing/assets/images/docarchive_07_buckets.png b/modules/eventing/assets/images/docarchive_07_buckets.png new file mode 100644 index 000000000..6e64947b3 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_07_buckets.png differ diff --git a/modules/eventing/assets/images/docarchive_07_preexpired.png b/modules/eventing/assets/images/docarchive_07_preexpired.png new file mode 100644 index 000000000..15879344d Binary files /dev/null and b/modules/eventing/assets/images/docarchive_07_preexpired.png differ diff --git a/modules/eventing/assets/images/docarchive_08_expired.png b/modules/eventing/assets/images/docarchive_08_expired.png new file mode 100644 index 000000000..f2c1f3601 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_08_expired.png differ diff --git a/modules/eventing/assets/images/docarchive_cnta.png b/modules/eventing/assets/images/docarchive_cnta.png new file mode 100644 index 000000000..62ca7aeac Binary files /dev/null and b/modules/eventing/assets/images/docarchive_cnta.png differ diff --git a/modules/eventing/assets/images/docarchive_cntb.png b/modules/eventing/assets/images/docarchive_cntb.png new file mode 100644 index 000000000..05a380500 Binary files /dev/null and b/modules/eventing/assets/images/docarchive_cntb.png differ diff --git a/modules/eventing/assets/images/docexpiry_01_settings.png b/modules/eventing/assets/images/docexpiry_01_settings.png new file mode 100644 index 000000000..f8063034f Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_01_settings.png differ diff --git a/modules/eventing/assets/images/docexpiry_02_editor_with_default.png b/modules/eventing/assets/images/docexpiry_02_editor_with_default.png new file mode 100644 index 000000000..bf702308d Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/docexpiry_03_editor_with_code.png b/modules/eventing/assets/images/docexpiry_03_editor_with_code.png new file mode 100644 index 000000000..1c6875cc6 Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/docexpiry_03a_deploy.png b/modules/eventing/assets/images/docexpiry_03a_deploy.png new file mode 100644 index 000000000..6400f2c9d Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_03a_deploy.png differ diff --git a/modules/eventing/assets/images/docexpiry_04_buckets.png b/modules/eventing/assets/images/docexpiry_04_buckets.png new file mode 100644 index 000000000..68a42e0c0 Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_04_buckets.png differ diff --git a/modules/eventing/assets/images/docexpiry_04a_buckets.png b/modules/eventing/assets/images/docexpiry_04a_buckets.png new file mode 100644 index 000000000..b992ce0e0 Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_04a_buckets.png differ diff --git a/modules/eventing/assets/images/docexpiry_05_buckets.png b/modules/eventing/assets/images/docexpiry_05_buckets.png new file mode 100644 index 000000000..671b5e7ac Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_05_buckets.png differ diff --git a/modules/eventing/assets/images/docexpiry_05a_buckets.png b/modules/eventing/assets/images/docexpiry_05a_buckets.png new file mode 100644 index 000000000..f7f64eb60 Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_05a_buckets.png differ diff --git a/modules/eventing/assets/images/docexpiry_06_buckets.png b/modules/eventing/assets/images/docexpiry_06_buckets.png new file mode 100644 index 000000000..4f0a61891 Binary files /dev/null and b/modules/eventing/assets/images/docexpiry_06_buckets.png differ diff --git a/modules/eventing/assets/images/enrich_ip_nums.png b/modules/eventing/assets/images/enrich_ip_nums.png new file mode 100644 index 000000000..2837b2049 Binary files /dev/null and b/modules/eventing/assets/images/enrich_ip_nums.png differ diff --git a/modules/eventing/assets/images/enrichcase1_01_settings.png b/modules/eventing/assets/images/enrichcase1_01_settings.png new file mode 100644 index 000000000..9a1f87cf4 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase1_01_settings.png differ diff --git a/modules/eventing/assets/images/enrichcase1_02_editor_with_default.png b/modules/eventing/assets/images/enrichcase1_02_editor_with_default.png new file mode 100644 index 000000000..49f2965e4 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase1_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/enrichcase1_03_editor_with_code.png b/modules/eventing/assets/images/enrichcase1_03_editor_with_code.png new file mode 100644 index 000000000..723946641 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase1_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/enrichcase1_03a_deploy.png b/modules/eventing/assets/images/enrichcase1_03a_deploy.png new file mode 100644 index 000000000..49343934b Binary files /dev/null and b/modules/eventing/assets/images/enrichcase1_03a_deploy.png differ diff --git a/modules/eventing/assets/images/enrichcase1_03b_undeploy.png b/modules/eventing/assets/images/enrichcase1_03b_undeploy.png new file mode 100644 index 000000000..b99276989 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase1_03b_undeploy.png differ diff --git a/modules/eventing/assets/images/enrichcase2_01_settings.png b/modules/eventing/assets/images/enrichcase2_01_settings.png new file mode 100644 index 000000000..7e84fdc42 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase2_01_settings.png differ diff --git a/modules/eventing/assets/images/enrichcase2_02_editor_with_code.png b/modules/eventing/assets/images/enrichcase2_02_editor_with_code.png new file mode 100644 index 000000000..6fc355e74 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase2_02_editor_with_code.png differ diff --git a/modules/eventing/assets/images/enrichcase2_02_editor_with_default.png b/modules/eventing/assets/images/enrichcase2_02_editor_with_default.png new file mode 100644 index 000000000..41a3411a1 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase2_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/enrichcase2_03_editor_with_code.png b/modules/eventing/assets/images/enrichcase2_03_editor_with_code.png new file mode 100644 index 000000000..6df7366cb Binary files /dev/null and b/modules/eventing/assets/images/enrichcase2_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/enrichcase2_03a_deploy.png b/modules/eventing/assets/images/enrichcase2_03a_deploy.png new file mode 100644 index 000000000..70de7afb1 Binary files /dev/null and b/modules/eventing/assets/images/enrichcase2_03a_deploy.png differ diff --git a/modules/eventing/assets/images/eventing-collections-multi-tenant.jpg b/modules/eventing/assets/images/eventing-collections-multi-tenant.jpg new file mode 100644 index 000000000..5c838e4f9 Binary files /dev/null and b/modules/eventing/assets/images/eventing-collections-multi-tenant.jpg differ diff --git a/modules/eventing/assets/images/eventing-collections-single-tenant.jpg b/modules/eventing/assets/images/eventing-collections-single-tenant.jpg new file mode 100644 index 000000000..ad33bd3cc Binary files /dev/null and b/modules/eventing/assets/images/eventing-collections-single-tenant.jpg differ diff --git a/modules/eventing/assets/images/eventing-service-onboarding-information.jpg b/modules/eventing/assets/images/eventing-service-onboarding-information.jpg new file mode 100644 index 000000000..63755e9db Binary files /dev/null and b/modules/eventing/assets/images/eventing-service-onboarding-information.jpg differ diff --git a/modules/eventing/assets/images/eventing_curl_bindings.png b/modules/eventing/assets/images/eventing_curl_bindings.png new file mode 100644 index 000000000..bfe7c462e Binary files /dev/null and b/modules/eventing/assets/images/eventing_curl_bindings.png differ diff --git a/modules/eventing/assets/images/eventing_ui_handler_stats.png b/modules/eventing/assets/images/eventing_ui_handler_stats.png new file mode 100644 index 000000000..04b02be91 Binary files /dev/null and b/modules/eventing/assets/images/eventing_ui_handler_stats.png differ diff --git a/modules/eventing/assets/images/ext_rest_via_curl_01_settings.png b/modules/eventing/assets/images/ext_rest_via_curl_01_settings.png new file mode 100644 index 000000000..1fcb19f99 Binary files /dev/null and b/modules/eventing/assets/images/ext_rest_via_curl_01_settings.png differ diff --git a/modules/eventing/assets/images/ext_rest_via_curl_02_editor_with_default.png b/modules/eventing/assets/images/ext_rest_via_curl_02_editor_with_default.png new file mode 100644 index 000000000..9b0eefed1 Binary files /dev/null and b/modules/eventing/assets/images/ext_rest_via_curl_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/ext_rest_via_curl_03_editor_with_code.png b/modules/eventing/assets/images/ext_rest_via_curl_03_editor_with_code.png new file mode 100644 index 000000000..4cfabad9b Binary files /dev/null and b/modules/eventing/assets/images/ext_rest_via_curl_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/ext_rest_via_curl_03a_deploy.png b/modules/eventing/assets/images/ext_rest_via_curl_03a_deploy.png new file mode 100644 index 000000000..0434c6f5b Binary files /dev/null and b/modules/eventing/assets/images/ext_rest_via_curl_03a_deploy.png differ diff --git a/modules/eventing/assets/images/ext_rest_via_curl_get_04_log_active1.png b/modules/eventing/assets/images/ext_rest_via_curl_get_04_log_active1.png new file mode 100644 index 000000000..59eb8071e Binary files /dev/null and b/modules/eventing/assets/images/ext_rest_via_curl_get_04_log_active1.png differ diff --git a/modules/eventing/assets/images/ext_rest_via_curl_get_04_log_active2.png b/modules/eventing/assets/images/ext_rest_via_curl_get_04_log_active2.png new file mode 100644 index 000000000..cef4088fe Binary files /dev/null and b/modules/eventing/assets/images/ext_rest_via_curl_get_04_log_active2.png differ diff --git a/modules/eventing/assets/images/functions_add_4exp3.png b/modules/eventing/assets/images/functions_add_4exp3.png new file mode 100644 index 000000000..45d288402 Binary files /dev/null and b/modules/eventing/assets/images/functions_add_4exp3.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_01_bucket_edit.png b/modules/eventing/assets/images/high_risk_txns_01_bucket_edit.png new file mode 100644 index 000000000..72a4383d4 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_01_bucket_edit.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_01_buckets.png b/modules/eventing/assets/images/high_risk_txns_01_buckets.png new file mode 100644 index 000000000..20bc7f7f1 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_01_buckets.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_01_data_in_scope.png b/modules/eventing/assets/images/high_risk_txns_01_data_in_scope.png new file mode 100644 index 000000000..9dc9dafe2 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_01_data_in_scope.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_01_documents.png b/modules/eventing/assets/images/high_risk_txns_01_documents.png new file mode 100644 index 000000000..48b47b10d Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_01_documents.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_01_settings.png b/modules/eventing/assets/images/high_risk_txns_01_settings.png new file mode 100644 index 000000000..37fda93e3 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_01_settings.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_01a_documents.png b/modules/eventing/assets/images/high_risk_txns_01a_documents.png new file mode 100644 index 000000000..8cab3a5e5 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_01a_documents.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_02_default_code.png b/modules/eventing/assets/images/high_risk_txns_02_default_code.png new file mode 100644 index 000000000..2c9a44d14 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_02_default_code.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_03_bucket_settings.png b/modules/eventing/assets/images/high_risk_txns_03_bucket_settings.png new file mode 100644 index 000000000..4b70385ec Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_03_bucket_settings.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_03_code.png b/modules/eventing/assets/images/high_risk_txns_03_code.png new file mode 100644 index 000000000..eeb9d28a8 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_03_code.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_04_bucket_edit.png b/modules/eventing/assets/images/high_risk_txns_04_bucket_edit.png new file mode 100644 index 000000000..3a5850776 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_04_bucket_edit.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_04_controls.png b/modules/eventing/assets/images/high_risk_txns_04_controls.png new file mode 100644 index 000000000..e6b114f05 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_04_controls.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_05_create_indexes.png b/modules/eventing/assets/images/high_risk_txns_05_create_indexes.png new file mode 100644 index 000000000..8f9388b09 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_05_create_indexes.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_05_deploy.png b/modules/eventing/assets/images/high_risk_txns_05_deploy.png new file mode 100644 index 000000000..22a4a9b3e Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_05_deploy.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_06_json_loaded.png b/modules/eventing/assets/images/high_risk_txns_06_json_loaded.png new file mode 100644 index 000000000..d1808f757 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_06_json_loaded.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_06a_deploy.png b/modules/eventing/assets/images/high_risk_txns_06a_deploy.png new file mode 100644 index 000000000..d7a1e2f29 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_06a_deploy.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_07_log.png b/modules/eventing/assets/images/high_risk_txns_07_log.png new file mode 100644 index 000000000..a635c2128 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_07_log.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_08_bucket.png b/modules/eventing/assets/images/high_risk_txns_08_bucket.png new file mode 100644 index 000000000..d87f46e7a Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_08_bucket.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_08_bucket_documents.png b/modules/eventing/assets/images/high_risk_txns_08_bucket_documents.png new file mode 100644 index 000000000..f44fc7b21 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_08_bucket_documents.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_08_bucket_documents_by_id.png b/modules/eventing/assets/images/high_risk_txns_08_bucket_documents_by_id.png new file mode 100644 index 000000000..07704b674 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_08_bucket_documents_by_id.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_08_bucket_documents_edit.png b/modules/eventing/assets/images/high_risk_txns_08_bucket_documents_edit.png new file mode 100644 index 000000000..e39c37ff4 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_08_bucket_documents_edit.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_09_n1ql_a.png b/modules/eventing/assets/images/high_risk_txns_09_n1ql_a.png new file mode 100644 index 000000000..fe8bf23ae Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_09_n1ql_a.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_09_n1ql_b.png b/modules/eventing/assets/images/high_risk_txns_09_n1ql_b.png new file mode 100644 index 000000000..8855bbba2 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_09_n1ql_b.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_09_n1ql_c.png b/modules/eventing/assets/images/high_risk_txns_09_n1ql_c.png new file mode 100644 index 000000000..6de54323d Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_09_n1ql_c.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_09_n1ql_d.png b/modules/eventing/assets/images/high_risk_txns_09_n1ql_d.png new file mode 100644 index 000000000..9ffcf1c82 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_09_n1ql_d.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_09_n1ql_e.png b/modules/eventing/assets/images/high_risk_txns_09_n1ql_e.png new file mode 100644 index 000000000..2319c0515 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_09_n1ql_e.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_09_n1ql_f.png b/modules/eventing/assets/images/high_risk_txns_09_n1ql_f.png new file mode 100644 index 000000000..5c5a06ec5 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_09_n1ql_f.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_bucket_register_id.png b/modules/eventing/assets/images/high_risk_txns_10_bucket_register_id.png new file mode 100644 index 000000000..92c8f075c Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_bucket_register_id.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_flush_review.png b/modules/eventing/assets/images/high_risk_txns_10_flush_review.png new file mode 100644 index 000000000..a42bf7ae4 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_flush_review.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_modify.png b/modules/eventing/assets/images/high_risk_txns_10_modify.png new file mode 100644 index 000000000..32036e4d8 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_modify.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_pause.png b/modules/eventing/assets/images/high_risk_txns_10_pause.png new file mode 100644 index 000000000..1a59bcee4 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_pause.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_pause_confirm.png b/modules/eventing/assets/images/high_risk_txns_10_pause_confirm.png new file mode 100644 index 000000000..c0b6c15ea Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_pause_confirm.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_resume.png b/modules/eventing/assets/images/high_risk_txns_10_resume.png new file mode 100644 index 000000000..f1eee3240 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_resume.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_10_resume_confirm.png b/modules/eventing/assets/images/high_risk_txns_10_resume_confirm.png new file mode 100644 index 000000000..49360d518 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_10_resume_confirm.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_11_undeploy.png b/modules/eventing/assets/images/high_risk_txns_11_undeploy.png new file mode 100644 index 000000000..f8739ce62 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_11_undeploy.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_11_undeploy_confirm.png b/modules/eventing/assets/images/high_risk_txns_11_undeploy_confirm.png new file mode 100644 index 000000000..0127fbfc4 Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_11_undeploy_confirm.png differ diff --git a/modules/eventing/assets/images/high_risk_txns_11_verbose_3.png b/modules/eventing/assets/images/high_risk_txns_11_verbose_3.png new file mode 100644 index 000000000..e7f9d394d Binary files /dev/null and b/modules/eventing/assets/images/high_risk_txns_11_verbose_3.png differ diff --git a/modules/eventing/assets/images/high_risks_transactions_handler_code.png b/modules/eventing/assets/images/high_risks_transactions_handler_code.png new file mode 100644 index 000000000..e83c68385 Binary files /dev/null and b/modules/eventing/assets/images/high_risks_transactions_handler_code.png differ diff --git a/modules/eventing/assets/images/high_risks_transactions_handler_deploy.png b/modules/eventing/assets/images/high_risks_transactions_handler_deploy.png new file mode 100644 index 000000000..2bc1f3dee Binary files /dev/null and b/modules/eventing/assets/images/high_risks_transactions_handler_deploy.png differ diff --git a/modules/eventing/assets/images/highrisk_01_settings.png b/modules/eventing/assets/images/highrisk_01_settings.png new file mode 100644 index 000000000..25d5b2700 Binary files /dev/null and b/modules/eventing/assets/images/highrisk_01_settings.png differ diff --git a/modules/eventing/assets/images/highrisk_01_settings2.png b/modules/eventing/assets/images/highrisk_01_settings2.png new file mode 100644 index 000000000..500129324 Binary files /dev/null and b/modules/eventing/assets/images/highrisk_01_settings2.png differ diff --git a/modules/eventing/assets/images/highrisk_02_editor_with_default.png b/modules/eventing/assets/images/highrisk_02_editor_with_default.png new file mode 100644 index 000000000..12ceb8b59 Binary files /dev/null and b/modules/eventing/assets/images/highrisk_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/highrisk_03_editor_with_code.png b/modules/eventing/assets/images/highrisk_03_editor_with_code.png new file mode 100644 index 000000000..a8fac21a9 Binary files /dev/null and b/modules/eventing/assets/images/highrisk_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/highrisk_04_buckets.png b/modules/eventing/assets/images/highrisk_04_buckets.png new file mode 100644 index 000000000..b290710a5 Binary files /dev/null and b/modules/eventing/assets/images/highrisk_04_buckets.png differ diff --git a/modules/eventing/assets/images/highrisk_05_n1ql_query.png b/modules/eventing/assets/images/highrisk_05_n1ql_query.png new file mode 100644 index 000000000..44bc1b296 Binary files /dev/null and b/modules/eventing/assets/images/highrisk_05_n1ql_query.png differ diff --git a/modules/eventing/assets/images/input-output-overview-6.5.png b/modules/eventing/assets/images/input-output-overview-6.5.png new file mode 100644 index 000000000..7d6579124 Binary files /dev/null and b/modules/eventing/assets/images/input-output-overview-6.5.png differ diff --git a/modules/eventing/assets/images/lifecycle_overview_notitle.png b/modules/eventing/assets/images/lifecycle_overview_notitle.png new file mode 100644 index 000000000..3dcaa23e2 Binary files /dev/null and b/modules/eventing/assets/images/lifecycle_overview_notitle.png differ diff --git a/modules/eventing/assets/images/ondelete-functions.png b/modules/eventing/assets/images/ondelete-functions.png new file mode 100644 index 000000000..cfeaa487b Binary files /dev/null and b/modules/eventing/assets/images/ondelete-functions.png differ diff --git a/modules/eventing/assets/images/query-results-ondelete.png b/modules/eventing/assets/images/query-results-ondelete.png new file mode 100644 index 000000000..53f11870e Binary files /dev/null and b/modules/eventing/assets/images/query-results-ondelete.png differ diff --git a/modules/eventing/assets/images/queryresults_ondelerte.png b/modules/eventing/assets/images/queryresults_ondelerte.png new file mode 100644 index 000000000..b7265e961 Binary files /dev/null and b/modules/eventing/assets/images/queryresults_ondelerte.png differ diff --git a/modules/eventing/assets/images/rbac_admin_view.png b/modules/eventing/assets/images/rbac_admin_view.png new file mode 100644 index 000000000..290ea7f81 Binary files /dev/null and b/modules/eventing/assets/images/rbac_admin_view.png differ diff --git a/modules/eventing/assets/images/rbac_min_a.png b/modules/eventing/assets/images/rbac_min_a.png new file mode 100644 index 000000000..4cfaeb4bf Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_a.png differ diff --git a/modules/eventing/assets/images/rbac_min_add_add_group.png b/modules/eventing/assets/images/rbac_min_add_add_group.png new file mode 100644 index 000000000..bda2fab9b Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_add_add_group.png differ diff --git a/modules/eventing/assets/images/rbac_min_add_add_user.png b/modules/eventing/assets/images/rbac_min_add_add_user.png new file mode 100644 index 000000000..58794c83c Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_add_add_user.png differ diff --git a/modules/eventing/assets/images/rbac_min_b.png b/modules/eventing/assets/images/rbac_min_b.png new file mode 100644 index 000000000..47018810b Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_b.png differ diff --git a/modules/eventing/assets/images/rbac_min_c.png b/modules/eventing/assets/images/rbac_min_c.png new file mode 100644 index 000000000..41c27031c Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_c.png differ diff --git a/modules/eventing/assets/images/rbac_min_groups.png b/modules/eventing/assets/images/rbac_min_groups.png new file mode 100644 index 000000000..f3661d576 Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_groups.png differ diff --git a/modules/eventing/assets/images/rbac_min_users.png b/modules/eventing/assets/images/rbac_min_users.png new file mode 100644 index 000000000..f70a7c1fb Binary files /dev/null and b/modules/eventing/assets/images/rbac_min_users.png differ diff --git a/modules/eventing/assets/images/rbac_user_view.png b/modules/eventing/assets/images/rbac_user_view.png new file mode 100644 index 000000000..576ae3812 Binary files /dev/null and b/modules/eventing/assets/images/rbac_user_view.png differ diff --git a/modules/eventing/assets/images/recuring_timer_03a_deploy.png b/modules/eventing/assets/images/recuring_timer_03a_deploy.png new file mode 100644 index 000000000..498605081 Binary files /dev/null and b/modules/eventing/assets/images/recuring_timer_03a_deploy.png differ diff --git a/modules/eventing/assets/images/recurring_timer_01_add_document.png b/modules/eventing/assets/images/recurring_timer_01_add_document.png new file mode 100644 index 000000000..aa961cc9f Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_01_add_document.png differ diff --git a/modules/eventing/assets/images/recurring_timer_01_buckets.png b/modules/eventing/assets/images/recurring_timer_01_buckets.png new file mode 100644 index 000000000..fbda74545 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_01_buckets.png differ diff --git a/modules/eventing/assets/images/recurring_timer_01_data_in_scope.png b/modules/eventing/assets/images/recurring_timer_01_data_in_scope.png new file mode 100644 index 000000000..793ca1ca0 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_01_data_in_scope.png differ diff --git a/modules/eventing/assets/images/recurring_timer_01_docdata.png b/modules/eventing/assets/images/recurring_timer_01_docdata.png new file mode 100644 index 000000000..b62eb7b22 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_01_docdata.png differ diff --git a/modules/eventing/assets/images/recurring_timer_01_documents.png b/modules/eventing/assets/images/recurring_timer_01_documents.png new file mode 100644 index 000000000..66f824f83 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_01_documents.png differ diff --git a/modules/eventing/assets/images/recurring_timer_01_settings.png b/modules/eventing/assets/images/recurring_timer_01_settings.png new file mode 100644 index 000000000..b7e40c7e5 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_01_settings.png differ diff --git a/modules/eventing/assets/images/recurring_timer_02_editor_with_default.png b/modules/eventing/assets/images/recurring_timer_02_editor_with_default.png new file mode 100644 index 000000000..618f37f6c Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_02_editor_with_default.png differ diff --git a/modules/eventing/assets/images/recurring_timer_03_editor_with_code.png b/modules/eventing/assets/images/recurring_timer_03_editor_with_code.png new file mode 100644 index 000000000..d52ff490a Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_03_editor_with_code.png differ diff --git a/modules/eventing/assets/images/recurring_timer_04_log_active1.png b/modules/eventing/assets/images/recurring_timer_04_log_active1.png new file mode 100644 index 000000000..3694602a9 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_04_log_active1.png differ diff --git a/modules/eventing/assets/images/recurring_timer_04_log_active2.png b/modules/eventing/assets/images/recurring_timer_04_log_active2.png new file mode 100644 index 000000000..4b904c634 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_04_log_active2.png differ diff --git a/modules/eventing/assets/images/recurring_timer_04_log_fired1.png b/modules/eventing/assets/images/recurring_timer_04_log_fired1.png new file mode 100644 index 000000000..73ef32226 Binary files /dev/null and b/modules/eventing/assets/images/recurring_timer_04_log_fired1.png differ diff --git a/modules/eventing/assets/images/reserved-words-6_5.png b/modules/eventing/assets/images/reserved-words-6_5.png new file mode 100644 index 000000000..df1052378 Binary files /dev/null and b/modules/eventing/assets/images/reserved-words-6_5.png differ diff --git a/modules/eventing/assets/images/reserved-words-7_0.png b/modules/eventing/assets/images/reserved-words-7_0.png new file mode 100644 index 000000000..5cec2ed18 Binary files /dev/null and b/modules/eventing/assets/images/reserved-words-7_0.png differ diff --git a/modules/eventing/assets/images/reserved-words.png b/modules/eventing/assets/images/reserved-words.png new file mode 100644 index 000000000..42297ced8 Binary files /dev/null and b/modules/eventing/assets/images/reserved-words.png differ diff --git a/modules/eventing/assets/images/stats.png b/modules/eventing/assets/images/stats.png new file mode 100644 index 000000000..9409c186f Binary files /dev/null and b/modules/eventing/assets/images/stats.png differ diff --git a/modules/eventing/assets/images/stats_00_counts.png b/modules/eventing/assets/images/stats_00_counts.png new file mode 100644 index 000000000..4797a7de6 Binary files /dev/null and b/modules/eventing/assets/images/stats_00_counts.png differ diff --git a/modules/eventing/assets/images/stats_01_counts_and_charts.png b/modules/eventing/assets/images/stats_01_counts_and_charts.png new file mode 100644 index 000000000..567fbc72f Binary files /dev/null and b/modules/eventing/assets/images/stats_01_counts_and_charts.png differ diff --git a/modules/eventing/assets/images/stats_02_add_charts.png b/modules/eventing/assets/images/stats_02_add_charts.png new file mode 100644 index 000000000..4a7e822f7 Binary files /dev/null and b/modules/eventing/assets/images/stats_02_add_charts.png differ diff --git a/modules/eventing/assets/images/stats_02_system_charts.png b/modules/eventing/assets/images/stats_02_system_charts.png new file mode 100644 index 000000000..1f80e8e14 Binary files /dev/null and b/modules/eventing/assets/images/stats_02_system_charts.png differ diff --git a/modules/eventing/pages/add-eventing-functions.adoc b/modules/eventing/pages/add-eventing-functions.adoc new file mode 100644 index 000000000..413d22fca --- /dev/null +++ b/modules/eventing/pages/add-eventing-functions.adoc @@ -0,0 +1,149 @@ += Add Eventing Functions +:description: Use the Capella UI to add Eventing Functions to the Eventing Service in your cluster. +:page-aliases: clusters:eventing-service/manage-functions.adoc, clusters:eventing-service/add-eventing-functions.adoc + +[abstract] +{description} + + +[#add-function-prerequisites] +== Prerequisites + +Before you add Eventing Functions to your Eventing Service, you must first deploy the Eventing Service. +See xref:cloud:clusters:modify-database.adoc#add-service[Add a Service] for more information. + + +[#add-function] +== Add a New Eventing Function + +To add a new Eventing Function: + +. On the *Operational Clusters* page, select the cluster where you want to add a Function. +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. Configure the <>. +. Click btn:[Next]. +. To add a new binding, click btn:[Add Binding]. +. Configure the <>. +. Click btn:[Next] to save your binding. +. In the code editor, customize the provided `OnUpdate` and `OnDelete` JavaScript functions or enter your own JavaScript functions. +You can also leave the provided code unchanged. +. Click btn:[Create Function] to create your new Eventing Function in an undeployed state. + + +[#function-settings] +== Function Settings + +[cols="1,2",options="header"] + +|=== + +|Field +|Description + +|Name +a|A unique name for your Eventing Function. +The Function name must: + +* Start with an uppercase character (A-Z), lowercase character (a-z), or number (0-9) +* Contain only uppercase characters (A-Z), lowercase characters (a-z), numbers (0-9), underscores (_), and hyphens (-) + +|Description +|An optional description that describes the purpose of your Eventing Function. + +|Listen to Location +|A bucket, scope, and collection currently defined on your cluster and where you want your Eventing Function to monitor document mutations. + +|Eventing Storage +|A bucket, scope, and collection currently defined on your cluster and where you want to store system data for your Eventing Function. +This is the Function's metadata bucket. + +You must choose a bucket that's not being used by any other application. +You can choose to share this bucket across different Eventing Functions. +You can also choose the same bucket and scope as your *Listen to Location* bucket and scope, but you must choose a different collection. + +|Workers +|The number of worker threads per node to be allocated to the Eventing Function to process events. + +The minimum number of workers is `1` and the maximum is `64`. + +The default is `1`. + +|Script Timeout +|The number of seconds to elapse before the script times out and is terminated. + +The default is `60`. + +|Time Context Max Size +|The size limit of the context for any Timer created by the Eventing Function. + +The default is `1024`. + +|{sqlpp} Consistency +|The default consistency level of {sqlpp} statements in the handler. + +|Deployment Feed Boundary +|The Feed Boundary determines if the Eventing Function's activities need to include documents that already exist. +When you set the Feed Boundary to `Everything`, the Function is invoked on all mutations available in your cluster. +When you set the Feed Boundary to `From Now`, the Function is only invoked on future instances of data mutation after the Function's deployment. + +|Language Compatibility +|The language version of the handler for backward compatibility. + +|Enable App Services Compatibility +|Select this option only when using App Services with the same collection as this Eventing Function, as it prevents duplicate processing. + +This setting is selected by default and mandatory when an App Service already links to the Eventing Function's chosen collection. + +|=== + +For more information about terminology, see xref:eventing-terminologies.adoc[Eventing terminology]. + + +[#binding-settings] +== Binding Settings + +Your Eventing Function can have no binding, one binding, or multiple bindings. +A binding is a construct that lets you separate environment-specific variables, such as bucket names, external endpoints, and credentials, from the handler source code. +It helps move a handler definition from development to production environments without changing the code. + +Binding names must be valid JavaScript identifiers and cannot conflict with any built-in types. + +[cols="1,2",options="header"] + +|=== + +|Bindings +|Description + +|Bucket +|Bucket bindings allow JavaScript handlers to access Couchbase buckets from the Data Service. +These buckets are accessible by the bound name as a JavaScript map in the global space of the handler. + +To add a Bucket binding, select *Bucket*, enter an alias name, and choose an access level, a bucket, a scope, and a collection. + +|URL +|URL bindings are used by the cURL language construct to access external resources. +They specify the endpoint, the protocol (HTTP/HTTPS), and the credentials if necessary. +You can enable cookie support through URL binding when accessing trusted remote nodes. + +The target of a URL binding should not be a node that belongs to the Couchbase cluster. + +To add a URL binding, select *URL*, enter an alias name and a URL, choose an authentication type, and select *Allow cookies* and *Validate SSL Certificate*. + +|Constant +|Constant bindings define global variables that you can use inside your Eventing Function. +You can use the alias name inside your Function to use the set value of your Constant binding. + +To add a Constant binding, select *Constant* and enter an alias name and a value. +Values can be integers, decimal numbers, strings, booleans, or JSON objects. + +|=== + + +== Next Steps + +After you add Eventing Functions, you can: + +* xref:deploy-eventing-functions.adoc[Deploy the Eventing Functions] +* xref:manage-eventing-functions.adoc[Manage the Eventing Functions] diff --git a/modules/eventing/pages/deploy-eventing-functions.adoc b/modules/eventing/pages/deploy-eventing-functions.adoc new file mode 100644 index 000000000..656f04fa1 --- /dev/null +++ b/modules/eventing/pages/deploy-eventing-functions.adoc @@ -0,0 +1,77 @@ += Deploy Eventing Functions +:description: Use the Capella UI to deploy and undeploy Eventing Functions in your cluster. +:page-aliases: clusters:eventing-service/deploy-eventing-functions.adoc + +[abstract] +{description} + + +[#deploy-function] +== Deploy an Eventing Function + +When you add an Eventing Function to your cluster, the Function is saved in an undeployed state. +To activate an Eventing Function, you must deploy it. + +Deploying a Function: + +* Lets the handler to receive and process events or mutations +* Creates necessary metadata +* Spawns worker processes +* Calculates initial partitions +* Initiates checkpointing of processed stream data + +[NOTE] +==== +You cannot edit the JavaScript source code of a deployed Eventing Function. +==== + +To deploy an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to the Function you want to deploy. +. Click *Deploy* to deploy your Function. + + +[#undeploy-function] +== Undeploy an Eventing Function + +You can undeploy a deployed Eventing Function to deactivate it. +After a Function is undeployed, you can edit the JavaScript source code. + +To undeploy an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to the Function you want to undeploy. +. Click *Undeploy* to undeploy your Function. + + +[#deployment-statistics] +== Check the Deployment Statistics + +You can check the deployment statistics for your deployed Function by clicking the expand arrow next to it. + + +[cols="1,2",options="header"] +|=== + +|Type +|Description + +|Success +|The number of processed Functions. + +|Failure +|The number of failures while processing the Function handler code. + +|Timeout +|The number of Functions that have timed out. + +|Backlog +|The number of mutations to be processed by a Function. + +|=== + + +== Next Steps + +After you deploy Eventing Functions, you can xref:manage-eventing-functions.adoc[manage them]. diff --git a/modules/eventing/pages/eventing-Terminologies.adoc b/modules/eventing/pages/eventing-Terminologies.adoc new file mode 100644 index 000000000..d616d1fb1 --- /dev/null +++ b/modules/eventing/pages/eventing-Terminologies.adoc @@ -0,0 +1,420 @@ += Eventing Terminology +:description: The following terminology is used by the Eventing Service. +:page-toclevels: 2 + +[abstract] +{description} + +== Eventing Service + +The Eventing Service executes user-defined code and responds in real time whenever applications interact and cause your data to change. + +The Eventing Service can run one or more Eventing Functions. + + +== Eventing Functions + +Eventing Functions handle data changes in the Eventing Service. +They're standalone JavaScript fragments that trigger in real time as a response to document mutations and that must execute from start to finish before a specified timeout is reached. + +Eventing Functions allow you to: + +* Integrate with the Data Service to: +** Read, write, and delete documents +** Work with Atomic Counters, CAS, and TTLS +* Integrate with the Query Service to use inline {sqlpp} queries or statements +* Enable a Timer to schedule functions to run in the future +* Interact with external REST endpoints through cURL functionality +* Route mutations to the entry points `OnUpdate` and `OnDelete` +* Route fired timers to a user-defined Timer callback + +NOTE: The JavaScript code in an Eventing Function is compressed in Couchbase Server versions 6.5.0 and later. +The compressed size is limited to 128KB. + + +=== Handlers + +The Eventing Service calls the `OnUpdate`, `OnDelete`, and Timer Callback handlers on mutations and fired timers. + +==== `OnUpdate` + +The `OnUpdate` handler is called when you create or modify a document. + +The entry point `OnUpdate(doc,meta)` passes `doc`, the document, and `meta`, which contains additional data like the document ID, CAS, expiration date, and data type. + +There are two limitations to the `OnUpdate` handler: + +* If you modify a document several times in a short period of time, the handler calls can merge into a single event due to deduplication +* It is not possible to distinguish between Create and Update operations + +NOTE: To prevent the suppression of binary documents, you must set the language compatibility of your Function to Couchbase Server version 6.6.2 or later. + +==== `OnDelete` + +The `OnDelete` handler is called when you delete a document or when the document expires. + +The entry point `OnDelete(meta,options)` passes `meta`, which contains information like the document, and `options`, which contains the boolean parameter `options.expired` that indicates if the document was removed because of a deletion or an expiration. + +It is not possible to get the value of a document that has been deleted or expired. + +==== Timer Callback + +Timer callbacks are user-defined JavaScript functions passed as the `callback` argument to the built-in function call `createTimer(callback,date,reference,context)`. + +When you create a Timer, the `callback` argument is executed at or close to the `date` argument. +The `reference` argument works as an identifier for the Timer scoped to an Eventing Function and callback. +The `context` argument must be serializable data that is available to the callback when the Timer is fired. + +For more information about Timer callbacks, see xref:eventing-timers.adoc#createtimer-function[`createTimer()` and `cancelTimer()`]. + + +=== Statelessness + +The persistent state of an Eventing Function is captured in the following external elements: + +* Documents or mutations and their extended attributes +* Listen to Location, or the Eventing source: a collection that is the source of mutations sent to the Function through the Database Change Protocol (DCP) +* Eventing Storage, or the Eventing metadata: a collection used as a scratchpad for the state of the Function +* Optional bindings for the Function: +** Bucket alias: an alias and access mode used by the Function to access a collection +** URL alias: an alias and HTTP/S setting used by the Function to access external REST APIs +** Constant alias: an alias to an integer, decimal number, string, boolean, or a JSON object used as a global variable within the Function + +All states in the execution stack are short-lived. + + +=== Deduplication + +Couchbase does not store every version a document permanently. +When a handler receives the mutation history of documents from Eventing, it sees a truncated history of each document. + +NOTE: Because the current state of a document is always available in the database, the final state of a document is always present in the mutation history. + +To ensure high performance, the KV data engine deduplicates multiple mutations made to an individual document in succession. +Handlers might not see all intermediate states of a document when it mutates quickly, but they do see its final state. + + +=== Recursive Mutation + +A potentially recursive mutation happens when a handler manipulates documents in a keyspace that also serves as the mutation source for this or another handler. +The write originated by the handler causes a mutation to be seen by itself or by another handler. + + +[#json_number_precision] +=== JSON Number Precision + +JSON does not have specialized types for integral and floating-point numbers, so many JavaScript runtimes use floating-point numbers to hold JSON numbers. +This means that JavaScript numbers have a large range but less precision when it comes to traditional integers of the same size. + +The JavaScript and WebAssembly engine V8 uses 64-bit floating-point numbers that yield a 53-bit precision. +Only integers up to +/- 253 can be safely handled by Eventing JavaScript. + +To handle large integers of 15 or more digits, you can use JavaScript `BigInt` types. +The constants `Number.MAX_SAFE_INTEGER` and `Number.MIN_SAFE_INTERGER` show the exact numbers where integral precision is defined and lost by JavaScript. + +Large integers are usually tokens that require equality comparisons. +In Eventing, this can be seen in the CAS values generated by Advanced Keyspace Operations and in the results generated by the `crc64()` Function. +In these cases, you can hold the large integers as strings. +The strings ensure full fidelity and retain the ability to do equality comparisons. + +For more information about the `crc64()` Function, see xref:eventing-language-constructs.adoc#crc64_call[`crc64()` Function Call]. + + +[#function-scope] +=== Function Scope + +You can use a `bucket.scope` to identify Functions that belong to the same group. + +As a best practice, you should set your Function scope to the `bucket.scope` that contains the collection that's the source of your Eventing Function mutations. +This makes sure that your Function does not undeploy by removing a scope that points to a resource that's not required for the Function to run. + +NOTE: To set the `bucket.scope` to `+`.`+`, you must have the `Eventing Full Admin` or the `Full Admin` role. +All other users must use a scope that references an existing resource of their `bucket.scope`. + + +[#section_mzd_l1p_m2b] +=== Bindings + +A binding is a construct that lets you separate environment-specific variables, like keyspace names, external endpoint URLS and credentials, and global constrains, from the source code of the Eventing Function. + +A binding provides indirection between environment-specific artifacts and symbolic names, and helps move a Function definition from development to a production environment without changing your code. +Binding names must be valid JavaScript identifiers, and cannot conflict with built-in types. + +Your Eventing Function can have no binding, one binding, or several bindings. + +==== Bucket alias + +A bucket alias binding gives the JavaScript of a Function access to the Couchbase KV collections from the Data Service or KV. +The keyspaces `bucket.scope.collection` are accessible by the bound name as a JavaScript map in the global space of the Function. + +You can add bucket aliases by selecting *Bucket alias* and entering an alias-name, a keyspace, and the access level. +This sequence of values does the following: + +* alias-name is the name you can use to refer to the keyspace or collection from your Eventing Function code +* keyspace is the full path to a collection in the cluster +* the access level provides access to the keyspace as `read only` or `read and write` +** `read only` lets you read documents from the collection but not write (create, update, or delete) documents in the collection +** `read and write` lets you read and write documents in the collection + +NOTE: You must have one or more bucket alias bindings for your Eventing Function to perform operations directly against the Data Service. + +An Eventing Function can listen to multiple collections when you use the `{asterisk}` wildcard in its scope or collection. +You can also use the `{asterisk}` wildcard in the scope or collection of the bucket alias code. +If the bucket alias has a `{asterisk}` wildcard, only the Advanced Keyspace Accessors can read or write the Data Service. + +==== URL alias + +A URL alias binding is used by the cURL language construct to access external resources. +The URL alias specifies the endpoint, the HTTP/S protocol, and the credentials. + +You can enable cookie support through the binding when you access trusted remote nodes. +The target of a URL alias should not be a node that belongs to the Couchbase cluster. + +You can add URL aliases by selecting *URL alias* and entering an alias-name, a URL, settings to allow cookies, security settings to validate SSL certificate, and an authorization type of `no auth`, `basic`, `bearer`, and `digest`. + +For more information about URL aliases, see xref:eventing-curl-spec.adoc#bindings[cURL Bindings]. + +==== Constant alias + +A constant alias is used by the JavaScript code of the Eventing Function as a global variable. + +You can add constant aliases by selecting *Constant alias* and entering an alias-name and a value. +The valuje can be an integer, a decimal number, a string, a boolean, or a JSON object. + +For example, you can have an alias of `debug` with a value of `true` or `false` that controls logging. +This alias acts in the same way as adding a `const debug = true` statement at the beginning of your JavaScript code. + + +[#eventing-keyspaces] +=== Eventing Keyspaces + +A keyspace is a path to a collection in the format `bucket-name.scope-name.collection-name`. + +For backward compatibility, you can also use the format `bucket-name._default._default`. +This is the format of a bucket from Couchbase Server version 6.6 that has been upgraded to version 7.0. + +The following are the two keyspaces used by Eventing Functions: + +* <>, which represents the Eventing source +* <>, which represents the Eventing metadata + +[#listen-to-location] +==== Listen to Location + +Eventing Functions use a collection as the source for their data mutations. +This collection is called the Eventing source, and can be made up of Couchbase or Ephemeral keyspace types. +Memcached keyspace types are not supported. + +When you create an Eventing Function, you must specify a source collection. +The `OnUpdate` and `OnDelete` handlers are the entry points for this collection; they receive events and receive and track data mutations. + +When you delete a source collection, all deployed and paused Functions associated with the collection are undeployed. + +While a Function is processing its JavaScript code, the Function's documents can be mutated in different collections. +You can set keyspaces as destination collections, which are then bound to the Function through bucket aliases. + +The Function's JavaScript code triggers data mutations on documents through Basic Keyspace Accessors or Advanced Keyspace Accessors in the Data Service. +If the code directly modifies documents in the source collection, the Eventing Service suppresses the mutation back to the Function performing the mutation. + +The Function's JavaScript code can also trigger mutations on documents through inline {sqlpp} statements in the Query Service or `N1QL()` function calls. +You might need to add additional business logic to terminate or protect the Function against possible recursion. + +NOTE: When you implement multiple Functions, you can create infinite recursions. +The Eventing Service prevents the deployment of Functions that might result in recursion loops. +For more information abotu cyclic generation of data changes, see xref:troubleshooting-best-practices.adoc#cyclicredun[Bucket Allocation Considerations]. + +To get the `Listen To` keyspace to listen to multiple collections, you can use a `{asterisk}` wildcard for the scope or collection. +If the bucket binding used by the JavaScript code also has a `{asterisk}` wildcard for its scope or collection, you must use Advanced Keyspace Accessors to read or write the Data Service. For more information about Advanced Keyspace Accessors, see xref:eventing-advanced-keyspace-accessors.adoc#multiple-collection-functions[Eventing Functions that Listen to Multiple Collections]. + +TIP: You can have multiple Functions listening to the same collection while running different code. +To use less resources, though, you can use only one Function and code an if-then-else or switch statement in your handler's JavaScript. + +[#eventing-storage] +=== Eventing Storage + +The Eventing Storage is the Eventing Function's metadata bucket. +The metadata bucket stores artifacts, or configuration documents, that contain information about DCP streams, worker allocations, Timer information and state, and internal checkpoints. + +When you create an Eventing Function, you must make sure that a separate collection has been designated as an Eventing metadata and reserved for the Eventing Service's internal use. +You can use a common Eventing metadata collection across multiple Eventing Functions for the same tenant. + +The Eventing Storage keyspace must be in a Couchbase-type bucket. +If this keyspace is not persistent, the Data Service evicts Timer and checkpoint documents when it hits quota, and loses track of Timers and mutations that have been processed. + +NOTE: Do not delete the Eventing metadata collection. +Make sure that your Function's JavaScript code does not perform a write or delete operation on the Eventing metadata collection. +If you delete the metadata collection, all deployed Eventing Functions are undeployed and all associated indexes and constructs are dropped. + + +[#function-settings] +=== Eventing Function Settings + +[cols="1,2",options="header"] + +|=== + +|Function setting +|Description + +|Function Name +a|A unique name for your Eventing Function. +The Function name must: + +* Start with an uppercase character (A-Z), lowercase character (a-z), or number (0-9) +* Contain only uppercase characters (A-Z), lowercase characters (a-z), numbers (0-9), underscores (_), and hyphens (-) + +|Description +|An optional description that describes the purpose of your Eventing Function. + +|Deployment Feed Boundary +|The Feed Boundary determines if the Eventing Function's activities need to include documents that already exist. + +When you set the Feed Boundary to `Everything`, the Function deploys all mutations available in your database. +When you set the Feed Boundary to `From Now`, the Function only processes instances of data mutation that happen after the Function's deployment. + +The Feed Boundary also works as a checkpoint for paused Functions. +When you resume a paused Function, the Feed Boundary makes sure that no mutations are lost or processed again. + +You can only modify the Feed Boundary when you create a Function or when a Function is undeployed or paused. + +|System Log Level +|Determines the granularity of messages logged across the Eventing Function. +Can be one of `Info` (the default), `Error`, `Debug`, `Warning`, or `Trace`. + +|Application Log Location +|The directory path to the log file for the Eventing Function. +The format is `.log`. +The Function uses `log()` statements to write to this file. + +When you select the *Log* value on the UI, all log files are combined across Eventing nodes and displayed. +The log value is read-only and cannot be changed. + +|{sqlpp} Consistency +|The default consistency level of {sqlpp} statements in the Eventing Function. + +You can set the consistency level by statement. +Can be one of `None` (the default) or `Request`. + +|Workers +|The number of worker threads per node to be allocated to the Eventing Function to process events. +Allows the Function to scale up. + +The minimum number of workers is `1` (the default) and the maximum is `64`. + +|Language Compatibility +|The language version of the Eventing Function for backward compatibility. + +If the semantics of a language construct change during a release, the Language Compatibility setting makes sure that an older Eventing Function continues to produce the runtime behavior from when the Function was initially created. +The older Function only stops this behavior when the behavior is deprecated and removed. + +Couchbase versions 6.0.0, 6.5.0, and 6.6.2 are the only versions that are currently defined. +New Functions default to the highest compatibility version available of 6.6.2. + +In version 6.5.0, trying to access a non-existing item from a keyspace returns an undefined value. +In version 6.0.0, it throws an exception. + +Only a Function with a language compability setting of version 6.6.2 passes binary documents to Eventing Function handlers. +Versions 6.0.0 and 6.5.0 filter all binary documents out of the DCP mutation stream. + +|Script Timeout +|The number of seconds to elapse before the script times out and is terminated. + +The entry points into the handler processing for each mutation must run from start to finish before the specified timeout duration. +The default number of seconds is `60`. + +|Time Context Max Size +|The size limit of the context for any Timer created by the Eventing Function. + +A context can be any JSON document. Timers can store and access a context, which is then used to store the state of when a Timer is created and to retrieve the state of when a Timer is fired. + +The default is `1024`. + +|=== + + +== Operations + +Operations exposed through the UI, couchbase-cli, and REST APIs. + +=== Deploy + +The deploy operation activates an Eventing Function in a cluster. +It performs validations and allows only valid Eventing Functions to be deployed. + +Deploying an Eventing Function: + +* Creates necessary metadata +* Spawns worker processes +* Calculates initial partitions +* Initiates check-pointing of DCP streams to process +* Allows the Function to receive and process mutations and Timer callbacks + +You cannot edit the source code of a deployed Eventing Function. + +During deployment, you must choose one of the following *Deployment Feed Boundary* settings: + +* *Everything*, which provides the Eventing Function with a deduplicated history of all documents, ending with the current value of each document. This means the Function sees every document in the keyspace at least once. +* *From now*, which provides the Eventing Function with mutations starting at deployment. This means the Function only sees documents that have mutated after the Function's deployment. + +=== Undeploy + +The undeploy operation causes the Eventing Function to stop processing events of all types. +It also shuts down the worker processes associated with the Function. + +Undeploying an Eventing Function: + +* Deletes all Timers and context documents created by the Function +* Releases any runtime resources acquired by the Function + +You can edit the code and change the settings of an undeployed Eventing Function. + +When you create a new Eventing Function, the Function's state is undeployed. + +=== Pause + +The pause operation causes the Eventing Function to pause all mutations and Timer callbacks. +It also performs a checkpoint to be used for resuming the Function. + +You can edit the code and change the settings of a paused Eventing Function. + +A paused Function can be resumed or undeployed. + +=== Resume + +The resume operation continues processing mutations and Timer callbacks of an Eventing Function that was previously paused. + +The resume operation is similar to the deploy operation, but it uses a progress checkpoint to restart the Function. This means no mutations are lost or processed again. + +When you resume a Function, the backlog of mutations that occurred when the Function was in a paused state is processed. The backlog of Timers also fires, even if the time of the Timers has already passed. + +Depending on the system capacity and on how long the Function was paused, clearing the backlog can take some time. After the backlog is cleared, the Function goes on to process current mutations and Timers. + +=== Delete + +The delete operation deletes the following in the Eventing Function: + +* The source code implementing the Function +* All Timers and Timer contexts +* All processing checkpoints +* Application logs +* Any other artifacts in the metadata provider + +You can only delete an undeployed Eventing Function. + +=== Debug + +The debug operation traps and sends the next event instance received by the Eventing Function to a separate v8 worker with debugging enabled. Debug is a special flag that can be attach to a Function. + +The debug operation pauses the trapped event, opens a TCP port, and generates a Chrome Developer Tools URL with a session cookie that can be used to control the debug worker. +With the exception of the trapped event instance, all other Eventing Function events continue processing. + +When the trapped event finishes debugging, the debug operation traps another event instance. +This continues until you stop the operation. + + +== See Also + +* xref:eventing-advanced-keyspace-accessors.adoc[Advanced Keyspace Accessors] +* xref:eventing-language-constructs.adoc#basic_bucket_accessors[Basic Keyspace Accessors] +* xref:eventing-curl-spec.adoc[cURL] +* xref:troubleshooting-best-practices.adoc[Troubleshooting and Best Practices] diff --git a/modules/eventing/pages/eventing-advanced-keyspace-accessors.adoc b/modules/eventing/pages/eventing-advanced-keyspace-accessors.adoc new file mode 100644 index 000000000..60b577eaa --- /dev/null +++ b/modules/eventing/pages/eventing-advanced-keyspace-accessors.adoc @@ -0,0 +1,875 @@ += Advanced Keyspace Accessors +:description: Use Advanced Keyspace Accessors to access advanced Key Value functionality. +:page-aliases: eventing:eventing-advanced-bucket-accessors.adoc +:page-toclevels: 2 + +[abstract] +{description} + +Advanced Keyspace Accessors use the same bucket bindings defined in the handler as xref:eventing-language-constructs.adoc#bucket_accessors[Basic Keyspace Accessors], but they expose a larger set of options and operators. +These operators can be used to: + +* Set or retrieve document expirations in the Data Service +* Solve race conditions through CAS +* Manipulate KV items under high contention using JavaScript inside Eventing Functions +* Perform distributed atomic counter operations + +Couchbase supports the following: + +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> + + +[#advanced-get-op] +== Advanced GET Operation + +`result = couchbase.get(binding, meta)` + +The GET operation lets you read a document with metadata from your bucket. +It also allows any subsequent operations to use CAS and check or modify the expiration date of the document. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input doc', doc); + log('input meta', meta); + // could be the same or different + var new_meta = {"id": "test_adv_get::1"}; + var result = couchbase.get(src_col, new_meta); + if (result.success) { + log('success adv. get: result', result); + } else { + log('failure adv. get: id', new_meta.id, 'result',result); + } +} +---- +==== + +You can use the <> with the GET operation. + + +[#advanced-insert-op] +== Advanced INSERT Operation + +`result = couchbase.insert(binding, meta, doc)` + +The INSERT operation lets you create a new document in your bucket. +It also lets you specify an expiration date (or TTL) for the document. + +The operation fails if the document with the key you specified already exists. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + // Can be the same or different + var new_meta = {"id": "test_adv_insert:1"}; + // (Optional) Set an expiry time of 60 seconds in the future + // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); + var new_doc = doc; + new_doc.random = Math.random(); + var result = couchbase.insert(src_col, new_meta, new_doc); + if (result.success) { + log('success adv. insert: result', result); + } else { + log('failure adv. insert: id', new_meta.id, 'result', result); + } +} +---- +.Results +[source,javascript] +---- +{ + "meta": { + "id": "test_adv_insert:1", + "cas": "1610041053310025728" + }, + "success": true +} + +{ + "error": { + "code": 272, + "name": "LCB_KEY_EEXISTS", + "desc": "The document key already exists in the server.", + "key_already_exists": true + }, + "success": false +} +---- +==== + +You can use the <> with the INSERT operation. + + +[#advanced-upsert-op] +== Advanced UPSERT Operation + +`result = couchbase.upsert(binding, meta, doc)` + +The UPSERT operation lets you update an existing document in your bucket. +It also lets you specify an expiration date (or TTL) for the document. + +If no documents exist in your bucket, the operation creates a new document with the key you specified. + +The operation does not allow you to specify CAS. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + // Can be the same or different + var new_meta = {"id": "test_adv_upsert:1"}; // If supplied, the CAS is ignored + // (Optional) Set an expiry time of 60 seconds in the future + // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); + var new_doc = doc; + new_doc.random = Math.random(); + var result = couchbase.upsert(src_col, new_meta, new_doc); + if (result.success) { + log('success adv. upsert: result', result); + } else { + log('failure adv. upsert: id', new_meta.id, 'result', result); + } +} +---- +==== + +You can use the <> with the UPSERT operation. + + +[#advanced-replace-op] +== Advanced REPLACE Operation + +`result = couchbase.replace(binding, meta, doc)` + +The REPLACE operation lets you replace an existing document in your bucket with a new document. +It also lets you specify the following: + +* An expiration date (or TTL) for the document +* A CAS value to be used as a pre-condition for the operation + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + + var mode = 3; // 1-> no CAS, 2-> mismatch in CAS, 3-> good CAS + + // Set up the operation, make sure there is a document to be replaced, ignore any errors + couchbase.insert(src_col,{"id": "test_adv_replace:10"},{"a:": 1}); + + var new_meta; + if (mode === 1) { + // If no CAS is passed, the operation succeeds + new_meta = {"id": "test_adv_replace:10"}; + // (Optional) Set an expiry time of 60 seconds in the future + // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); + } + if (mode === 2) { + // If a non-matching CAS is passed, the operation fails + new_meta = {"id": "test_adv_replace:10", "cas": "1111111111111111111"}; + } + if (mode === 3) { + // If the current or matching CAS is passed, the operation succeeds + var tmp_r = couchbase.get(src_col, {"id": "test_adv_replace:10"}); + if (tmp_r.success) { + // Use the current CAS to read through the couchbase.get(...) operation + new_meta = {"id": "test_adv_replace:10", "cas": tmp_r.meta.cas}; + } else { + log('Cannot replace a non-existing key. Recreate the key and rerun the operation.', "test_adv_replace:10"); + return; + } + } + var new_doc = doc; + new_doc.random = Math.random(); + var result = couchbase.replace(src_col, new_meta, new_doc); + if (result.success) { + log('success adv. replace: result', result); + } else { + log('failure adv. replace: id', new_meta.id, 'result', result); + } +} +---- +.Results +[source,javascript] +---- +{ + "meta": { + "id": "test_adv_replace:10", + "cas": "1610130177286144000" + }, + "success": true +} + +{ + "error": { + "code": 272, + "name": "LCB_KEY_EEXISTS", + "desc": "The document key exists but it has a CAS value that is different from the specified value.", + "cas_mismatch": true + }, + "success": false +} +---- +==== + +You can use the <> with the REPLACE operation. + + +[#advanced-delete-op] +== Advanced DELETE Operation + +`result = couchbase.delete(binding, meta)` + +The DELETE operation lets you delete a document in your bucket. +You can use the document key to specify the document you want to delete. + +This operation also lets you specify a CAS value to be matched as a pre-condition to proceed with the operation. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + + var mode = 4; // 1-> no CAS, 2-> mismatch in CAS, 3-> good CAS, 4-> no CAS key + + // Set up the operation, make sure there is a document to be deleted, ignore any errors + couchbase.insert(src_col,{"id": "test_adv_delete:10"},{"a:": 1}); + + var new_meta; + if (mode === 1) { + // If no CAS is passed, the operation succeeds + new_meta = {"id": "test_adv_delete:10"}; + // (Optional) Set an expiry time of 60 seconds in the future + // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); + } + if (mode === 2) { + // If a non-matching CAS is passed, the operation fails + new_meta = {"id": "test_adv_delete:10", "cas": "1111111111111111111"}; + } + if (mode === 3) { + // If the current or matching CAS is passed, the operation succeeds + var tmp_r = couchbase.get(src_col,{"id": "test_adv_delete:10"}); + if (tmp_r.success) { + // Use the current CAS to read through the couchbase.get(...) operation + new_meta = {"id": "test_adv_delete:10", "cas": tmp_r.meta.cas}; + } else { + log('Cannot delete a non-existing key. Recreate the key and rerun the operation.',"test_adv_delete:10"); + return; + } + } + if (mode === 4) { + // Remove so that we have: no such key + delete src_col["test_adv_delete: 10"] + new_meta = {"id": "test_adv_delete:10"}; + } + var result = couchbase.delete(src_col, new_meta); + if (result.success) { + log('success adv. delete: result', result); + } else { + log('failure adv. delete: id', new_meta.id, 'result', result); + } +} +---- +.Results +[source,javascript] +---- +{ + "meta": { + "id": "key::10", + "cas": "1609374065129816064" + }, + "success": true +} + +{ + "error": { + "code": 272, + "name": "LCB_KEY_EEXISTS", + "desc": "The document key exists with a CAS value different than the specified value", + "cas_mismatch": true + }, + "success": false +} + +{ + "error": { + "code": 272, + "name": "LCB_KEY_ENOENT", + "desc": "The document key does not exist on the server", + "key_not_found": true + }, + "success": false +} +---- +==== + + +[#advanced-increment-op] +== Advanced INCREMENT Operation + +`result = couchbase.increment(binding, meta)` + +The INCREMENT operation lets you increment the `count` field in a specific document. + +For example, the document can have the structure `{ count: 23 }`, where 23 is the example counter value. + +If the specified counter document does not exist, the operation creates a new document with a `count` value of 0. If the `count` value is 0, the first returned value is 1. + +The INCREMENT operation cannot manipulate full document counters because of limitations in the KV engine API. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + + // The operation creates a doc.count if it does not already exist + var ctr_meta = {"id": "my_atomic_counter:1" }; + var result = couchbase.increment(src_col, ctr_meta); + if (result.success) { + log('success adv. increment: result', result); + } else { + log('failure adv. increment: id', ctr_meta.id, 'result', result); + } +} +---- +==== + + +[#advanced-decrement-op] +== Advanced DECREMENT Operation + +`result = couchbase.decrement(binding, meta)` + +The DECREMENT operation lets you decrement the `count` field in a specific document. + +For example, the document can have the structure `{ count: 23 }`, where 23 is the example counter value. + +If the specified counter document does not exist, the operation creates a new document with a `count` value of 0. If the `count` value is 0, the first returned value is -1. + +The DECREMENT operation cannot manipulate full document counters because of limitations in the KV engine API. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + + // The operation creates a doc.count if it does not already exist + var ctr_meta = {"id": "my_atomic_counter:1" }; + var result = couchbase.decrement(src_col, ctr_meta); + if (result.success) { + log('success adv. decrement: result', result); + } else { + log('failure adv. decrement: id', ctr_meta.id, 'result', result); + } +} +---- +==== + + +[#advanced-touch-op] +== Advanced TOUCH Operation + +[.status]#Couchbase Server 7.6# + +`result = couchbase.touch(binding, meta)` + +The TOUCH operation lets you modify the expiration time of a document without the need to access that document first. + +You can use this operation if your application does not need to access the database when handling a user session. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input meta', meta); + log('input doc', doc); + + var expiry = new Date(); + expiry.setSeconds(expiry.getSeconds() + 10); + + var req = {"id": "doc1", "expiry_date": expiry}; + var result = couchbase.touch(dst_bucket, req); + if (result.success) { + log('success adv. touch: result', result); + } else { + log('failure adv. touch: id', req.id, 'result', result); + } +} +---- +.Results +[source,javascript] +---- +{ + "meta": { + "id": "doc1", + "cas": "1708978502129614848" + }, + "success": true +} + +{ + "error": { + "code": 1, + "name": "LCB_KEY_ENOENT", + "desc": "The document key does not exist on the server", + "key_not_found": true + }, + "success": false +} +---- +==== + + +[#advanced-subdoc-array-op-mutatein] +== Sub-Document MUTATEIN Operation + +[.status]#Couchbase Server 7.6# + +`result = couchbase.mutateIn(binding, meta, subdoc_operation_array, options)` + +Sub-Document MUTATEIN operations let you modify only parts of a document instead of the entire document. +This makes them faster and more efficient than full-document operations like REPLACE and UPSERT. + +By default, a MUTATEIN operation does not modify Extended Attributes (XATTRs). +To modify a document's XATTRs, you must: + +* Pass `xattrs` as the third argument of your OnUpdate function. +* Pass `{ "xattrs": true }` in the `subdoc_operation_array` argument of your OnUpdate function. + +Sub-Document array operations do not have concurrency issues and can be performed without checking CAS. + +==== Examples +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + var meta = {"id": meta.id}; + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.insert("testField", "insert") + ]); + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.replace("testField", "replace") + ]); + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.remove("testField") + ]); +} +---- +==== + +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + var meta = {"id": meta.id}; + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.upsert("arrayTest", []), + couchbase.MutateInSpec.arrayAppend("arrayTest", 2), + couchbase.MutateInSpec.arrayPrepend("arrayTest", 1), + couchbase.MutateInSpec.arrayInsert("arrayTest[0]", 0), + couchbase.MutateInSpec.arrayAddUnique("arrayTest", 3) + ]); +}; +---- +==== + +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta, xattrs) { + var meta = {"id": meta.id}; + + // INSERT XATTR + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.insert("testField", "insert", {"xattrs": true}) + ]); + + // UPSERT XATTR + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.upsert("testField", "upsert", {"xattrs": true}) + ]); + + // REPLACE XATTR + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.replace("testField", "replace", {"xattrs": true}) + ]); + + // REMOVE XATTR + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.remove("testField", {"xattrs": true}) + ]); + + // ARRAY OPERATIONS WITH XATTR + couchbase.mutateIn(dst_bucket, meta, [ + couchbase.MutateInSpec.upsert("arrayTest", [], {"xattrs": true}), + couchbase.MutateInSpec.arrayAppend("arrayTest", 2, {"xattrs": true}), + couchbase.MutateInSpec.arrayPrepend("arrayTest", 1, {"xattrs": true}), + couchbase.MutateInSpec.arrayInsert("arrayTest[0]", 0, {"xattrs": true}), + couchbase.MutateInSpec.arrayAddUnique("arrayTest", 3, {"xattrs": true}) + ]); +}; +---- +==== + + +[#advanced-subdoc-array-op-lookupin] +== Sub-Document LOOKUPIN Operation + +[.status]#Couchbase Server 7.6.2# + +`result = couchbase.lookupIn(binding, meta, subdoc_array, options)` + +Sub-Document LOOKUPIN operations let you search for a specific field in a document without having to search and retrieve the entire document. + +By default, a LOOKUPIN operation does not fetch Extended Attributes (XATTRs). +To fetch a document's XATTRs, you must: + +* Pass `xattrs` as the third argument of your OnUpdate function. +* Pass `{ "xattrs": true }` in the `subdoc_array` argument of your OnUpdate function. + +The `subdoc_array` argument contains one or more of the following `couchbase.lookupIn.get` specs: + +* ``, which is the key of the subdocument you want to fetch. +* `{ "xattrs": true }`, if you want to fetch a document's XATTRs. +* `{ "doc":[{ "value”: , ”success”: }, { "value”: , ”success”:} ], ”meta”: , ”success”: }`, which returns results. +* `result.doc[i].value`, which gives you access to the i-th value of the subdocument. +If there's an error in fetching the i-th `subdoc_path`, the `result.doc[i].value` is undefined. + +==== Example +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta, xattrs) { + var meta = {"id": meta.id}; + var result = couchbase.lookupIn(dst_bucket, meta, [ + couchbase.LookupInSpec.get("", {"xattrs": true}), + couchbase.LookupInSpec.get("", {"xattrs": true}) + ]); + var value_0 = result.doc[0].value; + var value_1 = result.doc[1].value; +} +---- +==== + + +[#multiple-collection-functions] +== Eventing Functions that Listen to Multiple Collections + +You can use the wildcard `{asterisk}` in an Eventing Function's scope or collection to listen to multiple collections. + +If the binding used by the Advanced Keyspace Accessor also contains a wildcard `{asterisk}` for its scope or collection, you must use the additional `meta.keyspace` parameter. + +The following example includes a `meta.keyspace` parameter that specifies the keyspace in which the INSERT operation is to take place: + +==== Example +==== +.Operation +[source,javascript] +---- +couchbase.insert( + src_col, { + "id": id_str, + "keyspace": { + "bucket_name": "bkt01", + "scope_name": "scp01", + "collection_name": "col01" + } + }, + some_doc +) +---- +==== + +See the xref:eventing-examples.adoc#examples-scriptlets-advanced-accessors[multiCollectionEventing example] for a detailed example of Eventing Functions that listen to multiple collections. + + +[#optional-params] +== Optional Parameters + +=== Optional `{ "cache": true }` Parameter + +You can use an optional third parameter `{ "cache": true }` to enable a bucket backed cache to hold the documents for one second. +This cache exists on each Eventing node and is shared across all Eventing Functions in the same node. + +The cache has "read your own write" (RYOW) semantics. Writing and then reading the same document with `{ "cache": true }` always retrieves the value that has just been written. + +This parameter loads near static data from the Data Service, where every mutation needs external data to drive the business logic of Eventing Functions. +The performance of this operator is usually 18 to 25 times faster than reading data directly from the Data Service. + +This parameter can be used with the <> advanced operation. + +[#optional-params-cache] +==== Example using the optional `{ "cache": true }` parameter +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('input doc', doc); + log('input meta', meta); + // Can be the same or different + var new_meta = { "id": "test_adv_get::1" }; + var result = couchbase.get(src_col, new_meta, { "cache": true }); + if (result.success) { + log('success adv. get: result', result); + } else { + log('failure adv. get: id', new_meta.id, 'result',result); + } +} +---- +.Results +[source,javascript] +---- +{ + "doc": { + "id": 1, + "type": "test_adv_get" + }, + "meta": { + "id": "test_adv_get::1", + "cas": "1610034762747412480", + "datatype": "json" + }, + "success": true +} + +{ + "doc": { + "a": 1, + "random": 0.09799092443129842 + }, + "meta": { + "id": "test_adv_insert:1", + "cas": "1610140272584884224", + "expiry_date": "2021-01-08T21:12:12.000Z", + "datatype": "json" + }, + "success": true +} + +{ + "error": { + "code": 272, + "name": "LCB_KEY_ENOENT", + "desc": "The document key does not exist on the server", + "key_not_found": true + }, + "success": false +} +---- +==== + +[#optional-params-recursion] +=== Optional `{ "self_recursion": true }` Parameter + +[.status]#Couchbase Server 7.6# + +You can use the optional fourth parameter `{ "self_recursion": true }` to prevent the suppression of recursive source bucket mutations and to process the mutations that you have just created. + +If you do not add `{ "self_recursion": true }` to your operation, all source bucket mutations are suppressed. + +This parameter can be used with the <>, <>, and <> advanced operations. + +==== Example using the optional parameter `{ "self_recursion": true }` +==== +.Operation +[source,javascript] +---- +function OnUpdate(doc, meta) { + if (!doc.count) { + doc = { "count": 1, "id": meta.id }; + meta.id = meta.id + "_test"; + couchbase.insert(src, meta, doc, { "self_recursion": true }); + return; + } + + if (doc.count < 3) { + doc.count++ + couchbase.upsert(src, meta, doc, { "self_recursion": true }); + return; + } + + if (doc.count < 6) { + doc.count++; + couchbase.replace(src, meta, doc, { "self_recursion": true }); + return; + } + + couchbase.delete(src, { "id": meta.id }); + couchbase.delete(src, { "id": doc.id }); +} +==== + + +== Return Values + +[cols="40,25,60",options="header"] + +|=== +|Value +|Type +|Description + +|`binding` +|string +|The name of the binding that references the target bucket. + +For the Advanced GET operation, the binding can have an access level of read or read/write. + +For all other operations, the binding must have an access level of read/write. + +|`meta` +|Object +|The positional parameter that represents the metadata of the operation. + +|`meta.id` +|string +|The key of the document to be used in the operation. +This is a mandatory parameter that must be a JavaScript string. + +|`meta.keyspace` +|Object +|The keyspace of the document to be used for the operation. + +Must be in the JavaScript format `"keyspace": { "bucket_name": string, "scope_name": string, "collection_name": string }`. + +|`meta.cas` +|string +|(Optional) Specifies the CAS value to be used as a pre-condition for the operation. + +If the CAS value of the document does not match the CAS value specified in this field, the operation fails and sets the parameter `cas_mismatch` to true in the error return object. + +|`meta.expiry_date` +|Date +|(Optional) Sets the expiry time for the document. +If specified, must be in the JavaScript format `Date`. + +|`doc` +|string, number, boolean, null, Object, or Array +|The document content of the operation. + +|`result` +|Object +|Indicates the success or failure of the operation. + +If the operation is successful, it returns the data that was fetched. +If the operation fails, it returns the details of the error. + +|`result.success` +|boolean +|Indicates if the operation is successful or not. +This field is always present in the return object. + +|`result.meta` +|Object +|Contains metadata about the object that was fetched. +This field is only present is the operation is successful. + +If the specified key is not present in the bucket, the operation fails and returns `key_not_found` in the error object. + +|`result.meta.id` +|string +|The key of the document fetched by the operation. + +|`result.meta.cas` +|string +|The CAS value of the document fetched by the operation. + +|`result.meta.expiry_date` +|Date +|The expiration date of the document. +This field is only present if an expiration is set on the document. + +|`result.meta.datatype` +|string +|Indicates whether the document is `json` or `binary`. + +|`result.doc` +|string, number, boolean, null, Object, or Array +|Returns the content of the requested document if the operation is successful. + +|`result.error` +|Object +|Returns an error if the operation fails. + +|`result.error.cas_mismatch` +|boolean +|If true, this field indicates that the operation failed because a CAS value was not specified or because the CAS value on the object did not match the CAS value in the request. + +|`result.error.key_not_found` +|boolean +|If true, this field indicates that the operation failed because the specified key did not exist in the bucket. + +|`result.error.key_already_exists` +|boolean +|If true, this field indicates that the operation failed because the specified key already exists in the bucket. + +|`result.error.code` +|number +|Represents the SDK error code that triggered the operation to fail. +Usually returns an internal numeric code. + +|`result.error.name` +|string +|Indicates the error that the SDK triggered and that caused the operation to fail. + +|`result.error.desc` +|string +|A description of the error. +This description can be used for diagnostics and logging, and can change over time. +Programming logic should not be tied to the specific contents of this field. + +|`exceptions` +|- +|Indicates errors through the error object in the return value. +Exceptions are only thrown during system failure conditions. +|=== + +== See Also + +* xref:eventing-examples.adoc#examples-scriptlets-advanced-accessors[Advanced Accessor Handler scriptlets] for complete examples of Advanced Keyspace Accessors, including JavaScript, input mutations, output mutations, and log messages +* xref:eventing-language-constructs.adoc#bucket_accessors[Basic Keyspace Accessors] diff --git a/modules/eventing/pages/eventing-buckets-to-collections.adoc b/modules/eventing/pages/eventing-buckets-to-collections.adoc new file mode 100644 index 000000000..3ec6bdf39 --- /dev/null +++ b/modules/eventing/pages/eventing-buckets-to-collections.adoc @@ -0,0 +1,97 @@ += Buckets vs Collections +:description: Now in Couchbase version 7.0 the concept of scopes and collections have been introduced allowing greater \ +flexibility in grouping data and also the ability to support multitenancy. +:page-edition: Enterprise Edition + +{description} + +In older versions of Couchbase, data was organized like this (documents exist only in Buckets): + +* Cluster +* Bucket +* Document + +In Couchbase 7.0, there are two new organizational layers, Scope and Collection, thus the hierarchy now looks like the following (documents exist only in Collections): + +* Cluster +* Bucket +* Scope +* Collection +* Document + +Scopes are the level of organization below a buckets. Scopes contain collections and collections contain documents. There are +different ways to use scopes, depending on what the Couchbase cluster is being used for. If it is supporting many different internal +applications for a company, each application should have a scope of its own. If the cluster is being used to serve many client +organizations, each running its own copy of an application, each copy should have a scope of its own. Similarly, if a cluster is +being used by dev groups, perhaps for testing, the unit of allocation should be a scope. In each case, the owner can then create +whatever collections they want under the scope they are assigned. + +Collections are the lowest level of document organization, and directly contain documents. They are useful because they let you group +documents more precisely than was possible before. Rather than dumping all different types of documents (products, orders, customers) +into a single bucket and distinguishing them by a type field, you can instead create a collection for each type. And when you query, +you can query against the collection, not just the whole bucket. You will also eventually be able to control access at the collection level. + +Prior to Couchbase version 7.0 all services, including Eventing, were Bucket oriented where multiple sets of documents were +written to a limited set of buckets (typically no more than 30 buckets). Non-homogeneous documents within the same bucket +were typically differentiated by an additional type property. + +[source,javascript] +---- +{ + "id": 10025, + "type": "hotel", + "brand": "Hilton", + * + * +} +---- + +[source,javascript] +---- +{ + "id": 10, + "type": "airline", + "iata": "Q5", + * + * +} +---- + +Every created bucket is automatically given a default scope, and within it, a default collection. Each is named *_default*. +This allows a simple seamless migration from a Cluster/Bucket/Document model to a Cluster/Bucket/Scope/Collection/Document model without concern to any reorganization. + +Thus a bucket called `travelinfo` prior to 7.0 essentially becomes a single collection `travelinfo._default._default` and the data set can remain unchanged after upgrading your cluster to 7.0. + +However all types could be split up and moved into individual collections perhaps all airline documents to a keyspace of `travelinfo.data.airline` and all hotel documents to a keyspace of `travelinfo.data.hotel`. + +NOTE: The Eventing Service can be used to quickly and efficiently migrate a bucket into a set of collections. An example scriptlet xref:eventing:eventing-handler-ConvertBucketToCollections.adoc[ConvertBucketToCollections] has been provided to demonstrate the migration of the `beer-sample` data set from a bucket paradigm to a collection paradigm. + +The benefits of reorganizing to collections are numerous: + +* We no longer need the type property. +* Operations such as query, XDCR, and backup and restore. +* Increased efficiency of indexing, due to the Data Service being able to provide documents from specific collections to the Index Service. +* Simplified querying, since query statements are able to easily specify particular subsets of documents. +* Easier migration from relational databases to Couchbase Server, since collections can be designed to correspond to pre-existing relational tables. +* Secure isolation of different document-types, within a bucket; allowing applications to be specifically authorized to use only their appropriate subsets of data. + +For complete details on how to set up your keyspaces refer to xref:manage:manage-buckets/create-bucket.adoc[creating buckets] and +xref:manage:manage-scopes-and-collections/manage-scopes-and-collections.add[creating scopes and collections]. + +Eventing in the collections world can just use the _default scope and the _default collection and essentially run without and changes. However there are opportunities for reorganizing the groupings of your data to lower the needed resources or increase throughput. + +[#single-tenancy] +*Eventing with Full Collections Support: Single Tenancy* + +image::eventing-collections-single-tenant.jpg[,%100] + +*Eventing with Full Collections Support: Multi Tenancy* + +[#multi-tenancy] +image::eventing-collections-multi-tenant.jpg[,%100] + +If we put the put ‘Eventing Storage’ (in collections) in the same bucket as with data with non 100% residency the Evening performance can easily drop by a factor of five (5) or more. + +Of course you can put everything including the ‘Eventing Storage’ collection into a single bucket, if the bucket is 100% resident you will not suffer slowdowns but as the residency rate of this bucket drops you will start accessing your underlying disk for Eventing control documents (definitions, timers, and checkpoints). This behavior is analogous to swapping to disk when your active computer's programs combined are larger than your computer's memory. + +Typically the overhead of the Eventing housekeeping area "Eventing Storage" is quite small, just 1024 documents per Function and occasional check point documents. However if Timers are used the size of this collection can grow to about 1K bytes x number of active timers (_for 1M active timers this is 1.5G bytes_). As such the enclosing bucket holding the ‘Eventing Storage’ needs to be sized appropriately. diff --git a/modules/eventing/pages/eventing-curl-spec.adoc b/modules/eventing/pages/eventing-curl-spec.adoc new file mode 100644 index 000000000..942eb0b9b --- /dev/null +++ b/modules/eventing/pages/eventing-curl-spec.adoc @@ -0,0 +1,248 @@ += cURL +:description: The curl() function provides a way of interacting with external entities via a REST endpoint using HTTP or HTTPS. +:page-edition: Enterprise Edition + +{description} + +Eventing functions can interact with external systems by using the curl() function to call their REST APIs. The possibility to interact with external systems opens a lot of new use cases, such as: + +* Propagation of data changes to other systems. +* Notifying the application about interesting events. +* Enriching documents with data from external systems. + +This feature is both reliable and secure: the cURL calls are limited to a predefined set of URL bindings, and for each binding we can specify authentication, encryption, and certificate validation as necessary. + +A few important aspects related to cURL are listed below: + +* Automatic parsing of common types of data. +* Automatic marshaling of common types of data. +* Ability to access HTTP request and response headers. +* Ability to handle HTTPS connections. +* Support for session cookies. +* Multiple authentication types are supported. + +The URL needs to point to a REST endpoint and must be either http:// or https:// only. No other protocol is supported. + +== Language Syntax + +To make a cURL call use the below syntax: + +---- +response_object = curl(method, binding, [request_object]) +---- +In the curl syntax: + +* method - The HTTP method of the cURL request. Must be a string having one of the following values: GET | POST | PUT | HEAD | DELETE. +* binding - The cURL binding that represents the http endpoint URL that will be accessed by this call. +* request_object - This parameter captures the request and related information. The request_object is a JavaScript object having the following keys: +** headers - Optional. A JavaScript Object of key-value pairs with key representing the header name and value representing the header content. Both key and value must be strings. +** body - A JavaScript variable representing the content of the request body. See below for details on how various JavaScript variable types are marshalled to form the HTTP request. +** encoding - Optional. A directive on how to encode the body. A string having one of following values: ++ +FORM | JSON | TEXT | BINARY. +** path - The sub-path the request is made. This must be a string and will be appended to the URL specified on the binding object. +** params - This must be a JavaScript Object of key-value pairs. Keys must be strings, and values must be either a string, number or boolean. These will be URL encoded as HTTP request parameters and appended to the request URL. +** Return value (response_object) - The returned value from the cURL call which captures the response of the remote HTTP server to the request made. This is a JavaScript Object containing the following fields: +*** body - A JavaScript variable representing the content of the response body. See below for details on how the response is unmarshalled into various JavaScript variable types. +*** status - The numeric HTTP status code. +*** headers - A JavaScript Object of key-value pairs with key representing the header name and value representing the header content. Both key and value will be strings. +** Exceptions Thrown - When an unexpected error occurs, a JavaScript exception of type CurlError inheriting from the JavaScript Error class will be thrown. + +== Bindings + +To access an HTTP server using cURL, the Eventing Function needs to declare a URL binding and pass the alias of the binding to curl() calls. The binding specifies the remote URL to be accessed and all calls made using such a binding are limited to descendants of the URL specified in the binding. + +HTTPS is used when the URL specifies the https:// prefix. Such a link uses https for encryption of contents, and if enabled, verifies the server certificate using the underlying OS support for server certificate verification. Client certificates are not currently supported. + +The binding may also specify the authentication mechanism and credentials to use. Basic, Digest and Bearer authentication methods are supported. It is strongly recommended that when authentication is used, the binding uses only https protocol to ensure credentials are encrypted when transmitted. + +Cookie support may be enabled at binding level if desired when accessing controlled and trusted endpoints. + +image::eventing_curl_bindings.png[,800] + + +== Example + +In the below example, a cURL request is created to the specified binding profile_svc_binding with the sub-URL /person with URL parameters action and id and the body being a JSON object. The response is a JSON object and is seen containing a field profile_id. In this example, the request is automatically encoded as application/json and response is automatically parsed from JSON response, as no explicit encoding is specified. + +---- +var request = { + path: '/person', + params: { + 'action': 'create', + 'id': 23012 + }, + body: { + 'name': 'John Smith', + 'age': 25, + 'state': 'CA', + 'country': 'US', + } +}; + +var response = curl('POST', profile_svc_binding, request); +if (response.status == 200) { + var profile_id = response.body.profile_id; + log("Successfully created profile " + profile_id); +} +---- + +== Request marshalling + + +[#optional-id1,cols="1,1,1,1",options="header"] +|=== + +| *JS object passed to the body param* +| *Value passed for encoding param* +| *Encoding used for request body* +| *Content-Type header sent* (unless overridden by headers param) + +| +| +| +| + +| JS String +| (not specified) +| UTF-8 +| text/plain + +| JS Object +| (not specified) +| JSON +| application/json + +| JS ArrayBuffer +| (not specified) +| Raw Bytes +| application/octet-stream + +| +| +| +| + +| JS String +| TEXT +| UTF-8 +| text/plain + +| JS Object +| TEXT +| (disallowed) +| (disallowed) + +| JS ArrayBuffer +| TEXT +| (disallowed) +| (disallowed) + +| +| +| +| + +| JS String +| FORM +| URL Encoding +| application/x-www-form-urlencoded + +| JS Object +| FORM +| URL Encoding +| application/x-www-form-urlencoded + +| JS ArrayBuffer +| FORM +| (disallowed) +| (disallowed) + +| +| +| +| + +| JS String +| JSON +| JSON +| application/json + +| JS Object +| JSON +| JSON +| application/json + +| JS ArrayBuffer +| JSON +| (disallowed) +| (disallowed) + +| +| +| +| + +| JS String +| BINARY +| UTF-8 +| application/octet-stream + +| JS Object +| BINARY +| (disallowed) +| (disallowed) + +| JS ArrayBuffer +| BINARY +| Raw Bytes +| application/octet-stream +|=== + +Users who wish to utilize custom encoding can do so by specifying an appropriate Content-Type using the _headers_ parameter of the request object and passing the custom encoded object as an ArrayBuffer as the _body_ parameter of the request. + +== Response unmarshalling + +Response object from the remote is automatically unmarshalled if the response contains a recognized Content-Type header. The following table identifies the action used to unmarshal responses: + +[#optional-id2,cols="1,1,1",options="header"] +|=== + +| *Content-Type specified by response* +| *Unmarshalling action* +| *Response body param* + +| text/plain +| Convert to string as UTF-8 +| JS string + +| application/json +| JSON.parse() +| JS Object + +| application/x-www-form-urlencoded +| decodeURI() +| JS Object or JS String + +| application/octet-stream +| Store raw bytes +| JS ArrayBuffer + +| (Content-Type not listed above) +| Store raw bytes +| JS ArrayBuffer + +| (Content-Type header missing) +| Store raw bytes +| JS ArrayBuffer + +|=== + +== Session handling + +Cookie support is turned off by default on a cURL binding. So, no cookies will be accepted from the remote server. Cookies can be enabled if accessing a controlled and trusted endpoint. If enabled, cookies are accepted and stored in-memory of the worker object, scoped to the binding object. + +Note that Eventing utilizes multiple workers and multiple HTTP cURL sessions and so a Eventing Function cannot rely on all requests executing on the same HTTP session. It can rely on issued cookies being presented on subsequent requests only within the duration of a single Eventing Function invocation. + + +// The xref:eventing-examples.adoc[Eventing Examples] section provides two examples that show the use of Timers. The first example xref:eventing-examples-docexpiry.adoc[Document Expiry] and second example is xref:eventing-examples-docarchive.adoc[Document Archive]. diff --git a/modules/eventing/pages/eventing-debugging-and-diagnosability.adoc b/modules/eventing/pages/eventing-debugging-and-diagnosability.adoc new file mode 100644 index 000000000..bce69e658 --- /dev/null +++ b/modules/eventing/pages/eventing-debugging-and-diagnosability.adoc @@ -0,0 +1,498 @@ += Debugging and Diagnosability +:description: Debugging and diagnostics in the Eventing Service comprises of debugging functions, functions log, and log redaction. +:page-edition: Enterprise Edition +ifndef::flag-devex-rest-api[] +:page-embargo: EMBARGOED +endif::flag-devex-rest-api[] + +[abstract] +{description} + +[#debugging-functions] +== Debugging Functions + +Couchbase Server, for its Eventing Service framework, includes a powerful full function online real-time JavaScript Debugger. +Debug is a special flag on a Function. +The Debug option integrates seamlessly with the Google Chrome Debugger engine for running the JavaScript code of any Eventing Function. + +The default Eventing debug port is *9140*. To change the default port settings, see <>. + +=== Debugging Workflow + +* During a debug session, a single mutation received by the Eventing Function is taken from the primary processing stream(s) and sent to the Debugger. +This technique ensures that processing of the other data mutations in the cluster does not stall or get blocked. +* When a worker thread traps the next event-instance for debugging, it opens an ephemeral TCP port, and generates a Chrome dev-tools URL, with a session cookie that controls the debug worker. +* The Chrome dev-tools URL must be hand copied due to built-in security in the browser. +* All other events processed by the Eventing Function are unaffected except for the single the trapped event-instance. +* Using the Debug option, you can place breakpoints in the code and run the Function execution, step through your code one line at a time, and inspect values of your variables. +The step-step execution helps while troubleshooting the deployed Eventing Function under real world constraints. +* If the debugged event-instance completes execution, no further event-instances get trapped for debugging. If you wish to debug a second event-instance you need to stop and restart the debugger in the Function's code editor. +* If a debug session gets terminated during execution, then the mutation may be abruptly processed or canceled. +* Debugging is a convenience-feature intended to help during Function development: it is highly discouraged for use in production environments. ++ +WARNING: Debug mode should be avoided in production environments, as it affects the in-order processing of the document mutations as well as introducing timing related issues. + +=== Enable Debugging of Eventing Functions + +The debugger should only be enabled when you plan to debug your functions. When done with interactive debugging you should disable the option to increase security. This setting change is needed to enable the *Debug* button in the *View JavaScript* code editor for a deployed Function. + +* To enable debugging for the Eventing Service, navigate to *Couchbase Web Console* > *Eventing* page ++ +image::debugger_01_eventing_page.png[,100%] +* Click *SETTINGS" in the top banner. +* In the "Eventing Settings" Dialog check the *Enable debugger" checkbox. ++ +image::debugger_02_eventing_settings.png[,350] +* Click "*Save* + +=== Debugging a Function + +Below we have expanded the deployed Eventing Function "case_2_enrich_ips" from the Example xref:eventing-example-data-enrichment[Data Enrichment]. + +* The deployed Function expands (when you click the Function's name) to provide additional options: ++ +image::debugger_03_deployed_function.png[,100%] + +* Click *View JavaScript* to bring up the Function's JavaScript ++ +image::debugger_04_function_editor.png[,100%] + +* Because we enabled debugging we now have a button, *Debug*, in the lower left of the code editor + +* From the *View JavaScript* page, click *Debug*. +This will activate a one-time debug session. As a result, the next event-instance will get trapped and is forwarded to the Debugger. ++ +image::debugger_05_debugger_waiting.png[,100%] + +* In the above screen, you can notice the message: "Waiting for mutation." ++ +NOTE: During a debugging session this window must remain active. When you are presented a debug URL you must copy then paste it into a new browser window (described below). If you are using the UI to create the mutation, you must use a different browser tab/window to create the mutation. + +* Since we are using an Example we need to trigger a mutation in another tab/window, _*do not close this browser tab/window with your debugging dialog*_. ++ +If you are debugging an Eventing Function that has a constant stream of mutations you would not need to make your own mutation. + +* *In tab/another window* access the *Couchbase Web Console* > *Buckets* page and click the *Scopes and Collections* link of the *bulk* bucket. +** Click *Documents* in the upper right banner for the *data* scope. +** Select the keyspace *bulk*, *data*, *source* ++ +image::debugger_06a_make_event.png[,100%] +** You should see no user records (for this example). +** Click *Add Document* in the upper right banner +** For the *ID* in the *Create New Document* dialog specify *SampleDocument* ++ +---- +ID [ SampleDocument ] +---- ++ +** For the document body in the *Create New Document* dialog, the following text is displayed: ++ +---- +{ +"click": "to edit", +"with JSON": "there are no reserved field names" +} +---- +** replace the above text with the following JSON document via a cut-n-paste ++ +---- +{ +"country": "AD", + "ip_start": "5.62.60.1", + "ip_end": "5.62.60.9" +} +---- ++ +image::debugger_06b_make_event.png[,100%] +** Click *Save* to generate a mutation in your Eventing Function's "Listen to Location". + +* Return to the tab/window that was in "Waiting for mutation." state. You can see the one-time debugging URL is now filled in and available to copy. ++ +image::debugger_07_debugger_have_url.png[,100%] + +* In the above debugging dialog Click *COPY* + +* Open a new tab/window, _*do not close this browser tab/window with your debugging dialog*_, for the Google Chrome Debugging session. + +* Paste the copied one-time debugging URL into the address bar and hit return. ++ +image::debugger_08_new_tab_paste_url.png[,100%] + +* When the debugger comes up it may or may not display your Eventing Function's JavaScript. If you do not see your code you may have to Click on the *step* button once or twice in the debugger (see the highlighted RED box above and below). Once you see your Function's JavaScript code adjust the sizes of the various debugging windows to your personal preference. ++ +image::debugger_09_chrome_step.png[,100%] + +* Set a breakpoint at line 12 by clicking on the line # on the left (see the highlighted RED box below). Once a break point is set it will display a bold BLUE bookmark. ++ +image::debugger_10_chrome_breakpoint.png[,100%] + +* Click the *Resume* button in the debugger to continue execution and to run until the break point you set. ++ +image::debugger_11_chrome_run_to_bp.png[,100%] + +* The Eventing Function will execute (accessing KV and/or {sqlpp} and interacting with REST endpoints) as it would in production until it hits your breakpoint. ++ +image::debugger_12_chrome_run_at_bp.png[,100%] + +* Note the variable values displayed while at the breakpoint set at line 12. Click on the *Resume* button a second time to finish executing your Function. + +* The debugger is done return to the tab/window where your one-time debugging URL was created and Click *Stop debugging*. If you need to debug another mutation Click *Debug* again and repeat the process. + +* If you are done with all needed interactive debugger disable debugging via the *SETTINGS*. + +=== Possible Debugging Problems and Issues + +* During a debugging session this window must remain active. When you are presented a debug URL you must copy then paste it into a new browser window (described below). If you are using the UI to create the mutation, you must use a different tab/browser window to create the mutation. A debug session will also be terminated if from the Debugging pop-up (or debugging dialog), you can click *Stop Debugging*. + +* The URL you copied is valid only for a single mutation, to debug another subsequent mutation you must click *Stop debugging* button and capture click *Debug* again to get a fresh one-time debugging URL. + +* You are trying to debug a Couchbase server via a NAT'd IP Address and the debugger doesn't work because the generated one-time debugger URL doesn't reflect the NAT. ++ +Example NAT'd setup ++ +---- +Couchbase server is running 192.168.3.150 key ports 8091 for UI and 9140 for websocket devtools debugger +A public NAT for 192.168.3.150 is 4.71.116.187 (for both ports 8091 and 9140) in your firewall +---- ++ +Solution: ++ +On the actual Couchbase server, i.e. 192.168.3.150, set up an alternate address for the debugger as follows for 7.0 GA (and also 6.6.3): ++ +---- +curl -X PUT http://$CB_USERNAME:$CB_PASSWORD@localhost:8091/node/controller/setupAlternateAddresses/external \ + -d hostname=4.71.116.187 -d eventingDebug=9140 +---- ++ +The Debug URL is now correct and needs no hand editing. ++ +To delete/remove the alternate address on 192.168.3.150 on the actual server host, i.e. 192.168.3.150 run the following: ++ +---- +curl -X DELETE http://$CB_USERNAME:$CB_PASSWORD@localhost:8091/node/controller/setupAlternateAddresses/external \ + -d hostname=4.71.116.187 -d eventingDebug=9140 +---- + +* Although every effort is done to remain current Google changes the websocket URL format from time to time. You might have to manually alter the start of the debugging URL from *chrome-devtools://* to just *devtools://* and also at the end of debugging URL from *js_app.html* to *inspector.html* depending on the version of your Google Chrome browser due to a recent changes made by Google. Currently these manual changes (if needed) have to be done after pasting the URL into a new Chrome browser tab. ++ +There are currently three known URL variants from the oldest Chrome release to newest Chrome release: + +** chrome-devtools://devtools/bundled/js_app.html +** devtools://devtools/bundled/js_app.html +** *devtools://devtools/bundled/inspector.html + +* Potential issue with debugging International Components for Unicode (ICU) ++ +WARNING: In earlier versions 6.5.0, 6.5.1, and 6.6.0 users might experience bug MB-41508 a Chrome "WebSocket Disconnected" when debugging Eventing functions that call either toLocaleString() or Intl.DateTimeFormat. Essentially the file "icudtl.dat" which provides support for International Components for Unicode (ICU) is not in the needed location. The following step (copying the Chrome "icudtl.dat" file) is necessary only for development or staging clusters as users aren't expected to spawn a debugger in a live production environment. ++ +Typically this issue will occur when the debugger hits an ICU function like _Intl.DateTimeFormat_ or _toLocaleString_, the result is your debugging session is disconnected as follows: ++ +image::debug_websocket_disconnected.png[,400] ++ +To fix the issue in Chrome you merely need to copy a file on the server to the expected file system location. + +** Linux ++ +cp -p /opt/couchbase/bin/icudtl.dat /opt/couchbase/var/lib/couchbase +** macOS ++ +cp -p /Applications/Couchbase\ Server.app/Contents/Resources/couchbase-core/bin/icudtl.dat /Users/$USER/Library/Application\ Support/Couchbase/ +//// +* Windows ++ +_need to add copy syntax_ +//// + +=== Transpiler and Source Map + +A transpiler accepts source code provided as input from one high-level programming language and produces an equivalent code in another high-level programming language. + +Couchbase Server uses a native transpiler. This transpiler converts the Eventing Function's JavaScript syntax into a pure JavaScript representation that the JavaScript engine can understand. If this transpiler was unavailable, then the JavaScript engine would have failed to compile any native {sqlpp} queries or curl() functions. + +When your source code is transformed, debugging becomes a problem because we must know where the original code is. Source maps solve this problem by providing a mapping between the original and the transformed source code. + +A source map, generated by our native transpiler provides a mapping between the transpiled code and the original function Eventing Function JavaScript code. Debugging is easy as the debugger detects the source map and presents the code to the developer in the original Eventing Function JavaScript format. + +Upon source map detection, a text confirmation flag gets displayed in the bottom of your browser's debug window as a very long comment an example is highlighted below: + +[.out]`//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpb` *truncated* + +// This image does't exist +// image::debug_sourcemap.png[,600] + +[#modifydebugport] +=== Modifying the Debug Port + +The Eventing Service Debugger port, `eventing_debug_port` (9140), is an internal port and is one of the ports that are configured by the *ns_server*. Note this port is not supported for external access outside of the cluster and should only be used in development environments. To modify this port setting (Linux example): + +. xref:install:install-intro.adoc[Install Couchbase Server]. +. xref:install:startup-shutdown.adoc[Stop the Couchbase Server service]. +. Edit the */opt/couchbase/etc/couchbase/static_config* file to add the new eventing_debug_port and the new port-number information. For example, to change the Eventing debugging port from 9140 to 9444, you would add the following line (enclosed in braces and terminated by a period): ++ +[source,console] +---- +{eventing_debug_port, 9444}. +---- +. If Couchbase Server was previously configured, you'll need to delete the */opt/couchbase/var/lib/couchbase/config/config.dat* file to remove the old configuration. +. xref:install:startup-shutdown.adoc[Start Couchbase Server]. + +For detailed information on the modifying *ns_server* port mappings, refer to xref:install:install-ports.adoc#map-custom-ports[Custom Port Mapping]. + +WARNING: Changing port mappings should only be done at the time of initial node/cluster setup as the required reset and reconfiguration will also purge all data on the node. + +[#logging-functions] +== Logging Functions + +The Eventing Service creates two different types of logs: + +* System Log +* Application Logs + +Couchbase Server creates different application log files depending on the level and severity of the reported problem, as configured during Function definition + +[#system-log] +=== System Log + +For the Eventing Service, Couchbase Server creates a system log file named *eventing.log* (refer to Table 1 for filesystem location by platform). +This file is common across all Eventing Functions. +The system log file captures information related to general management and supervision of the Eventing service (not the business logic of the Function). +In addition this log file also captures life cycle or housekeeping information of every individual Eventing function depending on the Function's "System Log Level" setting. +An end user cannot write a message (via their JavaScript code in an Eventing Function) to this log file it is intended for debugging for customers that are on support contracts. + +.Eventing System Log Location in Platform +[cols="20%,80%"] +|=== +| Platform | Location + +| Linux +| /opt/couchbase/var/lib/couchbase/logs/eventing.log + +| Windows +| C:\Program Files\Couchbase\Server\var\lib\couchbase\logs\eventing.log + +(Assumes default installation location) + +| Mac OS X +| /Users//Library/Application\ Support/Couchbase/var/lib/couchbase/logs/eventing.log +|=== + +The *eventing.log* contains redactable user data and the log is collected using the *cbcollect_info* tool. +For log rotation, refer to xref:manage:manage-logging/manage-logging.adoc#log-file-rotation[Log File Rotation]. + +The available logging levels are: _Info, Error, Warning, Debug, and Trace (Info is the default since version 6.0)_. +The level can be altered via the "System Log Level" choice in the Settings dialog of each individual Eventing function and impacts the detail and quantity of information sent to the System Log (but has no effect on a specific Function's Application Log). Unless directed by support you should not change the "System Log Level". + +image::debug_5_log_level.png[,484] + +[#application-logs] +=== Application Logs + +Application logs allow you to identify and capture various business logic related activities and errors via user defined messages specific to each Eventing function. + +You must have the appropriate RBAC privileges to view an Eventing Function's Application log in the UI or via the REST API. The role of either "Full Admin" or "Eventing Full Admin" can see Application log or can access any Eventing Function's Application log. For more information refer to xref:eventing-rbac.adoc[Eventing Role-Based Access Control]. + +Unlike the System Log, Application logs can be viewed in the UI for any deployed function by clicking on the function's “Log” hyperlink in the Eventing page. + +Each Eventing function will have its own Application log based on the function name, e.g. *the_function_name.log*. (refer to Table 2 for filesystem path by platform). The information that goes to these log files is solely dependent the logic of the Function via _log(…)_ statements put inside the individual Eventing Function’s JavaScript code. Unlike the system log there is currently is no logging level for Application logs. Application logs are primarily used for development and debugging business logic. + +// All Function-related activities such as editing the Eventing Function JavaScript code, debugging, or modifying feed boundaries +// conditions, get recorded in the Application logs. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('document', doc); + try { + var response = curl( + 'http://localhost:3000/notify', + {method : 'POST', data : doc} + ); + log('curl', response); + } catch (e) { + log('error', e); + } +} +---- + +Application logs receive user defined messages when a _log(...)_ statement is encountered in the Function's JavaScript code (they do not have a Log Level). + +As a best practice the use of _log(...)_ messages with try catch blocks can greatly assist Eventing Function development and debugging. + +Below a function processes one mutation from the test bucket *travel-sample* but has an undefined JavaScript variable *a* without a try catch block. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + if (meta.id != "airport_1255") return + log('id', meta.id); + // undefined variable 'a' stops processing, an error indicator [X] will be + // displayed via selecting "View JavaScript" when the function is deployed. + // Failure(s) will also be logged in Eventing Stats: _function_name_ in the + // UI 'Server > Statistics' view for the charts of the _function_name_ + if (a == 1) { + log('a is 1') + } + // never reached + log('complete') +} +---- + +Only the first of three log messages is emitted and the processing stops and is marked as failed in the statistics. + +[source,text] +---- +2020-02-09T07:12:17.936-08:00 [INFO] "id" "airport_1255" +---- + +By selecting the "View JavaScript" button when the function is deployed a [X] indicator at the exact line in the JavaScript code failed will be displayed. By hovering over the [X] indicator more information is revealed. + +However, by adding a try catch block the root cause of the failure is easily apparent, and the function is +considered processed (without a failure) because the error is caught and handled in the function. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + if (meta.id != "airport_1255") return + log('id', meta.id); + try { + if (a == 1) { + log('a is 1') + } + } catch (e) { + log('error', e); + } + log('complete') +} +---- + +The output now indicates the exact error that occurred via the Function's Application log as follows: + +[source,text] +---- +2020-02-09T07:12:17.936-08:00 [INFO] "id" "airport_1255" +2020-02-09T07:12:17.936-08:00 [INFO] "error" "ReferenceError: a is not defined" +2020-02-09T07:12:17.936-08:00 [INFO] "complete" +---- + +As previously indicated, by selecting the "View JavaScript" button when the function is deployed a [X] indicator at the exact line in the JavaScript code failed will be displayed. By hovering over the [X] indicator more information is revealed. + +Application logs can also record summaries of low level issues and exceptions once a minute per worker. For example if you have 1M items that all throw the same exception, you will only see a few messages with the line number along with a count of each exception. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + if (a == 1) { + // never reached + log('a is 1') + } + // never reached + log('complete') +} +---- + +Running the above on a source keyspace `travel-sample`.`_default`.`_default` will result in a failure count of 31,951 however the errors will be summarized into a single line per worker. + +[source,text] +---- +2021-07-19T15:35:44.895-07:00 [INFO] {"count":31591,"exception":"\"ReferenceError: a is not defined\"","file":"test_summary.js","line":2,"since":"2021-07-19T15:35:44","srcLine":"if (a == 1) {","stack":"ReferenceError: a is not defined\n at OnUpdate (test_summary.js:3:5)"} +---- + +This summarization greatly reduces the size of the Eventing logs in the event there is a low level issue or a syntax error that detected only at deploy time. + +You can access a Function's Application log file using the UI by selecting the Function name and clicking on the 'Log' hyperlink/button or by opening a terminal and issuing Linux commands such as _cat_, _more_, _head_, _tail_, or ‘_tail -F_’ on a specific Eventing function’s log. + +Couchbase Server creates an individual log file for every Function in the cluster on each Eventing node. Application logs will only contain information for the mutations processed on a given Eventing node. + +By default, the maximum size of a node's Application log file is 40MB, and the number of log files before rotation is 10. +Unlike system logs, the Application logs are user-configurable in number and size. + +NOTE: The *cbcollect_info* tool does not collect the Application log files. + +.Eventing Application Logs Location by Platform +[cols="20%,80%"] +|=== +| Platform | Location + +| Linux +| /opt/couchbase/var/lib/couchbase/data/@eventing/ + +| Windows +| C:\Program Files\Couchbase\Server\var\lib\couchbase\data\@eventing\ + +(Assumes default installation location) + +| Mac OS X +| /Users//Library/Application\ Support/Couchbase/var/lib/couchbase/data/@eventing/ +|=== + +NOTE: During Cluster setup, if you have chosen a custom path, then the path for Application logs is same as that of the selected Indexes Path. The @eventing folder in the selected Indexes Path stores the Application logs. + +To configure an Application log, use the REST endpoint settings option. Note you must always specify deployment_status (deployed/undeployed) and processing_status (paused/not-paused) when using this REST endpoint. + +*Sample URL*: `192.168.1.5:8091/_p/event/api/v1/functions//settings` + +*Sample Payload*: + +---- +{ + "settings": + { + "deployment_status":false, + "processing_status":false, + "app_log_max_files": 10, + "app_log_max_size": 10485760 + } + } +---- + +The sample payload above illustrates that the system stores 10 application log files and each file records about 10 MB of data. + +At some point in time, old application log files that are no longer necessary need to be deleted to make way for new log records. +When an Application log file reaches the set limit, a new log file gets created. +All the recorded information from the active log file gets transferred to this newly created file. + +For illustration, consider *case_1_enrich_ips* from the example xref:eventing-example-data-enrichment[Data Enrichment] as the name of the Function. +A corresponding Application log file, *case_1_enrich_ips.log*, gets created in the Couchbase cluster. +Whenever the *case_1_enrich_ips.log* reaches 10MB in size, assuming the maximum size of an Application log file is 10MB and the number of log files before rotation is 10, the system automatically generates the *case_1_enrich_ips.log.1* file, during its first iteration. +The file *case_1_enrich_ips.log* transfers all the log information to this new log file. +For this illustration, since the number of log files is 10, the system stores 10 such files, the currently active log file along with 9 truncated files, at any given instance. + + +[#log-redaction] +== Log Redaction + +Log redaction refers to the suppression of sensitive data such as personally identifiable information (PII), hostnames, internal asset information, and credit card details during the logging operation. + +Organizations can implement log redaction as part of their legal compliance and security risk mitigations. + +Couchbase Server provides a capability to redact sensitive user data from getting captured in the logs. + +NOTE: Log redaction is applicable only for System logs and not for Application logs. + +For details, see xref:server:manage:manage-logging/manage-logging.adoc#understanding_redaction[Understanding Redaction]. + +//
    +//
  1. From the Couchbase Web Console Logs tab, select Collect +// Information.
  2. +//
  3. Select all nodes or use the filter nodes⦠option to select +// nodes from where you want to collect logs and diagnostic information.
  4. +//
  5. From the Redact Logs pane select No Redaction or Partial +// Redaction.
      +//
    • No Redaction: Select this option to enable capturing of log data that may +// include any sensitive information. +//
    • +//
    • Partial Redaction. +// Select this option to enable abstraction of sensitive +// information in the log files.

      When the Partial Redaction option is selected, +// Couchbase automatically stores two types of files, one with redaction and another +// without data redaction. +// Use the log file without data redaction for internal +// troubleshooting purposes, and in case you are using the Upload to Couchbase +// log option, use the log file with data redaction. +// The above information message +// also gets displayed in the Web console UI as follows: "Couchbase +// Server will collect and save a redacted log file at the location you specify, +// but also save an unredacted version which could be useful for further +// troubleshooting. +// If you use the "Upload to Couchbase" feature below, ONLY the +// redacted log will be uploaded."

    • +//
  6. +//
      diff --git a/modules/eventing/pages/eventing-example-data-enrichment.adoc b/modules/eventing/pages/eventing-example-data-enrichment.adoc new file mode 100644 index 000000000..c78234f38 --- /dev/null +++ b/modules/eventing/pages/eventing-example-data-enrichment.adoc @@ -0,0 +1,288 @@ += Improve Document Searchability +:description: Make searching documents easier by adding new attributes to existing documents. +:page-toclevels: 2 + +[abstract] +{description} + +Legacy document sets can contain attributes with formats that are difficult to search on. +To make searching easier, you can use Eventing Functions to duplicate and add new attributes to your documents. + +The `OnUpdate` JavaScript handler listens to mutations or data changes within a specified source collection. +When you create or modify data in the source collection, the Eventing Function executes its JavaScript code. + +In the examples on this page, you create a document with two named fields that contain IP addresses corresponding to the beginning and the end of an address range. +You then create the Eventing Function routine `get_numip_first_3_octets(ip)`, which converts each of the IP addresses to an integer and upserts them as new fields in a new or existing document. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.source` and `bulk.data.target`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Example: Create a New Document in a Target Collection + +This example walks you through how to create a new document in a target collection. +This new document is a copy of the original document in the source collection, but it includes two new additional fields that contain integers that correspond to IP addresses. +The original document in the source collection does not change. + +=== Create the Original Document in the Source Collection + +To create the original document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click btn:[Create Document]. +. In the *Document ID* field, enter *SampleDocument*. +. Replace the JSON text with the following: ++ +[source,json] +---- +{ + "country": "AD", + "ip_start": "5.62.60.1", + "ip_end": "5.62.60.9" +} +---- ++ +. Click btn:[Save] to create the document. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *case_enrich_ips* under *Name*. +** *On mutation, create a new document in a different collection with additional fields* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create two bindings. +** For the first binding: +*** Select *Bucket*. +*** Enter *src* as the *Alias Name*. +*** Enter the keyspace `bulk.data.source` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read Only* under *Permission*. +** For the second binding: +*** Select *Bucket*. +*** Enter *tgt* as the *Alias Name*. +*** Enter the keyspace `bulk.data.target` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('document', doc); + doc["ip_num_start"] = get_numip_first_3_octets(doc["ip_start"]); + doc["ip_num_end"] = get_numip_first_3_octets(doc["ip_end"]); + tgt[meta.id]=doc; +} + +function get_numip_first_3_octets(ip) { + var return_val = 0; + if (ip) { + var parts = ip.split('.'); + // IP Number = A x (256*256*256) + B x (256*256) + C x 256 + D + return_val = (parts[0]*(256*256*256)) + (parts[1]*(256*256)) + (parts[2]*256) + parseInt(parts[3]); + return return_val; + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +The `OnUpdate` handler specifies that, when a change happens to the data inside the bucket, the routine `get_numip_first_3_octets` runs on each on each document that contains `ip_start` and `ip_end`. +This routine creates a new document, copies the data and metadata of the original document, and adds the data fields `ip_num_start` and `ip_num_end`. + +These data fields contain the numeric values returned by `get_numip_first_3_octets`, which splits the IP address, converts each fragment into a numeral, and adds the numerals together to form a single value. The Eventing Function then returns this single value. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *case_1_enrich_ips*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +=== Check the Results in the Target Collection + +To check that a new document has been created in the target collection: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.target` in the *Get documents from* list. +. Click *SampleDocument* to open the *Edit Document* dialog. +The JSON document is a copy of the *SampleDocument* document you created earlier in the keyspace `bulk.data.source`, but it includes two new calculated fields `ip_num_start` and `ip_num_end`. ++ +[source,json] +---- +{ + "country": "AD", + "ip_end": "5.62.60.9", + "ip_start": "5.62.60.1", + "ip_num_start": 87964673, + "ip_num_end": 87964681 +} +---- + +=== Test the Eventing Function + +To test that your Eventing Function runs on new mutations: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click btn:[Create Document]. +. In the *Document ID* field, enter *AnotherSampleDocument*. +. Replace the JSON text with the following: ++ +[source,json] +---- +{ + "country": "RU", + "ip_start": "7.12.60.1", + "ip_end": "7.62.60.9" +} +---- ++ +. Click btn:[Save] to create the document. +. Select the keyspace `bulk.data.target` in the *Get documents from* list. +. Click *AnotherSampleDocument* to open the *Edit Document* dialog. +The JSON document is a copy of the *AnotherSampleDocument* document you created earlier in the keyspace `bulk.data.source`, but it includes two new calculated fields `ip_num_start` and `ip_num_end`. ++ +[source,json] +---- +{ + "country": "RU", + "ip_end": "7.62.60.9", + "ip_start": "7.12.60.1", + "ip_num_start": 118242305, + "ip_num_end": 121519113 +} +---- + + +== Example: Update an Existing Document in the Source Collection + +NOTE: This example assumes that you have already created all of the documents from the first example. + +Before following the steps for this example, you must undeploy the Eventing Function *case_enrich_ips* from the first example. +To undeploy the Function, go to menu:DataTools[Eventing] and click btn:[Undeploy] in *More Options (⋮)*. + +Unlike the previous example in which you created a new document in a target collection, this example walks you through how to update an existing document in the source collection. +This updated document includes two new additional fields that contain integers that correspond to IP addresses. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *case_2_enrich_ips* under *Name*. +** *On mutation, create a new document in the same collection with additional fields* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create the following binding: +** Select *Bucket*. +** Enter *src* as the *Alias Name*. +** Enter the keyspace `bulk.data.source` under *Bucket*, *Scope*, and *Collection*. +** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('document', doc); + doc["ip_num_start"] = get_numip_first_3_octets(doc["ip_start"]); + doc["ip_num_end"] = get_numip_first_3_octets(doc["ip_end"]); + // Write back to the source bucket + src[meta.id]=doc; +} + +function get_numip_first_3_octets(ip) { + var return_val = 0; + if (ip) { + var parts = ip.split('.'); + // IP Number = A x (256*256*256) + B x (256*256) + C x 256 + D + return_val = (parts[0]*(256*256*256)) + (parts[1]*(256*256)) + (parts[2]*256) + parseInt(parts[3]); + return return_val; + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +The `OnUpdate` handler specifies that, when a change happens to the data inside the bucket, the routine `get_numip_first_3_octets` runs on each on each document that contains `ip_start` and `ip_end`. +This routine creates a new document, copies the data and metadata of the original document, and adds the data fields `ip_num_start` and `ip_num_end`. + +These data fields contain the numeric values returned by `get_numip_first_3_octets`, which splits the IP address, converts each fragment into a numeral, and adds the numerals together to form a single value. The Eventing Function then returns this single value. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *case_2_enrich_ips*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +=== Check the Results in the Source Collection + +To check that the document in the source collection has been updated: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click *SampleDocument* to open the *Edit Document* dialog. +The JSON document has been updated to include the two new calculated fields `ip_num_start` and `ip_num_end`. ++ +[source,json] +---- +{ + "country": "AD", + "ip_end": "5.62.60.9", + "ip_start": "5.62.60.1", + "ip_num_start": 87964673, + "ip_num_end": 87964681 +} +---- + +The *AnotherSampleDocument* document has also been updated to include the two new fields. + +=== Test the Eventing Function + +To test that your Eventing Function runs on new mutations: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click *SampleDocument* to open the *Edit Document* dialog. +. In the JSON text, change the value of `ip_start` to `6.12.60.1`. +. Click btn:[Save Document]. +. Click *SampleDocument* to open the *Edit Document* dialog again. +The value of `ip_num_start` has changed to reflect the new IP. ++ +[source,json] +---- +{ + "country": "AD", + "ip_start": "6.12.60.1", + "ip_end": "5.62.60.9", + "ip_num_start": 101465089, + "ip_num_end": 87964681 +} +---- diff --git a/modules/eventing/pages/eventing-examples-cancel-overwrite-timer.adoc b/modules/eventing/pages/eventing-examples-cancel-overwrite-timer.adoc new file mode 100644 index 000000000..7dd8fa35c --- /dev/null +++ b/modules/eventing/pages/eventing-examples-cancel-overwrite-timer.adoc @@ -0,0 +1,371 @@ += Cancel or Overwrite a Timer +:description: Create, cancel, and overwrite Timers. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +The `OnUpdate` JavaScript handler listens to mutations or data changes within a specified source collection. +When you create or modify data in the source collection, the Eventing Function executes its JavaScript code. + +The Timer callback function relies on a control document which, if mutated, controls whether a Timer is created, cancelled, or overwritten. + +This page contains the following: + +* An example where a control document is created or mutated, which creates a Timer. +This Timer fires every 60 seconds and writes a document to another collection. +The original document in the source collection does not change. +* An example where a control document is mutated, which cancels any existing Timer with a reference that matches the control document's `meta.id`. +* An example where a control document is mutated, which overwrites any existing Timer with a reference that matches the control document's `meta.id`. +This is similar to cancelling a Timer that already exists, and then creating a new Timer that fires 60 seconds after it has been overwritten. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.source` and `bulk.data.target`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Setup + +Before following the examples on this page, you must set up a control document and an Eventing Function. + +=== Create the Control Document + +To create the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click btn:[Create Document]. +. In the *Document ID* field, enter *type_of_interest::1*. +. Replace the JSON text with the following: ++ +[source,json] +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": false, + "cancel_timer": false, + "overwrite_timer": false, + "a_number": 1 +} +---- ++ +. Click btn:[Save] to create the document. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *cancel_overwrite_timer* under *Name*. +** *Create, cancel, and overwrite Timers.* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create the following binding: +** Select *Bucket*. +** Enter *tgt_col* as the *Alias Name*. +** Enter the keyspace `bulk.data.target` under *Bucket*, *Scope*, and *Collection*. +** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function DocTimerCallback(context) { + log('From DocTimerCallback: timer fired', context); + + // Creates a new document in another collection + tgt_col[context.docId] = context; // upserts the context as our new document +} + +function OnUpdate(doc,meta) { + // Filters mutations of interest + if (doc.type != 'type_of_interest') return; + + // Looks at key conditions to decide what to do + if (doc.needed_condition === true && doc.cancel_timer === false) { + if (doc.overwrite_timer === true) { + log('From OnUpdate: overwriting timer with same reference', meta.id); + } else { + log('From OnUpdate: creating timer', meta.id); + } + // Creates a timestamp 60 seconds from now + var oneMinuteFromNow = new Date(); // Gets current time & add 60 seconds to it + oneMinuteFromNow.setSeconds(oneMinuteFromNow.getSeconds() + 60); + + // Creates a document to use as the context + var context = {docId : meta.id, random_text : "arbitrary text", "tmr_time_to_fire": oneMinuteFromNow}; + createTimer(DocTimerCallback, oneMinuteFromNow, meta.id, context); + } + if (doc.cancel_timer === true && doc.overwrite_timer === false) { + // Cancels an existing timer (if it is active) by reference meta.id + if (cancelTimer(DocTimerCallback, meta.id)) { + log('From OnUpdate: cancel request, timer was canceled',meta.id); + } else { + log('From OnUpdate: cancel request, no such timer may have fired',meta.id); + } + } + if (doc.cancel_timer === true && doc.overwrite_timer === true) { + log('From OnUpdate: both cancel and overwrite, will ignore',meta.id); + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +When a change happens to the data inside the source collection, the `OnUpdate` handler targets the control document by ignoring all documents that do not have a `doc.type` of `type_of_interest`. +It then uses the fields `needed_condition`, `cancel_timer`, and `overwrite_timer` to determine which action to take: + +* If `needed_condition` is true but both `cancel_timer` and `overwrite_timer` are false, the Eventing Function creates a Timer that fires 60 seconds into the future. +* If both `needed_condition` and `cancel_timer` are true, the Eventing Function cancels the existing Timer. +* If both `needed_condition` and `overwrite_timer` are true, the Eventing Function overwrites the existing Timer with a new Timer that fires 60 seconds into the future. +* If both `cancel_timer` and `overwrite_timer` are true, the Eventing Function throws an error and nothing happens. + +When a Timer created by the Eventing Function fires, the callback `DocTimerCallback` executes and writes a new document in the target collection with the same key as the document in the source collection. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *cancel_overwrite_timer*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + + +== Example: Create a Timer and Allow the Timer to Fire + +This example walks you through how to create a Timer and have the Timer fire. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *type_of_interest::1* to open the *Edit Document* dialog. +. Change `needed_condition` to `true`: ++ +[source,json] +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": true, + "cancel_timer": false, + "overwrite_timer": false, + "a_number": 1 +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *cancel_overwrite_timer* Eventing Function. +You should see the line `"From OnUpdate: creating timer" "type_of_interest::1"` in the debug log. +. Wait a few minutes and click the *Log* icon again. +The Timer should have fired and executed the `DocTimerCallback` callback, and you should see the line `"From DocTimerCallback: timer fired" {"docId":"type_of_interest::1 ","random_text":"arbitrary text","tmr_time_to_fire":"2022-05-10T23:07:54.226Z"}` in the debug log. + +=== Check the Results in the Target Collection + +To check that a new document has been created in the target collection: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.target` in the *Get documents from* list. +. Click *type_of_interest::1* to open the *Edit Document* dialog. +The JSON document includes data written by the Timer's callback. ++ +[source,json] +---- +{ + "docId": "type_of_interest::1", + "random_text": "arbitrary text", + "tmr_time_to_fire": "2022-05-10T23:07:54.226Z" +} +---- +. Close the *Edit Document* dialog. +. Click the *Delete* icon next to *type_of_interest::1*. +. In the *Delete Document* dialog, enter *delete* and click btn:[Delete document]. + + +== Example: Create a Timer and Cancel the Timer + +This example walks you through how to create a Timer and cancel the Timer. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *type_of_interest::1* to open the *Edit Document* dialog. +. Change `a_number` to `2`: ++ +[source,json] +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": true, + "cancel_timer": false, + "overwrite_timer": false, + "a_number": 2 +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *cancel_overwrite_timer* Eventing Function. +You should see the line `"From OnUpdate: creating timer" "type_of_interest::1"` in the debug log. + +=== Edit the Control Document Again + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *type_of_interest::1* to open the *Edit Document* dialog. +. Change `cancel_timer` to `true`: ++ +[source,json] +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": true, + "cancel_timer": true, + "overwrite_timer": false, + "a_number": 2 +} +---- ++ +. Click btn:[Save] to create a mutation. + +=== Check the Eventing Function Log Again + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *cancel_overwrite_timer* Eventing Function. +You should see the line `"From OnUpdate: cancel request, timer was canceled" "type_of_interest::1"` in the debug log. + +The Timer has been cancelled and did not fire. + + +== Example: Create a Timer and Overwrite the Timer + +This example walks you through how to create a Timer and overwrite the Timer. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *type_of_interest::1* to open the *Edit Document* dialog. +. Change `cancel_timer` to `false`: ++ +[source,json] +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": true, + "cancel_timer": false, + "overwrite_timer": false, + "a_number": 2 +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *cancel_overwrite_timer* Eventing Function. +You should see the line `"From OnUpdate: creating timer" "type_of_interest::1"` in the debug log. + +=== Edit the Control Document Again + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *type_of_interest::1* to open the *Edit Document* dialog. +. Change `overwrite_timer` to `true`: ++ +[source,json] +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": true, + "cancel_timer": true, + "overwrite_timer": true, + "a_number": 2 +} +---- ++ +. Click btn:[Save] to create a mutation. + +=== Check the Eventing Function Log Again + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *cancel_overwrite_timer* Eventing Function. +You should see the line `"From OnUpdate: overwriting timer with same reference" "type_of_interest::1"` in the debug log. +. Wait a few minutes and click the *Log* icon again. +The Timer should have fired and executed the `"From DocTimerCallback: timer fired" {"docId":"type_of_interest::1","random_text":"arbitrary text","tmr_time_to_fire":"2022-05-10T23:13:57.125Z"}` in the debug log. + +=== Check the Results in the Target Collection + +To check that a new document has been created in the target collection: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.target` in the *Get documents from* list. +. Click *type_of_interest::1* to open the *Edit Document* dialog. +The JSON document includes data written by the Timer's callback. ++ +[source,json] +---- +{ + "docId": "type_of_interest::1 ", + "random_text": "arbitrary text", + "tmr_time_to_fire": "2022-05-10T23:13:57.125Z" +} +---- +. Close the *Edit Document* dialog. +. Click the *Delete* icon next to *type_of_interest::1*. +. In the *Delete Document* dialog, enter *delete* and click btn:[Delete document]. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-cascade-delete.adoc b/modules/eventing/pages/eventing-examples-cascade-delete.adoc new file mode 100644 index 000000000..61bc6e810 --- /dev/null +++ b/modules/eventing/pages/eventing-examples-cascade-delete.adoc @@ -0,0 +1,227 @@ += Cascade Delete Documents +:description: Use the Eventing Service to perform cascade delete operations on your documents. +:page-toclevels: 2 + +[abstract] +{description} + +When you delete a user from Couchbase Capella, you can use Eventing Functions to delete all documents associated with that deleted user. + +The `OnDelete` handler listens to mutations or data changes within a specified user's source collection. +When you delete a user, the Eventing Function executes its JavaScript code to remove the deleted user and all of their associated data. + +Unlike the similar scriptlet xref:eventing-handler-cascadeKvDeleteWithDoc.adoc[cascadeKvDeleteWithDoc], which uses KV or the Data Service, the example on this page uses {sqlpp}. + + +== Prerequisites + +Before trying out the example on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.users` and `bulk.data.transactions`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Example: Cascade Delete Documents + +This example walks you through how to create an Eventing Function to cascade delete documents. +Whenever you delete a user from your `users` collection, the Function automatically deletes all transactions in the `transactions` collection that are associated with the deleted user. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *delete_orphaned_txns* under *Name*. +** *Delete orphaned transactions from the `bulk.data.transactions` collection when the `user_id` is greater than or equal to 100.* under *Description*. +** The keyspace `bulk.data.users` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create the following binding: +** Select *Bucket*. +** Enter *src_user* as the *Alias Name*. +** Enter the keyspace `bulk.data.users` under *Bucket*, *Scope*, and *Collection*. +** Select *Read Only* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + log('OnUpdate NOOP id: ' + meta.id + ' document:',doc); +} +function OnDelete(meta) { + // Ignores all keys not matching "user_#" and allows other types in the source collection + if ((meta.id).startsWith("user_") == false) return; + // Implements a contrived filter and keeps all user transactions where the user_id > 100 + var id = meta.id; + var numeric_id = parseInt(id.substring(5)); + if(!isNaN(numeric_id) && numeric_id >= 100) { + try { + DELETE FROM bulk.data.transactions WHERE user_id = $numeric_id; + log('OnDelete: removed orphaned transactions for:', id); + } catch(e) { + log('OnDelete: Exception:', e) + } + } else { + log('OnDelete: user_id < 100, kept orphaned transactions for:', id); + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +The `OnDelete` handler checks if the `user_id` is greater than or equal do 100, and then triggers a {sqlpp} query to delete all user-related information. + +The `OnDelete` handler also checks if the orphaned transactions have been removed and logs the result to the Function log file. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *delete_orphaned_txns*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +=== Create Users, Transactions, and Indexes + +To create new users and transactions: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket and *data* as the scope. +. In the code editor, enter the following query to create users: ++ +[source,sqlpp] +---- +INSERT INTO `bulk`.`data`.`users` (KEY,VALUE) + VALUES ( "user_50", { "user_id": 50, "name": "jeff shoemaker", "age": "77"} ), + VALUES ( "user_100", { "user_id": 100, "name": "john doe", "age": "30"} ), + VALUES ( "user_101", { "user_id": 101, "name": "frank smith", "age": "20"} ), + VALUES ( "user_102", { "user_id": 102, "name": "jenny jones", "age": "47"} ), + VALUES ( "user_103", { "user_id": 103, "name": "jerry springer", "age": "28"} ); +---- ++ +. Click btn:[Run] to run the query and insert the new users into the `users` collection. +. In the code editor, replace the previous query with the following query to create transactions: ++ +[source,sqlpp] +---- +INSERT INTO `bulk`.`data`.`transactions` (KEY,VALUE) + VALUES ( "txid_999", { "user_id": 50, "item": "vitamins", "price": 2.99} ), + VALUES ( "txid_1000", { "user_id": 100, "item": "milk", "price": 3.50} ), + VALUES ( "txid_1001", { "user_id": 100, "item": "cheese", "price": 2.50} ), + VALUES ( "txid_1002", { "user_id": 100, "item": "beer", "price": 7.89} ), + VALUES ( "txid_1003", { "user_id": 100, "item": "pizza", "price": 12.53} ), + VALUES ( "txid_1004", { "user_id": 101, "item": "lettuce", "price": 1.30} ), + VALUES ( "txid_1005", { "user_id": 101, "item": "salad dressing", "price": 4.15} ), + VALUES ( "txid_1006", { "user_id": 102, "item": "chicken", "price": 4.32} ), + VALUES ( "txid_1007", { "user_id": 103, "item": "steak", "price": 6.53} ); +---- ++ +. Click btn:[Run] to run the query and insert the new transactions into the `transactions` collection. +. In the code editor, replace the previous query with the following query to create indexes: ++ +[source,sqlpp] +---- +CREATE PRIMARY INDEX `def_primary` ON `bulk`.`data`.`users`; +CREATE PRIMARY INDEX `transactions` ON `bulk`.`data`.`transactions`; +---- ++ +. Click btn:[Run] to run the query and create a `def_primary` index and a `transactions` index. + +Before testing the Eventing Function against your data, you can check if your users and transactions have been created correctly: + +. In the query code editor, enter the following query and click btn:[Run] to return the list of users: ++ +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`users` ORDER BY user_id; +---- ++ +. Replace the previous query with the following query and click btn:[Run] to return the list of transactions: ++ +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`transactions` ORDER BY user_id; +---- ++ +. Replace the previous query with the following query and click btn:[Run] to count the number of users and transactions in your `data` scope: ++ +[source,sqlpp] +---- +SELECT count(*) FROM `bulk`.`data`.`users`; +SELECT count(*) FROM `bulk`.`data`.`transactions`; +---- + +=== Delete a User + +To delete a user: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.users` in the *Get documents from* list to return the users you created in the previous step. +. Click the *Delete* icon next to *user_100*. +. In the *Delete Document* dialog, enter *delete* and click btn:[Delete document]. + +The list of users no longer includes *user_100*. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *delete_orphaned_txns* Eventing Function. +You should see the line `"OnDelete: removed orphaned transactions for:" "user_100"`. + +=== Delete All Users + +To delete all users: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket and *data* as the scope. +. In the code editor, enter the following query to delete all users: ++ +[source,sqlpp] +---- +DELETE FROM `bulk`.`data`.`users`; +---- ++ +. Click btn:[Run] to run the query and delete all users. + +To confirm that all users and all data associated with the users have been deleted, enter the following query in the code editor and click btn:[Run]: +[source,sqlpp] +---- +SELECT count(*) FROM `bulk`.`data`.`users`; +SELECT count(*) FROM `bulk`.`data`.`transactions`; +---- +This query returns no users and but it returns one transaction. + +To find out which user this one transaction is associated with, enter the following query in the code editor and click btn:[Run]: +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`transactions`; +---- +This query returns information related to the transaction, which is associated with `user_50`. + +=== Check the Eventing Function Log Again + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *delete_orphaned_txns* Eventing Function. +You should see the following lines: +---- +2024-05-06T22:35:03.958+00:00 [INFO] "OnDelete: user_id < 100, kept orphaned transactions for:" "user_50" +2024-05-06T22:35:03.958+00:00 [INFO] "OnDelete: removed orphaned transactions for:" "user_103" +2024-05-06T22:35:03.953+00:00 [INFO] "OnDelete: removed orphaned transactions for:" "user_102" +2024-05-06T22:35:03.953+00:00 [INFO] "OnDelete: removed orphaned transactions for:" "user_101" +---- +The log shows that all transactions from `user_103`, `user_102`, and `user_101` have been removed because of the Eventing Function business logic, which deletes orphaned transactions from users with IDs greater than or equal to 100. +One transaction from `user_50` has been kept due to the user ID being less than 100. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-delete-v-expiry.adoc b/modules/eventing/pages/eventing-examples-delete-v-expiry.adoc new file mode 100644 index 000000000..53aa6ef8d --- /dev/null +++ b/modules/eventing/pages/eventing-examples-delete-v-expiry.adoc @@ -0,0 +1,291 @@ += Differentiate between Expiration and Deletion +:description: Differentiate between document deletion and document expiration in Eventing Function logs. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +The `OnDelete` handler in an Eventing Function runs whenever a document is deleted or has expired. +The Function accesses the `expired` field of the handler's second optional argument, and logs whether a document was deleted or expired from a collection. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.source` and `bulk.data.target`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +clusters:eventing-service/add-eventing-functions.adoc + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Example: Differentiate between Expiration and Deletion + +This example walks you through how to differentiate between expiration and deletion in Eventing Function logs. + +=== Create a New Document + +You can create a test document with an expiration time in one of the following ways: + +* Using a {sqlpp} statement in the Query Workbench +* Using the command line KV client (`cbc`) +* Using a Python or Java SDK script + +[{tabs}] +==== +{sqlpp} statement:: ++ +-- +To use a {sqlpp} statement in the Query Workbench: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket and *data* as the scope. +. In the code editor, enter the following query: + +[source,sqlpp] +---- +UPSERT INTO `bulk`.`data`.`source` (KEY, VALUE) VALUES ("SampleDocument2", {"a_key":"a_value"}, {"expiration":600}); +---- + +For information about setting a document's expiration time with {sqlpp}, see xref:n1ql:n1ql-language-reference/insert.adoc#insert-document-with-expiration[Insert a document with expiration]. +-- + +KV client:: ++ +-- +The KV client method depends on your operating system. + +On Linux, run the following command: + +[source,console] +---- +/opt/couchbase/bin/cbc \ + create SampleDocument2 -V '{"a_key": "a_value"}' \ + -U couchbase://localhost/source \ + --scope=data --collection=source \ + -u Administrator -P password \ + --expiry=600 +---- + +On macOS, run the following command: + +[source,console] +---- +/Applications/Couchbase\ Server.app/Contents/Resources/couchbase-core/bin/cbc \ + create SampleDocument2 -V '{"a_key": "a_value"}' -U couchbase://localhost/source \ + --scope=data --collection=source \ + -u Administrator -P password \ + --expiry=600 +---- + +If you get the error `dyld: Library not loaded` when running `cbc` on macOS, follow the instructions on the Jira ticket https://issues.couchbase.com/browse/MB-37768[MB-37768^]. + +On Windows, run the following command: + +[source,console] +---- +"C:\Program Files\Couchbase\Server\bin\cbc" ^ + create SampleDocument2 -V "{'a_key': 'a_value'}" -U couchbase://localhost/source ^ + --scope=data --collection=source ^ + -u Administrator -P password ^ + --expiry=600 +---- + +For more information about the `cbc` tool, see xref:reference:command-line-tools.adoc[]. +-- + +Python SDK script:: ++ +-- +Copy and paste the following code sample inside an executable SDK script. + +Alternatively, you can: + +. Run the command `python3` to start a Python session. +. Run the code sample without the line `#!/usr/bin/python3` to create the sample document. +. Enter ^D to close the Python session. + +[source,python] +---- +#!/usr/bin/python3 +import sys +import couchbase.collection +import couchbase.subdocument as SD +from couchbase.cluster import Cluster, ClusterOptions +from couchbase_core.cluster import PasswordAuthenticator +from couchbase.durability import ServerDurability, Durability +from datetime import timedelta + +pa = PasswordAuthenticator('Administrator', 'password') +cluster = Cluster('couchbase://127.0.0.1', ClusterOptions(pa)) +bucket = cluster.bucket('bulk') +collection = bucket.scope('data').collection('source') + +try: + document = dict( a_key="a_value" ) + result = collection.upsert( + 'SampleDocument2', + document, + expiry=timedelta(minutes=10) + ) + print("UPSERT SUCCESS") + print("cas result:", result.cas) +except: + print("exception:", sys.exc_info()) +---- + +For more information about the Couchbase Python SDK, see xref:python-sdk:hello-world/start-using-sdk.adoc[Start Using the Python SDK]. +-- + +Java SDK script:: ++ +-- +Copy and paste the following code sample inside an executable SDK script. + +[source,java] +---- +// Must use the Collections API +package com.jonstrabala; +import java.time.Duration; +import com.couchbase.client.java.*; +import com.couchbase.client.java.json.JsonObject; +import static com.couchbase.client.java.kv.UpsertOptions.upsertOptions; +public class DocExpiryTestCC { + public static void main(String... args) throws Exception { + // Note, if not on the server you need to change "localhost" to your DNS name or IP + Cluster cluster = Cluster.connect("localhost", "Administrator", "password"); + Bucket bucket = cluster.bucket("bulk"); + // Collection collection = bucket.defaultCollection(); + Collection collection = bucket.scope("data").collection("source"); + String docID = "SampleDocument2"; + Duration dura = Duration.ofMinutes(10); + try { + collection.upsert( + docID, JsonObject.create().put("a_key", "a_value"), + upsertOptions().expiry(dura) ); + System.out.println("docID: " + docID + " expires in " + dura.getSeconds()); + } catch (Exception e) { + System.out.println("upsert error for docID: " + docID + " " + e); + } + bucket = null; + collection = null; + cluster.disconnect(Duration.ofSeconds(2000)); + } +} +---- + +For more information about the Couchbase Java SDK, see xref:java-sdk:hello-world:start-using-sdk.adoc[Start Using the Java SDK]. +-- +==== + +You now have a document in the `source` collection with a set expiration date. +This document is deleted after 600 seconds. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *delete_v_expiry* under *Name*. +** *Determine if a document was removed due to an expiration or a deletion.* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Next]. +You do not need to create any bindings for this Function. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnDelete(meta, options) { + if (options.expired) { + log("doc expired:",meta.id); + } else { + log("doc deleted:",meta.id); + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +The `OnDelete` handler creates a log that shows whether a document expired or was deleted. + +When the document reaches its expiration time, the document is deleted as soon as one of the following happens: + +* You try to access the document +* The expiry pager runs (every 60 minutes) +* Compaction runs + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *delete_v_expiry*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +=== Check Document Expiration + +When a document reaches its expiration time, the document is deleted as soon as one of the following happens: + +* You try to access the document +* The expiry pager runs (every 60 minutes) +* Compaction runs + +To check that the Eventing Function is targeting expired documents: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. + +The document *SampleDocument2* is already deleted if its expiration time has been reached. + +If the document *SampleDocument2* is still being displayed, go to another page on the Capella UI and thenr return to menu:Data Tools[Documents]. +The collection updates and deletes the document because you tried to access it. + +=== Check the Eventing Function Log for Expiration + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *delete_v_expiry* Eventing Function. +You should see the line `"doc expired:" "SampleDocument2"`. + +=== Check Document Deletion + +To check that the Eventing Function is targeting deleted documents: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click btn:[Create Document]. +. In the *Document ID* field, enter *SampleDocument3*. +. Leave the placeholder JSON text. ++ +[source,json] +---- +{ +"click": "to edit", +"with JSON": "there are no reserved field names" +} +---- ++ +. Click btn:[Save] to create the document. +. Click the *Delete* icon next to *SampleDocument3*. +. In the *Delete Document* dialog, enter *delete* and click btn:[Delete document]. + +=== Check the Eventing Function Log for Deletion + +To check the Eventing Function log for deletion: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *delete_v_expiry* Eventing Function. +You should see the line `"doc deleted:" "SampleDocument3"`. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-docarchive.adoc b/modules/eventing/pages/eventing-examples-docarchive.adoc new file mode 100644 index 000000000..cb7a7295a --- /dev/null +++ b/modules/eventing/pages/eventing-examples-docarchive.adoc @@ -0,0 +1,154 @@ += Archive Documents After Expiration +:description: When a document in an existing collection is about to expire, use the Eventing Service to create an archived copy of that document in a different collection. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +This example is similar to the xref:eventing-examples-docexpiry.adoc[] example, but has the following differences: + +* It archives a perfect copy in the target collection +* It does not log errors unless a document is missing when the callback function to archive the document is triggered +* Does not rely on a Couchbase SDK - instead, it relies on the expiry set on the source collection, where all documents have an expiration of 10 minutes from the time of their first mutation + +The `OnUpdate` JavaScript handler runs whenever a document is created or mutated. +The Eventing Function calls a Timer, which executes a callback function 2 minutes before a document expires and archives an identical document with the same key in a specified target bucket. + +The original document in the source bucket does not change, but is deleted following the bucket's expiration date. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Import the `tavel-sample` sample bucket. +* Create two new buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.source` and `bulk.data.target`. +* Update the `source` collection's TTL (Time-to-Live) to *600*. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Example: Archive Documents After Expiration + +This example walks you through how to archive documents after they have expired. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *archive_before_expiry* under *Name*. +** *Archive all documents in a collection before a document expires.* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create two bindings. +** For the first binding: +*** Select *Bucket*. +*** Enter *src* as the *Alias Name*. +*** Enter the keyspace `bulk.data.source` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read Only* under *Permission*. +** For the second binding: +*** Select *Bucket*. +*** Enter *tgt* as the *Alias Name*. +*** Enter the keyspace `bulk.data.target` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + // Only processes documents that have a non-zero TTL + if (meta.expiration == 0 ) return; + // Note: JavaScript Data() is in milliseconds and meta.expiration is in seconds + if (new Date().getTime()/1000 > (meta.expiration - 120)) { + // If within the 120 second limit for expiry, creates a copy now + // Creates a new document with the same ID in the target collection + // log('OnUpdate: copy src to tgt for DocId:', meta.id); + tgt[meta.id] = doc; + } else { + // Computes 120 seconds before the TTL (note that JavaScript Date() is in milliseconds) + var twoMinsPrior = new Date((meta.expiration - 120) * 1000); + // Creates a Timer with a context to run in the future, 120 seconds before the expiry + // log('OnUpdate: create Timer '+meta.expiration+' - 120, for DocId:', meta.id); + createTimer(DocTimerCallback, twoMinsPrior , meta.id, meta.id); + } +} +function DocTimerCallback(context) { + // This context is the key to the document that expires in 120 seconds + var doc = src[context]; + if (doc) { + // Creates a new document with the same ID in the target collection + // log('DocTimerCallback: copy src to tgt for DocId:', context); + tgt[context] = doc; + } else { + log('DocTimerCallback: issue missing value for DocId:', context); + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +The `OnUpdate` handler creates a Timer that fires 2 minutes before the document's expiration time. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *archive_before_expiry*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +=== Insert Documents into Source Bucket + +To insert documents into your *source* bucket: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *travel-sample* as the bucket and *_default* as the scope. +. In the code editor, enter the following query to locate a large set of data in the sample bucket: ++ +[source,sqlpp] +---- +SELECT COUNT(*) FROM `travel-sample`.`_default`.`_default` where type = 'airport' +---- ++ +. Click btn:[Run] to run the query. +. In the code editor, replace the previous query with the following query to insert documents from the *_default* collection of the *travel-sample* bucket into the *source* collection you created earlier: ++ +[source,sqlpp] +---- +INSERT INTO `bulk`.`data`.`source`(KEY _k, VALUE _v) + SELECT META().id _k, _v FROM `travel-sample`.`_default`.`_default` _v WHERE type="airport"; +---- ++ +. Click btn:[Run] to run the query. +. Go to menu:Data Tools[Eventing]. +. Click the *archive_before_expiry* function. The number under *Successes* should be 1968, which is the same number of documents inserted into the *source* collection from the *_default* collection of the *travel-sample* bucket. + +=== Check Document Archival + +To check that your Eventing Function is running properly and archiving documents: + +. Go to menu:Data Tools[Documents]. +. Expand the *rr100* bucket and the *eventing* scope. The *metadata* collection should have 1280 documents in it that are related to your Eventing Function, and 4192 documents that are related to active Timers. +. Expand the *bulk* bucket and the *data* scope. The *source* collection should have 1968 documents in it, inserted through the {sqlpp} query earlier. +. Wait a few minutes and check the *Documents* tab again. +The Timer has fired and executed the `DocTimerCallback` function, which archives the documents from the *source* collection into the *target* collection. +You should see the following: +* 1968 documents in the *source* collection. +* 1968 documents in the *target* collection. +. Go to menu:Data Tools[Eventing]. +. Click the *archive_before_expiry* function. The number under *Successes* should have doubled to 3936. + +If you wait a few more minutes until the 120 second expiry window is reached, the documents inside the *source* collection are no longer accessible because of the collection's pre-defined TTL. +The 1968 archived documents are still in the *target* collection, but the original documents in the *source* collection have expired. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-docexpiry.adoc b/modules/eventing/pages/eventing-examples-docexpiry.adoc new file mode 100644 index 000000000..f7189cdd3 --- /dev/null +++ b/modules/eventing/pages/eventing-examples-docexpiry.adoc @@ -0,0 +1,277 @@ += Create Documents After Expiration +:description: When a document in an existing collection is about to expire, use the Eventing Service to create a new document in a different collection. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +The `OnUpdate` JavaScript handler listens to mutations or data changes within a specified source collection. +The Eventing Function calls a Timer, which executes a callback function before a document expires and retrieves a value from that document. +This function then stores a document with the same key in a specified target collection. + +The original document in the source collection does not change when its value is copied. +The document is then deleted folowing the bucket's expiration date. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.source` and `bulk.data.target`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Example: Create a New Document When a Document Expires + +This example walks you through how to create a new document whenever another document expires. + +=== Create a New Document + +You can create a test document with an expiration time in one of the following ways: + +* Using a {sqlpp} statement in the Query Workbench +* Using the command line KV client (`cbc`) +* Using a Python or Java SDK script + +[{tabs}] +==== +{sqlpp} statement:: ++ +-- +To use a {sqlpp} statement in the Query Workbench: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket and *data* as the scope. +. In the code editor, enter the following query: + +[source,sqlpp] +---- +UPSERT INTO `bulk`.`data`.`source` (KEY, VALUE) VALUES ("SampleDocument2", {"a_key":"a_value"}, {"expiration":600}); +---- + +For information about setting a document's expiration time with {sqlpp}, see xref:n1ql:n1ql-language-reference/insert.adoc#insert-document-with-expiration[Insert a document with expiration]. +-- + +KV client:: ++ +-- +The KV client method depends on your operating system. + +On Linux, run the following command: + +[source,console] +---- +/opt/couchbase/bin/cbc \ + create SampleDocument2 -V '{"a_key": "a_value"}' \ + -U couchbase://localhost/source \ + --scope=data --collection=source \ + -u Administrator -P password \ + --expiry=600 +---- + +On macOS, run the following command: + +[source,console] +---- +/Applications/Couchbase\ Server.app/Contents/Resources/couchbase-core/bin/cbc \ + create SampleDocument2 -V '{"a_key": "a_value"}' -U couchbase://localhost/source \ + --scope=data --collection=source \ + -u Administrator -P password \ + --expiry=600 +---- + +If you get the error `dyld: Library not loaded` when running `cbc` on macOS, follow the instructions on the Jira ticket https://issues.couchbase.com/browse/MB-37768[MB-37768^]. + +On Windows, run the following command: + +[source,console] +---- +"C:\Program Files\Couchbase\Server\bin\cbc" ^ + create SampleDocument2 -V "{'a_key': 'a_value'}" -U couchbase://localhost/source ^ + --scope=data --collection=source ^ + -u Administrator -P password ^ + --expiry=600 +---- + +For more information about the `cbc` tool, see xref:reference:command-line-tools.adoc[]. +-- + +Python SDK script:: ++ +-- +Copy and paste the following code sample inside an executable SDK script. + +Alternatively, you can: + +. Run the command `python3` to start a Python session. +. Run the code sample without the line `#!/usr/bin/python3` to create the sample document. +. Enter ^D to close the Python session. + +[source,python] +---- +#!/usr/bin/python3 +import sys +import couchbase.collection +import couchbase.subdocument as SD +from couchbase.cluster import Cluster, ClusterOptions +from couchbase_core.cluster import PasswordAuthenticator +from couchbase.durability import ServerDurability, Durability +from datetime import timedelta + +pa = PasswordAuthenticator('Administrator', 'password') +cluster = Cluster('couchbase://127.0.0.1', ClusterOptions(pa)) +bucket = cluster.bucket('bulk') +collection = bucket.scope('data').collection('source') + +try: + document = dict( a_key="a_value" ) + result = collection.upsert( + 'SampleDocument2', + document, + expiry=timedelta(minutes=10) + ) + print("UPSERT SUCCESS") + print("cas result:", result.cas) +except: + print("exception:", sys.exc_info()) +---- + +For information about the Couchbase Python SDK, see xref:python-sdk:hello-world:start-using-sdk.adoc[Start Using the Python SDK]. +-- + +Java SDK script:: ++ +-- +Copy and paste the following code sample inside an executable SDK script. + +[source,java] +---- +// Must use the Collections API +package com.jonstrabala; +import java.time.Duration; +import com.couchbase.client.java.*; +import com.couchbase.client.java.json.JsonObject; +import static com.couchbase.client.java.kv.UpsertOptions.upsertOptions; +public class DocExpiryTestCC { + public static void main(String... args) throws Exception { + // Note, if not on the server you need to change "localhost" to your DNS name or IP + Cluster cluster = Cluster.connect("localhost", "Administrator", "password"); + Bucket bucket = cluster.bucket("bulk"); + // Collection collection = bucket.defaultCollection(); + Collection collection = bucket.scope("data").collection("source"); + String docID = "SampleDocument2"; + Duration dura = Duration.ofMinutes(10); + try { + collection.upsert( + docID, JsonObject.create().put("a_key", "a_value"), + upsertOptions().expiry(dura) ); + System.out.println("docID: " + docID + " expires in " + dura.getSeconds()); + } catch (Exception e) { + System.out.println("upsert error for docID: " + docID + " " + e); + } + bucket = null; + collection = null; + cluster.disconnect(Duration.ofSeconds(2000)); + } +} +---- + +For more information about the Couchbase Java SDK, see xref:java-sdk:hello-world:start-using-sdk.adoc[Start Using the Java SDK]. +-- +==== + +You now have a document in the `source` collection with a set expiration date. +This document is deleted after 600 seconds. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *add_timer_before_expiry* under *Name*. +** *Fire a Timer before a document expires.* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create two bindings. +** For the first binding: +*** Select *Bucket*. +*** Enter *src* as the *Alias Name*. +*** Enter the keyspace `bulk.data.source` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read Only* under *Permission*. +** For the second binding: +*** Select *Bucket*. +*** Enter *tgt* as the *Alias Name*. +*** Enter the keyspace `bulk.data.target` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + // Only processes for those documents that have a non-zero TTL + if (meta.expiration == 0 ) return; + // Gets the TTL and computes 2 minutes prior to the TTL. JavaScript Date() takes msec. + var twoMinsPrior = new Date((meta.expiration - 2*60) * 1000); + // Creates a context and then creates a timer with the context + var context = { docID : meta.id, expiration : meta.expiration }; + createTimer(DocTimerCallback, twoMinsPrior , meta.id, context); + log('OnUpdate add Timer 2 min. prior to TTL to DocId:', meta.id); +} +function DocTimerCallback(context) { + log('DocTimerCallback 1 on DocId:', String(context.docID)); + // Creates a new document with the same ID, but in the target collection + tgt[context.docID] = "To Be Expired in 2 min., Key's Value is:" + JSON.stringify(src[context.docID]); + log('DocTimerCallback 2 src expiry:', new Date(context.expiration * 1000)); + log('DocTimerCallback 3 tgt archive via Key:', String(context.docID)); +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +The `OnUpdate` handler creates a Timer that fires 2 minutes before the document's expiration time. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *add_timer_before_expiry*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *add_timer_before_expiry* Eventing Function. +You should see the line `"OnUpdate add Timer 2 min. prior to TTL to DocId:" "SampleDocument2"`. + +Wait a few minutes and check the Eventing Function log again. +The Timer has fired and executed the `DocTimerCallback` function 2 minutes before the TTL was scheduled. +You should see the following lines in the log: +---- +2024-05-07T21:01:15.386+00:00 [INFO] "DocTimerCallback 3 tgt archive via Key:" "SampleDocument2" +2024-05-07T21:01:15.386+00:00 [INFO] "DocTimerCallback 2 src expiry:" "2024-05-07T21:02:05.000Z" +2024-05-07T21:01:15.236+00:00 [INFO] "DocTimerCallback 1 on DocId:" "SampleDocument2" +2024-05-07T21:01:06.821+00:00 [INFO] "OnUpdate add Timer 2 min. prior to TTL to DocId:" "SampleDocument2" +---- + +NOTE: The document had an expiration time of 600 seconds, or 10 minutes. The `DocTimerCallback` function fires a Timer 2 minutes before the initial expiration time. + +The final result is a new document named `SourceDocument2` which contains a copy of the data from the original document. +This new document is written to the `target` collection. + +The original document in the `source` collection is deleted after it reaches its expiration time of 10 minutes. +The new document in the `target` collection is not deleted. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-high-risk.adoc b/modules/eventing/pages/eventing-examples-high-risk.adoc new file mode 100644 index 000000000..eb5afe2f5 --- /dev/null +++ b/modules/eventing/pages/eventing-examples-high-risk.adoc @@ -0,0 +1,521 @@ += Generate Credit Card Transaction Alerts +:description: Use an Eventing Function to generate high-risk alerts whenever a customer makes certain credit card transactions. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +This page walks you through generating high-risk transaction alerts whenever a credit card transaction exceeds the customer's available credit limit or are made in a foreign currency. + +The `OnUpdate` JavaScript handler listens to mutations or data changes within a specified `register` collection. +When you create or modify data in a document of the type `transaction` inside the `register` collection, the Eventing Function executes its JavaScript code. + +The Eventing Function then: + +* Looks up details from the customer's card information, like date, spending limits, location, and default currency. +This data is collected from the `register` collection and has the type `card`. +* Looks up the exchange rates for the date of the transaction. +This data is collected from the `register` collection and has the type `exchange_rates`. +* Transforms the currency of the transaction and the currency of the spending limit into USD, following the correct date's exchange rate. +* Determines if the customer exceeded the spending threshold. +* Determines if the purchase was made in a foreign currency. +* Generates a new document for high-risk transactions that contains transaction information and calculated data. +* Writes the new document to the `review` collection with type `transaction`. +* (Optional) Uses custom applications written in a Couchbase SDK or a third-party integration like Kafka to read items in the `review` collection. +This lets you create more automated actions. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create two keyspaces called `bulk.data.register` and `bulk.data.review`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Example: Generate High Risk Credit Card Transaction Alerts + +This example walks you through how to create an Eventing Function to cascade delete documents. + +=== Flush Items from the UI + +Flushing clears a bucket of all documents and resets it to an empty state while maintaining the bucket's configuration and settings. + +To enable Capella to flush documents: + +. Go to menu:Settings[Buckets]. +. Click *More Options (⋮)* next to the *bulk* bucket. +. Click *Settings*. +. In the *Settings* page, expand the *Advanced Settings* section. +. Turn on the *Flush* toggle. +. Click btn:[Save] to save the bucket settings. + +For more information about flushing, see xref:cloud:data-service:manage-buckets.adoc#configure-advanced-bucket-settings[Configure Advanced Bucket Settings]. + +=== Create Indexes + +To create indexes for the *register* and *review* collections: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket. +. In the code editor, enter the following query to create indexes: ++ +[source,sqlpp] +---- +CREATE INDEX `adv_type_rg` ON `bulk`.`data`.`register`(`type`); +CREATE INDEX `adv_type_rv` ON `bulk`.`data`.`review`(`type`); +CREATE PRIMARY INDEX `adv_prim_rv` ON `bulk`.`data`.`review`; +---- + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *high_risk_txns* under *Name*. +** *Flag transactions that go over a credit threshold or are made in a foreign currency.* under *Description*. +** The keyspace `bulk.data.register` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create two bindings. +** For the first binding: +*** Select *Bucket*. +*** Enter *register* as the *Alias Name*. +*** Enter the keyspace `bulk.data.register` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read Only* under *Permission*. +** For the second binding: +*** Select *Bucket*. +*** Enter *review* as the *Alias Name*. +*** Enter the keyspace `bulk.data.review` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + if (doc.type != "transaction") return; + try { + var verbose = 0; // logging - 0: minimal, 1: moderate, 2: massive + if (verbose > 0) log(meta.id + ' Process transaction for doc.card: ' + + doc.card + ', doc.amount: ' + nformat(doc.amount, 0, 2)); + + // Loads the associated card info of this transaction + var card = register['card:' + doc.card]; + if (!card) { + log(meta.id + ' warn card does not exist: ' + doc.card); + return; + } + + // Loads the exchange rate table for the day of the transaction + var erid = 'exchange_rates:er-' + (doc.date).substr(0, 10); + var exchange_rates = register[erid]; + if (!exchange_rates) { + log(meta.id + ' WARNING exchange_rates does not exist: ' + erid); + return; + } + var to_USD = exchange_rates['to_USD']; + var trxn_2_USD = to_USD[doc.currency]; + var card_2_USD = to_USD[card['currency']]; + if (!trxn_2_USD || !card_2_USD) { + log(meta.id + ' WARNING exchange_rates for either ' + card['currency'] + + ' or ' + doc.currency + ' does exist'); + return; + } + + // Converts transaction charge and credit card limit into USD + var trxn_amount_USD = doc.amount / trxn_2_USD; + var card_thresh_USD = card['threshold'] / card_2_USD; + + if (verbose > 1) { + log(meta.id + ' doc ', doc); + log(meta.id + ' card ', card); + log(meta.id + ' rates ', exchange_rates) + } + if (verbose > 0) { + log(meta.id + ' 1 doc.amount ' + nformat(doc.amount, 8, 2) + + ', card_limit ' + nformat(card['threshold'], 8, 2)); + log(meta.id + ' 2 trxn_currency ' + sformat(doc.currency, 8) + + ', card_currency ' + sformat(card['currency'], 8)); + log(meta.id + ' 3 trxn_2_USD ' + nformat(trxn_2_USD, 8, 6) + + ', card_2_USD ' + nformat(card_2_USD, 8, 6)); + log(meta.id + ' 4 trxn_amount_USD ' + nformat(trxn_amount_USD, 8, 2) + + ', card_thresh_USD ' + nformat(card_thresh_USD, 8, 2)); + } + + // Checks if transaction is high risk due to being over threshold limit + if (card_thresh_USD < trxn_amount_USD) { + var msg = 'High Risk Txn: amount: ' + nformat(doc.amount, 8, 2) + ' ' + + doc.currency + ' exceeds purchase threshold: ' + + nformat(card['threshold'], 8, 2) + ' ' + card['currency']; + log(meta.id + ' *** ' + msg); + doc["comments"] = msg; // Appends description to the document + doc["reason_code"] = 'X-CREDIT'; // Appends the code to the document + delete doc["city"]; // Removes city sub document + review[meta.id] = doc; // Saves the modified document for review + return; + } + + // Checks if transacton is high risk due to being in a foreign currency + if (doc.currency != card['currency']) { + var msg = 'High Risk Txn: currency mismatch card: ' + + card['currency'] + ' != txn: ' + doc.currency; + log(meta.id + ' *** ' + msg); + doc["comments"] = msg; // Appends description to the document + doc["reason_code"] = 'X-MISMATCH'; // Appends the code to the document + delete doc["city"]; // Removes city sub document + review[meta.id] = doc; // Saves the modified document for review + return; + } + if (verbose > 0) log(meta.id + ' Charge by ' + card["firstname"] + ' ' + + card["lastname"] + ' appears normal in the amount of ' + + nformat(doc.amount, 0, 2) + ' ' + doc.currency); + } catch (e) { + // Notifies the user if there is a processing error or exception + log(meta.id + 'ERROR in OnUpdate:', e); + } +} + +// Right justify string with given width +function sformat(s, width) { + var str = s; + while (width > str.length) str = ' ' + str; + return str; +} + +// Right justify number with given width with given precision +function nformat(n, width, prec) { + return sformat(n.toFixed(prec), width, prec); +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +When a change happens to the data inside the source collection, the `OnUpdate` handler is triggered and checks if the transaction amount is under the customer's credit limit and if the transaction has been made in a foreign currency. +If any of these conditions are true, the Eventing Function flags the transaction as a high-risk transaction. + +The Eventing Function then copies the transaction to the `review` bucket. +The `OnUpdate` handler: + +* Enriches the document with pre-defined `comments` and provides a `reason code` +* Performs currency validation +* Converts the credit limit and transaction amount to USD currency based on the exchange rate of the exact date of the transaction + +=== Populate Your Cluster with Sample Data + +To seed your data and populate your cluster, download the following data files: + +[#optional-id1,cols="3,3,3,2,2",options="header"] +|=== + +| Data Set +| Description +| JSON Type Indicator +| Number of Records +| File Link + +| cards.json +| Credit card information +| type='card' +| 7 +| link:{attachmentsdir}/examples/high_risk/cards.json[Link,window=_blank] + +| merchants.json +| Merchant information +| type='merchant' +| 5001 +| link:{attachmentsdir}/examples/high_risk/merchants.json[Link,window=_blank] + +| exchange_rates.json +| Daily exchange rates +| type='exchange_rates' +| 422 +| link:{attachmentsdir}/examples/high_risk/exchange_rates.json[Link,window=_blank] + +| txns.json +| Credit card charges +| type='transaction' +| 417 +| link:{attachmentsdir}/examples/high_risk/txns.json[Link,window=_blank] + +|=== + +Right-click the file link and choose *Save Link As...* to download the files, or right-click the file link and choose *Copy Link Address* to download the files using cURL. + +.A record from the `cards.json` file, which contains the information from a credit card. +==== +[source,json] +---- +{ + "type": "card", + "cardnumber": "4273-6623-8686-4599", + "firstname": "Winfred", + "lastname": "Raftery", + "street": "3965 I-80 E Off Ramp", + "mobile": "+1-617-555-1371", + "sms": true, + "city": { + "name": "Uxbridge", + "code": "MA", + "state": "Massachusetts", + "county": "Worcester", + "display": "Uxbridge" + }, + "issued": "11/15", + "expiry": "6/19", + "ccv": 736, + "issuer": "Helena National Bank", + "maxcredit": 1000, + "threshold": 9500, + "country": "US", + "currency": "USD" +} +---- +==== + +.A record from the `merchants.json` file, which contains the information from the merchant. +==== +[source,json] +---- +{ + "type": "merchant", + "merchantid": "merchant-501233450539197794-0", + "name": "FlightAware Inc", + "city": { + "name": "Bentonville", + "code": "IN", + "state": "Indiana", + "county": "Fayette", + "display": "Bentonville" + } +} +---- +==== + +.A record from the `exchange_rates.json` file, which contains the information from a set of exchange rates. +==== +[source,json] +---- +{ + "type": "exchange_rates", + "erid": "er-2017-09-01", + "to_USD": { + "CAD": 1.2441275168, + "INR": 64.0331375839, + "EUR": 0.8389261745, + "USD": 1, + "SGD": 1.3545302013, + "GBP": 0.7724412752, + "CNY": 6.5591442953, + "AUD": 1.2601510067 + } +} +---- +==== + +.A record from the `txns.json` file, which contains the information from a transaction or a credit card charge. +==== +[source,json] +---- +{ + "type": "transaction", + "txnid": "tx-1526311379-002", + "amount": 15.99, + "product": "Thread Bore Brush: .22 Caliber, Centerfire", + "card": "4273-6623-8686-4599", + "merchant": "GoodGuide Inc", + "city": { + "name": "Waseca", + "code": "MN", + "state": "Minnesota", + "county": "Waseca", + "display": "Otisco" + }, + "date": "2018-05-14T20:52:59+05:30", + "currency": "USD" +} +---- +==== + +After downloading the files, you must import them into your `register` collection. +To import them into the collection: + +. Go to menu:Data Tools[Import]. +. Select *Load from your browser*. +. In the *Choose your source* section, click *Upload* and select the files you want to import. +. In the *Choose your target* section, select *bulk* for the bucket, *data* for the scope, and *register* for the collection. +. Click btn:[Import] to import and seed the data. + +=== Deploy the Eventing Function + +To deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *high_risk_txns*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + +The Eventing Function reads the data you loaded into the `register` collection and creates 40 new high-risk transaction alert documents in the `review` collection. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *high_risk_txns* Eventing Function. +You should see something similar to the following: +---- +2021-07-18T16:00:58.953-07:00 [INFO] "transaction:tx-1511710690-182 *** High Risk Txn: amount: 12506.00 USD exceeds purchase threshold: 12000.00 USD" +2021-07-18T16:00:58.952-07:00 [INFO] "transaction:tx-1505402809-074 *** High Risk Txn: currency mismatch card: USD != txn: EUR" +2021-07-18T16:00:58.938-07:00 [INFO] "transaction:tx-1514648212-166 *** High Risk Txn: amount: 12506.00 USD exceeds purchase threshold: 12000.00 USD" +2021-07-18T16:00:58.934-07:00 [INFO] "transaction:tx-1505315650-406 *** High Risk Txn: currency mismatch card: USD != txn: GBP" +---- + +=== Check the Results in the `review` Collection + +To check that the document in the `review` collection has been updated: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.review` in the *Get documents from* list. +You should see 40 new high-risk alert documents in the `review` collection. +. Click one of the 40 documents to open the *Edit Document* dialog. +The JSON document indicates that a credit card transaction was either made in a currency different than USD, or that it has surpassed the customer's credit limit. ++ +[source,json] +---- +{ + "type": "transaction", + "txnid": "tx-1505315650-403", + "amount": 5383.35, + "product": "Computer, iMac 64GB 4TB Nvme", + "card": "4273-6623-8686-4599", + "merchant": "Apple Regent Street", + "date": "2018-09-14T20:46:10+05:30", + "currency": "GBP", + "comments": "High Risk Txn: currency mismatch card: USD != txn: GBP", + "reason_code": "X-MISMATCH" +} +---- + +=== Run {sqlpp} Queries to Return Data + +To run {sqlpp} queries to return data: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket. +. In the code editor, enter the following queries: +* To return the number of high-risk transactions: ++ +[source,sqlpp] +---- +SELECT COUNT(*) num_high_risk FROM `bulk`.`data`.`review` WHERE type='transaction'; +---- ++ +* To return the data in a specific order: ++ +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`review` WHERE type='transaction' +ORDER BY currency, amount DESC; +---- ++ +* To return summarized data in a group and in a specific order: ++ +[source,sqlpp] +---- +SELECT COUNT(*) count, reason_code, SUM(amount) total_amount, currency +FROM `bulk`.`data`.`review` WHERE type='transaction' +GROUP BY reason_code, currency ORDER by count DESC; +---- ++ +* To return the transaction records by key: ++ +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`register` USE KEYS ('transaction:tx-1505315650-403'); +---- ++ +* To return the credit card records by key: ++ +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`register` USE KEYS ('card:4273-6623-8686-4599'); +---- ++ +* To return the flagged transaction record by key: ++ +[source,sqlpp] +---- +SELECT * FROM `bulk`.`data`.`review` USE KEYS ('transaction:tx-1505315650-403'); +---- + +=== Run the Eventing Function Again + +To run your Eventing Function again: + +. Go to menu:Data Tools[Query]. +. For the *Query Context*, select *bulk* as the bucket. +. In the code editor, enter the following query to delete all data from the bucket: ++ +[source,sqlpp] +---- +DELETE FROM `bulk`.`data`.`review`; +---- ++ +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *high_risk_txns*. +. Click *Pause* to pause your Function. +. Click the *Settings* icon to edit the Function. +. In the code editor, change `var verbose = 0` to `var verbose = 3`: ++ +[source,JavaScript] +---- +function OnUpdate(doc, meta) { + if (doc.type != "transaction") return; + try { + var verbose = 3; // logging - 0: minimal, 1: moderate, 2: massive + // ... + } +} +---- ++ +. Click btn:[Save] to save your edits. +. In the *Eventing* page, click *More Options (⋮)* next to *high_risk_txns*. +. Click *Resume* to resume your Function. +The Function resumes from the checkpoint created when you paused it. +It then executes on all new documents and on any mutations that occur after the checkpoint. +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.register` in the *Get documents from* list. +. Click the document `transaction:tx-1505315650-403` to open the *Edit Document* dialog. +. Change `"amount": 5383.35` to `"amount": 5383.36`. +. Click btn:[Save] to create a mutation. +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *high_risk_txns* Eventing Function. +You should see something similar to the following: +---- +2021-07-18T16:41:20.522-07:00 [INFO] "transaction:tx-1505315650-403 Process transaction for doc.card: 4273-6623-8686-4599, doc.amount: 5383.36" +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 doc " {"type":"transaction","txnid":"tx-1505315650-403","amount":5383.36,"product":"Computer, iMac 64GB 4TB Nvme","card":"4273-6623-8686-4599","merchant":"Apple Regent Street","city":{"name":"London","code":"W1B 2EL","county":"Westminster","display":"London Westminster"},"date":"2018-09-14T20:46:10+05:30","currency":"GBP"} +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 card " {"type":"card","cardnumber":"4273-6623-8686-4599","firstname":"Winfred","lastname":"Raftery","street":"3965 I-80 E Off Ramp","mobile":"+1-617-555-1371","sms":true,"city":{"name":"Uxbridge","code":"MA","state":"Massachusetts","county":"Worcester","display":"Uxbridge"},"issued":"11/15","expiry":"6/19","ccv":736,"issuer":"Helena National Bank","maxcredit":1000,"threshold":9500,"country":"US","currency":"USD"} +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 rates " {"type":"exchange_rates","erid":"er-2018-09-14","to_USD":{"CAD":1.3008811703,"INR":71.8162374882,"EUR":0.8555051758,"USD":1,"SGD":1.3698348875,"GBP":0.7633501583,"CNY":6.8543074686,"AUD":1.3910514159}} +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 1 doc.amount 5383.36, card_limit 9500.00" +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 2 trxn_currency GBP, card_currency USD" +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 3 trxn_2_USD 0.763350, card_2_USD 1.000000" +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 4 trxn_amount_USD 7052.28, card_thresh_USD 9500.00" +2021-07-18T16:41:20.525-07:00 [INFO] "transaction:tx-1505315650-403 *** High Risk Txn: currency mismatch card: USD != txn: GBP" +---- + +The Eventing Function debug log displays the following: + +* The transaction document or `doc` that has just mutated +* The credit card or `card` that the customer used to make the transaction +* Daily exchange rates or `rates` for the date of the transaction +* If the transaction is considered high-risk \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-recurring-timer.adoc b/modules/eventing/pages/eventing-examples-recurring-timer.adoc new file mode 100644 index 000000000..c56dd4593 --- /dev/null +++ b/modules/eventing/pages/eventing-examples-recurring-timer.adoc @@ -0,0 +1,255 @@ += Create a Recurring Timer +:description: Create a Timer that continues to execute until you manually cancel it. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +The `OnUpdate` JavaScript handler listens to mutations or data changes within a specified source collection. +When you create or modify data in the source collection, the Eventing Function executes its JavaScript code. + +The Timer callback function relies on a control document which, if mutated, controls whether a recurring Timer is created or cancelled. + +This page contains the following: + +* An example where a control document is created or mutated, which creates a Timer. +This Timer fires every 30 seconds and writes a document to the source collection. +The original document in the source collection does not change. +The Timer continues to execute until you cancel it. +* An example where a control document is mutated, which cancels any existing Timer with a reference that matches the control document's `meta.id`. +This has no effect if the Timer created has already fired. + + +== Prerequisites + +Before trying out the examples on this page, you must first: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create one keyspace called `bulk.data.source`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Setup + +Before following the examples on this page, you must set up a control document and an Eventing Function. + +=== Create the Control Document + +To create the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click btn:[Create Document]. +. In the *Document ID* field, enter *recurring_timer::1*. +. Replace the JSON text with the following: ++ +[source,json] +---- +{ + "type": "recurring_timer", + "id": 1, + "active": false +} +---- ++ +. Click btn:[Save] to create the document. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *recurring_timer* under *Name*. +** *Test recurring timers.* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create the following binding: +** Select *Bucket*. +** Enter *src_col* as the *Alias Name*. +** Enter the keyspace `bulk.data.source` under *Bucket*, *Scope*, and *Collection*. +** Select *Read and Write* under *Permission*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function CreateRecurringTimer(context) { + log('From CreateRecurringTimer: creating timer', context.mode, context.id); + // Creates a timestamp 30 seconds from now + var thirtySecFromNow = new Date(); // Gets current time & adds 30 seconds to it + thirtySecFromNow.setSeconds(thirtySecFromNow.getSeconds() + 30); + // Creates a document to use as the context + createTimer(RecurringTimerCallback, thirtySecFromNow, context.id, context); +} + +function RecurringTimerCallback(context) { + log('From RecurringTimerCallback: timer fired', context); + // Re-executes the timer ASAP to ensure the Timer keeps running in case + // errors or script timeouts happen in later "recurring work" + CreateRecurringTimer({ "id": context.id, "mode": "via_callback" }); + // Any sort of recurring work happens here and updates a date_stamp in a document + src_col["cur_" + context.id] = { "last_update": new Date() }; +} + +function OnUpdate(doc, meta) { + // Filters mutations of interest + if (doc.type !== 'recurring_timer') return; + if (doc.active === false) { + if (cancelTimer(RecurringTimerCallback, meta.id)) { + log('From OnUpdate: canceled active Timer, doc.active', + doc.active, meta.id); + } else { + log('From OnUpdate: no active Timer to cancel, doc.active', + doc.active, meta.id); + } + } else { + log('From OnUpdate: create/overwrite doc.active', doc.active, meta.id); + CreateRecurringTimer({ "id": meta.id, "mode": "via_onupdate" }); + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +When a change happens to the data inside the source collection, the `OnUpdate` handler targets the control document by ignoring all documents that do not have a `doc.type` of `recurring_timer`. +It then uses the field `active` to determine which action to take: + +* If `active` is true, the Eventing Function creates a series of Timers that fire 30 seconds into the future. +* If `active` is false, the Eventing Function cancels any existing Timers. + +When a Timer created by the Eventing Function fires, the callback `RecurringTimerCallback` executes and writes a new document in the source collection with a similar key as another document in the source collection. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *recurring_timer*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + + +== Example: Create a Recurring Timer and Allow the Timer to Fire and Rearm + +This example walks you through how to create a Timer, have the Timer fire, and then have the Timer rearm. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *recurring_timer::1* to open the *Edit Document* dialog. +. Change `active` to `true`: ++ +[source,json] +---- +{ + "type": "recurring_timer", + "id": 1, + "active": true +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *recurring_timer* Eventing Function. +You should see the following in the debug log: ++ +---- +2021-07-18T10:50:37.879-07:00 [INFO] "From OnUpdate: create/overwrite doc.active" true "recurring_timer::1" +2021-07-18T10:50:37.879-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_onupdate" "recurring_timer::1" +2021-07-18T10:50:06.147-07:00 [INFO] "From OnUpdate: no active Timer to cancel, doc.active" false "recurring_timer::1" +---- ++ +. Wait a few minutes and click the *Log* icon again. +The Timer should have fired and executed the `RecurringTimerCallback` callback, and you should see the following in the debug log: ++ +---- +2021-07-18T10:54:04.705-07:00 [INFO] "From RecurringTimerCallback: timer fired" {"id":"recurring_timer::1","mode":"via_callback"} +2021-07-18T10:54:04.705-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_callback" "recurring_timer::1" +2021-07-18T10:53:22.712-07:00 [INFO] "From RecurringTimerCallback: timer fired" {"id":"recurring_timer::1","mode":"via_callback"} +2021-07-18T10:53:22.712-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_callback" "recurring_timer::1" +2021-07-18T10:52:40.708-07:00 [INFO] "From RecurringTimerCallback: timer fired" {"id":"recurring_timer::1","mode":"via_callback"} +2021-07-18T10:52:40.708-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_callback" "recurring_timer::1" +2021-07-18T10:51:58.703-07:00 [INFO] "From RecurringTimerCallback: timer fired" {"id":"recurring_timer::1","mode":"via_callback"} +2021-07-18T10:51:58.703-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_callback" "recurring_timer::1" +2021-07-18T10:51:16.713-07:00 [INFO] "From RecurringTimerCallback: timer fired" {"id":"recurring_timer::1","mode":"via_onupdate"} +2021-07-18T10:51:16.713-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_callback" "recurring_timer::1" +2021-07-18T10:50:37.879-07:00 [INFO] "From OnUpdate: create/overwrite doc.active" true "recurring_timer::1" +2021-07-18T10:50:37.879-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_onupdate" "recurring_timer::1" +2021-07-18T10:50:06.147-07:00 [INFO] "From OnUpdate: no active Timer to cancel, doc.active" false "recurring_timer::1" +---- + +=== Check the Results in the Source Collection + +To check that a new document has been created in the source collection: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the new document *cur_recurring_timer::1* to open the *Edit Document* dialog. +The JSON document includes data written by the Timer's callback. ++ +[source,json] +---- +{ + "last_update": "2021-07-18T17:56:10.707Z" +} +---- ++ +. Click *Cancel* to close the editor. + +The Eventing Function you created writes a timestamp to the *cur_recurring_timer::1* document every 30 seconds. + + +== Example: Cancel the Recurring Timer + +This example walks you through how to cancel the recurring Timer. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *recurring_timer::1* to open the *Edit Document* dialog. +. Change `active` to `false`: ++ +[source,json] +---- +{ + "type": "recurring_timer", + "id": 2, + "active": false +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *recurring_timer* Eventing Function. +You should see the line `"From OnUpdate: canceled active Timer, doc.active" false "recurring_timer::1"` in the debug log. + +The recurring Timer has been cancelled. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples-rest-via-curl-get.adoc b/modules/eventing/pages/eventing-examples-rest-via-curl-get.adoc new file mode 100644 index 000000000..74028b247 --- /dev/null +++ b/modules/eventing/pages/eventing-examples-rest-via-curl-get.adoc @@ -0,0 +1,458 @@ += Create a Recurring Timer with a REST API +:description: Create a recurring Timer that fetches documents from an external REST endpoint until you manually cancel it. +:page-toclevels: 2 +:tabs: + +[abstract] +{description} + +This page walks you through creating an Eventing Function that contains an `OnUpdate` handler with a cURL GET request in a Timer callback function. + +The `OnUpdate` JavaScript handler listens to mutations or data changes within a specified source collection. +When you create or modify data in the source collection, the Eventing Function executes its JavaScript code and fetches exchange rates. + +The Timer callback function creates the initial Timer 30 seconds into the future. +It then creates the next Timer 2-N at the start of the following day. + +The Timer callback function relies on a control document which, if mutated, controls whether a recurring Timer is created or cancelled. + +This page contains the following: + +* An example where a control document is created of mutated, which creates a Timer. +This Timer initially fires 30 seconds into the future. +It fetches a document from an external REST endpoint and writes the document to the source bucket. ++ +The original control document does not change. ++ +The Timer is rearmed at the start of the following day, and continues to fetch daily exchange rates until you cancel it. +* An example where the control document is mutated, which cancels any existing Timer with a reference that matches the control document's `meta.id`. +This has no effect if the Timer created has already fired. + + +== Prerequisites + +Before trying out the examples on this page, you must first test your API connection and create buckets, scopes, and collections. + +=== Test API Connection + +The examples on this page rely on a public REST API that you can access through a cURL GET operation. +You can test your connection to make sure the REST endpoint is live. + +To test your connection, enter the following command in your terminal: + +[source,shell] +---- +curl -q -X GET 'https://api.frankfurter.app/latest' +---- + +If the URL is offline, you can start your own Python server. +To do so, enter the following in your terminal: + +[source,shell] +---- +#!/usr/bin/env python3 + +from http.server import HTTPServer, BaseHTTPRequestHandler +from http import HTTPStatus +from datetime import datetime +import json +import time + +class _RequestHandler(BaseHTTPRequestHandler): + # Borrowing from https://gist.github.com/nitaku/10d0662536f37a087e1b + def _set_headers(self): + self.send_response(HTTPStatus.OK.value) + self.send_header('Content-type', 'application/json') + self.send_header('Access-Control-Allow-Origin', '*') + self.end_headers() + + def do_GET(self): + message = '{"amount":1.0,"base":"EUR","date":"' + \ + datetime.today().strftime('%Y-%m-%d') + \ + '","rates":{"AUD":1.5907,"BGN":1.9558,"USD":1.1802}}' + self._set_headers() + self.wfile.write(json.dumps(message).encode('utf-8')) + +def run_server(): + server_address = ('', 8001) + httpd = HTTPServer(server_address, _RequestHandler) + print('serving at %s:%d' % server_address) + httpd.serve_forever() + +if __name__ == '__main__': + run_server() +---- + +A successful JSON payload should look similar to the following: + +[source,json] +---- +{ + "base": "EUR", + "rates": { + "GBP": 0.90265, + "HKD": 9.1871, + "IDR": 17247.57, + "ILS": 4.0397, + "DKK": 7.4508, + "INR": 88.709, + "CHF": 1.077, + "MXN": 26.7125, + "CZK": 26.097, + "SGD": 1.6228, + "THB": 36.759, + "HRK": 7.4683, + "MYR": 4.9698, + "NOK": 10.6585, + "CNY": 8.2277, + "BGN": 1.9558, + "PHP": 58.12, + "SEK": 10.2865, + "PLN": 4.3935, + "ZAR": 20.4221, + "CAD": 1.5703, + "ISK": 160.2, + "BRL": 6.2311, + "RON": 4.8345, + "NZD": 1.7809, + "TRY": 8.3311, + "JPY": 125.37, + "RUB": 86.3692, + "KRW": 1405.74, + "USD": 1.1854, + "HUF": 344.5, + "AUD": 1.6415 + }, + "date": "2020-08-05" +} +---- + +If you're running your own Python server, the returning JSON data is static but contains a current date. + +[source,shell] +---- +curl -q -X GET 'https://localhost:8001/api/latest' +---- + +[source,json] +---- +{ + "amount": 1.0, + "base": "EUR", + "date": "2021-07-18", + "rates": { + "AUD": 1.5907, + "BGN": 1.9558, + "USD": 1.1802 + } +} +---- + +NOTE: You must use a real IP address if you're not on the Couchbase Server. + +=== Create Keyspaces + +Create the following keyspaces: + +* Create two buckets called `bulk` and `rr100` with a minimum size of 100MB. +* Inside the `bulk` bucket, create one keyspace called `bulk.data.source`. +* Inside the `rr100` bucket, create one keyspace called `rr100.eventing.metadata`. + +For more information about creating buckets, scopes, and collections, see xref:clusters:data-service/manage-buckets.adoc[]. + +NOTE: Do not add, modify, or delete documents in the Eventing storage keyspace `rr100.eventing.metadata` while your Eventing Functions are in a deployed state. + + +== Setup + +Before following the examples on this page, you must set up a control document and an Eventing Function. + +=== Create the Control Document + +To create the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click btn:[Create Document]. +. In the *Document ID* field, enter *recurring_timer::1*. +. Replace the JSON text with the following: ++ +[source,json] +---- +{ + "type": "recurring_timer", + "id": 1, + "active": false +} +---- ++ +. Click btn:[Save] to create the document. + +=== Create an Eventing Function + +To create a new Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click btn:[Add Function]. +. In the *Settings* page, enter the following Function settings: +** *external_rest_via_curl_get* under *Name*. +** *Use a recurring Timer to access an external REST endpoint through a GET operation. The initial fetch is 30 seconds into the future, with following fetches happening at the start of each subsequent day.* under *Description*. +** The keyspace `bulk.data.source` under *Listen to Location*. +** The keyspace `rr100.eventing.metadata` under *Eventing Storage*. +. Click btn:[Next]. +. In the *Bindings* page, click btn:[Add Binding] and create two bindings. +** For the first binding: +*** Select *Bucket*. +*** Enter *src_col* as the *Alias Name*. +*** Enter the keyspace `bulk.data.source` under *Bucket*, *Scope*, and *Collection*. +*** Select *Read and Write* under *Permission*. +** For the second binding: +*** Select *URL*. +*** Enter *exchangeRateApi* as the *Alias Name*. +*** Enter *https://api.frankfurter.app/latest* as the *URL*. +*** Select *No Auth* under *Authentication*. +. Click btn:[Next]. +. In the code editor, replace the placeholder JavaScript code with the following code sample: ++ +[source,javascript] +---- +function CreateRecurringTimer(context) { + log('From CreateRecurringTimer: creating timer', context.mode, context.id); + var nextSchedule = null; + if (context.mode === "via_onupdate") { + // Creates a timestamp 30 seconds from now for the initial Timer + var thirtySecFromNow = new Date(); // Gets current time & adds 30 seconds to it + thirtySecFromNow.setSeconds(thirtySecFromNow.getSeconds() + 30); + nextSchedule = thirtySecFromNow; + } else { + // Must be: context.mode === "via_callback" + // Creates UTC timestamp to fire a Timer for the next day + // Does this for timers 2 to N + var tomorrow = new Date(); + tomorrow.setHours(0,0,0,0); + tomorrow.setDate(tomorrow.getDate() + 1); + nextSchedule = tomorrow; + } + log("Finish CreateRecurringTimer (local time) nextSchedule", localISOTime(nextSchedule)); + createTimer(RecurringTimerCallback, nextSchedule, context.id, context); +} + +function localISOTime (indate) { + // JavaScript works with dates as UTC times, but sometimes you might prefer to see local time + return new Date(indate.getTime() - indate.getTimezoneOffset() * 60 * 1000) + .toISOString().split(/[TZ]/).slice(0, 2).join('T'); +} + +function RecurringTimerCallback(context) { + log('From RecurringTimerCallback: timer fired', context); + // Does any sort of recurring work here and updates a date_stamp in a document + var now = new Date(); + var nowLoc = localISOTime(now); + var dt_beg = now.getTime(); + // Generates a YYYY-MM-DD string in UTC for Yesterday + var yesterday = new Date(); + yesterday.setHours(0,0,0,0); + yesterday.setDate(yesterday.getDate() - 1); + var apiReqDateUtc = yesterday.toISOString().substring(0, 10); + // Generates a YYYY-MM-DD string in Local Time for Yesterday + var apiReqDateLoc = localISOTime(yesterday).substring(0, 10); + try { + // ============================== + // Performs a cURL GET here + var request = { + path: apiReqDateUtc + }; + // Performs the cURL request using the URL alias form the settings + var response = curl('GET', exchangeRateApi, request); + var status = "OKAY"; + if (response.status != 200 && response.status != 302) { + status = "FAIL"; + } + // ============================== + var curl_time_ms = new Date().getTime() - dt_beg; + log('USER FUNCTION DONE ' + status + + ' (curl ' + response.status + ' took ' + curl_time_ms + ' ms.)'); + if (response && response.body && response.body.date && response.body.base) { + // Writes the exchange lookup table document + // Does this 365 times a year + src_col["exchange::" + response.body.date] = response.body; + + // Write status document of success + src_col["cur_" + context.id] = { + "last_update_loc": nowLoc, + "last_update_utc": now, "apiReqDateUtc": apiReqDateUtc, + "curl_success": true, "valid": true, "curl_time_ms": curl_time_ms + }; + + } else { + // Write status doc of failure + src_col["cur_" + context.id] = { + "last_update_loc": nowLoc, + "last_update_utc": now, "apiReqDateUtc": apiReqDateUtc, + "curl_success": true, "body_valid": false, "curl_time_ms": curl_time_ms + }; + } + } catch (e) { + var curl_time_ms = new Date().getTime() - dt_beg; + log('USER FUNCTION DONE ' + status + + ' (curl ERROR ' + e + ' took ' + curl_time_ms + ' ms.)'); + // Write status document of failure + src_col["cur_" + context.id] = { + "last_update_loc": nowLoc, + "last_update_utc": now, "apiReqDateUtc": apiReqDateUtc, + "curl_success": false, "body_valid": false, "curl_time_ms": curl_time_ms + }; + } + // Rearms the Timer + CreateRecurringTimer({ "id": context.id, "mode": "via_callback" }) +} + +function OnUpdate(doc, meta) { + // Filters mutations of interest + if (doc.type !== 'recurring_timer') return; + if (doc.active === false) { + if (cancelTimer(RecurringTimerCallback, meta.id)) { + log('From OnUpdate: canceled active Timer, doc.active', doc.active, meta.id); + } else { + log('From OnUpdate: no active Timer to cancel, doc.active', doc.active, meta.id); + } + } else { + log('From OnUpdate: create/overwrite doc.active', doc.active, meta.id); + CreateRecurringTimer({ "id": meta.id, "mode": "via_onupdate" }); + } +} +---- ++ +. Click btn:[Create function] to create your Eventing Function. + +When a change happens to the data inside the source collection, the `OnUpdate` handler targets the control document by ignoring all documents that do not have a `doc.type` of `recurring_timer`. +It then uses the field `active` to determine which action to take: + +* If `active` is true, the Eventing Function creates a series of daily Timers, with the first Timer firing 30 seconds into the future and subsequent Timers firing at the beginning of every following day. +* If `active` is false, the Eventing Function cancels any existing Timers. + +When a Timer created by the Eventing Function fires, the callback `RecurringTimerCallback` executes and writes a new document in the source collection with a similar key as another document in the source collection. + +=== Deploy the Eventing Function + +Deploy your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to *recurring_timer*. +. Click *Deploy* to deploy your Function. + +After it's deployed, the Eventing Function executes on all existing documents and any documents you create in the future. + + +== Example: Create a Recurring Timer and Allow the Timer to Fire and Rearm + +This example walks you through how to create a Timer, have the Timer fire, and then have the Timer rearm. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *recurring_timer::1* to open the *Edit Document* dialog. +. Change `active` to `true`: ++ +[source,json] +---- +{ + "type": "recurring_timer", + "id": 1, + "active": true +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *external_rest_via_curl_get* Eventing Function. +You should see the following in the debug log: ++ +---- +2021-07-18T14:37:25.136-07:00 [INFO] "Finish CreateRecurringTimer (local time) nextSchedule" "2021-07-18T14:37:55.134" +2021-07-18T14:37:25.134-07:00 [INFO] "From OnUpdate: create/overwrite doc.active" true "recurring_timer::1" +2021-07-18T14:37:25.134-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_onupdate" "recurring_timer::1" +2021-07-18T14:36:55.177-07:00 [INFO] "From OnUpdate: no active Timer to cancel, doc.active" false "recurring_timer::1" +---- ++ +. Wait a few minutes and click the *Log* icon again. +The Timer should have fired and executed the `RecurringTimerCallback` callback, and you should see the following in the debug log: ++ +---- +2021-07-18T14:37:59.164-07:00 [INFO] "From CreateRecurringTimer: creating timer" "via_callback" "recurring_timer::1" +2021-07-18T14:37:59.164-07:00 [INFO] "Finish CreateRecurringTimer (local time) nextSchedule" "2021-07-19T00:00:00.000" +2021-07-18T14:37:59.161-07:00 [INFO] "USER FUNCTION DONE OKAY (curl 200 took 443 ms.)" +2021-07-18T14:37:58.718-07:00 [INFO] "From RecurringTimerCallback: timer fired" {"id":"recurring_timer::1","mode":"via_onupdate"} +---- + +=== Check the Results in the Source Collection + +To check that a new document has been created in the source collection: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the new document *cur_recurring_timer::1* to open the *Edit Document* dialog. +The JSON document includes data written by the Timer's callback. ++ +[source,json] +---- +{ + "last_update_loc": "2021-07-18T14:04:06.408", + "last_update_utc": "2021-07-18T21:04:06.408Z", + "apiReqDateUtc": "2021-07-17", + "curl_success": true, + "body_valid": false, + "curl_time_ms": 442 +} +---- ++ +. Click *Cancel* to close the editor. + +The Eventing Function you created writes a timestamp to the *cur_recurring_timer::1* document at the beginning of every following day. + + +== Example: Cancel the Recurring Timer + +This example walks you through how to cancel the recurring Timer. + +=== Edit the Control Document + +To edit the control document: + +. Go to menu:Data Tools[Documents]. +. Select the keyspace `bulk.data.source` in the *Get documents from* list. +. Click the control document *recurring_timer::1* to open the *Edit Document* dialog. +. Change `active` to `false`: ++ +[source,json] +---- +{ + "type": "recurring_timer", + "id": 2, + "active": false +} +---- ++ +. Click btn:[Save] to create a mutation. + +The document mutation causes the Eventing Function to create a Timer. + +=== Check the Eventing Function Log + +To check the Eventing Function log: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the *external_rest_via_curl_get* Eventing Function. +You should see the line `"From OnUpdate: canceled active Timer, doc.active" false "recurring_timer::1"` in the debug log. + +The recurring Timer has been cancelled. \ No newline at end of file diff --git a/modules/eventing/pages/eventing-examples.adoc b/modules/eventing/pages/eventing-examples.adoc new file mode 100644 index 000000000..977a0f415 --- /dev/null +++ b/modules/eventing/pages/eventing-examples.adoc @@ -0,0 +1,146 @@ += Examples: Using the Eventing Service +:description: This page contains examples of how to use the Eventing Service with the Couchbase Web Console. +:page-edition: Enterprise Edition + ++++ +++ +[abstract] +{description} + +[#examples-step-by-step] +== Step-by-Step Examples + +[#Couchbase-Eventing-Examples] +=== Detailed Examples + +The following tutorial-like guides have detailed start-to-finish instructions and are ideal for new users to learn the basics of the Eventing Service. + +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-example-data-enrichment.adoc[] +| xref:eventing:eventing-examples-cascade-delete.adoc[] +| xref:eventing:eventing-examples-docexpiry.adoc[] +| xref:eventing:eventing-examples-delete-v-expiry.adoc[] +| xref:eventing:eventing-examples-docarchive.adoc[] +| xref:eventing:eventing-examples-cancel-overwrite-timer.adoc[] +| xref:eventing:eventing-examples-recurring-timer.adoc[] +| xref:eventing:eventing-examples-rest-via-curl-get.adoc[] +| xref:eventing:eventing-examples-high-risk.adoc[] +| +| +| +|=== + +[#examples-scriptlets] +== Scriptlets + +[#Couchbase-Eventing-Scriptlets] +[#examples-scriptlets-kv] +=== Basic Accessor Eventing Functions + +The following scriptlets are examples of standadlone Eventing Functions. + +[#Couchbase-Eventing-Snippets] +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-handler-basicBucketOps.adoc[basicBucketOps] +| xref:eventing:eventing-handler-curl-get.adoc[basicCurlGet] +| xref:eventing:eventing-handler-curl-post.adoc[basicCurlPost] +| xref:eventing:eventing-handler-simpleTimer.adoc[simpleTimer] +| xref:eventing:eventing-handler-cascadeKvDeleteWithDoc.adoc[cascadeKvDeleteWithDoc] +| xref:eventing:eventing-handler-redactSharedData.adoc[redactSharedData] +| xref:eventing:eventing-handler-simpleFlatten.adoc[simpleFlatten] +| xref:eventing:eventing-handler-fixEmailDomains.adoc[fixEmailDomains] +| xref:eventing:eventing-handler-keepLastN.adoc[keepLastN] +| xref:eventing:eventing-handler-docControlledSelfExpiry.adoc[docControlledSelfExpiry] +| xref:eventing:eventing-handler-shippingNotifier.adoc[shippingNotifier] +| xref:eventing:eventing-handler-ConvertBucketToCollections.adoc[convertBucketToCollections] +|=== + +[#examples-scriptlets-n1ql] +=== Basic {sqlpp} Eventing Functions + +The following scriptlets demonstrate how to use {sqlpp} or the Query Service with an Eventing Function. + +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-handler-basicN1qlSelectStmt.adoc[basicN1qlSelectStmt] +| xref:eventing:eventing-handler-basicN1qlPreparedSelectStmt.adoc[basicN1qlPreparedSelectStmt] +| +| +|=== + +[#examples-scriptlets-generic] +=== Generic Manipulation Eventing Functions + +The following scriptlets are examples of advanced use cases that focus on mutating a document without knowing that document's schema. + +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-handler-dateToEpochConversion.adoc[dateToEpochConversion] +| xref:eventing:eventing-handler-deepCloneAndModify.adoc[deepCloneAndModify] +| xref:eventing:eventing-handler-removeObjectStubs.adoc[removeObjectStubs] +| xref:eventing:eventing-handler-removeNullsAndEmptys.adoc[removeNullsAndEmptys] +| xref:eventing:eventing-handler-genericRename.adoc[genericRename] +| xref:eventing:eventing-handler-genericFlatten.adoc[genericFlatten] +| xref:eventing:eventing-handler-convertXMLtoJSON.adoc[convertXMLtoJSON] +| xref:eventing:eventing-handler-convertAdvXMLtoJSON.adoc[convertAdvXMLtoJSON] +|=== + +[#examples-scriptlets-advanced-accessors] +=== Advanced Accessor Eventing Functions + +The following scriptlets demonstrate how to use Advanced Keyspace Accessors, which allow you to: + +* Use CAS +* Set expiry (TTL) dates +* Use distributed atomic counters to increment and decrement counts + +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-handler-advancedGetOp.adoc[advancedGetOp] +| xref:eventing:eventing-handler-advancedGetOpWithCache.adoc[advancedGetOpWithCache] +| xref:eventing:eventing-handler-advancedInsertOp.adoc[advancedInsertOp] +| xref:eventing:eventing-handler-advancedUpsertOp.adoc[advancedUpsertOp] +| xref:eventing:eventing-handler-advancedReplaceOp.adoc[advancedReplaceOp] +| xref:eventing:eventing-handler-advancedDeleteOp.adoc[advancedDeleteOp] +| xref:eventing:eventing-handler-advancedIncrementOp.adoc[advancedIncrementOp] +| xref:eventing:eventing-handler-advancedDecrementOp.adoc[advancedDecrementOp] +| xref:eventing:eventing-handler-advancedTouchOp.adoc[advancedTouchOp] +| xref:eventing:eventing-handler-advanced-keepLastN.adoc[advancedKeepLastN] +| xref:eventing:eventing-handler-advanced-docControlledSelfExpiry.adoc[advancedDocControlledSelfExpiry] +| xref:eventing:eventing-handler-multiCollectionEventing.adoc[multiCollectionEventing] +| xref:eventing:eventing-handler-advancedSelfRecursion.adoc[advancedSelfRecursion] +| xref:eventing:eventing-handler-advancedMutateInField.adoc[advancedMutateInField] +| xref:eventing:eventing-handler-advancedMutateInArray.adoc[advancedMutateInArray] +| xref:eventing:eventing-handler-advancedLookupInOp.adoc[advancedLookupInField] +|=== + +[#examples-scriptlets-binary-documents] +=== Binary Document Support + +The following scriptlets demonstrate support for binary documents in Eventing. + +Your Eventing Function must have a language compatibility setting of Couchbase Server version 6.6.2 or above to pass binary documents in its `OnUpdate(doc,meta)` handler. + +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-handler-basicBinaryKV.adoc[basicBinaryKV] +| xref:eventing:eventing-handler-advancedBinaryKV.adoc[advancedBinaryKV] +| +| +|=== + +[#examples-scriptlets-performance] +=== Performance Eventing Functions + +The following scriptlets are examples of performance-oriented or benchmark Eventing Functions. + +[cols="1,1,1,1"] +|=== +| xref:eventing:eventing-handler-fasterToLocalString.adoc[fasterToLocalString] +| +| +| +|=== + ++++ +++ diff --git a/modules/eventing/pages/eventing-faq.adoc b/modules/eventing/pages/eventing-faq.adoc new file mode 100644 index 000000000..c5170ac5e --- /dev/null +++ b/modules/eventing/pages/eventing-faq.adoc @@ -0,0 +1,322 @@ += Frequently Asked Questions +:description: This section provides answers to commonly asked questions pertaining to the Eventing Service and Functions. +:page-edition: Enterprise Edition + +[abstract] +{description} + + +== Generic + +* Is Eventing an MDS-enabled service? + ++ +Yes. MDS enables workload isolation in a Couchbase cluster. +Eventing nodes can be added as more Functions are added, or if the mutation rates are high. + + +* What kind of nodes do I run my Eventing Service on? ++ +Eventing leverages the latest trends in multi-core CPUs; therefore nodes that you select for the Eventing Service should optimally have a higher number of cores than those for indexing. + + +* Can the Eventing Service be co-located with other services? ++ +Yes, the Eventing Service node can be co-located with other MDS-enabled services. + + +* Is it supported for both text and binary formats of the documents? ++ +*Yes* only for versions 6.6.2+ ++ +For versions 6.6.2 and later, the value or the document can be either text or binary. Starting with version 6.6.2, Eventing processes binary documents. Eventing Functions can read a binary value from a bucket alias or via an Advanced Accessor. The documents are based on a key-value format where the value can be arbitrary text or binary data. However, in practice the value is typically a well formatted JSON text payload. Note, Eventing Functions via the curl() function can also handle binary data to and from an external REST endpoint. Furthermore, every mutation OnUpdate(doc,meta) will now have a property "datatype" set to either "binary" or "json", however this information is not available via OnDelete(meta,options) or Basic Bucket Ops. ++ +*No* for versions 6.6.1 and earlier. ++ +For versions 6.6.1 and earlier, the value or the document must always be text. Eventing currently doesn't process binary documents (binary documents will not generate mutations). Additionally, an Eventing Function can’t currently read a binary value from a bucket alias. The documents are based on a key-value format where the value can be arbitrary text. However, in practice the value is typically a well formatted JSON text payload. There is one exception, Eventing Functions via the curl() function can handle binary data to and from an external REST endpoint. ++ + + +== Change Capture + +* Will all the updates to a document be seen in DCP? ++ +When a document is updated multiple times in a small time-window, not all updates are seen in DCP. +This means that the event entry points of *OnUpdate* and *OnDelete* to the Eventing Function will see only those deduplicated events that are published in DCP. + + +* Can a Function listen to all changes across Couchbase Server? ++ +A defined Function listens only to changes that are exposed using the DCP for the source collection (Couchbase and Ephemeral) in the data-nodes. +Memcached buckets (and thus underlying collections) are not supported. +The Function cannot listen to changes happening in other Couchbase components, such as FTS, Views, or GSI; nor can it listen to system events. + + +* Can we determine what has changed on the document? ++ +No. But you can implement versioning as part of the application logic. +If versioning is important, include it as part of the data architecture. + + +* Can I get old and new values of the document inside the Function? + ++ +No. We do not support versioning of documents; therefore, this feature is not available out of the box. However, you can have a parent bucket and its replica version. The replica bucket would retain the version of documents before the current set of changes. Look at the Eventing examples and scriptlets for various work arounds. + +* Is the ordering of document mutations enforced? ++ +All changes from a document are always processed in order. + + +== Functions + +* Are Functions similar to a Database Trigger? ++ +In a rough sense, Eventing Functions are similar to the Post-Triggers of the database world. +But with Functions, the action is already completed at the data-layer, and the entry points of *OnUpdate* and *OnDelete* give an interface by which developers can key in the logic of what needs to happen ‘after’ the action is done. +What an Eventing Function sees is the actual event of the change, and hence it does not directly correlate with Database Triggers. + + +* Are Functions similar to a Rules Engine? ++ +Not exactly. +A Rules Engine enforces ordering and other semantics that is not possible out of the box with Functions. +The Function in its purest form offers a business rule to implemented closer to the data, but cannot trigger another Function directly. + + +* Are Functions similar to a Stored Procedure? ++ +Stored Procedures enforce a request-response model. +A stored procedure will not be invoked automatically; it has to be invoked by a calling method. +Functions are based on the idea of events. +Changes to the data or mutations are the events that trigger Functions, and hence this is not a request-response model in its purest sense. + + +* Do I need a separate middleware to consume the Functions? How do I consume changes in my middleware/application? ++ +No. +Functions do not require any additional infrastructure mutations are consumed and acted upon by the defined Function. There is no other programmatic way of accessing the changes processed by a Function (such as by using an SDK, or some other form of middleware). REST endpoints are exposed, to perform administrative operations. + + +* Can I import my own JS libraries or Node Modules? ++ +No. +We do not allow import of node modules or external JS libraries or Node modules. Though you can define other JavaScript functions inside a Eventing Function (outside the scope of OnUpdate and OnDelete) that can be invoked any number of times from JavaScript code within the Eventing Function. + + +* Are Functions supported for both Data Node and Document storage? ++ +The Eventing Service listens to changes that appear in the Database Change Protocol (DCP) stream. +Since DCP is valid for the Data Service, and Eventing Functions only operate on documents that are text based. The documents are based on a key-value format where the value can be arbitrary text. However in practice the value is typically a well formatted JSON text payload. Note, the key is passed as meta.id and the value is passed as doc to the *OnUpdate* handler and only the key as meta.id is passed to the *OnDelete* handler. + +* Can Functions interact with external processes? ++ +Yes. +Functions support a cURL API as a way of interacting with external entities or REST endpoints using HTTP. This functionality +allows propagation of data changes to other systems, notifying the application about interesting events, enriching documents +with data from external resources, and so on. The native cURL that lets users propagate events of interest to other APIs when +mutation rates are low. + +ifdef::flag-devex-rest-api[] +* Can a Function be debugged and what happens when a Function is debugged? ++ +Yes. +Functions offer multiple diagnosability solutions (debugger, logs, and statistics), all designed to have minimal impact on overall +performance and scalability. +When debugging a function a single mutation is blocked and handed off to the debugger session, while the rest of the mutations continue to be serviced by the Eventing Function, refer to the xref:eventing:eventing-debugging-and-diagnosability.adoc[Debugging and Diagnosability] section. +endif::flag-devex-rest-api[] + +* Can the logic in a Function in production be altered while it is running? ++ +Yes. +Functions can be "paused, edited and resumed" without losing a single mutation; as such continuity is maintained. Note this sequence is similar to the operations of "undeploy, edited, and deployed with a feed boundary ‘From now’", however in this later case you can lose mutations. + +ifdef::flag-devex-command-line[] +* How do I perform a Function's lifecycle operations from CI/CD? ++ +To perform Functions lifecycle operations from CI/CD, refer to the xref:cli:cbcli/couchbase-cli-eventing-function-setup.adoc[CLI Eventing] section. +endif::flag-devex-command-line[] + +ifdef::flag-devex-rest-api[] +* How to invoke a REST endpoint from inside the Function? ++ +To invoke a REST Endpoint from inside the Function, refer to the xref:eventing-api.html[] section. +endif::flag-devex-rest-api[] + +* How does the Functions offering compare with the Couchbase’s Kafka Connector? ++ +The Functions offering is about server-side processing or compute of business logic; it does not require any additional infrastructure layer or middleware to be deployed or managed. +Couchbase’s Kafka connector is an SDK component that needs an application container or middleware to run. + +* Do I have to update and/or deploy my Functions on each Eventing node? ++ +No. The Eventing service will properly distribute the Function code or lifecycle requests across all Eventing nodes. +It is a best practice to only have one (1) Admin UI to a single node in your cluster when developing or modifying your Eventing Functions. +Note that if you edit Eventing Functions (code or settings) in two browser windows or tabs (to same node or different nodes), you might inadvertently deploy a slightly older or “stale” definition if you switch back and forth between different UI sessions. + +== Eventing Function Code + +* What languages are supported? ++ +Only JavaScript (ECMAScript 6) is supported. However, to support the ability to shard and scale Function execution automatically, some capabilities have been removed (Global state, Asynchrony, etc.), refer to the xref:eventing:eventing-language-constructs.adoc#removed-lang-features[Language Constructs: Removed Language Features] section. + + +* Why can’t I create global variables? ++ +Functions do not allow global variables, this restriction is mandatory for the Function logic to shard and scale and remain agnostic during rebalance. All state must be saved and retrieved from persistence providers, therefore KV bucket(s) made available to the Function through bindings can be used to store any required global state. Eventing Functions (as of 7.0.0) do however support global constants via the "Constant alias" binding. + +* What is in the "meta" Function parameter (OnUpdate, OnDelete)? Is this the metadata we currently write in order to figure out what has changed in the document? ++ +No, the meta parameter does not include information on what fields changed or mutated in the document. +This parameter is composed of the meta fields associated with the document. For more information, refer to the xref:server:learn:data/data.adoc#metadata[metadata] section. ++ +It should be noted, “document metadata” is different from the "Eventing Storage" keyspace (metadata collection), described in the next section, used by the Eventing Service to maintain state and checkpoints. + +* Can there be more than one Function listening to changes to a collection? ++ +Yes. +More than one Function can be defined for the same source collection. +This lets you process the change according to the business logic that you enforce. +But there is no enforced ordering; for example, if collection 'wine' has three different Functions, which are FunctionA, FunctionB, and FunctionC, you cannot enforce the order in which these Functions are executed. ++ +However, for each Function you start a set of DCP streams so for a busy system you will get better performance by coalescing multiple Eventing Functions that have the same source collection into a single Function. +This merging is easy to do with a JavaScript switch statement or a simple if-then-else block. + +* Is it possible to get additional state during a Function execution? ++ +Yes. +For example, you can fetch related data from another document (using a document id) from any other collection that is exposed to the Function via a "bucket binding". +It is also possible to utilize the cURL API to read additional state from an external REST endpoint. + +* Is it possible to update state (or change a document) during a Function execution? ++ +Yes. +For example, you can your enrich or update a document with data from another document (using a document id) from any other collection that is exposed to the Function via a binding with access level of "Read Write" inclusive of the source collection. + +== The Eventing Storage keyspace (or metadata collection) + +* What is the Eventing Storage keyspace? Do I need to create a separate collection? ++ +To provide better resiliency and restartability semantics across Eventing nodes, some of the metadata that is used by the Eventing service needs a collection to be stored in a standard xref:clusters:data-service/about-buckets-scopes-collections.adoc[Couchbase bucket] (hereafter referred to as the 'metadata collection'). ++ +After provisioning the Eventing nodes in your cluster, you'll need to create the metadata collection before you can start using the Eventing service. +All Eventing functions within a cluster can share the same metadata collection (this is a best practice but not a requirement), regardless of the number of functions, or their source and destination collection. +(Setting up a metadata collection is a one-time activity for the cluster should you choose to follow this best practice.) ++ +Some additional requirements of the metadata collection are as follows: ++ +** You should enable xref:clusters:data-service/manage-buckets.adoc#add-bucket[replicas] on the metadata collection to allow for failure recovery. +** You should reserve the metadata collection solely for Eventing housekeeping. +It shouldn't be used for any other data storage. +** Each Eventing function always requires a fixed amount of space of about 2MB (1024 docs * 1884 bytes). +** If an Eventing function uses timers, then an additional fixed amount of space of about 0.2MB (1024 * docs of 196 bytes) is needed. +From version 6.6.1 on only 0.04MB (256 docs * 196 bytes) is needed if the function uses timers. +** If an Eventing function uses timers, then for each active timer, an additional amount of space between 832 and 1856 bytes (832 bytes + sizeof(context)) is needed. +Where by default the context cannot be larger than 1024 bytes and the maximum number of active timers is based on both the business logic and the mutation rate. +ifdef::flag-devex-rest-api[] +Note, the "timer_context_size" can be overridden on a per function bases via the xref:eventing-api.adoc[Eventing: REST API]. +endif::flag-devex-rest-api[] +It is best to keep the size of the context small by using a reference rather than passing and storing a massive document in the timer. +** Every timer requires up to three documents (_root_, _alarm_, and _context_) which are stored in the Eventing Storage (or metadata collection). +Note sometimes only two (2) additional documents are needed if the timer shares the same scan interval or _root_ document with a previous timer. + +* Why is the metadata collection not getting cleared when I cancel a timer or a set of timers. ++ +When a timer is canceled the _context_ document is removed immediately, however the _root_ and _alarm_ documents are removed in a lazy fashion when the canceled timer was originally scheduled to fire. +Thus is 100K timers are scheduled to fire one (1) year in the future and canceled up to 2 additional documents will persist for one (1) year. +Note the _cancelTimer()_ function was introduced in version 6.6.0. + +== Timer Behavior + +* Timer Delays: When I schedule a timer to fire at an exact time, I see some delay. Why? ++ +The timer implementation is designed to handle large numbers of distributed timers (i.e., millions of timers) and the only promise is to run timers as soon as possible, e.g. no timers lost. ++ +In a steady state you may see a 3-4 second delay from the scheduled time, however if scheduling timers close to the system wall-clock this delay may increase to about 14 seconds. +For more details on Timer scheduling refer to xref:eventing-timers.adoc#wall-clock-accuracy[Timers: Wall-clock Accuracy] section. + +* Can I cancel a Timer? ++ +Yes. +As of the release 6.6.0 Eventing Timers can be cancelled using _cancelTimer()_ function, or by creating a new Timer with the same reference as an existing Timer. +Refer to xref:eventing-timers.adoc[]. + +* Can I create a Recurring timer? ++ +Yes. +As of the release 6.6.0 Recurring Timers are fully supported, i.e. a function that is invoked by a Timer callback can reliably create fresh Timers. +Refer to xref:eventing-timers.adoc[]. + +* Can I schedule a Timer far into the future? ++ +Yes. +As of the release 6.6.0, recurring Timers can be created days, weeks, or years in the future with no adverse performance impact on an otherwise idle Eventing system. Refer to xref:eventing-timers.adoc[]. + +* Why do I see a burst of activity in bucket OPs (in the bucket that holds the metadata collection) after a timer is paused for an extended period of time? ++ +Resuming an Eventing Function with a timer callback or handler after a prolonged period of time where the Function was in the paused state (like days) will cause a period of high bucket OPs upon resuming the Function. In addition mutation processing is blocked until the timer scan is completed which can take some time (this delay is proportional to the duration of pause). + +* Why do I see unexpected documents in the metadata collection when I cancel or overwrite an Eventing Timer? ++ +When overwriting or canceling a Timer only one of possible three documents, i.e. the "context", is immediately cleared from the metadata bucket. The extra documents, an "alarm" document associated with each Timer and a "root" document (1 per vBucket for the specific time) are left in the metadata bucket. These items are cleaned up at the original execution time that the Timer was scheduled to fire. + +* Can I pass a binding (Bucket or URL alias) in a Timer's context? ++ +No. +Bindings, whether a Bucket alias or an URL alias, are not serializable objects and only exist in the scope of the executing V8 worker. When a Timer fires it can execute on a different thread. Of course the Timer's callback can reference the binding directly. However you can pass a "Constant alias" to a timer callback. + +* Can I pass a JavaScript function in a Timer's context? ++ +No. +A JavaScript function is a memory reference in a given V8 worker. As such, it is not a serializable object and only exists in the scope of the executing V8 worker. When a Timer fires it can execute on a different thread. Of course the Timer's callback can reference the function directly. Additionally, if needed, you can pass the name of the function in the context and utilize JavaScript's eval method. + +== Cluster Behavior + +* What happens to the Eventing Service during a failover condition? ++ +When the Data service experiences a failover condition, mutations may be lost and these lost mutations are not processed by the Eventing service. +When the Eventing node experiences a failover condition, few mutations may be processed more than once. + +* Does a rebalance have any effect on the firing of events? ++ +No. Functions do not lose any mutations during a rebalance operation. + +* I have Functions deployed on my cluster, when can I perform an Eventing rebalance operation? ++ +The Function lifecycle operations (deploying, undeploying, pausing, resuming, and deleting) and the Eventing rebalance operation are mutually exclusive. +The Eventing rebalance operation fails when a Function lifecycle operation is currently in progress. +Likewise, when the Eventing rebalance operation is in progress, you cannot perform a Function lifecycle operation. ++ +Due to a regression, https://issues.couchbase.com/browse/MB-43343[MB-43343], impacting only 6.6.1 during a rebalance in of an Eventing node a race can occur resulting in Eventing functions becoming hung in deploying state. +Users can run into this issue when they have multiple functions deployed against the same source collection and they try to rebalance-in an eventing node. +The workaround is to ensure that you pause all Eventing Functions before any rebalance. + +* How do I increase performance of an Eventing Function? ++ +You can scale up vertically by adding additional workers (in the Eventing Function's settings) to increase performance for a specific Function. +You can also scale out horizontally via Couchbase’s elastic scaling option by adding another node and rebalancing. +In this case each eventing node is assigned a subset of vBuckets. Note this sharding increases overall performance for all Functions. ++ +In 7.0.0 the default number of workers for new Eventing Functions is now one (1), previously it was one (3). Thus pay attention to your performance and adjust the number of works to fit your application. Note, all upgrades of existing Functions will keep the number of workers they were created with. ++ +However keep in mind that sometimes the Function is limited by the overall performance of the Data Service. +In this case it is appropriate to scale the Data service. + +* When I maximize the workers Eventing Function I sometimes see a stall in processing? ++ +When scaling up vertically by adding additional workers (in the Eventing Function's settings) typically above 48 workers (_the issues is workload +dependent and occurs typically on source collection updates_) you may see a stall in Eventing Function's progress. This is typically related +to resources given to the Eventing service and can be solved by adding additional Memory Quota to Eventing in the Cluster Settings. By +default Eventing allocates 256 MB, raising this value to 512 MB will typically solve this resource issue (this is one of the rare instances +that you may need to raise the Memory Quota for Eventing). ++ +However keep in mind that sometimes the Function is limited by both the number of cores in the Eventing instance the overall +performance of the Data Service. In these cases it is appropriate to either scale compute power of the Eventing node, scale the +Eventing service, or scale the Data service. + +* Does Eventing support node-to-node encryption ? ++ +Yes, node-to-node encryption is available in the Couchbase Server for the Eventing Service in the 7.X train starting with version 7.0.2 and the 6.X train starting with version 6.6.5. +Therefore, on earlier versions (in either train), when _all_ is specified, the data passed to and from all other Couchbase Services is passed in encrypted form, whereas the data passed to and from the Eventing Service continues to be passed in _unencrypted_ form. ++ +When node-to-node encryption is enabled or disabled all deployed Eventing Functions need to be temporarily paused and can be resumed after the necessary changes have been made (to prevents the potential loss of mutations during the encryption change.) diff --git a/modules/eventing/pages/eventing-function-export.adoc b/modules/eventing/pages/eventing-function-export.adoc new file mode 100644 index 000000000..4ba3d280f --- /dev/null +++ b/modules/eventing/pages/eventing-function-export.adoc @@ -0,0 +1,23 @@ += Exporting Functions +:description: Couchbase provides an option to export Functions as a JSON document. +:page-edition: Enterprise Edition + +[abstract] +{description} +Using the export and import options, you can port defined Functions from your Test-to-Test, Test-to-Production, or Production-to-Production environments. + +To export a Function: + +. Access the *Couchbase Web Console* > *Eventing* page. +. Click on any *function name* to expand the UI to show additional controls. ++ +image::addfunc_04_newundeployed.png[,100%] + +. Click on the *Export* button in the Function's controls. +The Function definition gets exported to your local file system. + +A sample exported file for the *case_2_enrich_ips* function demonstrated in the xref:eventing-example-data-enrichment.adoc[Data Enrichment] Example is shown below. Ensure that you refrain from editing an exported file before importing the file back to the Couchbase cluster. + +---- +[{"appcode":"function OnUpdate(doc, meta) {\n log('document', doc);\n doc[\"ip_num_start\"] = get_numip_first_3_octets(doc[\"ip_start\"]);\n doc[\"ip_num_end\"] = get_numip_first_3_octets(doc[\"ip_end\"]);\n // !!! write back to the source bucket !!!\n src[meta.id]=doc;\n}\nfunction get_numip_first_3_octets(ip) {\n var return_val = 0;\n if (ip) {\n var parts = ip.split('.');\n //IP Number = A x (256*256*256) + B x (256*256) + C x 256 + D\n return_val = (parts[0]*(256*256*256)) + (parts[1]*(256*256)) + (parts[2]*256) + parseInt(parts[3]);\n return return_val;\n }\n}","depcfg":{"buckets":[{"alias":"src","bucket_name":"source","access":"rw"}],"curl":[],"metadata_bucket":"metadata","source_bucket":"source"},"version":"evt-6.5.0-4960-ee","handleruuid":1408181362,"id":0,"function_instance_id":"S8vQl1","appname":"case_2_enrich_ips","settings":{"dcp_stream_boundary":"everything","deadline_timeout":62,"deployment_status":false,"description":"On mutation enrich the mutated document in the same bucket with additional fields","execution_timeout":60,"language_compatibility":"6.5.0","log_level":"INFO","n1ql_consistency":"none","processing_status":false,"user_prefix":"eventing","using_timer":false,"worker_count":3},"using_timer":false,"src_mutation":true}] +---- diff --git a/modules/eventing/pages/eventing-handler-ConvertBucketToCollections.adoc b/modules/eventing/pages/eventing-handler-ConvertBucketToCollections.adoc new file mode 100644 index 000000000..408fb50a8 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-ConvertBucketToCollections.adoc @@ -0,0 +1,106 @@ += Function: Convert Bucket to Collections +:description: pass:q[Demonstrate Converting "upgraded" Buckets to Collections.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *ConvertBucketToCollections* demonstrates a simple technique to reorganize into buckets. +* Requires Eventing Storage (or metadata collection) and a "source" collection listing to the sample "beer-sample". +* The sample "beer-sample" is equivalent to an upgraded bucket where all data resides in `beer-sample`.`_default`.`_default`. +* Needs Bindings of type "Constant alias" (as documented in the Scriptlet). +* Needs Bindings of type "bucket alias" (as documented in the Scriptlet). +* If "Constant alias" *DO_COPY* is true +** move all type` = "brewery" to COLLECTION `bulk`.`data`.`brewery` +** move all type` = "beer" to COLLECTION `bulk`.`data`.`beer` +* If "Constant alias" *DO_DELETE* is true +** remove all type` = "brewery" from upgrade COLLECTION `beer-sample`.`_default`.`_default` +** remove all type` = "beer" from upgrade COLLECTION `beer-sample`.`_default`.`_default` +* The function should have higher throughput as you add more workers up to the # of vCPUs. +* Example of performance using this technique: +** Test cluster is a symmetric 3 x AWS r5.2xlarge (64 GiB of memory, 8 vCPUs, 64-bit platform). +** Will process 93K ops/sec in a steady state. +** 250M small documents: takes 44 minutes to reorganize a bucket with 80 types into a new bucket with 80 collections. +** 1B small documents: takes 3 hours to reorganize a bucket with 80 types into a new bucket with 80 collections. + +NOTE: If you alter this function and attempt to run this Eventing function in a single bucket you will have to disable recursion checks. +Refer to xref:eventing:troubleshooting-best-practices.adoc#recursionchecks[Disabling infinite recursion checks]. +In this case, always test your Eventing Function on a non-production system to ensure you do not mistakenly create an infinite recursion loop. + +[{tabs}] +==== +ConvertBucketToCollections:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, ConvertBucketToCollections, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try beer-sample.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// beer-sample.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "beer-sample._default._default", "read and write" +// "bucket alias", "brewery_col", "bulk.data.brewery", "read and write" +// "bucket alias", "beer_col", "bulk.data.beer", "read and write" +// +// 2. "binding type", "alias name...", "value", +// "Constant alias", "DO_COPY", true +// "Constant alias", "DO_DELETE", true +// +// Version 6.6.2 (not applicable) + +// Upgrades `beer-sample` from a bucket paradigm to a collection/keyspace paradigm. + +function OnUpdate(doc, meta) { + if (doc.type === 'beer') { + if (DO_COPY) beer_col[meta.id] = doc; + if (DO_DELETE) { + if (!beer_col[meta.id]) { // safety check + log("skip delete copy not found type=" + doc.type + ", meta.id=" + meta.id); + } else { + delete src_col[meta.id]; + } + } + } + if (doc.type === 'brewery') { + if (DO_COPY) brewery_col[meta.id] = doc; + if (DO_DELETE) { + if (!brewery_col[meta.id]) { // safety check + log("skip delete copy not found type=" + doc.type + ", meta.id=" + meta.id); + } else { + delete src_col[meta.id]; + } + } + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,text] +---- +LOAD THE SAMPLE `beer-sample` from the UI Settings page +CREATE two empty keyspaces `bulk`.`data`.`brewery` and `bulk`.`data`.`beer` +---- +-- + +Output Data/Logged:: ++ +-- +[source,text] +---- +THE `beer-sample`.`_default`.`_default` keyspace is empty (0 documents) +The keyspace `bulk`.`data`.`brewery` has 1,412 documents of type == "brewery" +The keyspace `bulk`.`data`.`beer` has 5,891 documents of type == "beer" +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advanced-docControlledSelfExpiry.adoc b/modules/eventing/pages/eventing-handler-advanced-docControlledSelfExpiry.adoc new file mode 100644 index 000000000..6ec3d26f7 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advanced-docControlledSelfExpiry.adoc @@ -0,0 +1,194 @@ += Function: Advanced Document Controlled Expiry +:description: pass:q[Purge a document automatically based on the document's self-contained start and duration fields.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedDocControlledSelfExpiry` function: + +* Demonstrates the self-expiry of a document (for example, a user trial) +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Processes the initial mutation to calculate and set the TTL of a newly-created document +* Uses a JavaScript data object to set document expiration +* Operates on any document where `type == "trial_custoimers"` +* Ignores any document with a TTL that is not zero + +When you use a simple integer instead of a proper date or time object for your document's expiration value, the expiration value is specified in one of the following ways: + +* As an offset from the current time if the value is less than 30 days (60 * 60 * 24 * 30 seconds). +* As an absolute Unix time stamp if the value is greater than 30 days (60 * 60 * 24 * 30 seconds). + +If a `Bucket Max Time-to-Live` is set and specified in seconds, it's enforced as a hard upper limit. +Any subsequent document mutation, whether by {sqlpp}, Eventing, or a Couchbase SDK, results in the document having its expiration adjusted and set to the bucket's maximum TTL if the operation has: + +* No TTL +* A TTL of zero +* A TTL greater than the bucket's TTL + +[{tabs}] +==== +advancedDocControlledSelfExpiry:: ++ +-- +There are two variants of this function available: a xref:eventing-handler-docControlledSelfExpiry.adoc[Couchbase Server version 6.6 that relies on {sqlpp}], and a Couchbase Server version 6.6.1+/7.0.0+ that directly sets the expiration. + +You can improve your function's performance by avoiding N1QL() and using `couchbase.replace(bucket_binding, meta, doc)` instead. + +The following example directly sets the expiration. + +[source,javascript] +---- +// Configure the settings for the advancedDocControlledSelfExpiry function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + // Filter items that have not been updated + if (meta.expiration !== 0) { + log(meta.id, "IGNORE expiration "+meta.expiration+" !== 0 or "+ + new Date(meta.expiration).toString()); + return; + } + + // Optional filter to a specific field like 'type' + if (doc.type !== 'trial_customers') return; + + // The expiry is based on a JavaScript date parsable field + if (!doc.trialStartDate || !doc.trialDurationDays) return; + + // Convert the doc field timeStamp to Unix epoch time in milliseconds + var docTimeStampMs = Date.parse(doc.trialStartDate); + + var keepDocForMs = doc.trialDurationDays * 1000 * 60 * 60 * 24 ; + var nowMs = Date.now(); // Get current Unix time in milliseconds + + // Archive if it has been kept for too long; you do not need to set an expiration + if( nowMs >= (docTimeStampMs + keepDocForMs) ) { + + // Delete the document from the source collection through the map alias + delete src_col[meta.id]; + + log(meta.id, "DELETE from src_col to dst_bkt alias as our expiration " + + new Date(docTimeStampMs + keepDocForMs).toString()) + " is already past"; + } else { + var key = meta.id; + // Set the meta.expiration=ttlMs + var ttlMs = docTimeStampMs + keepDocForMs; + + if (ttlMs !== 0) { + log(meta.id, "UPDATE expiration "+meta.expiration+" === 0 set to "+ + ttlMs+" or " + new Date(ttlMs).toString()); + // Advanced Bucket Accessors use JavaScript Date objects + var expiryDate = new Date(ttlMs); + // This is 4X to 5X faster than using N1QL(...) and you do not need to worry about recursion + var res = couchbase.replace(src_col,{"id":meta.id,"expiry_date":expiryDate},doc); + if (!res.success) { + log(meta.id,'Setting TTL to',expiryDate,'failed',res); + } + } + } +} +---- +-- + +Input data:: ++ +-- +Create a test set of 4 documents using the Query Editor to insert the data items. +You do not need an Index. + +If today's date is past 08-25-2021 (MM-DD-YYYY), you can change the `trialStartDate` for the last two records to at least 90 days from today. + +[source,sqlpp] +---- + UPSERT INTO `bulk`.`data`.`source` (KEY,VALUE) + VALUES ( "trial_customers::0", { + "type": "trial_customers", + "id": 0, + "trialStartDate": "08-25-2019", + "trialDurationDays": 30, + "note": "this is old will get immeadiately deleted" + } ), + VALUES ( "trial_customers::1", + { + "type": "trial_customers", + "id": 1, + "trialStartDate": "01-27-2020", + "trialDurationDays": 30, + "note": "this is old will get immeadiately deleted" + } ), + VALUES ( "trial_customers::2", + { + "type": "trial_customers", + "id": 2, + "trialStartDate": "08-25-2021", + "trialDurationDays": 30, + "note": "this will get an exiration set" + } ), + VALUES ( "trial_customers::3", + { + "type": "trial_customers", + "id": 3, + "trialStartDate": "08-26-2021", + "trialDurationDays": 60, + "note": "this will get an exiration set" + } ); +---- +-- + +Output data:: ++ +-- +[source,json] +---- +NEW/OUTPUT: KEY trial_customers::2 + +{ + "id": 2, + "note": "this will get an exiration set", + "trialDurationDays": 30, + "trialStartDate": "08-25-2021", + "type": "trial_customers" +} + +NEW/OUTPUT: KEY trial_customers::3 + +{ + "id": 3, + "note": "this will get an exiration set", + "trialDurationDays": 60, + "trialStartDate": "08-26-2021", + "type": "trial_customers" +} + +Returns 2 of the 4 documnents. + +* "trial_customers::0" was deleted +* "trial_customers::1" was deleted +* "trial_customers::2" has an meta.expiration set for 1632466800 (or 2021-09-24 07:00:00 UTC) in it's metadata +* "trial_customers::3" has an meta.expiration set for 1635145200 (or 2021-10-25 07:00:00 UTC) in it's metadata + +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advanced-keepLastN.adoc b/modules/eventing/pages/eventing-handler-advanced-keepLastN.adoc new file mode 100644 index 000000000..b05bfac25 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advanced-keepLastN.adoc @@ -0,0 +1,262 @@ += Function: Advanced Keep the Last N User Items +:description: pass:q[Keep the last N user notifications related to a user ID.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedKeepLastN` function: + +* Demonstrates how to keep a user record with the last N activities +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where the KEY starts with `nu:` in the form `nu:#:#` +** The KEY `nu:#:#` has 2 numbers. The first is an increasing notification number and the second is the user ID. +* Only keeps N records for each user +* Removes the earliest notification record for a user whenever a new record is inserted for that user + +The following example assumes that N always increases across time and ignores any duplicates. +It keeps only the 3 most recent notifications for each user ID. + +[{tabs}] +==== +advancedKeepLastN:: ++ +-- +There are two variants of this function available: a xref:eventing-handler-keepLastN.adoc[Couchbase Server version 6.6 that implements userspace CAS], and a Couchbase Server version 6.6.1+/7.0.0+ that uses true CAS. + +The following example uses true CAS. + +[source,javascript] +---- +// Configure the settings for the advancedKeepLastN function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +/* + * Process all mutations; updateNotifyArrayInKV(...) only processes data with KEYS like nu:#:# + */ +function OnUpdate(doc, meta) { + const MAX_ARRAY = 3; // Keep 'N' items + const DEBUG = false; // If true, the debug log can be too long + + updateNotifyArrayInKV(doc, meta, MAX_ARRAY, DEBUG); +} + +/* + * Manipulate the in-memory document to only keep 'MAX_ARRAY' items + */ +function addToNtfyArray(user_doc, user_id, insert_json, MAX_ARRAY, DEBUG) { + var ntfy_id = insert_json.nid; + if (user_doc.notifications && user_doc.notifications[0] && + user_doc.notifications[0].nid >= ntfy_id && + user_doc.notifications.length === MAX_ARRAY) { + // Do nothing; this is older data + return null; + } else { + // Find the insert position + for (var i = 0; i <= user_doc.notifications.length + 1; i++) { + if (i < user_doc.notifications.length && user_doc.notifications[i].nid === ntfy_id) { + // Do nothing; this is duplicated data + if (DEBUG) log('Ignore DUP ntfy_id', ntfy_id, 'user_id', user_id, 'insert_json', insert_json); + return null; + } + if (i == user_doc.notifications.length || user_doc.notifications[i].nid > ntfy_id) { + // Add to middle or end of array + user_doc.notifications.splice(i, 0, insert_json); + break; + } + } + } + while (user_doc.notifications.length > MAX_ARRAY) { + // Ensure proper size + user_doc.notifications.shift(); + } + return user_doc; +} + +/* + * Creates, gets, and updates (via replace) the KV tracking array document + */ +function updateNotifyArrayInKV(doc, meta, MAX_ARRAY, DEBUG) { + // Process ALL data like nu:#:# + var parts = meta.id.split(':'); + if (!parts || parts.length != 3 || parts[0] != "nu") return; + var ntfy_id = parseInt(parts[1]); + var user_id = parseInt(parts[2]); + //log("Doc created/updated " + meta.id + " ntfy_id " + ntfy_id + " user_id " + user_id); + + var insert_json = { + "nid": ntfy_id, + doc + }; + // In version 6.6.1, use CAS in Eventing to avoid race conditions + var res = null; + var req_id = "user_plus_ntfys:" + user_id; + var req_meta = { + id: req_id + }; + var user_doc = null; + var user_meta = null; + while (res === null) { + res = couchbase.get(src_col, req_meta); + if (DEBUG) log('couchbase.get(src_col,', req_meta, ') success==' + res.success, res); + if (res.success) { + user_doc = res.doc; + // EXAMPLE user_meta + // {"id":"user_plus_ntfys:2","cas":"1609965779014844416","data_type":"json"} + user_meta = res.meta; + } else { + if (!res.error.key_not_found) { + // Do nothing; this is a big error + log("FAILED to insert id: " + meta.id, doc, 'res', res) + return; + } + // Create the document and initialize it + user_doc = { + "type": "user_plus_ntfys", + "id": user_id, + "notifications": [] + }; + res = couchbase.insert(src_col, req_meta, user_doc); + if (DEBUG) log('couchbase.insert(src_col,', req_meta, user_doc, ') success==' + res.success, res); + // Redo the loop to force couchbase.get + res = null; + } + if (res !== null) { + // Successful couchbase.get(...) for both user_doc and user_meta + // Manipulate the copy of the user_doc to keep only MAX_ARRAY + var new_doc = addToNtfyArray(user_doc, user_id, insert_json, MAX_ARRAY, DEBUG); + if (new_doc == null) { + // Ignore or skip duplicated data + break; + } + // Try to replace the user_doc with new_doc; pass CAS to test for race conditions + res = couchbase.replace(src_col, user_meta, new_doc); + if (DEBUG) log('couchbase.replace(src_col,', user_meta, new_doc, ') success==' + res.success, res); + if (res.success) { + // CAS matches and operation is successful + break; + } else { + // Redo loop and try again + res = null; + } + } + } +} +---- +-- + +Input data:: ++ +-- + +Create a new test document set using the Query Editor to insert the data items. +You do not need an Index. + +[cols="1,3",width=50%,frame=all] +|=== +|key |data + +|nu:1:1 |{"somekey":"someValue"} +|nu:2:2 |{"somekey":"someValue"} +|nu:3:1 |{"somekey":"someValue"} +|nu:4:1 |{"somekey":"someValue"} +|nu:5:1 |{"somekey":"someValue"} +|nu:6:2 |{"somekey":"someValue"} +|nu:7:2 |{"somekey":"someValue"} +|nu:8:1 |{"somekey":"someValue"} +|nu:9:2 |{"somekey":"someValue"} +|nu:10:2 |{"somekey":"someValue"} + +|=== + +[source,sqlpp] +---- + UPSERT INTO `bulk`.`data`.`source` (KEY,VALUE) + VALUES ( "nu:1:1", {"somekey":"someValue"} ), + VALUES ( "nu:2:2", {"somekey":"someValue"} ), + VALUES ( "nu:3:1", {"somekey":"someValue"} ), + VALUES ( "nu:4:1", {"somekey":"someValue"} ), + VALUES ( "nu:5:1", {"somekey":"someValue"} ), + VALUES ( "nu:6:2", {"somekey":"someValue"} ), + VALUES ( "nu:7:2", {"somekey":"someValue"} ), + VALUES ( "nu:8:1", {"somekey":"someValue"} ), + VALUES ( "nu:9:2", {"somekey":"someValue"} ), + VALUES ( "nu:10:2", {"somekey":"someValue"} ); +---- +-- + +Output data:: ++ +-- +[source,json] +---- +NEW/OUTPUT: KEY user_plus_ntfys:1 + +{ + "type": "user_plus_ntfys", + "id": 1, + "notifications": [{ + "nid": 4, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 5, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 8, + "doc": { + "somekey": "someValue" + } + }], + "random": 0.9071605464143964 +} + +NEW/OUTPUT: KEY user_plus_ntfys:2 + +{ + "type": "user_plus_ntfys", + "id": 2, + "notifications": [{ + "nid": 7, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 9, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 10, + "doc": { + "somekey": "someValue" + } + }] +} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedBinaryKV.adoc b/modules/eventing/pages/eventing-handler-advancedBinaryKV.adoc new file mode 100644 index 000000000..408fc01c1 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedBinaryKV.adoc @@ -0,0 +1,157 @@ += Function: Advanced Binary KV +:description: pass:q[Show and Advanced Accessor Binary Write.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *advancedBinaryKV* demonstrates creating, marshalling and unmarshalling binary docs. +* Requires Eventing Storage (or metadata collection) a "source" collection, and a "destination" collection. +* Needs a Binding of type "bucket alias" (as documented in the Scriptlet). +* Will operate on any mutation where the KEY or meta.id starts with "advancedbinarykv". +* The function will create two documents: a binary document and a normal JSON document. +* Each document will be updated via the Advanced Accessor couchbase.upsert() and then will be verified. +* The verification and logging will demonstrate binary marshalling and unmarshalling. +* The return value of couchbase.upsert() on success will indicate either "datatype":"json" or "datatype":"binary" + +[{tabs}] +==== +advancedBinaryKV:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, advancedBinaryKV, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "dst_col", "bulk.data.destination", "read and write" +// +// Version 6.6.2 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "dst_col", "destination", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("advancedbinarykv")) return; + + var doc_is_binary = true; + var prefix; + var wrkdoc; + var is_bin_ary = [true, false]; + + // loop twice first create a binary doc and then create a normal JSON doc + for (let doc_is_binary of is_bin_ary) { + if (doc_is_binary) { + // Note, we could create binary docs via 'cbc' + // "cbc create bindoc -V '^LZ' -U couchbase://localhost/source -u Administrator -P password" + // However it is easier to make a binary document via pure JavaScript code + prefix = "bindoc"; + var arr = new Uint8Array([1, 0, 2, 3]); + var bindoc = arr.buffer; + wrkdoc = bindoc; + } else { + // make a normal JSON doc + prefix = "jsondoc"; + wrkdoc = { + "jsondoc": 1 + }; + } + + // ======================================================================== + // Test basic Bucket Op, i.e. JavaScript map exposed via a bucket binding + dst_col[prefix + "_put"] = wrkdoc; + + // ======================================================================== + // Test Advanced Accessors + // Make a key for Advanced Accessor tests ( note, "datatype" in meta is not needed / ignored ) + var key = prefix + "_upsert"; + var new_meta = { "id": key }; + + log("1 RUN couchbase.upsert(dst_col,", new_meta, ",", wrkdoc, ")"); + var result = couchbase.upsert(dst_col, new_meta, wrkdoc); + if (result.success) { + log('2 success adv. upsert: result', result); + } else { + log('2 failure adv. upsert: id', key, 'result', result); + } + var tmp = couchbase.get(dst_col, { "id": key }); + log('3 couchbase.get(dst_col', { "id": key }, ') => ', tmp); + couchbase.upsert(dst_col, { "id": key + "_from_adv_get", "datatype": "bin" }, tmp.doc); + + var tag; + var disp; + if (tmp.meta.datatype && tmp.meta.datatype == "binary") { + tag = "binary"; + disp = new Uint8Array(tmp.doc); + log('4 ' + tag + ' equal = ' + buffersEqual(tmp.doc, wrkdoc), '(was binary so unmarshalled)', disp); + } else { + tag = "json"; + disp = tmp.doc; + log('4 ' + tag + ' equal = ' + (JSON.stringify(tmp.doc) === JSON.stringify(wrkdoc)), + '(was json so just the doc)', disp); + } + } +} + +function buffersEqual(buf1, buf2) { + if (buf1.byteLength != buf2.byteLength) return false; + var dv1 = new Uint8Array(buf1); + var dv2 = new Uint8Array(buf2); + for (var i = 0; i != buf1.byteLength; i++) { + if (dv1[i] != dv2[i]) return false; + } + return true; +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY advancedbinarykv:1 + +{ + "id": 1, + "type": "advancedbinarykv" +} +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-19T11:16:20.566-07:00 [INFO] "1 RUN couchbase.upsert(dst_col," {"id":"bindoc_upsert"} "," {} ")" + +2021-07-19T11:16:20.566-07:00 [INFO] "2 success adv. upsert: result" {"meta":{"id":"bindoc_upsert","cas":"1626718580566458368"},"success":true} + +2021-07-19T11:16:20.567-07:00 [INFO] "3 couchbase.get(dst_col" {"id":"bindoc_upsert"} ") => " {"doc":{},"meta":{"id":"bindoc_upsert","cas":"1626718580566458368","datatype":"binary"},"success":true} + +2021-07-19T11:16:20.567-07:00 [INFO] "4 binary equal = true" "(was binary so unmarshalled)" {"0":1,"1":0,"2":2,"3":3} + +2021-07-19T11:16:20.567-07:00 [INFO] "1 RUN couchbase.upsert(dst_col," {"id":"jsondoc_upsert"} "," {"jsondoc":1} ")" + +2021-07-19T11:16:20.568-07:00 [INFO] "2 success adv. upsert: result" {"meta":{"id":"jsondoc_upsert","cas":"1626718580568031232"},"success":true} + +2021-07-19T11:16:20.568-07:00 [INFO] "3 couchbase.get(dst_col" {"id":"jsondoc_upsert"} ") => " {"doc":{"jsondoc":1},"meta":{"id":"jsondoc_upsert","cas":"1626718580568031232","datatype":"json"},"success":true} + +2021-07-19T11:16:20.568-07:00 [INFO] "4 json equal = true" "(was json so just the doc)" {"jsondoc":1} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advancedDecrementOp.adoc b/modules/eventing/pages/eventing-handler-advancedDecrementOp.adoc new file mode 100644 index 000000000..6fb8e1aa1 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedDecrementOp.adoc @@ -0,0 +1,134 @@ += Function: Advanced DECREMENT Operation +:description: pass:q[Perform the Advanced DECREMENT operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedDecrementOp` function: + +* Performs the Advanced DECREMENT operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation +* Counts down the mutations subject to DCP deduplication + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-decrement-op[Advanced DECREMENT Operation]. + +[{tabs}] +==== +advancedDecrementOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedDecrementOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("dec:")) return; + // log('input meta', meta); + // log('input doc ', doc); + + // Creates doc.count if it does not already exist + var ctr_meta = {"id": "my_atomic_counter:1" }; + var result = couchbase.decrement(src_col,ctr_meta); + if (result.success) { + log('success adv. decrement: result',result); + } else { + log('failure adv. decrement: id',ctr_meta.id,'result',result); + } +} +---- +-- +Input data:: ++ +-- +[source,json] +---- +UPSERT INTO `bulk`.`data`.`source` (KEY,VALUE) + VALUES ( "dec:1", {"somekey":"someValue"} ), + VALUES ( "dec:2", {"somekey":"someValue"} ), + VALUES ( "dec:3", {"somekey":"someValue"} ), + VALUES ( "dec:4", {"somekey":"someValue"} ), + VALUES ( "dec:5", {"somekey":"someValue"} ), + VALUES ( "dec:6", {"somekey":"someValue"} ), + VALUES ( "dec:7", {"somekey":"someValue"} ), + VALUES ( "dec:8", {"somekey":"someValue"} ), + VALUES ( "dec:9", {"somekey":"someValue"} ), + VALUES ( "dec:10", {"somekey":"someValue"} ); +---- +-- ++ +Output data:: ++ +Insert 10 documents and count the mutations through decrementing. ++ +-- +[source,json] +---- +KEY: my_atomic_counter:1 + +{ + "count": -10 +} +---- +-- + +Output log:: ++ +-- +[source,json] +---- +2021-01-08T12:30:59.910-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-1},"meta":{"id":"my_atomic_counter:1","cas":"1610137859908960256"},"success":true} + +2021-01-08T12:30:59.910-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-2},"meta":{"id":"my_atomic_counter:1","cas":"1610137859909222400"},"success":true} + +2021-01-08T12:30:59.911-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-3},"meta":{"id":"my_atomic_counter:1","cas":"1610137859911385088"},"success":true} + +2021-01-08T12:30:59.931-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-4},"meta":{"id":"my_atomic_counter:1","cas":"1610137859929997312"},"success":true} + +2021-01-08T12:30:59.931-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-5},"meta":{"id":"my_atomic_counter:1","cas":"1610137859930193920"},"success":true} + +2021-01-08T12:30:59.932-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-6},"meta":{"id":"my_atomic_counter:1","cas":"1610137859932160000"},"success":true} + +2021-01-08T12:30:59.932-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-7},"meta":{"id":"my_atomic_counter:1","cas":"1610137859932356608"},"success":true} + +2021-01-08T12:30:59.948-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-8},"meta":{"id":"my_atomic_counter:1","cas":"1610137859946381312"},"success":true} + +2021-01-08T12:30:59.948-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-9},"meta":{"id":"my_atomic_counter:1","cas":"1610137859946708992"},"success":true} + +2021-01-08T12:30:59.948-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":-10},"meta":{"id":"my_atomic_counter:1","cas":"1610137859948412928"},"success":true} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedDeleteOp.adoc b/modules/eventing/pages/eventing-handler-advancedDeleteOp.adoc new file mode 100644 index 000000000..3945f9ef9 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedDeleteOp.adoc @@ -0,0 +1,265 @@ += Function: Advanced DELETE Operation +:description: pass:q[Perform the Advanced DELETE operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedDeleteOp` function: + +* Performs the Advanced DELETE operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where `doc.type === "control_adv_delete"` +* Always tries to insert the test document and ignores insert errors +* Has 4 modes of operation: `no_cas`, `bad_cas`, `good_cas`, and `no_key` + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-delete-op[Advanced DELETE Operation]. + +[{tabs}] +==== +advancedDeleteOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedDeleteOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("control_adv_delete")) return; + + log('input meta', meta); + log('input doc ', doc); + + // Setup, make sure there is a doc to "delete", ignore any errors + couchbase.insert(src_col,{"id":"test_adv_delete:" + doc.ins_id},{"a:": 1}); + + var new_meta; + if (doc.mode && doc.mode === "no_cas") { + // No CAS is passed - it always succeeds + new_meta = {"id":"test_adv_delete:" + doc.ins_id}; + } + if (doc.mode && doc.mode === "bad_cas") { + // Pass a non-matching CAS - it always fails + new_meta = {"id":"test_adv_delete:" + doc.ins_id, "cas":"1111111111111111111"}; + } + if (doc.mode && doc.mode === "good_cas") { + // Pass the matching or current CAS - it succeeds + var tmp_r = couchbase.get(src_col,{"id":"test_adv_delete:" + doc.ins_id}); + if (tmp_r.success) { + // Use the current CAS to read via couchbase.get(...) + new_meta = {"id":"test_adv_delete:" + doc.ins_id, "cas": tmp_r.meta.cas}; + } else { + log('Cannot delete due to no such key',"test_adv_delete:" + doc.ins_id); + return; + } + } + if (doc.mode && doc.mode === "no_key") { + // Remove (delete with a basic bucket op) so that we have: no such key + delete src_col["test_adv_delete:" + doc.ins_id] + new_meta = {"id":"test_adv_delete:" + doc.ins_id}; + } + var result = couchbase.delete(src_col,new_meta); + if (result.success) { + log('success adv. delete: result',result); + } else { + log('failure adv. delete: id',new_meta.id,'result',result); + } +} +---- +-- +Input data:: ++ +-- +[source,json] +---- +Mutation #1 + +INPUT: KEY control_adv_delete::1 + +{ + "id": 1, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "no_cas" +} + +Mutation #2 + +INPUT: KEY control_adv_delete::2 + +{ + "id": 2, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "bad_cas" +} + +Mutation #3 + +INPUT: KEY control_adv_delete::3 + +{ + "id": 3, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "no_key" +} + +Mutation #4 + +INPUT: KEY control_adv_delete::4 + +{ + "id": 4, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "good_cas" +} +---- +-- ++ +Output data:: ++ +Perform 4 deletion attempts. +The second attempt fails because of a CAS mismatch. +The third attempt fails because the document key does not exist. ++ +-- +[source,json] +---- +Logs from Mutation #1 + +2021-01-08T11:45:02.897-08:00 [INFO] "input meta" +{ + "cas": "1610134800219308032", + "id": "control_adv_delete::1", + "expiration": 0, + "flags": 33554438, + "vb": 221, + "seq": 1 +} +2021-01-08T11:45:02.898-08:00 [INFO] "input doc " +{ + "id": 1, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "no_cas" +} +2021-01-08T11:45:02.899-08:00 [INFO] "success adv. delete: result" +{ + "meta": { + "id": "test_adv_delete:10", + "cas": "1610135102898962432" + }, + "success": true +} + +Logs from Mutation #2 + +2021-01-08T11:46:11.225-08:00 [INFO] "input meta" +{ + "cas": "1610135171148152832", + "id": "control_adv_delete::2", + "expiration": 0, + "flags": 33554438, + "vb": 468, + "seq": 3 +} +2021-01-08T11:46:11.225-08:00 [INFO] "input doc " +{ + "id": 2, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "bad_cas" +} +2021-01-08T11:46:11.228-08:00 [INFO] "failure adv. delete: id" "test_adv_delete:10" "result" +{ + "error": { + "code": 272, + "name": "LCB_KEY_EEXISTS", + "desc": "The document key exists with a CAS value different than specified", + "cas_mismatch": true + }, + "success": false +} + +Logs from Mutation #3 + +2021-01-08T11:52:51.520-08:00 [INFO] "input meta" +{ + "cas": "1610135571485425664", + "id": "control_adv_delete::3", + "expiration": 0, + "flags": 33554438, + "vb": 723, + "seq": 5 +} +2021-01-08T11:52:51.520-08:00 [INFO] "input doc " +{ + "id": 3, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "no_key" +} +2021-01-08T11:52:51.522-08:00 [INFO] "failure adv. delete: id" "test_adv_delete:10" "result" +{ + "error": { + "code": 272, + "name": "LCB_KEY_ENOENT", + "desc": "The document key does not exist on the server", + "key_not_found": true + }, + "success": false +} + +Logs from Mutation #4 + +2021-01-08T11:53:36.070-08:00 [INFO] "input meta" +{ + "cas": "1610135616063602688", + "id": "control_adv_delete::4", + "expiration": 0, + "flags": 33554438, + "vb": 183, + "seq": 3 +} +2021-01-08T11:53:36.070-08:00 [INFO] "input doc " +{ + "id": 4, + "type": "control_adv_delete", + "ins_id": 10, + "mode": "good_cas" +} +2021-01-08T11:53:36.074-08:00 [INFO] "success adv. delete: result" +{ + "meta": { + "id": "test_adv_delete:10", + "cas": "1610135616073760768" + }, + "success": true +} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedGetOp.adoc b/modules/eventing/pages/eventing-handler-advancedGetOp.adoc new file mode 100644 index 000000000..f890d1c75 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedGetOp.adoc @@ -0,0 +1,126 @@ += Function: Advanced GET Operation +:description: pass:q[Perform the Advanced GET operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedGetOp` function: + +* Performs the Advanced GET operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where `doc.type === "test_adv_get"` + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-get-op[Advanced GET Operation]. + +[{tabs}] +==== +advancedGetOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedGetOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + // filter out non-intersting documents + if (!doc.type || doc.type !== "test_adv_get") return; + log('input doc ', doc); + log('input meta', meta); + // let's read the same item and then try to read a non existent item + var meta_ary = [{"id":"test_adv_get::1"}, {"id":"not_present::1"}]; + for (var i = 0; i < meta_ary.length; i++) { + var result = couchbase.get(src_col,meta_ary[i]); + if (result.success) { + log('success adv. get: result',result); + } else { + log('failure adv. get: id',meta_ary[i].id,'result',result); + } + } +} +---- +-- + +Input data:: ++ +-- +[source,json] +---- +INPUT: KEY test_adv_get::1 + +{ + "id": 1, + "type": "test_adv_get" +} + +---- +-- + +Output data:: ++ +-- +[source,json] +---- +2021-01-07T07:57:24.706-08:00 [INFO] "input doc " +{ + "id": 1, + "type": "test_adv_get" +} +2021-01-07T07:57:24.706-08:00 [INFO] "input meta" +{ + "cas": "1610034762747412480", + "id": "test_adv_get::1", + "expiration": 0, + "flags": 33554438, + "vb": 324, + "seq": 1 +} +2021-01-07T07:57:24.707-08:00 [INFO] "success adv. get: result" +{ + "doc": { + "id": 1, + "type": "test_adv_get" + }, + "meta": { + "id": "test_adv_get::1", + "cas": "1610034762747412480", + "data_type": "json" + }, + "success": true +} +2021-01-07T07:57:24.707-08:00 [INFO] "failure adv. get: id" "not_present::1" "result" +{ + "error": { + "code": 272, + "name": "LCB_KEY_ENOENT", + "desc": "The document key does not exist on the server", + "key_not_found": true + }, + "success": false +} + +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedGetOpWithCache.adoc b/modules/eventing/pages/eventing-handler-advancedGetOpWithCache.adoc new file mode 100644 index 000000000..80783c6dc --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedGetOpWithCache.adoc @@ -0,0 +1,115 @@ += Function: Advanced GET Operation with Cache +:description: pass:q[Perform the Advanced GET operation with cache where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedGetOpWithCache` function: + +* Performs the Advanced GET operation with an enabled bucket-backed cache +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where `doc.type === "test_adv_get"` +* Has an optional parameter to `couchbase.get` called `{ "cache": true }`, which enables caching of documents for up to 1 second + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#optional-cache-true-parameter[Optional `{ "cache": true }` Parameter]. + +[{tabs}] +==== +advancedGetOpWithCache:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedGetOpWithCache function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0.2+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" + +function OnUpdate(doc, meta) { + // filter out non-intersting documents + if (!doc.type || doc.type !== "test_adv_get") return; + log('input doc ', doc); + log('input meta', meta); + // let's read the same item and then try to read a non existent item + var meta_ary = [{"id":"test_adv_get::1"}, {"id":"not_present::1"}]; + for (var i = 0; i < meta_ary.length; i++) { + var result = couchbase.get(src_col,meta_ary[i],{"cache": true}); + if (result.success) { + log('success adv. get with cache: result',result); + } else { + log('failure adv. get with cache: id',meta_ary[i].id,'result',result); + } + } +} +---- +-- + +Input data:: ++ +-- +[source,json] +---- +INPUT: KEY test_adv_get::1 + +{ + "id": 1, + "type": "test_adv_get" +} + +---- +-- + +Output data:: ++ +-- +[source,json] +---- +2021-10-04T15:54:31.101-07:00 [INFO] "input doc " { + "id": 1, + "type": "test_adv_get" +} +2021-10-04T15:54:31.101-07:00 [INFO] "input meta" { + "cas": "1633388049399873536", + "id": "test_adv_get::1", + "expiration": 0, + "flags": 33554438, + "vb": 324, + "seq": 3, + "datatype": "json" +} +2021-10-04T15:54:31.102-07:00 [INFO] "success adv. get with cache: result" { + "doc": { + "id": 1, + "type": "test_adv_get" + }, + "meta": { + "id": "test_adv_get::1", + "cas": "1633388049399873536", + "datatype": "json" + }, + "success": true +} +2021-10-04T15:54:31.102-07:00 [INFO] "failure adv. get with cache: id" "not_present::1" "result" { + "error": { + "code": 1, + "name": "LCB_KEY_ENOENT", + "desc": "The document key does not exist on the server", + "key_not_found": true + }, + "success": false +} + +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedIncrementOp.adoc b/modules/eventing/pages/eventing-handler-advancedIncrementOp.adoc new file mode 100644 index 000000000..c83cb1ca7 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedIncrementOp.adoc @@ -0,0 +1,134 @@ += Function: Advanced INCREMENT Operation +:description: pass:q[Perform the Advanced INCREMENT operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedIncrementOp` function: + +* Performs the Advanced INCREMENT operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation +* Counts the mutations subject to DCP deduplication + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-increment-op[Advanced INCREMENT Operation]. + +[{tabs}] +==== +advancedIncrementOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedIncrementOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("inc:")) return; + // log('input meta', meta); + // log('input doc ', doc); + + // Creates doc.count if it does not already exist + var ctr_meta = {"id": "my_atomic_counter:1" }; + var result = couchbase.increment(src_col,ctr_meta); + if (result.success) { + log('success adv. increment: result',result); + } else { + log('failure adv. increment: id',ctr_meta.id,'result',result); + } +} +---- +-- +Input data:: ++ +-- +[source,json] +---- +UPSERT INTO `bulk`.`data`.`source` (KEY,VALUE) + VALUES ( "inc:1", {"somekey":"someValue"} ), + VALUES ( "inc:2", {"somekey":"someValue"} ), + VALUES ( "inc:3", {"somekey":"someValue"} ), + VALUES ( "inc:4", {"somekey":"someValue"} ), + VALUES ( "inc:5", {"somekey":"someValue"} ), + VALUES ( "inc:6", {"somekey":"someValue"} ), + VALUES ( "inc:7", {"somekey":"someValue"} ), + VALUES ( "inc:8", {"somekey":"someValue"} ), + VALUES ( "inc:9", {"somekey":"someValue"} ), + VALUES ( "inc:10", {"somekey":"someValue"} ); +---- +-- + +Output data:: ++ +Insert 10 documents and count the mutations through incrementing. ++ +-- +[source,json] +---- +KEY: my_atomic_counter:1 + +{ + "count": 10 +} +---- +-- + +Output log:: ++ +-- +[source,json] +---- +2021-01-08T12:30:59.910-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":1},"meta":{"id":"my_atomic_counter:1","cas":"1610137859908960256"},"success":true} + +2021-01-08T12:30:59.910-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":2},"meta":{"id":"my_atomic_counter:1","cas":"1610137859909222400"},"success":true} + +2021-01-08T12:30:59.911-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":3},"meta":{"id":"my_atomic_counter:1","cas":"1610137859911385088"},"success":true} + +2021-01-08T12:30:59.931-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":4},"meta":{"id":"my_atomic_counter:1","cas":"1610137859929997312"},"success":true} + +2021-01-08T12:30:59.931-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":5},"meta":{"id":"my_atomic_counter:1","cas":"1610137859930193920"},"success":true} + +2021-01-08T12:30:59.932-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":6},"meta":{"id":"my_atomic_counter:1","cas":"1610137859932160000"},"success":true} + +2021-01-08T12:30:59.932-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":7},"meta":{"id":"my_atomic_counter:1","cas":"1610137859932356608"},"success":true} + +2021-01-08T12:30:59.948-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":8},"meta":{"id":"my_atomic_counter:1","cas":"1610137859946381312"},"success":true} + +2021-01-08T12:30:59.948-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":9},"meta":{"id":"my_atomic_counter:1","cas":"1610137859946708992"},"success":true} + +2021-01-08T12:30:59.948-08:00 [INFO] "success adv. increment: result" +{"doc":{"count":10},"meta":{"id":"my_atomic_counter:1","cas":"1610137859948412928"},"success":true} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedInsertOp.adoc b/modules/eventing/pages/eventing-handler-advancedInsertOp.adoc new file mode 100644 index 000000000..d0cac0065 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedInsertOp.adoc @@ -0,0 +1,224 @@ += Function: Advanced INSERT Operation +:description: pass:q[Perform the Advanced INSERT operation where Eventing interacts with the Data Service.]] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedInsertOp` function: + +* Performs the Advanced INSERT operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where `doc.type === "control_adv_insert"` + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-insert-op[Advanced INSERT Operation]. + +[{tabs}] +==== +advancedInsertOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedInsertOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("control_adv_insert")) return; + log('input meta', meta); + log('input doc ', doc); + // two modes: typical insert and setting an expiration/TTL + var new_meta = {"id":"test_adv_insert:"+doc.ins_id}; + if (doc.set_expiry && doc.set_expiry === true) { + new_meta = {"id":"test_adv_insert:"+doc.ins_id, expiry_date: new Date(Date.now() + 60 * 1000)}; + } + var new_doc = { type: "test_adv_insert", id:+doc.ins_id, random: Math.random()} + var result = couchbase.insert(src_col,new_meta,new_doc); + if (result.success) { + log('success adv. insert: result',result); + } else { + log('failure adv. insert: id',new_meta.id,'result',result); + } +} +---- +-- +Input data:: ++ +-- +[source,json] +---- +Mutation #1 + +INPUT: KEY control_adv_insert::1 + +{ + "id": 1, + "type": "control_adv_insert", + "ins_id": 1, + "set_expiry": false +} + +Mutation #2 + +INPUT: KEY control_adv_insert::2 + +{ + "id": 2, + "type": "control_adv_insert", + "ins_id": 2, + "set_expiry": true +} + +Mutation #3 + +INPUT: KEY control_adv_insert::3 + +{ + "id": 3, + "type": "control_adv_insert", + "ins_id": 1, + "set_expiry": false +} +---- +-- ++ +Output data:: ++ +The output data inserts 3 documents. +The first 2 insertions are successful. +The `test_adv_insert: 2` has an expiration of 60 seconds. +The third insertion attempt fails because `test_adv_insert: 1` already exists. ++ +-- +[source,json] +---- +KEY: test_adv_insert:1 + +{ + "type": "test_adv_insert", + "id": 1, + "random": 0.6213609884848352 +} + +KEY: test_adv_insert:2 + +{ + "type": "test_adv_insert", + "id": 2, + "random": 0.005665509244788591 +} +---- +-- ++ +Output log:: ++ +-- +[source,json] +---- +Logs from Mutation #1 + +2021-01-07T16:52:24.525-08:00 [INFO] "input meta" +{ + "cas": "1610067144497299456", + "id": "control_adv_insert::1", + "expiration": 0, + "flags": 33554438, + "vb": 651, + "seq": 6 +} +2021-01-07T16:52:24.525-08:00 [INFO] "input doc " +{ + "id": 1, + "type": "control_adv_insert", + "ins_id": 1, + "set_expiry": false +} +2021-01-07T16:52:24.527-08:00 [INFO] "success adv. insert: result" +{ + "meta": { + "id": "test_adv_insert:1", + "cas": "1610067144526397440" + }, + "success": true +} + +Logs from Mutation #2 + +2021-01-07T16:52:48.243-08:00 [INFO] "input meta" +{ + "cas": "1610067168218185728", + "id": "control_adv_insert::2", + "expiration": 0, + "flags": 33554438, + "vb": 898, + "seq": 3 +} +2021-01-07T16:52:48.243-08:00 [INFO] "input doc " +{ + "id": 2, + "type": "control_adv_insert", + "ins_id": 2, + "set_expiry": true +} +2021-01-07T16:52:48.245-08:00 [INFO] "success adv. insert: result" +{ + "meta": { + "id": "test_adv_insert:2", + "cas": "1610067168243810304", + "expiry_date": "2021-01-08T00:53:48.000Z" + }, + "success": true +} + +Logs from Mutation #3 + +2021-01-07T16:53:20.498-08:00 [INFO] "input meta" +{ + "cas": "1610067200451018752", + "id": "control_adv_insert::3", + "expiration": 0, + "flags": 33554438, + "vb": 133, + "seq": 1 +} +2021-01-07T16:53:20.498-08:00 [INFO] "input doc " +{ + "id": 3, + "type": "control_adv_insert", + "ins_id": 1, + "set_expiry": false +} +2021-01-07T16:53:20.500-08:00 [INFO] "failure adv. insert: id" "test_adv_insert:1" "result" +{ + "error": { + "code": 272, + "name": "LCB_KEY_EEXISTS", + "desc": "The document key already exists in the server.", + "key_already_exists": true + }, + "success": false +} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedLookupInOp.adoc b/modules/eventing/pages/eventing-handler-advancedLookupInOp.adoc new file mode 100644 index 000000000..5bab06f88 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedLookupInOp.adoc @@ -0,0 +1,80 @@ += Function: Advanced Sub-Document LOOKUPIN Operation +:description: pass:q[Perform the Advanced Sub-Document LOOKUPIN operation on a field where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedLookupInField` function: + +* Demonstrates the CAS-free Sub-Document LOOKUPIN operation on a document field +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where the `meta.id` or KEY starts with `lookupinfield:` + +For more information about the Advanced Sub-Document LOOKUPIN operation, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-subdoc-array-op-lookupin[Sub-Document LOOKUPIN Operation]. + +[{tabs}] +==== +advancedLookupInField:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedLookupInField function as follows: +// +// Version 7.6+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" + +function OnUpdate(doc, meta, xattrs) { + if (meta.id.startsWith("lookupinfield:") === false) return; + + var meta = { "id": meta.id }; + var res; + var opcnt = 1; + + res = + couchbase.lookupIn(src_col, meta, [ + couchbase.LookupInSpec.get("", {"xattrs": false}), + couchbase.LookupInSpec.get("") + ]); + log(opcnt++,res); +} +---- +-- + +Input data:: ++ +-- +[source,json] +---- +INPUT: KEY lookupinfield:001 + +{ + "id": "lookupinfield:001", +} + +---- +-- + +Output data:: ++ +-- +[source,json] +---- +2024-03-15T14:42:53.314-07:00 [INFO] 1 {"meta":{"id":"lookupinfield:001","cas":"1710538973313433600"},"success":true} + +2024-03-15T14:42:53.316-07:00 [INFO] 2 {"meta":{"id":"lookupinfield:001","cas":"1710538973315596288"},"success":true} + +2024-03-15T14:42:53.317-07:00 [INFO] 3 {"meta":{"id":"lookupinfield:001","cas":"1710538973316841472"},"success":true} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advancedMutateInArray.adoc b/modules/eventing/pages/eventing-handler-advancedMutateInArray.adoc new file mode 100644 index 000000000..a80b6fe47 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedMutateInArray.adoc @@ -0,0 +1,84 @@ += Function: Advanced Sub-Document MUTATEIN Array Operation +:description: pass:q[Perform the Advanced Sub-Document MUTATEIN operation on an array where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedMutateInArray` function: + +* Demonstrates the CAS-free Sub-Document MUTATEIN operation on a document array field +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where the `meta.id` or KEY is `combine_landmark_names` + +For example, you can generate an input document with the KEY `combine_landmark_names` and the DATA `{ "id": "combine_landmark_names", "landmark_names": [] }`, then set the number of workers in the Eventing Function's setting to 18. +Running the Function adds 4,495 landmark names to an array without conflict and in no particular order. + +For more information about the Advanced Sub-Document MUTATEIN operation, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-subdoc-array-op-mutatein[Sub-Document MUTATEIN Operation]. + +[{tabs}] +==== +advancedMutateInArray:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedMutateInArray function as follows: +// +// Version 7.6+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// "Listen to Location" +// travel-sample.inventory.landmark +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "dst_col", "bulk.data.source", "read and write" + +function OnUpdate(doc, meta) { + var accum_meta = {"id": "combine_landmark_names" }; + couchbase.mutateIn(dst_col, accum_meta, [ + couchbase.MutateInSpec.arrayAppend("landmark_names", doc.name), + ]); +} +---- +-- + +Input data before deployment:: ++ +-- +[source,json] +---- +INPUT: KEY combine_landmark_names + +{ + "id": "combine_landmark_names", + "landmark_names": [] +} +---- +-- + +Output data after deployment:: ++ +-- +[source,json] +---- +OUTPUT: KEY combine_landmark_names + +{ + "id": "combine_landmark_names", + "landmark_names": [ + "Gabriel's Wharf", + "Blue Bear Performance Hall", + "Circle Bar", + *** 4490 lines removed *** + "Quarry Bank Mill & Styal Estate", + "Mad Cat Brewery", + "Casbah Café" + ] +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advancedMutateInField.adoc b/modules/eventing/pages/eventing-handler-advancedMutateInField.adoc new file mode 100644 index 000000000..4a1ba67eb --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedMutateInField.adoc @@ -0,0 +1,91 @@ += Function: Advanced Sub-Document MUTATEIN Operation +:description: pass:q[Perform the Advanced Sub-Document MUTATEIN operation on a field where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedMutateInField` function: + +* Demonstrates the CAS-free Sub-Document MUTATEIN operation on a document field +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where the `meta.id` or KEY starts with `mutateinfield:` + +For more information about the Advanced Sub-Document MUTATEIN operation , see xref:eventing-advanced-keyspace-accessors.adoc#advanced-subdoc-array-op-mutatein[Sub-Document MUTATEIN Operation]. + +[{tabs}] +==== +advancedMutateInField:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedMutateInField function as follows: +// +// Version 7.6+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" + +function OnUpdate(doc, meta) { + if (meta.id.startsWith("mutateinfield:") === false) return; + + var meta = { "id": meta.id }; + var res; + var opcnt = 1; + + res = + couchbase.mutateIn(src_col, meta, [ + couchbase.MutateInSpec.insert("testField", "insert") + ]); + log(opcnt++,res); + + res = + couchbase.mutateIn(src_col, meta, [ + couchbase.MutateInSpec.replace("testField", "replace") + ]); + log(opcnt++,res); + + res = + couchbase.mutateIn(src_col, meta, [ + couchbase.MutateInSpec.remove("testField") + ]); + log(opcnt++,res); +} +---- +-- + +Input data:: ++ +-- +[source,json] +---- +INPUT: KEY mutateinfield:001 + +{ + "id": "mutateinfield:001", +} + +---- +-- + +Output data:: ++ +-- +[source,json] +---- +2024-03-15T14:42:53.314-07:00 [INFO] 1 {"meta":{"id":"mutateinfield:001","cas":"1710538973313433600"},"success":true} + +2024-03-15T14:42:53.316-07:00 [INFO] 2 {"meta":{"id":"mutateinfield:001","cas":"1710538973315596288"},"success":true} + +2024-03-15T14:42:53.317-07:00 [INFO] 3 {"meta":{"id":"mutateinfield:001","cas":"1710538973316841472"},"success":true} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advancedReplaceOp.adoc b/modules/eventing/pages/eventing-handler-advancedReplaceOp.adoc new file mode 100644 index 000000000..8cdb54e9d --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedReplaceOp.adoc @@ -0,0 +1,237 @@ += Function: Advanced REPLACE Operation +:description: pass:q[Perform the Advanced REPLACE operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedReplaceOp` function: + +* Performs the Advanced REPLACE operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where `doc.type === "control_adv_replace"` +* Always tries to insert the test document and ignores insert errors +* Has 3 modes of operation: `no_cas`, `bad_cas`, and `good_cas` + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-replace-op[Advanced REPLACE Operation]. + +[{tabs}] +==== +advancedReplaceOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedReplaceOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("control_adv_replace")) return; + + log('input meta', meta); + log('input doc ', doc); + + // Setup, make sure there is a doc to "replace", ignore any errors + couchbase.insert(src_col,{"id":"test_adv_replace:" + doc.ins_id},{"a:": 1}); + + var new_meta; + if (doc.mode && doc.mode === "no_cas") { + // No CAS is passed - it always succeeds + new_meta = {"id":"test_adv_replace:" + doc.ins_id}; + // (Optional) Set an expiry 60 seconds in the future + // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); + } + if (doc.mode && doc.mode === "bad_cas") { + // Pass a non-matching CAS - it always fails + new_meta = {"id":"test_adv_replace:" + doc.ins_id, "cas":"1111111111111111111"}; + } + if (doc.mode && doc.mode === "good_cas") { + // Pass the matching or current CAS - it succeeds + var tmp_r = couchbase.get(src_col,{"id":"test_adv_replace:" + doc.ins_id}); + if (tmp_r.success) { + // Use the current CAS to read via couchbase.get(...) + new_meta = {"id":"test_adv_replace:" + doc.ins_id, "cas": tmp_r.meta.cas}; + } else { + log('Cannot replace due to no such key',"test_adv_replace:" + doc.ins_id); + return; + } + } + var new_doc = {id: doc.ins_id, type: "test_adv_replace", random: Math.random()}; + var result = couchbase.replace(src_col,new_meta,new_doc); + if (result.success) { + log('success adv. replace: result',result); + } else { + log('failure adv. replace: id',new_meta.id,'result',result); + } +} +---- +-- +Input data:: ++ +-- +[source,json] +---- +Mutation #1 + +INPUT: KEY control_adv_replace::1 + +{ + "id": 1, + "type": "control_adv_replace", + "ins_id": 10, + "mode": "no_cas" +} + +Mutation #2 + +INPUT: KEY control_adv_replace::2 + +{ + "id": 2, + "type": "control_adv_replace", + "ins_id": 10, + "mode": "bad_cas" +} + +Mutation #3 + +INPUT: KEY control_adv_replace::3 + +{ + "id": 3, + "type": "control_adv_replace", + "ins_id": 10, + "mode": "good_cas" +} +---- +-- ++ +Output data:: ++ +Replace 3 documents. +The first and last replacements are successful; the second replacement fails because of a CAS mismatch. ++ +-- +[source,json] +---- +KEY: test_adv_replace:10 + +{ + "id": 10, + "type": "test_adv_replace", + "random": 0.40223830137164085 +} +---- +-- ++ +Output log:: ++ +-- +[source,json] +---- +Logs from Mutation #1 + +2021-01-08T10:58:39.846-08:00 [INFO] "input meta" +{ + "cas": "1610131902064820224", + "id": "control_adv_replace::1", + "expiration": 0, + "flags": 33554438, + "vb": 417, + "seq": 4 +} +2021-01-08T10:58:39.846-08:00 [INFO] "input doc " +{ + "id": 1, + "type": "control_adv_replace", + "ins_id": 10, + "mode": "no_cas" +} +2021-01-08T10:58:39.847-08:00 [INFO] "success adv. replace: result" +{ + "meta": { + "id": "test_adv_replace:10", + "cas": "1610132319847055360" + }, + "success": true +} + +Logs from Mutation #2 + +2021-01-08T10:59:04.151-08:00 [INFO] "input meta" +{ + "cas": "1610132344113397760", + "id": "control_adv_replace::2", + "expiration": 0, + "flags": 33554438, + "vb": 168, + "seq": 3 +} +2021-01-08T10:59:04.151-08:00 [INFO] "input doc " +{ + "id": 2, + "type": "control_adv_replace", + "ins_id": 10, + "mode": "bad_cas" +} +2021-01-08T10:59:04.154-08:00 [INFO] "failure adv. replace: id" "test_adv_replace:10" "result" +{ + "error": { + "code": 272, + "name": "LCB_KEY_EEXISTS", + "desc": "The document key exists with a CAS value different than specified", + "cas_mismatch": true + }, + "success": false +} + +Logs from Mutation #3 + +2021-01-08T10:59:35.692-08:00 [INFO] "input meta" +{ + "cas": "1610132375634706432", + "id": "control_adv_replace::3", + "expiration": 0, + "flags": 33554438, + "vb": 943, + "seq": 3 +} +2021-01-08T10:59:35.692-08:00 [INFO] "input doc " +{ + "id": 3, + "type": "control_adv_replace", + "ins_id": 10, + "mode": "good_cas" +} +2021-01-08T10:59:35.696-08:00 [INFO] "success adv. replace: result" +{ + "meta": { + "id": "test_adv_replace:10", + "cas": "1610132375695589376" + }, + "success": true +} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-advancedSelfRecursion.adoc b/modules/eventing/pages/eventing-handler-advancedSelfRecursion.adoc new file mode 100644 index 000000000..585cbe786 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedSelfRecursion.adoc @@ -0,0 +1,199 @@ += Function: Advanced Self-Recursion Parameter +:description: pass:q[Perform the Advanced Self-Recursion parameter where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedSelfRecursion` function: + +* Performs the Advanced Self-Recursion parameter +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where the `meta.id` or KEY starts with `doquery:` + +For more information about the Advanced Self-Recursion parameter, see xref:eventing-advanced-keyspace-accessors.adoc#optional-params-recursion[Optional { "self_recursion": true }` Parameter]. + +The following example shows you how to stop and restart a long-running process like a N1QL query. +It counts the number of hotels that start with a particular letter. + +[{tabs}] +==== +advancedSelfRecursion:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedSelfRecursion function as follows: +// +// Version 7.6+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// You must have the sample dataset travel-sample installed + +function OnUpdate(doc, meta) { + if ( meta.id.startsWith("doquery:") === false ) return; + if (doc.done && doc.done === true) return; + + if (! doc.continue) { + doc.queryBeg = new Date(); + doc.queryCnt = 0; + doc.currentQueryOffset = 0; + doc.namesProcessed = 0; + doc.letterHash = {}; + log(meta.id,'Query initialized at ' + doc.queryBeg); + } + + var offset = doc.currentQueryOffset; + var results = + SELECT name + FROM `travel-sample`.`inventory`.`hotel` + LIMIT 100 + OFFSET $offset; + + doc.queryCnt++; + doc.currentQueryOffset = doc.currentQueryOffset + 100; + + var loopCnt = 0; + for (var item of results) { + loopCnt++; + doc.namesProcessed++; + var name = item.name; + if (name && name.length > 0) { + // Extract the first character and convert it to lowercase + var firstChar = name[0].toLowerCase(); + + // If the letter exists in the hash, increment its count. Otherwise initialize it to 1. + if (doc.letterHash[firstChar]) { + doc.letterHash[firstChar]++; + } else { + doc.letterHash[firstChar] = 1; + } + } + } + results.close(); + + if (loopCnt < 100) { + // we are done + if (doc.continue) delete doc.continue + doc.done = true; + doc.queryEnd = new Date(); + log(meta.id,'Query cnt complete mutations ' + doc.queryCnt + ' namesProcessed ' + doc.namesProcessed ); + log(meta.id,'Query completed at ' + doc.queryEnd); + log(meta.id,'Result hotels starting with "a" ' + doc.letterHash['a'] + ', hotels starting with "b" ' + doc.letterHash['b'] + ', ...'); + // no self recursion + src_col[meta.id] = doc; + } else { + // we are not done + doc.continue = true; + log(meta.id,'Query cnt in progress mutations ' + doc.queryCnt + ' namesProcessed ' + doc.namesProcessed ); + // using self recursion results in a continuation of the query + couchbase.upsert(src_col, meta, doc, { "self_recursion": true }); + } +} +---- +-- + +Input data:: ++ +-- +[source,json] +---- +INPUT: KEY doquery:001 + +{ + "id": "doquery:001" +} + +---- +-- + +Output data:: ++ +-- +[source,json] +---- +OUTPUT: KEY doquery:001 +{ + "id": "doquery:001", + "queryBeg": "2024-03-15T21:07:38.114Z", + "queryCnt": 10, + "currentQueryOffset": 1000, + "namesProcessed": 917, + "letterHash": { + "1": 1, + "5": 2, + "8": 1, + "m": 58, + "t": 127, + "l": 41, + "g": 25, + "w": 27, + "a": 33, + "b": 48, + "r": 35, + "h": 168, + "n": 19, + "o": 15, + "p": 41, + "s": 64, + "c": 84, + "i": 23, + "u": 8, + "k": 15, + "j": 7, + "'": 1, + "e": 16, + "d": 21, + "q": 4, + "f": 16, + "y": 5, + "v": 12 + }, + "done": true, + "queryEnd": "2024-03-15T21:07:38.425Z" +} +---- +-- + +Output log:: ++ +-- +[source,json] +---- +2024-03-15T14:07:38.116-07:00 [INFO] "doquery:001" "Query initialized at Fri Mar 15 2024 14:07:38 GMT-0700 (Pacific Daylight Time)" + +2024-03-15T14:07:38.159-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 1 namesProcessed 100" + +2024-03-15T14:07:38.175-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 2 namesProcessed 200" + +2024-03-15T14:07:38.191-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 3 namesProcessed 300" + +2024-03-15T14:07:38.204-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 4 namesProcessed 400" + +2024-03-15T14:07:38.217-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 5 namesProcessed 500" + +2024-03-15T14:07:38.351-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 6 namesProcessed 600" + +2024-03-15T14:07:38.376-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 7 namesProcessed 700" + +2024-03-15T14:07:38.396-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 8 namesProcessed 800" + +2024-03-15T14:07:38.413-07:00 [INFO] "doquery:001" "Query cnt in progress mutations 9 namesProcessed 900" + +2024-03-15T14:07:38.425-07:00 [INFO] "doquery:001" "Query cnt complete mutations 10 namesProcessed 917" + +2024-03-15T14:07:38.425-07:00 [INFO] "doquery:001" "Query completed at Fri Mar 15 2024 14:07:38 GMT-0700 (Pacific Daylight Time)" + +2024-03-15T14:07:38.425-07:00 [INFO] "doquery:001" "Result hotels starting with \"a\" 33, hotels starting with \"b\" 48, ..." +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advancedTouchOp.adoc b/modules/eventing/pages/eventing-handler-advancedTouchOp.adoc new file mode 100644 index 000000000..17cb4bec6 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedTouchOp.adoc @@ -0,0 +1,119 @@ += Function: Advanced TOUCH Operation +:description: pass:q[Perform the Advanced TOUCH operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedTouchOp` function: + +* Performs the Advanced TOUCH operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where the `meta.id` or KEY starts with `ten_seconds:` +* Does not require that you send the document back to the Data Service to update the TTL + +For more information about the Advanced TOUCH operation, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-touch-op[Advanced TOUCH Operation]. + +[{tabs}] +==== +advancedTouchOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedTouchOp function as follows: +// +// Version 7.6+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" + +function OnUpdate(doc, meta) { + if (! meta.id.startsWith("ten_seconds:") ) return; + + log('input meta', meta); + log('input doc', doc); + + var expiry = new Date(); + expiry.setSeconds(expiry.getSeconds() + 10); + + var req = {"id": meta.id, "expiry_date": expiry}; + var result = couchbase.touch(src_col, req); + if (result.success) { + log('success adv. touch: result', result); + } else { + log('failure adv. touch: id', req.id, 'result', result); + } +} +---- +-- + +Input Data:: ++ +-- +[source,json] +---- +INPUT: KEY ten_seconds:001 + +{ + "id": "ten_seconds:001", + "type": "Auto-deletes in 10 seconds. Keep refreshing to retrieve documents." +} + +---- +-- + +Output Data:: ++ +-- +[source,json] +---- + +2024-03-15T11:57:51.103-07:00 [INFO] "input doc" +{ + "id": "ten_seconds:001", + "type": "Auto-deletes in 10 seconds. Keep refreshing to retrieve documents." +} + +2024-03-15T11:57:51.103-07:00 [INFO] "input meta" +{ + "cas": "1710529071079817216", + "id": "ten_seconds:001", + "expiration": 0, + "flags": 33554438, + "vb": 679, + "seq": 102, + "datatype": "json", + "keyspace": + { + "bucket_name": "travel-sample", + "scope_name": "tenant_agent_00", + "collection_name": "bookings" + }, + "cid": 18 +} + +2024-03-15T11:57:51.108-07:00 [INFO] "success adv. touch: result" +{ + "meta": + { + "id": "ten_seconds:001", + "cas": "1710529071107276800" + }, + "success": true +} + +2024-03-15T11:58:03.302-07:00 [INFO] "Doc deleted/expired" "ten_seconds:001" +{ + "expired": true +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-advancedUpsertOp.adoc b/modules/eventing/pages/eventing-handler-advancedUpsertOp.adoc new file mode 100644 index 000000000..ba5d54205 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-advancedUpsertOp.adoc @@ -0,0 +1,223 @@ += Function: Advanced UPSERT Operation +:description: pass:q[Perform the Advanced UPSERT operation where Eventing interacts with the Data Service.] +:page-edition: Enterprise Edition +:tabs: + +{description} + +The `advancedUpsertOp` function: + +* Performs the Advanced UPSERT operation +* Requires Eventing Storage (or a metadata collection) and a source collection +* Requires a binding of type `bucket alias` +* Operates on any mutation where `doc.type === "control_adv_insert"` + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#advanced-upsert-op[Advanced UPSERT Operation]. + +[{tabs}] +==== +advancedUpsertOp:: ++ +-- +[source,javascript] +---- +// Configure the settings for the advancedUpsertOp function as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.1 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (!meta.id.startsWith("control_adv_upsert")) return; + log('input meta', meta); + log('input doc ', doc); + // two modes: typical upsert and setting an expiration/TTL + // note that CAS, if supplied, is ignored. You can use REPLACE instead. + var new_meta = {"id":"test_adv_upsert:"+doc.ins_id}; + if (doc.set_expiry && doc.set_expiry === true) { + new_meta = {"id":"test_adv_upsert:"+doc.ins_id, expiry_date: new Date(Date.now() + 60 * 1000)}; + } + var new_doc = { type: "test_adv_upsert", id:+doc.ins_id, random: Math.random()} + var result = couchbase.upsert(src_col,new_meta,new_doc); + if (result.success) { + log('success adv. upsert: result',result); + } else { + log('failure adv. upsert: id',new_meta.id,'result',result); + } +} +---- +-- +Input data:: ++ +-- +[source,json] +---- +Mutation #1 + +INPUT: KEY control_adv_upsert::1 + +{ + "id": 1, + "type": "control_adv_upsert", + "ins_id": 1, + "set_expiry": false +} + +Mutation #2 + +INPUT: KEY control_adv_upsert::2 + +{ + "id": 2, + "type": "control_adv_upsert", + "ins_id": 2, + "set_expiry": true +} + +Mutation #3 + +INPUT: KEY control_adv_upsert::3 + +{ + "id": 3, + "type": "control_adv_upsert", + "ins_id": 1, + "set_expiry": false +} +---- +-- ++ +Output data:: ++ +The output data upserts 3 documents. +The first 2 upsertions are successful. +The `test_adv_insert: 2` has an expiration of 60 seconds. +The third upsertion attempt fails because `test_adv_insert: 1` already exists. ++ +-- +[source,json] +---- +KEY: test_adv_upsert:1 + +{ + "type": "test_adv_upsert", + "id": 1, + "random": 0.24687491488383362 +} + +KEY: test_adv_upsert:2 + +{ + "type": "test_adv_upsert", + "id": 2, + "random": 0.08984103133112087 +} +---- +-- ++ +Output log:: ++ +-- +[source,json] +---- +Logs from Mutation #1 + +2021-01-07T17:43:52.527-08:00 [INFO] "input meta" +{ + "cas": "1610070232443518976", + "id": "control_adv_upsert::1", + "expiration": 0, + "flags": 33554438, + "vb": 334, + "seq": 1 +} +2021-01-07T17:43:52.527-08:00 [INFO] "input doc " +{ + "id": 1, + "type": "control_adv_upsert", + "ins_id": 1, + "set_expiry": false +} +2021-01-07T17:43:52.529-08:00 [INFO] "success adv. upsert: result" +{ + "meta": { + "id": "test_adv_upsert:1", + "cas": "1610070232527667200" + }, + "success": true +} + +Logs from Mutation #2 + +2021-01-07T17:44:21.926-08:00 [INFO] "input meta" +{ + "cas": "1610070261867741184", + "id": "control_adv_upsert::2", + "expiration": 0, + "flags": 33554438, + "vb": 71, + "seq": 1 +} +2021-01-07T17:44:21.926-08:00 [INFO] "input doc " +{ + "id": 2, + "type": "control_adv_upsert", + "ins_id": 2, + "set_expiry": true +} +2021-01-07T17:44:21.929-08:00 [INFO] "success adv. upsert: result" +{ + "meta": { + "id": "test_adv_upsert:2", + "cas": "1610070261927641088", + "expiry_date": "2021-01-08T01:45:21.000Z" + }, + "success": true +} + +Logs from Mutation #3 + +2021-01-07T17:44:58.063-08:00 [INFO] "input meta" +{ + "cas": "1610070298010845184", + "id": "control_adv_upsert::3", + "expiration": 0, + "flags": 33554438, + "vb": 832, + "seq": 1 +} +2021-01-07T17:44:58.063-08:00 [INFO] "input doc " +{ + "id": 3, + "type": "control_adv_upsert", + "ins_id": 1, + "set_expiry": false +} +2021-01-07T17:44:58.065-08:00 [INFO] "success adv. upsert: result" +{ + "meta": { + "id": "test_adv_upsert:1", + "cas": "1610070298064257024" + }, + "success": true +} +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-basicBinaryKV.adoc b/modules/eventing/pages/eventing-handler-basicBinaryKV.adoc new file mode 100644 index 000000000..bc53563d0 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-basicBinaryKV.adoc @@ -0,0 +1,129 @@ += Function: Basic Binary KV +:description: pass:q[Show Basic Bucket Op Binary Write and Read.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *basicBinaryKV* demonstrates creating, marshalling and unmarshalling binary docs. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Needs a Binding of type "bucket alias" (as documented in the Scriptlet). +* Will operate on any mutation where the KEY or meta.id starts with "basicbinarykv". +* The function will create one binary document and write it then read it back. +* The document written will be read back and verified demonstrating binary marshalling and unmarshalling. +* On a second deployment the binary doc that was written on the first deployment will cause a mutation. + +[{tabs}] +==== +basicBinaryKV:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, basicBinaryKV, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.6.2 +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + if (meta.id === "bindoc_kvput") { + // if we deploy/undeploy/deploy we will see the document we created on the first deploy + // Note that meta.datatype === "binary" on this mutation. + log ("4. received binary mutation",doc,"unmarshalled ("+new Uint8Array(doc)+") meta:",meta); + log ("5. deleting the binary doc with KEY 'bindoc_kvput'"); + delete src_col["bindoc_kvput"]; + return; + } + + if (!meta.id.startsWith("basicbinarykv") || src_col["bindoc_kvput"]) return; + + var arr = new Uint8Array([1, 0, 2, 3]); + var bindoc = arr.buffer; + + // Write via a Basic Bucket Op, i.e. JavaScript map exposed via a bucket binding. + // Note the JavaScript map only returns the doc (unlike the mutations received via + // OnUpate which also has meta) so do not know if we just read a binary doc or text + src_col["bindoc_kvput"] = bindoc; + + log ("1. wrote bindoc",bindoc,"unmarshalled ("+new Uint8Array(bindoc)+")"); + + // Read via a Basic Bucket Op, i.e. JavaScript map exposed via a bucket binding + var retdoc = src_col["bindoc_kvput"]; + + log ("2. read retdoc",retdoc) + log ("3. test bindoc("+ + new Uint8Array(bindoc)+") == retdoc("+ + new Uint8Array(retdoc)+") => " + buffersEqual(bindoc,retdoc)); +} + +function buffersEqual(buf1, buf2) { + if (buf1.byteLength != buf2.byteLength) return false; + var dv1 = new Uint8Array(buf1); + var dv2 = new Uint8Array(buf2); + for (var i = 0; i != buf1.byteLength; i++) { + if (dv1[i] != dv2[i]) return false; + } + return true; +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY basicbinarykv:1 + +{ + "id": 1, + "type": "basicbinarykv" +} +---- +-- + +Output Data/Logged:: ++ +FIRST DEPLOYMENT ++ +-- +[source,json] +---- +2021-04-10T15:13:14.903-07:00 [INFO] "1. wrote bindoc" {} "unmarshalled (1,0,2,3)" + +2021-04-10T15:13:14.904-07:00 [INFO] "2. read retdoc" {} + +2021-04-10T15:13:14.904-07:00 [INFO] "3. test bindoc(1,0,2,3) == retdoc(1,0,2,3) => true" +---- +-- ++ +SECOND DEPLOYMENT (note the "datatype" of "binary") ++ +-- +[source,json] +---- +2021-04-10T15:14:06.581-07:00 [INFO] "4. received binary mutation" {} "unmarshalled (1,0,2,3) meta:" +{"cas":"1618092795477098496","id":"bindoc_kvput","expiration":0,"flags":0,"vb":430,"seq":9,"datatype":"binary"} + +2021-04-10T15:14:06.581-07:00 [INFO] "5. deleting the binary with KEY 'bindoc_kvput'" +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-basicBucketOps.adoc b/modules/eventing/pages/eventing-handler-basicBucketOps.adoc new file mode 100644 index 000000000..9bff22c8b --- /dev/null +++ b/modules/eventing/pages/eventing-handler-basicBucketOps.adoc @@ -0,0 +1,101 @@ += Function: Basic Bucket Ops +:description: pass:q[Perform the basic bucket operations where Eventing interacts with the Data service.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *basicBucketOps* merely demonstrates Eventing's Basic Bucket Accessors or BucketOps. +* Requires Eventing Storage (or metadata collection), a "source" collection, and a "destination" collection. +* Needs a Binding of type Bucket Alias (as documented in the Scriptlet). +* Will operate on any mutation where doc.type === "basic_bkt_ops". +* The final document is deleted, as such the output is the Application log file. +* For more detail refer to xref:eventing-language-constructs.adoc#bucket_accessors[Bucket Accessors] + +[{tabs}] +==== +basicBucketOps:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, basicBucketOps, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "dst_col", "bulk.data.destination", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "dst_col", "destination", "read and write" + +function OnUpdate(doc, meta) { + // filter out non-interesting docs + if (doc.type !== "basic_bkt_ops") return; + // Assuming 'dst_col' is a bucket alias binding in this case to a non source bucket + log("OnUpdate got mutation for id",meta.id,"doc",doc); + + // make a key based on the meta.id of the input mutation + var dst_key = "dst_" + meta.id; + // make a document to write, include the input mutation's doc + var doc_to_wr = {"status":3, "mutation": doc}; + + // this is a bucket SET operation. + dst_col[dst_key] = doc_to_wr; + log("wrote DOC to dst_col with id",dst_key,doc_to_wr); + + // this is a bucket GET operation. + var doc_read = dst_col[dst_key]; + log("read DOC from dst_col with id",dst_key,doc_read); + + // this is a bucket DEL operation. + delete dst_col[dst_key]; + log("deleted "+dst_key+" from dst_col"); +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY basic_bkt_ops::1 + +{ + "type": "basic_bkt_ops", + "id": 1, + "test": true +} + +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-18T17:56:56.021-07:00 [INFO] "read DOC from dst_col with id" "dst_basic_bkt_ops::1" {"status":3,"mutation":{"type":"basic_bkt_ops","id":1,"test":true}} + +2021-07-18T17:56:56.021-07:00 [INFO] "deleted dst_basic_bkt_ops::1 from dst_col" + +2021-07-18T17:56:56.020-07:00 [INFO] "wrote DOC to dst_col with id" "dst_basic_bkt_ops::1" {"status":3,"mutation":{"type":"basic_bkt_ops","id":1,"test":true}} + +2021-07-18T17:56:56.019-07:00 [INFO] "OnUpdate got mutation for id" "basic_bkt_ops::1" "doc" {"type":"basic_bkt_ops","id":1,"test":true} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-basicN1qlPreparedSelectStmt.adoc b/modules/eventing/pages/eventing-handler-basicN1qlPreparedSelectStmt.adoc new file mode 100644 index 000000000..770cc2e28 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-basicN1qlPreparedSelectStmt.adoc @@ -0,0 +1,100 @@ += Function: Basic {sqlpp} Prepared Select Statement +:description: pass:q[Iterate through a basic {sqlpp} SELECT where Eventing interacts with the Data service via a prepared {sqlpp} statement.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *basicN1qlPreparedSelectStmt* demonstrates how use a prepared {sqlpp} SELECT statement with a passed parameter. +* Typically, this is done for greater performance, the cluster will typically not prepare a statement if it is already prepared. +* We have just one positional parameter $1 for "doc.iata", if we had a second parameter we would use +the placeholder $2, and so on. Note positional parameters are passed in an array. +* A _commented out_ example of using named parameters is also shown. Note named parameters are passed and an object. +* Requires the "travel-sample" sample dataset to be loaded. +* Requires Eventing Storage (or metadata collection) and a "source" collection of travel-sample.inventory.airline. +* Deploy the Function with a Feed Boundary "From now" (Note you will log 187 lines if you use "Everything"). +* Assuming you deployed "From now" mutate any document in "travel-sample" to generate a log line. +* For additional details refer to xref:eventing-language-constructs.adoc#added-lang-features[{sqlpp} Statements] and +xref:eventing-language-constructs.adoc#n1ql_call[The N1QL() function call] +* [Optional] if Feed Boundary is "Everything" you can use {sqlpp} to add an index for performance: +** CREATE INDEX adv_airline_type ON `default`:`travel-sample`.`inventory`.`route`(`airline`) WHERE (`type` = 'route') + +[{tabs}] +==== +basicN1qlPreparedSelectStmt:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, basicN1qlPreparedSelectStmt, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try travel-sample.inventory if non-privileged) +// Version 7.0+ +// "Listen to Location" +// travel-sample.inventory.airline +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) - none +// +// Version 6.X +// "Source Bucket" +// travel-sample +// "MetaData Bucket" +// metadata +// Binding(s) - none + +function OnUpdate(doc, meta) { + // ignore information we don't care about + if (doc.type !== 'airline') return; + + var route_cnt = 0; // we want to get the total routes per iata + + // positional parameter(s) + var results = N1QL("SELECT COUNT(*) AS cnt " + + "FROM `travel-sample`.`inventory`.`route` " + + "WHERE type = \"route\" AND airline = $1", + [doc.iata], { isPrepared: true } + ); + + /* + // named parameter(s) + var max_dist = 120; + var results = N1QL("SELECT COUNT(*) AS cnt " + + "FROM `travel-sample`.`inventory`.`route` WHERE type = $mytype " + + "AND airline = $myairline AND distance <= $mydistance", + { '$mytype': 'route', '$mydistance': max_dist, '$myairline': doc.iata }, + { 'consistency': 'none', isPrepared: true } + ); + */ + + for (var item of results) { // Stream results using 'for' iterator. + route_cnt = item.cnt; + } + results.close(); // End the query and free resources held + + // Just log the KEY, AIRLINE and ROUTE_CNT it to the Application log + log("key: " + meta.id + ", airline: "+doc.iata+", route_cnt: "+route_cnt); +} +---- +-- + +Input Data/Mutation (via the following {sqlpp} statement):: ++ +-- +[source,sqlpp] +---- +UPDATE `travel-sample`.`inventory`.`route` USE KEYS "airline_24" SET id = 24; +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-19T07:48:10.810-07:00 [INFO] "key: airline_24, airline: AA, route_cnt: 2354" +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-basicN1qlSelectStmt.adoc b/modules/eventing/pages/eventing-handler-basicN1qlSelectStmt.adoc new file mode 100644 index 000000000..d50aa27fc --- /dev/null +++ b/modules/eventing/pages/eventing-handler-basicN1qlSelectStmt.adoc @@ -0,0 +1,83 @@ += Function: Basic {sqlpp} SELECT Statement +:description: pass:q[Iterate through a basic N1QL SELECT where Eventing interacts with the Data service via an inline {sqlpp} statement.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *basicN1qlSelectStmt* demonstrates how to use an inline N1QL SELECT statement with a passed parameter. +* Requires the "travel-sample" sample dataset to be loaded. +* Requires Eventing Storage (or metadata collection) and a "source" collection of travel-sample.inventory.airline. +* Assuming you deployed "From now" mutate any document in "travel-sample" to generate a log line. +* For more detail refer to xref:eventing-language-constructs.adoc#added-lang-features[{sqlpp} Statements]. +* Configure the Function with a Feed Boundary "From now" (Note you will log 187 lines if you use "Everything"). +* [Optional] if Feed Boundary is "Everything" you can use {sqlpp} to add an index for performance: +** CREATE INDEX adv_airline_type ON `default`:`travel-sample`.`inventory`.`route`(`airline`) WHERE (`type` = 'route') + +[{tabs}] +==== +basicN1qlSelectStmt:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, basicN1qlSelectStmt, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try travel-sample.inventory if non-privileged) +// Version 7.0+ +// "Listen to Location" +// travel-sample.inventory.airline +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) - none +// +// Version 6.X +// "Source Bucket" +// travel-sample +// "MetaData Bucket" +// metadata +// Binding(s) - none + +function OnUpdate(doc, meta) { + // ignore information we don't care about + if (doc.type !== 'airline') return; + + var route_cnt = 0; // we want to get the total routes per iata + var airline = doc.iata; // need a true variable as a SQL++ parameter + + var results = + SELECT COUNT(*) AS cnt + FROM `travel-sample`.`inventory`.`route` + WHERE type = "route" AND airline = $airline; + + for (var item of results) { // Stream results using 'for' iterator. + route_cnt = item.cnt; + } + results.close(); // End the query and free resources held + + // Just log the KEY, AIRLINE and ROUTE_CNT it to the Application log + log("key: " + meta.id + ", airline: "+doc.iata+", route_cnt: "+route_cnt); +} +---- +-- + +Input Data/Mutation (via the following {sqlpp} statement):: ++ +-- +[source,sqlpp] +---- +UPDATE `travel-sample`.`inventory`.`airline` USE KEYS "airline_24" SET id = 24 +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-19T07:37:39.237-07:00 [INFO] "key: airline_24, airline: AA, route_cnt: 2354" +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-cascadeKvDeleteWithDoc.adoc b/modules/eventing/pages/eventing-handler-cascadeKvDeleteWithDoc.adoc new file mode 100644 index 000000000..c517a0ba6 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-cascadeKvDeleteWithDoc.adoc @@ -0,0 +1,131 @@ += Function: cascadeKvDeleteWithDoc +:description: pass:q[Perform a cascade delete operation using just the Data Service (or KV).] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *cascadeKvDeleteWithDoc* merely demonstrates two different Eventing solutions +** A cascade delete using just KV or the Data Service. +** A work around for the fact that the OnDelete() entry point does not supply the actual document being deleted. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Needs a Binding of type Bucket Alias (as documented in the Scriptlet). +* Will utilize a special doc.type === "proxy" with a prefix KEY of "proxy::" where the suffix after "proxy::" is the KEY to the actual document. +* Will operate on any mutation where 1) doc.type exists and 2) doc.type !== "proxy". +* When a "proxy" document is deleted the corresponding "real" document is read from KV. This allows actions +such as cURL calls to be taken based on the data in the "real document. +* After the real document is read it is then deleted. +* This Scriptlet uses just KV unlike the similar example xref:eventing-examples-cascade-delete.adoc[Cascade Delete] which uses {sqlpp}. + +[{tabs}] +==== +cascadeKvDeleteWithDoc:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, cascadeKvDeleteWithDoc, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + // filter out any proxy:: docs, ignore all others + if ((meta.id).startsWith("proxy::") === true) return; + log('OnUpdate notified of insert/update to key', meta.id); +} + +function OnDelete(meta, options) { + // only process proxy:: docs, ignore all others + if ((meta.id).startsWith("proxy::") === false) return; + + // optional filter for just type == real or apply logic to all non 'proxy' types + // if ((meta.id).startsWith("real::") !== true) return; + + log('A. OnDelete notified of '+options.expired ? 'delete' : 'expiry'+' of proxy', meta.id); + var real_key = (meta.id).substr(7); + var real_doc = src_col[real_key]; + if (real_doc) { + delete src_col[real_key]; + log('B. OnDelete removed the real doc via key',real_key); + log('C. OnDelete do what you want curl, etc. with the real doc',real_doc) + } else { + log('D. OnDelete unexpected no real doc present for key', real_key); + } +} +---- +-- +We want a small "proxy" doc as a placeholder that we delete instead of the "real" document ++ +Input Data/Mutation(s):: ++ +-- +[source,json] +---- +INPUT: KEY: proxy::real::1 + +{ + "id": "real::1", + "type": "proxy" +} + +---- +-- ++ +-- +[source,json] +---- +INPUT: KEY: real::1 + +{ + "id": 1, + "type": "real", + "f1": "yes", + "f2": 1100, + "fn": "n" +} + +---- +-- +Steps to run: ++ +* Deploy the function +* Then add the two test documents via the UI's doc editor. +* Then delete the proxy:real::1 doc via the UI’s doc editor. +* The OnDelete() function will: +** Read and store the "real" doc for processing based on the "real" doc's internal data. +** Perform a cascade delete of the "real" doc. ++ +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-18T20:08:04.459-07:00 [INFO] "C. OnDelete do what you want curl, etc. with the real doc" {"id":1,"type":"real","f1":"yes","f2":1100,"fn":"n"} + +2021-07-18T20:08:04.459-07:00 [INFO] "B. OnDelete removed the real doc via key" "real::1" + +2021-07-18T20:08:04.457-07:00 [INFO] "A. OnDelete notified of expiry of proxy" "proxy::real::1" + +2021-07-18T20:08:00.757-07:00 [INFO] "OnUpdate notified of insert/update to key" "real::1" +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-convertAdvXMLtoJSON.adoc b/modules/eventing/pages/eventing-handler-convertAdvXMLtoJSON.adoc new file mode 100644 index 000000000..ce4cc3d61 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-convertAdvXMLtoJSON.adoc @@ -0,0 +1,287 @@ += Function: convertAdvXMLtoJSON +:description: pass:q[Recursively and generically convert advanced XML strings into JSON.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *convertAdvXMLtoJSON* shows how to convert advanced XML strings into JSON. +* This function will handle items and constructs that *xref:eventing-handler-convertXMLtoJSON.adoc[convertXMLtoJSON]* will fail on 1) empty-element tags and 2) attributes. ++ +-- +[source,javascript] +---- + + + + + SUBDATA + + +---- +-- +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on any mutation where the KEY or meta.id starts with "xml:". +* Will enrich the source document with a new JSON object representing the XML data. +* Maintains a checksum to prevent the overhead of conversion if the property `in_xml` is unchanged. + +[{tabs}] +==== +convertAdvXMLtoJSON:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, convertAdvXMLtoJSON, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +// =============================================================== +// THIS IS AN APPLICATION SPECIFIC CUSTOM TRANSFOMRATION ON NEED +function customParseFixups(key,tmp) { + // typically we would test the key for a name where we want to transform the value + + // Example 1: + // if (key === "resultStr") { + // // makes an array of strings + // // var data_array = tmp.trim().split(' '); + // return data_array; + // } + + // Example 2: + // if (key === "resultNumStr") { + // // makes an array of numbers + // // var data_array = tmp.trim().split(' ').map(str => Number(str)); + // return data_array; + // } + + // Do nothing this is a NOOP + return tmp; +} +// =============================================================== + +function OnUpdate(doc, meta) { + // filter out non XML + if (!meta.id.startsWith("advxml:")) return; + // The KEY started with "advxml" try to process it + // =========================================================== + // *** Do other work required here on non .in_xml changes *** + // =========================================================== + // let's see if we need to re-create our json representation. + var xmlchksum = crc64(doc.in_xml); + // =========================================================== + // Don't reprocess if the doc.in_xml has not changed this could be + // a big performance win if the doc has other fields that mutate. + // We do this via a checksum of the .in_xml property. + if (doc.xmlchksum && doc.xmlchksum === xmlchksum) return; + // Either this is the first pass, or the .in_xml property changed. + var jsonDoc = parseAdvXmlToJson(doc.in_xml); + log(meta.id,"1. INPUT xml doc.in_xml :", doc.in_xml); + log(meta.id,"2. CHECKSUM doc.in_xml :", xmlchksum); + log(meta.id,"3. OUTPUT doc.out_json :", jsonDoc); + doc.out_json = jsonDoc; + doc.xmlchksum = xmlchksum; + // =========================================================== + // enrich the source collection with .out_json and .xmlchksum + src_col[meta.id] = doc; +} + +// 7.0.0 version uses String.matchAll eliminates the need to make our own MatchAll function call as parseXmlToJson(xml) +function parseAdvXmlToJson(xml, recurs) { + const json = {}; + if (!recurs) { + // 1st call, Fix bad closures, Transform Example : '' becomes '' + xml = xml.replace(/\"\s*>/g, '" />'); + // 1st call, Transform Example : '' becomes 'attrValue' + xml = xml.replace(/<\s*([^\/><\s]+)\s+(\w[^<>]*)(\s*\/>)/gm, '<$1 $2>'); + } + for (const res of xml.matchAll(/(?:<([\w:]*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<([\w:]*)(?:\s*)*\/>/gm)) { + // find all sest of 1..N attributes if any + var attrs = {}; + for (const res1 of res[0].matchAll(/<\s*(\w[^\/><\s]*)\s+(\w[^<]*[^=<]\s*[=]\s*[\'\"][^<]+[\'\"])\s*>([^<>]*)value1 + log('Illegal can not have bare "' + res1[3] + '" value if we have attr(s) input:', res1[0]); + return null; + } else { + for (const res2 of res1[2].matchAll(/(\w+[^=<>]*)\s*[=]\s*[\"]([^\"]+)[\"]|(\w+[^=<>]*)\s*[=]\s*[\']([^\']+)[\']/gm)) { + if (res2[1] !== "") attrs[res1[1]][res2[1]] = res2[2]; + if (res2[3] !== "") attrs[res1[1]][res2[3]] = res2[4]; + } + } + } + const key = res[1] || res[3]; + var value = res[2] && parseAdvXmlToJson(res[2], true); + if (res[2] === "" && Object.keys(attrs).length > 0) { + value = {}; + } + if (attrs[key]) { + for (const p in attrs[key]) { + if (attrs[key][p]) { + value[p] = attrs[key][p]; + } + } + } + attrs = {}; + var tmp = ((value && Object.keys(value).length) ? value : res[2]) || null; + if (Array.isArray(json[key]) == false) { + if (json[key]) { + // we have seen this key before change from object to an array of objects + var old = json[key]; + json[key] = []; + json[key].push(old); + json[key].push(tmp); + } else { + // link to a custom function + tmp = customParseFixups(key,tmp); + json[key] = tmp; + } + } else { + json[key].push(tmp); + } + } + return json; +} + +/* +// need this for 6.6.0 version +function* MatchAll(str, regExp) { + if (!regExp.global) { + throw new TypeError('Flag /g must be set!'); + } + const localCopy = new RegExp(regExp, regExp.flags); + let match; + while (match = localCopy.exec(str)) { + yield match; + } +} + +// 6.6.0 version no String.matchAll need our own MatchAll function, call as parseXmlToJson(xml) +function parseAdvXmlToJson(xml, recurs) { + const json = {}; + if (!recurs) { + // 1st call, Fix bad closures, Transform Example : '' becomes '' + xml = xml.replace(/\"\s*>/g, '" />'); + // 1st call, Transform Example : '' becomes '' + xml = xml.replace(/<\s*([^\/><\s]+)\s+(\w[^<>]*)(\s*\/>)/gm, '<$1 $2>'); + } + for (const res of MatchAll(xml, /(?:<([\w:]*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<([\w:]*)(?:\s*)*\/>/gm)) { + // find all sest of 1..N attributes if any + var attrs = {}; + for (const res1 of MatchAll(res[0], /<\s*(\w[^\/><\s]*)\s+(\w[^<]*[^=<]\s*[=]\s*[\'\"][^<]+[\'\"])\s*>([^<>]*)value1 + log('Illegal can not have bare "' + res1[3] + '" value if we have attr(s) input:', res1[0]); + return null; + } else { + for (const res2 of MatchAll(res1[2], /(\w+[^=<>]*)\s*[=]\s*[\"]([^\"]+)[\"]|(\w+[^=<>]*)\s*[=]\s*[\']([^\']+)[\']/gm)) { + if (res2[1] !== "") attrs[res1[1]][res2[1]] = res2[2]; + if (res2[3] !== "") attrs[res1[1]][res2[3]] = res2[4]; + } + } + } + const key = res[1] || res[3]; + var value = res[2] && parseAdvXmlToJson(res[2], true); + if (res[2] === "" && Object.keys(attrs).length > 0) { + value = {}; + } + if (attrs[key]) { + for (const p in attrs[key]) { + if (attrs[key][p]) { + value[p] = attrs[key][p]; + } + } + } + attrs = {}; + var tmp = ((value && Object.keys(value).length) ? value : res[2]) || null; + if (Array.isArray(json[key]) == false) { + if (json[key]) { + // we have seen this key before change from object to an array of objects + var old = json[key]; + json[key] = []; + json[key].push(old); + json[key].push(tmp); + } else { + // link to a custom function + tmp = customParseFixups(key,tmp); + json[key] = tmp; + } + } else { + json[key].push(tmp); + } + } + return json; +} +*/ +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY advxml::1 + +{ + "type": "advxml", + "id": 1, + "in_xml": "SUBDATAEmpireBurlesqueBobDylanUSAColumbia10.901985" +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY advxml::1 + +{ + "type": "advxml", + "id": 1, + "in_xml": "SUBDATAEmpireBurlesqueBobDylanUSAColumbia10.901985", + "out_json": { + "CD": { + "ADVELEM1": { + "adv_attrA": "adv_valA" + }, + "ADVELEM2": { + "SUB": "SUBDATA", + "adv_attrA": "adv_valA", + "adv_attrB": "adv_valB" + }, + "TITLE": "EmpireBurlesque", + "ARTIST": "BobDylan", + "COUNTRY": "USA", + "COMPANY": "Columbia", + "PRICE": "10.90", + "YEAR": "1985" + } + }, + "xmlchksum": "99b252d9af646320" +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-convertXMLtoJSON.adoc b/modules/eventing/pages/eventing-handler-convertXMLtoJSON.adoc new file mode 100644 index 000000000..f02f57d35 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-convertXMLtoJSON.adoc @@ -0,0 +1,149 @@ += Function: convertXMLtoJSON +:description: pass:q[Recursively and generically convert simple XML strings into JSON.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *convertXMLtoJSON* shows how to convert simple XML strings into JSON. +* If you need to also convert XML attributes refer to *xref:eventing-handler-convertAdvXMLtoJSON.adoc[convertAdvXMLtoJSON]* +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on any mutation where the KEY or meta.id starts with "xml:". +* Will enrich the source document with a new JSON object representing the XML data. +* Maintains a checksum to prevent the overhead of conversion if the `in_xml` property is unchanged. + +[{tabs}] +==== +convertXMLtoJSON:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, convertXMLtoJSON, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + // filter out non XML + if (!meta.id.startsWith("xml:")) return; + // The KEY started with "xml" try to process it + // =========================================================== + // *** Do other work required here on non .in_xml changes *** + // =========================================================== + // let's see if we need to re-create our json representation. + var xmlchksum = crc64(doc.in_xml); + // =========================================================== + // Don't reprocess if the doc.in_xml has not changed this could be + // a big performance win if the doc has other fields that mutate. + // We do this via a checksum of the .in_xml property. + if (doc.xmlchksum && doc.xmlchksum === xmlchksum) return; + // Either this is the first pass, or the .in_xml property changed. + var jsonDoc = parseXmlToJson(doc.in_xml); + log(meta.id,"1. INPUT xml doc.in_xml :", doc.in_xml); + log(meta.id,"2. CHECKSUM doc.in_xml :", xmlchksum); + log(meta.id,"3. OUTPUT doc.out_json :", jsonDoc); + doc.out_json = jsonDoc; + doc.xmlchksum = xmlchksum; + // =========================================================== + // enrich the source collection with .out_json and .xmlchksum + src_col[meta.id] = doc; +} + +// 7.0.0 version uses String.matchAll eliminates the need to make our own MatchAll function +function parseXmlToJson(xml) { + const json = {}; + for (const res of xml.matchAll(/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) { + const key = res[1] || res[3]; + const value = res[2] && parseXmlToJson(res[2]); + json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null; + } + return json; +} + +/* +// need this for 6.6.0 version +function* MatchAll(str, regExp) { + if (!regExp.global) { + throw new TypeError('Flag /g must be set!'); + } + const localCopy = new RegExp(regExp, regExp.flags); + let match; + while (match = localCopy.exec(str)) { + yield match; + } +} + +// 6.6.0 version no String.matchAll need our own MatchAll function +function parseXmlToJson(xml) { + const json = {}; + for (const res of MatchAll(xml,/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) { + const key = res[1] || res[3]; + const value = res[2] && parseXmlToJson(res[2]); + json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null; + } + return json; +} +*/ +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY xml::1 + +{ + "type": "xml", + "id": 1, + "in_xml": "EmpireBurlesqueBobDylanUSAColumbia10.901985" +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY xml::1 + +{ + "type": "xml", + "id": 2, + "in_xml": "EmpireBurlesqueBobDylanUSAColumbia10.901985", + "out_json": { + "CD": { + "TITLE": "EmpireBurlesque", + "ARTIST": "BobDylan", + "COUNTRY": "USA", + "COMPANY": "Columbia", + "PRICE": "10.90", + "YEAR": "1985" + } + }, + "xmlchksum": "02087b7be275d0d8" +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-curl-get.adoc b/modules/eventing/pages/eventing-handler-curl-get.adoc new file mode 100644 index 000000000..9331196fd --- /dev/null +++ b/modules/eventing/pages/eventing-handler-curl-get.adoc @@ -0,0 +1,137 @@ += Function: Basic cURL GET +:description: pass:q[Perform a simple cURL GET using an external REST endpoint.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *basicCurlGet* communicates with a public REST service. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Needs a Binding of type URL Alias (as documented in the Scriptlet). +* Will operate on any mutation of the KEY "make_curl_request::1". +* The actual cURL request from the Eventing Function will be equivalent to either of the following (but test to make sure the service is live): ++ +[source,shell] +---- +curl -q -X GET 'https://api.frankfurter.app/latest' +curl -q -X GET 'https://api.ratesapi.io/api/latest' +---- +* Only logs the REST response JSON payload to the Application log file. +* For a more complete example using this public REST endpoint (or to make your own service), refer to xref:eventing:eventing-examples-rest-via-curl-get.adoc[External REST via cURL GET]. + +[{tabs}] +==== +basicCurlGet:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, basicCurlGet, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "URL...", "misc.", +// "URL alias", "exchangeRateApi", "https://api.frankfurter.app/", "no auth" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "URL...", "misc.", +// "URL alias", "exchangeRateApi", "https://api.frankfurter.app/", "no auth" + +function OnUpdate(doc, meta) { + // You would typically filter to mutations of interest + if (meta.id !== 'make_curl_request::1') return; + try { + // only make a cURL GET request id we see a mutation on the above KEY + var request = { path: "latest" }; // easiest API call could supply YYYY-MM-DD + // perform the cURL request using the URL alias from the settings + var response = curl('GET', exchangeRateApi, request); + if (response.status != 200 && response.status != 302) { + log("cURL GET failed response.status:",response.status) + } else { + log("cURL GET success, response.body:",response.body) + // optional write to a bucket - requires a binding alias in settings + // dst_col[meta.id] = response.body; + } + } catch (e) { + log("cURL request had an exception:",e) + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY make_curl_request::1 + +{ + "anything": 1 +} + +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-18T18:13:57.566-07:00 [INFO] "cURL GET success, response.body:" +{ + "amount": 1, + "base": "EUR", + "date": "2021-07-16", + "rates": { + "AUD": 1.5907, + "BGN": 1.9558, + "BRL": 6.0146, + "CAD": 1.4856, + "CHF": 1.0853, + "CNY": 7.6373, + "CZK": 25.538, + "DKK": 7.4381, + "GBP": 0.85298, + "HKD": 9.1684, + "HRK": 7.4968, + "HUF": 359.73, + "IDR": 17083, + "ILS": 3.8796, + "INR": 88.03, + "ISK": 145.9, + "JPY": 130.03, + "KRW": 1347.94, + "MXN": 23.459, + "MYR": 4.9681, + "NOK": 10.3878, + "NZD": 1.6836, + "PHP": 59.364, + "PLN": 4.5867, + "RON": 4.9285, + "RUB": 87.52, + "SEK": 10.2428, + "SGD": 1.5993, + "THB": 38.669, + "TRY": 10.0521, + "USD": 1.1802, + "ZAR": 16.984 + } +} + + +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-curl-post.adoc b/modules/eventing/pages/eventing-handler-curl-post.adoc new file mode 100644 index 000000000..0fed96ab6 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-curl-post.adoc @@ -0,0 +1,125 @@ += Function: Basic cURL POST +:description: pass:q[Perform a simple cURL POST using an external REST endpoint.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *basicCurlPost* communicates with a public REST echo service. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Needs a Binding of type URL Alias (as documented in the Scriptlet). +* Will operate on any mutation of the KEY "make_curl_request::1". +* The actual cURL request from the Eventing Function will be equivalent to (but test to make sure the service is live): + ++ +[source,shell] +---- +curl -q 'https://postman-echo.com/post' -d '{ "myboolean": true }' +---- +* Only logs the REST response JSON payload to the Application log file. + +[{tabs}] +==== +basicCurlPost:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, basicCurlPost, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "URL...", "misc.", +// "URL alias", "curlEchoApi", "https://postman-echo.com/", "no auth" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "URL...", "misc.", +// "URL alias", "curlEchoApi", "https://postman-echo.com/", "no auth" + + +function OnUpdate(doc, meta) { + // You would typically filter to mutations of interest + if (meta.id !== 'make_curl_request::1') return; + try { + // only make a cURL POST request we see a mutation on the above KEY + var request = { + path: 'post', // can also do 'get' in this API + body: { + "myboolean": true + } + }; + // perform the cURL request using the URL alias from the settings + var response = curl('POST', curlEchoApi, request); + if (response.status != 200 && response.status != 302) { + log("cURL POST failed response.status:",response.status) + } else { + log("cURL POST success, response.body:",response.body) + // optional write to a bucket - requires a binding alias in settings + // note the response.body.json is the echo back of request.body + // dst_col[meta.id] = response.body; + } + } catch (e) { + log("cURL request had an exception:",e) + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY make_curl_request::1 + +{ + "anything": 1 +} + +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-18T19:37:35.596-07:00 [INFO] "cURL POST success, response.body:" +{ + "args": {}, + "data": { + "myboolean": true + }, + "files": {}, + "form": {}, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-60f4e56f-2cfd45076d474c35198f8278", + "content-length": "18", + "user-agent": "libcurl/7.66.0-DEV couchbase/evt-7.0.0-0000-ee (eventing)", + "accept": "*/*", + "accept-encoding": "deflate, gzip", + "content-type": "application/json" + }, + "json": { + "myboolean": true + }, + "url": "https://postman-echo.com/post" +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-dateToEpochConversion.adoc b/modules/eventing/pages/eventing-handler-dateToEpochConversion.adoc new file mode 100644 index 000000000..d190e634a --- /dev/null +++ b/modules/eventing/pages/eventing-handler-dateToEpochConversion.adoc @@ -0,0 +1,219 @@ += Function: dateToEpochConversion +:description: pass:q[Recursively change String Dates into Unix Epoch timestamps.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *dateToEpochConversion* will recursively convert string dates to a UNIX Epoch timestamp. +* The sample can convert to either seconds from Epoch or milliseconds from Epoch. +* In addition the sample optionally rename fields by adding _ms or _sec suffix (note, arrays will not be renamed). +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on all documents where doc.type === "my_data_type". + +[{tabs}] +==== +dateToEpochConversion:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, dateToEpochConversion, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function convertStrToEpoch(key, val, control) { + + // We want to convert string dates to a Epoch tstamp, first we utilize + // a regex to filter, then if that passes we use Date.parse(..) + // to convert string to numeric timestamps, finally if the last argument + // is 'true' then add a suffix of "_ms" or "_sec" to the field name. + + // Date.parse("2009/06/29 13:30:10", "yyyy/MM/dd HH:mm:ss"); + // Date.parse("2020-06-24 09.55.22 -07:00", "yyyy-MM-dd HH:mm:ss Z"); + + // uses a self explanatory control document as follows: + + // var control = [ + // { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+$/g, "millis": true, "rename": true }, + // { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/g, "millis": false, "rename": true } + // ]; + + for (var i=0;i converTsStringsToEpochNumbers(item, control)); + } else { + Object.keys(obj).forEach((k) => { + var retval = { "key": k, "val": obj[k] }; + if (obj[k] && typeof obj[k] === 'string') { + retval = convertStrToEpoch(k, obj[k], control); + } + return newObj[retval.key] = converTsStringsToEpochNumbers(retval.val, control); + }) + } + return newObj; +} + +function OnUpdate(doc, meta) { + if (doc.type !== "my_data_type") return; + + var rename_with_ms_or_sec = true; // rename our fields + // Apply four (4) different datetime search patterns across the entire document + var control = [ + { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+$/g, "millis": true, "rename": true }, + { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/g, "millis": false, "rename": true }, + { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+ .\d\d:\d\d$/g, "millis": false, "rename": true }, + { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d .\d\d:\d\d$/g, "millis": true, "rename": true } + ]; + var newdoc = converTsStringsToEpochNumbers(doc, control); + + // alias src_col to our source collection. Will work since rev 6.5+ allowed to be in r/w mode + src_col[meta.id] = newdoc; +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY my_data_type::1001 + +{ + "type": "my_data_type", + "id": 1001, + "datet1a": "2009/06/29 13:30:10", + "datet1b": "2009/06/29 13:30:10", + "datet1c": "2009/06/29 13:30:10 -07:00", + "datet1d": "2009/06/29 13:30:10 -06:00", + "datet2a": "2009-06-29 13:30:10.333", + "datet2b": "2009-06-29 13:30:10.333", + "datet2c": "2009-06-29 13:30:10.333 -07:00", + "datet2d": "2009-06-29 13:30:10.333 -06:00", + "subdoc_same_dates": { + "datet1a": "2009/06/29 13:30:10", + "datet1b": "2009/06/29 13:30:10", + "datet1c": "2009/06/29 13:30:10 -07:00", + "datet1d": "2009/06/29 13:30:10 -06:00", + "datet2a": "2009-06-29 13:30:10.333", + "datet2b": "2009-06-29 13:30:10.333", + "datet2c": "2009-06-29 13:30:10.333 -07:00", + "datet2d": "2009-06-29 13:30:10.333 -06:00", + "subsubdoc_two_dates": { + "datet1a": "2009/06/29 13:30:10", + "datet1b": "2009/06/29 13:30:10", + "dary": [ + "2009/06/29 13:30:10", + "2009-06-29 13:30:10.333", + { "datet1a": "2009/06/29 13:30:10" } + ] + } + } +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY my_data_type::1001 + +{ + "type": "my_data_type", + "id": 1001, + "datet1a_sec": 1246307410, + "datet1b_sec": 1246307410, + "datet1c_ms": 1246307410000, + "datet1d_ms": 1246303810000, + "datet2a_ms": 1246307410333, + "datet2b_ms": 1246307410333, + "datet2c_sec": 1246307410, + "datet2d_sec": 1246303810, + "subdoc_same_dates": { + "datet1a_sec": 1246307410, + "datet1b_sec": 1246307410, + "datet1c_ms": 1246307410000, + "datet1d_ms": 1246303810000, + "datet2a_ms": 1246307410333, + "datet2b_ms": 1246307410333, + "datet2c_sec": 1246307410, + "datet2d_sec": 1246303810, + "subsubdoc_two_dates": { + "datet1a_sec": 1246307410, + "datet1b_sec": 1246307410, + "dary": [ + 1246307410, + 1246307410333, + { + "datet1a_sec": 1246307410 + } + ] + } + } +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-deepCloneAndModify.adoc b/modules/eventing/pages/eventing-handler-deepCloneAndModify.adoc new file mode 100644 index 000000000..734744137 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-deepCloneAndModify.adoc @@ -0,0 +1,214 @@ += Function: deepCloneAndModify +:description: pass:q[Recursively change a type 'string' or 'number' generically via an applied function.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *deepCloneAndModify* will recursively convert a given JavaScript type by applying a function +* The sample applies *convertStrToEpoch* and copies the behavior of the sample dateToEpochConversion. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on all documents where doc.type === "my_data_type". + +[{tabs}] +==== +deepCloneAndModify:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, deepCloneAndModify, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function convertStrToEpoch(key, val, control) { + + // We want to convert string dates to a Epoch tstamp, first we utilize + // a regex to filter, then if that passes we use Date.parse(..) + // to convert string to numeric timestamps, finally if the last argument + // is 'true' then add a suffix of "_ms" or "_sec" to the field name. + + // Date.parse("2009/06/29 13:30:10", "yyyy/MM/dd HH:mm:ss"); + // Date.parse("2020-06-24 09.55.22 -07:00", "yyyy-MM-dd HH:mm:ss Z"); + + // uses a self explanatory control document as follows: + + // var control = [ + // { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+$/g, "millis": true, "rename": true }, + // { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/g, "millis": false, "rename": true } + // ]; + + for (var i = 0; i < control.length; i++) { + var regxres = val.match(control[i].regx); + if (regxres !== null) { + var dt = Date.parse(val); + if (dt && dt !== null && !isNaN(dt)) { + var suffix = ""; + var epochMs = dt // .getTime(); + if (key !== "" && control[i].rename) { + if (control[i].millis) { + suffix = "_ms"; + } else { + suffix = "_sec"; + } + } + if (control[i].millis) { + val = epochMs; + } else { + val = Math.round(epochMs / 1000); + } + return { "key": key + suffix, "val": val, "converted": true }; + } + } + } + return { "key": key, "val": val, "converted": false }; +} + +function deepCloneAndModify(obj, control, fn, fntype) { + // This does a deepCopy or deepClone but applies convertStrToEpoch where needed + // process terminal strings + if (obj && typeof obj === fntype) { + var retval = fn("", obj, control); + return retval.val; + } + if (!obj || typeof obj !== 'object') { + return obj; + } + // process Object + let newObj = {}; + if (Array.isArray(obj)) { + newObj = obj.map(item => deepCloneAndModify(item, control, fn, fntype)); + } else { + Object.keys(obj).forEach((k) => { + var retval = { "key": k, "val": obj[k] }; + if (obj[k] && typeof obj[k] === fntype) { + retval = fn(k, obj[k], control); + } + return newObj[retval.key] = deepCloneAndModify(retval.val, control, fn, fntype); + }) + } + return newObj; +} + +function OnUpdate(doc, meta) { + if (doc.type !== "my_data_type") return; + + var rename_with_ms_or_sec = true; // rename our fields + // Apply four (4) different datetime search patterns across the entire document + var control = [ + { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+$/g, "millis": true, "rename": true }, + { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/g, "millis": false, "rename": true }, + { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+ .\d\d:\d\d$/g, "millis": false, "rename": true }, + { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d .\d\d:\d\d$/g, "millis": true, "rename": true } + ]; + var newdoc = deepCloneAndModify(doc, control, convertStrToEpoch, 'string'); + + // alias src_col to our source collection. Since rev 6.5+ allowed to be in r/w mode + src_col[meta.id] = newdoc; +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY my_data_type::1001 + +{ + "type": "my_data_type", + "id": 1001, + "datet1a": "2009/06/29 13:30:10", + "datet1b": "2009/06/29 13:30:10", + "datet1c": "2009/06/29 13:30:10 -07:00", + "datet1d": "2009/06/29 13:30:10 -06:00", + "datet2a": "2009-06-29 13:30:10.333", + "datet2b": "2009-06-29 13:30:10.333", + "datet2c": "2009-06-29 13:30:10.333 -07:00", + "datet2d": "2009-06-29 13:30:10.333 -06:00", + "subdoc_same_dates": { + "datet1a": "2009/06/29 13:30:10", + "datet1b": "2009/06/29 13:30:10", + "datet1c": "2009/06/29 13:30:10 -07:00", + "datet1d": "2009/06/29 13:30:10 -06:00", + "datet2a": "2009-06-29 13:30:10.333", + "datet2b": "2009-06-29 13:30:10.333", + "datet2c": "2009-06-29 13:30:10.333 -07:00", + "datet2d": "2009-06-29 13:30:10.333 -06:00", + "subsubdoc_two_dates": { + "datet1a": "2009/06/29 13:30:10", + "datet1b": "2009/06/29 13:30:10", + "dary": [ + "2009/06/29 13:30:10", + "2009-06-29 13:30:10.333", + { "datet1a": "2009/06/29 13:30:10" } + ] + } + } +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY my_data_type::1001 + +{ + "type": "my_data_type", + "id": 1001, + "datet1a_sec": 1246307410, + "datet1b_sec": 1246307410, + "datet1c_sec": 1246307410, + "datet1d_sec": 1246303810, + "datet2a_ms": 1246307410333, + "datet2b_ms": 1246307410333, + "datet2c_ms": 1246307410333, + "datet2d_ms": 1246303810333, + "subdoc_same_dates": { + "datet1a_sec": 1246307410, + "datet1b_sec": 1246307410, + "datet1c_sec": 1246307410, + "datet1d_sec": 1246303810, + "datet2a_ms": 1246307410333, + "datet2b_ms": 1246307410333, + "datet2c_ms": 1246307410333, + "datet2d_ms": 1246303810333, + "subsubdoc_two_dates": { + "datet1a_sec": 1246307410, + "datet1b_sec": 1246307410, + "dary": [ + 1246307410, + 1246307410333, + { + "datet1a_sec": 1246307410 + } + ] + } + } +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-docControlledSelfExpiry.adoc b/modules/eventing/pages/eventing-handler-docControlledSelfExpiry.adoc new file mode 100644 index 000000000..f8c522049 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-docControlledSelfExpiry.adoc @@ -0,0 +1,204 @@ += Function: Document Controlled Expiry +:description: pass:q[Purge a document automatically based on self-contained start and duration fields.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *docControlledSelfExpiry* demonstrates self-expiry of a document for example a user trial. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Needs a Binding of type "bucket alias" (as documented in the Scriptlet). +* When documents are created, they will have no expiration value. This function processes the initial mutation to calculate and set the proper TTL. +* In Couchbase, when using a simple integer expiry value (as opposed to a proper date or time object), the expiration can be specified in two ways: +** As an offset from the current time. If the absolute value of the expiry is less than 30 days (60 * 60 * 24 * 30 seconds), it is considered an offset. +** As an absolute Unix time stamp. If the value is greater than 30 days (60 * 60 * 24 * 30 seconds), it is considered an absolute time stamp. +** As described in xref:learn:data/expiration.adoc[Expiration], if a "Bucket Max Time-To-Live" is set (specified in seconds), it is an enforced hard upper limit. As such, any subsequent document mutation (by {sqlpp}, Eventing, or any Couchbase SDK) will result in the document having its expiration adjusted and set to the bucket’s maximum TTL if the operation has: +*** No TTL. +*** A TTL of zero. +*** A TTL greater than the bucket TTL. +* Will operate on any document with type == "trial_customers". +* Will ignore any doc with a non-zero TTL (prevents infinite recursion) +* Uses the _N1QL(...)_ function to update the source bucket instead of an inline {sqlpp} statement because inline {sqlpp} is prohibited from updating the source bucket of an Eventing handler to prevent infinite recursion scenarios. +* The recursion from the N1QL(...) statement is ignored via the _if (meta.expiration !== 0) { ... }_ filter. +* This is different than setting a TTL on a bucket which will typically update (or extend) the TTL of a document on each mutation. + +WARNING: You must use the function _N1QL(...)_ with great caution when updating the source bucket of your Eventing handler as you can easily create infinite recursion which may crash your server. + +// NOTE: Starting with Couchbase Server 6.6.1, you can completely avoid _N1QL(...)_ and use the call to _couchbase.replace(bucket_binding, meta, doc)_ instead +// this will have much greater performance. + +[{tabs}] +==== +docControlledSelfExpiry:: ++ +-- +Two variants of this function are available: a 6.6 version (*this Function*) that relies on {sqlpp}, and a 6.6.1 version that directly sets the expiration. +Using _N1QL(...)_ is much slower than using _couchbase.replace(bucket_binding, meta, doc)_ in the advancedDocControlledSelfExpiry variant. + +* <> +* xref:eventing-handler-advanced-docControlledSelfExpiry.adoc[advancedDocControlledSelfExpiry (direct TTL)] + +[#docControlledSelfExpiry] +docControlledSelfExpiry (indirect TTL via {sqlpp}) + +[source,javascript] +---- +// To run configure the settings for this Function, docControlledSelfExpiry, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function OnUpdate(doc, meta) { + // Filter items that don't have been updated, this also stops + // any recursion when we update meta.expiration via N1QL(...) + if (meta.expiration !== 0) { + log(meta.id, "IGNORE expiration "+meta.expiration+" !== 0 or "+ + new Date(meta.expiration).toString()); + return; + } + + // Optional filter to a specic field like 'type' + if (doc.type !== 'trial_customers') return; + + // Our expiry is based on a JavaScript date parsable field, it must exist + if (!doc.trialStartDate || !doc.trialDurationDays) return; + + // Convert the doc's field timeStamp and convert to unix epoch time (in ms.). + var docTimeStampMs = Date.parse(doc.trialStartDate); + + var keepDocForMs = doc.trialDurationDays * 1000 * 60 * 60 * 24 ; + var nowMs = Date.now(); // get current unix time (in ms.). + + // Archive if we have kept it for too long no need to set the expiration + if( nowMs >= (docTimeStampMs + keepDocForMs) ) { + + // Delete the document form the source bucket via the map alias + delete src_col[meta.id]; + + log(meta.id, "DELETE from src_col to dst_bkt alias as our expiration " + + new Date(docTimeStampMs + keepDocForMs).toString()) + " is already past"; + } else { + var key = meta.id; + //set the meta.expiration=ttlMs + var ttlMs = docTimeStampMs + keepDocForMs; + + // Use SQL++ to write back a non-zero TTL to the document hear we actually + // have to use the real bucket name "source" instead of the alias src_col + // as we are using SQL++. This will cause recursion but it will be ignored + // since we ignore all non-zero TTLs + + if (ttlMs !== 0) { + log(meta.id, "UPDATE expiration "+meta.expiration+" === 0 set to "+ + ttlMs+" or " + new Date(ttlMs).toString()); + + // Ensure non-zero, just be safe just in case somehow 1) doc.timeStamp + // evals to 0, and 2) keepDocForMs is set to 0 + var stmt = "UPDATE `source` USE KEYS \""+key+ + "\" SET meta().expiration = " + Math.floor(ttlMs/1000); + N1QL(stmt); + + // Future in 6.6.1+ we can avoid SQL++ via Eventing's new Advanced Bucket Ops + // couchbase.replace(src_col,{"id":meta.id,"expiry_date":new Date(ttlMs)},doc); + } + } +} +---- +-- + +Input Data/Mutation:: ++ +-- + +We want to create a test set of four (4) documents, use the Query Editor to insert the the data items (you do not need an index). + +Note, if the today is past 08-25-2021 (MM-DD-YYYY) just change the `trialStartDate` for the last two records to at least 90 days from now. + +[source,sqlpp] +---- + INSERT INTO `bulk`.`data`.`source` (KEY,VALUE) + VALUES ( "trial_customers::0", { + "type": "trial_customers", + "id": 0, + "trialStartDate": "08-25-2019", + "trialDurationDays": 30, + "note": "this is old will get immeadiately deleted" + } ), + VALUES ( "trial_customers::1", + { + "type": "trial_customers", + "id": 1, + "trialStartDate": "01-27-2020", + "trialDurationDays": 30, + "note": "this is old will get immeadiately deleted" + } ), + VALUES ( "trial_customers::2", + { + "type": "trial_customers", + "id": 2, + "trialStartDate": "08-25-2021", + "trialDurationDays": 30, + "note": "this will get an exiration set" + } ), + VALUES ( "trial_customers::3", + { + "type": "trial_customers", + "id": 3, + "trialStartDate": "08-26-2021", + "trialDurationDays": 60, + "note": "this will get an exiration set" + } ); +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +NEW/OUTPUT: KEY trial_customers::2 + +{ + "id": 2, + "note": "this will get an exiration set", + "trialDurationDays": 30, + "trialStartDate": "08-25-2021", + "type": "trial_customers" +} + +NEW/OUTPUT: KEY trial_customers::3 + +{ + "id": 3, + "note": "this will get an exiration set", + "trialDurationDays": 60, + "trialStartDate": "08-26-2021", + "type": "trial_customers" +} + +We end up with two (2) of the four documents (obviously you may need to adjust the N1QL INSERT in a few months as all the document would be immediately deleted). + +* "trial_customers::0" was deleted +* "trial_customers::1" was deleted +* "trial_customers::2" has an meta.expiration set for 1632466800 (or 2021-09-24 07:00:00 UTC) in it's metadata +* "trial_customers::3" has an meta.expiration set for 1635145200 (or 2021-10-25 07:00:00 UTC) in it's metadata +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-fasterToLocalString.adoc b/modules/eventing/pages/eventing-handler-fasterToLocalString.adoc new file mode 100644 index 000000000..817e658ed --- /dev/null +++ b/modules/eventing/pages/eventing-handler-fasterToLocalString.adoc @@ -0,0 +1,127 @@ += Function/Benchmark: fasterToLocalString +:description: pass:q[Explore faster local time zone date formating.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *fasterToLocalString* demonstrates a faster alternative to the built-in JavaScript function *toLocalString*. +* In Couchbase 6.6.0 the *fasterToLocalString* implementation is 708X faster than the v8 runner. +* In Couchbase 7.0.0 the *fasterToLocalString* implementation is 177X faster than the upgraded v8 runner. +* _The above demonstrates that all date conversions should be benchmarked._ +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on any mutation where doc.type === "basic_bkt_ops". +* Deploy from now +* Only mutate one document as this is a benchmark of ICU performance. + +[{tabs}] +==== +fasterToLocalString:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, docControlledSelfExpiry, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) - none +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) - none + +function fasterToLocalString(d) { + // adjust the input date by the UTC offset + var dadj = new Date(d.getTime() - d.getTimezoneOffset() * 60 * 1000); + var hr = dadj.getUTCHours(); + var min = dadj.getUTCMinutes(); + var sec = dadj.getUTCSeconds(); + var strLocalDate = (dadj.getUTCMonth()+1) + "/" + dadj.getUTCDate() + "/" + dadj.getUTCFullYear() + ", " + + ((hr < 13) ? hr : (hr - 12)) + ":" + + ((min<10) ? "0"+min : min) + ":" + + ((sec<10) ? "0"+sec : sec) + + ((hr < 12) ? " AM" : " PM"); + // should be the same as d.toLocaleString('en-US') + return strLocalDate; +} + +function OnUpdate(doc, meta) { + var cnt = 20000; + var d = new Date(); + var tbeg, tend; + + if (true) { +ifdef::flag-devex-rest-api[] + // This crash a debug session refer to eventing-debugging-and-diagnosability.html + // however it always work in no-debug but is very slow. +endif::flag-devex-rest-api[] + tbeg = Date.now(); + for (var i=1; i<=cnt; i++) { + var res = d.toLocaleString('en-US'); + if (i % cnt == 0) + log("d.toLocaleString('en-US') ",res); + } + tend = Date.now(); + log("d.toLocaleString('en-US') ", tend-tbeg + " ms."); + } + + if (true) { + tbeg = Date.now(); + for (var i=1; i<=cnt; i++) { + var res = fasterToLocalString(d); + if (i % cnt == 0) + log("fasterToLocalString(d) ",res); + } + tend = Date.now(); + log("fasterToLocalString(d) ", tend-tbeg + " ms."); + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +Create/Mutate any single document in the source collection + +---- +-- + +Output Data/Logged:: ++ +-- +This below messages are from the Application log in the file system (the UI would display the messages in reverse order) + +[source,json] +---- +6.6.0 +2020-09-16T18:40:48.430-07:00 [INFO] "d.toLocaleString('en-US') " "9/16/2020, 6:40:32 PM" +2020-09-16T18:40:48.430-07:00 [INFO] "d.toLocaleString('en-US') " "16299 ms." +2020-09-16T18:40:48.453-07:00 [INFO] "fasterToLocalString(d) " "9/16/2020, 6:40:32 PM" +2020-09-16T18:40:48.453-07:00 [INFO] "fasterToLocalString(d) " "23 ms." + +7.0.0 +2021-07-19T11:22:35.937-07:00 [INFO] "d.toLocaleString('en-US') " "7/19/2021, 11:22:31 AM" +2021-07-19T11:22:35.937-07:00 [INFO] "d.toLocaleString('en-US') " "4090 ms." +2021-07-19T11:22:35.960-07:00 [INFO] "fasterToLocalString(d) " "7/19/2021, 11:22:31 AM" +2021-07-19T11:22:35.960-07:00 [INFO] "fasterToLocalString(d) " "23 ms." +---- + +The above was run on a single Eventing node 12 cores at 2.2 GHz, shows that the v8 runner is not +performant for the built-in function toLocaleString. +In Couchbase 6.6.0 the *fasterToLocalString* implementation is 708X faster than the v8 runner. +In Couchbase 7.0.0 the *fasterToLocalString* implementation is 177X faster than the v8 runner. +-- +==== diff --git a/modules/eventing/pages/eventing-handler-fixEmailDomains.adoc b/modules/eventing/pages/eventing-handler-fixEmailDomains.adoc new file mode 100644 index 000000000..a6ab4ac95 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-fixEmailDomains.adoc @@ -0,0 +1,105 @@ += Function: fixEmailDomains +:description: pass:q[Redact Sensitive Data prior to sharing.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *fixEmailDomains* will fix email domains by ensuring only a top level domain is used. +* Example given an Email address like _jack.smith@mailhost.company.com_ we update it to use only the top level domain _jack.smith@company.com_. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on all documents where doc.type === "employees". + +[{tabs}] +==== +fixEmailDomains:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, fixEmailDomains, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function fixEmailDomain(doc,fieldname,emaildomain) { + /* + * doc: the mutated document + * fieldname: the name of the email field in "doc" to update + * emaildomain: the domain to use, for example @mycompany.com + */ + if (emaildomain.charAt(0) !== '@') return false; + var domary = emaildomain.substr(1).split("."); + var re = new RegExp('@.+?\.' + domary[0] + '\.' + domary[1] + '$'); + if (re.test(doc[fieldname])) { + var tmp = doc[fieldname].replace(re, emaildomain); + doc[fieldname] = tmp; + return true; + } + return false; +} + +function OnUpdate(doc, meta) { + if (doc.type !== "employees") return; + + // normalize email addresses + if (fixEmailDomain(doc,'email',"@bigmovies.com")) { + try { + log('OnUpdate: updated field email',doc.email); + src_col[meta.id] = doc; + } catch (e) { + log('OnUpdate: error',e); + } + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY employees::1001 + +{ + "type": "employees", + "id": 1001, + "email": "will.smith@mailhost.bigmovies.com" +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY employees::1001 + +{ + "type": "employees", + "id": 1001, + "email": "will.smith@bigmovies.com" +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-genericFlatten.adoc b/modules/eventing/pages/eventing-handler-genericFlatten.adoc new file mode 100644 index 000000000..eaaff28e1 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-genericFlatten.adoc @@ -0,0 +1,228 @@ += Function: genericFlatten +:description: pass:q[Recursively and Generically Flatten a document for integration with a non-NOSQL RDBMS.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *genericFlatten* shows how a document can be flattened into a RDBMS importable record. +* Requires Eventing Storage (or metadata collection), a "source" collection, and a "destination" collection. +* Will operate on all documents where doc.type === "my_data_to_flatten". +* Will write transformed or flattened documents to the destination collection with the same type and id. +* The destination collection can be shared (or replicated via XCDR to a business partner - maybe to AWS, GCP, or Azure). +* Will also remove the flattened document in the destination collection when the original source document is removed. +* Note since the document is not available during an OnDelete we will filter by KEY prefix starting with "my_data_to_flatten:". + +[{tabs}] +==== +genericFlatten:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, genericFlatten, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "dst_col", "bulk.data.destination", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "dst_col", "destinaton", "read and write" + +function deepFlatten(obj,flatDoc, path) { + if (!obj || typeof obj !== 'object') { + // log("terminal", path, obj); + // remove leading "_" and store the path as a key to the terminal value + flatDoc[path.substr(1)] = obj; + return obj; + } + // process Object + let newObj = {}; + if (Array.isArray(obj)) { + for (var i=0; i<= obj.length; i++ ) { + newObj[i] = deepFlatten(obj[i], flatDoc, path + "_" + i) + } + } else { + Object.keys(obj).forEach((k) => { + return newObj[k] = deepFlatten(obj[k], flatDoc, path + "_" + k); + }) + } + return newObj; +} + +function OnUpdate(doc, meta) { + if (doc.type !== "my_data_to_flatten") return; + + var flatDoc = {}; + deepFlatten(doc,flatDoc,""); + + // alias src_bkt to our source bucket. Since rev 6.5+ allowed to be in r/w mode + dst_col[meta.id] = flatDoc; +} + +function OnDelete(meta, options) { + // filter + if (!(meta.id.startsWith("my_data_to_flatten:"))) return; + + log("OnDelete expired=" + options.expired +" REM id: "+meta.id); + try { + delete dst_col[meta.id]; + } catch (e) { + log("Error on delete: "+e+", id:",meta.id); + } +} +---- +-- + +Input Data/Mutation:: in keyspace bulk.data.source ++ +-- +[source,json] +---- +INPUT: KEY my_data_to_flatten::1001 + +{ + "type": "my_data_to_flatten", + "id": 1001, + "a_first_super_long_name_right_here": 111, + "b": "my object", + "c": "", + "d": null, + "f": { + "v": 1, + "x": "", + "y": null, + "m": { + "a": "asd" + } + }, + "f2": { + "v": 1, + "x": "", + "y": null, + "m": { + "a": "asd", + "b": null, + "c": null, + "a_second_super_long_name_right_here": 222, + "ary1": [ + null, + 1, + null, + 2, + null, + 3 + ], + "ary2": [ + [ + 1, + 2 + ], + [ + 3, + 4 + ], + [ + 5, + null, + 6 + ], + { + "a": 1 + }, + { + "b": 2 + }, + { + "c": 3, + "d": null + }, + { + "e": null + }, + [ + null, + null, + null, + null + ] + ] + } + }, + "a_third_super_long_name_right_here": { + "x": 1, + "y": 2, + "z": null + } +} +---- +-- + +Output Data/Mutation:: in keyspace bulk.data.destination ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY my_data_to_flatten::1001 + +{ + "type": "my_data_to_flatten", + "id": 1001, + "a_first_super_long_name_right_here": 111, + "b": "my object", + "c": "", + "d": null, + "f_v": 1, + "f_x": "", + "f_y": null, + "f_m_a": "asd", + "f2_v": 1, + "f2_x": "", + "f2_y": null, + "f2_m_a": "asd", + "f2_m_b": null, + "f2_m_c": null, + "f2_m_a_second_super_long_name_right_here": 222, + "f2_m_ary1_0": null, + "f2_m_ary1_1": 1, + "f2_m_ary1_2": null, + "f2_m_ary1_3": 2, + "f2_m_ary1_4": null, + "f2_m_ary1_5": 3, + "f2_m_ary2_0_0": 1, + "f2_m_ary2_0_1": 2, + "f2_m_ary2_1_0": 3, + "f2_m_ary2_1_1": 4, + "f2_m_ary2_2_0": 5, + "f2_m_ary2_2_1": null, + "f2_m_ary2_2_2": 6, + "f2_m_ary2_3_a": 1, + "f2_m_ary2_4_b": 2, + "f2_m_ary2_5_c": 3, + "f2_m_ary2_5_d": null, + "f2_m_ary2_6_e": null, + "f2_m_ary2_7_0": null, + "f2_m_ary2_7_1": null, + "f2_m_ary2_7_2": null, + "f2_m_ary2_7_3": null, + "a_third_super_long_name_right_here_x": 1, + "a_third_super_long_name_right_here_y": 2, + "a_third_super_long_name_right_here_z": null +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-genericRename.adoc b/modules/eventing/pages/eventing-handler-genericRename.adoc new file mode 100644 index 000000000..74a35c8b6 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-genericRename.adoc @@ -0,0 +1,196 @@ += Function: genericRename +:description: pass:q[Recursively and Generically Rename Keys in a document.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *genericRename* shows how a document can have its keys or fields renamed. +* Requires Eventing Storage (or metadata collection), a "source" collection, and a "destination" collection. +* Will operate on all documents where doc.type === "my_data_to_rename". +* Will write transformed or flattened documents to the destination collection with the same type and id. +* The destination collection can be shared (or replicated via XCDR to a business partner - maybe to AWS, GCP, or Azure). +* Will also remove the transformed document in the destination collection when the original source document is removed. +* Note since the document is not available during an OnDelete we will filter by KEY prefix starting with "my_data_to_rename:". + +[{tabs}] +==== +genericRename:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, genericRename, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "dst_col", "bulk.data.destination", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "dst_col", "destinaton", "read and write" + +function renamePartsByMap(obj, rename_map) { + if (obj !== null && typeof obj == "object") { + Object.entries(obj).forEach(([k, v]) => { + if (obj[k] && typeof obj[k] === 'object') { + // recurse + renamePartsByMap(obj[k], rename_map) + } + if (obj[k]) { + // recurse + var tst = rename_map[k]; + if (tst) { + if (tst !== undefined && tst !== null) { + obj[rename_map[k]] = obj[k]; + delete(obj[k]); + } + } + } + }); + } + return obj; +} + +function OnUpdate(doc, meta) { + if (doc.type !== "my_data_to_rename") return; + + // rename long fields to shorter names using a MAP + var rename_map = { + "a_first_super_long_name_right_here": "a_short1", + "a_second_super_long_name_right_here": "a_short2", + "a_third_super_long_name_right_here": "a_short3" + }; + var newdoc = renamePartsByMap(doc, rename_map); + + // alias dst_col to our source collection. Since rev 6.5+ allowed to be in r/w mode + dst_col[meta.id] = newdoc; +} + +function OnDelete(meta, options) { + // filter + if (!(meta.id.startsWith("my_data_to_rename:"))) return; + + log("OnDelete expired=" + options.expired +" REM id: "+meta.id); + try { + delete dst_col[meta.id]; + } catch (e) { + log("Error on delete: "+e+", id:",meta.id); + } +} +---- +-- + +Input Data/Mutation:: in keyspace bulk.data.source ++ +-- +[source,json] +---- +INPUT: KEY my_data_to_rename::1001 + +{ + "type": "my_data_to_rename", + "id": 1001, + "a_first_super_long_name_right_here": 111, + "b": "my object", + "c": "", + "d": null, + "f": { + "m": { + "a": "asd" + } + }, + "f2": { + "m": { + "a": "asd", + "a_second_super_long_name_right_here": 222, + "ary1": [ + { + "a_second_super_long_name_right_here": 1 + }, + { + "a_second_super_long_name_right_here": 2 + }, + [ + { + "a_second_super_long_name_right_here": 1 + }, + { + "a_second_super_long_name_right_here": 2 + } + ] + ] + } + }, + "a_third_super_long_name_right_here": { + "x": 1, + "y": 2, + "not_a_key_will_not_change": "a_third_super_long_name_right_here" + } +} +---- +-- + +Output Data/Mutation:: in keyspace bulk.data.destination ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY my_data_to_rename::1001 + +{ + "type": "my_data_to_rename", + "id": 1001, + "b": "my object", + "c": "", + "d": null, + "f": { + "m": { + "a": "asd" + } + }, + "f2": { + "m": { + "a": "asd", + "ary1": [ + { + "a_short2": 1 + }, + { + "a_short2": 2 + }, + [ + { + "a_short2": 1 + }, + { + "a_short2": 2 + } + ] + ], + "a_short2": 222 + } + }, + "a_short1": 111, + "a_short3": { + "x": 1, + "y": 2, + "not_a_key_will_not_change": "a_third_super_long_name_right_here" + } +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-keepLastN.adoc b/modules/eventing/pages/eventing-handler-keepLastN.adoc new file mode 100644 index 000000000..d3abb12a7 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-keepLastN.adoc @@ -0,0 +1,248 @@ += Function: Keep the Last N User Items +:description: pass:q[Keep the last N user notifications seen related to a user ID (these could be any documents).] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *keepLastN* demonstrates how to keep a user record with the last N activities. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Needs a Binding of type "bucket alias" (as documented in the Scriptlet). +* Will operate on any mutation with a key starting with "nu:" of the form "nu:#:#". +* The key "nu:#:#" contains two numbers. The first # is an increasing notification number, the second # is the user ID. +* Anytime we insert a new record we want to remove the earliest notification record for the user so we only have at most N records for each user. +We assume that nid always increases across time as such we ignore duplicates. +* For our test we will keep just the three (3) most recent notifications per user ID. + +[{tabs}] +==== +keepLastN:: ++ +-- +Two variants of this function are available a 6.6 version (*this Function*) that implements userspace CAS and a 6.6.1+/7.0.0+ version which uses true CAS + +* <> +* xref:eventing-handler-advanced-keepLastN.adoc[advancedKeepLastN (true CAS)] + +[#keepLastN] +keepLastN (userspace CAS) +[source,javascript] +---- +// To run configure the settings for this Function, keepLastN, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +/* + * Process all mutations, however updateNotifyArrayInKV(...) will only + * data with KEYS like nu:#:# + */ + function OnUpdate(doc, meta) { + const MAX_RETRY = 16; + const MAX_ARRAY = 3; + const DEBUG = false; + + updateNotifyArrayInKV(doc, meta, MAX_RETRY, MAX_ARRAY, DEBUG); +} + +/* + * reads form KV and manipulates the result to only keep 'MAX_ARRAY' items + */ +function addToNtfyArray(src_col, user_id, insert_json, MAX_ARRAY, DEBUG) { + var ntfy_id = insert_json.nid; + var random_csum; + var user_doc = src_col["user_plus_ntfys:" + user_id]; + if (!user_doc) { + // generate unique random # + random_csum = Math.random(); + user_doc = { "type": "user_plus_ntfys", "id": user_id, "notifications" : [], "random": random_csum }; + user_doc.notifications.push(insert_json); + } else { + if (user_doc.notifications[0].nid >= ntfy_id && user_doc.notifications.length === MAX_ARRAY) { + // do nothing this is older data, we assume that nid always increases + return null; + } else { + // find insert position + for(var i=0; i<=user_doc.notifications.length + 1 ; i++) { + if (i < user_doc.notifications.length && user_doc.notifications[i].nid === ntfy_id) { + // do nothing this is duplicate data we already have it, assume no updates to notifys + return null; + } + if (i == user_doc.notifications.length || user_doc.notifications[i].nid > ntfy_id) { + // add to array middle or end + user_doc.notifications.splice(i, 0, insert_json); + random_csum = Math.random(); + // update unique random # + user_doc.random = random_csum; + break; + } + } + } + while (user_doc.notifications.length > MAX_ARRAY) { + // ensure proper size + user_doc.notifications.shift(); + } + } + if (DEBUG) log("user_plus_ntfys:" + user_id,user_doc); + return user_doc; +} + +/* + * creates, gets, and updates (via replace) the KV tracking array document + */ +function updateNotifyArrayInKV(doc, meta, MAX_RETRY, MAX_ARRAY, DEBUG) { + // will process ALL data like nu:#:# + var parts = meta.id.split(':'); + if (!parts || parts.length != 3 || parts[0] != "nu") return; + var ntfy_id = parseInt(parts[1]); + var user_id = parseInt(parts[2]); + //log("Doc created/updated " + meta.id + " ntfy_id " + ntfy_id + " user_id " + user_id); + + var insert_json = {"nid": ntfy_id, doc}; + // this is a can be improved in version 6.6.1 as CAS operations are supported. + // we utilize a 'random' tag in the document itself to emulate a CAS operation. + for (var tries=0; tries < 16; tries++) { + var user_doc = addToNtfyArray(src_col, user_id, insert_json, MAX_ARRAY, DEBUG); + if (user_doc == null) { + // do nothing + return; + } + var random_csum = user_doc.random; + // this is a read write alias to the functions source bucket, write then reread + src_col["user_plus_ntfys:" + user_id] = user_doc; + user_doc = src_col["user_plus_ntfys:" + user_id]; + // we use the random values to perform a CAS, we give up after 16 attempts + if (random_csum !== user_doc.random) { + // failure need to retry + tries++; + if (DEBUG) log("CAS like operation failed: tries "+tries+ + " random_csum:",random_csum,"!==", "user_doc.random",user_doc.random); + } else { + // success could even delete the input notification doc here + if (DEBUG) log("CAS like operation success: tries "+tries+ + " random_csum:",random_csum,"!==", "user_doc.random",user_doc.random); + return; + } + } + log ("FAILED to insert id: " + meta.id, doc) +} +---- +-- + +Input Data/Mutation:: ++ +-- + +We want to create a test doc set + +[cols="1,3",width=50%,frame=all] +|=== +|key |data + +|nu:1:1 |{"somekey":"someValue"} +|nu:2:2 |{"somekey":"someValue"} +|nu:3:1 |{"somekey":"someValue"} +|nu:4:1 |{"somekey":"someValue"} +|nu:5:1 |{"somekey":"someValue"} +|nu:6:2 |{"somekey":"someValue"} +|nu:7:2 |{"somekey":"someValue"} +|nu:8:1 |{"somekey":"someValue"} +|nu:9:2 |{"somekey":"someValue"} +|nu:10:2 |{"somekey":"someValue"} + +|=== + + +Use the Query Editor to insert the above data items (you do not need an Index) + +[source,sqlpp] +---- + UPSERT INTO `bulk`.`data`.`source` (KEY,VALUE) + VALUES ( "nu:1:1", {"somekey":"someValue"} ), + VALUES ( "nu:2:2", {"somekey":"someValue"} ), + VALUES ( "nu:3:1", {"somekey":"someValue"} ), + VALUES ( "nu:4:1", {"somekey":"someValue"} ), + VALUES ( "nu:5:1", {"somekey":"someValue"} ), + VALUES ( "nu:6:2", {"somekey":"someValue"} ), + VALUES ( "nu:7:2", {"somekey":"someValue"} ), + VALUES ( "nu:8:1", {"somekey":"someValue"} ), + VALUES ( "nu:9:2", {"somekey":"someValue"} ), + VALUES ( "nu:10:2", {"somekey":"someValue"} ); +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +NEW/OUTPUT: KEY user_plus_ntfys:1 + +Note, we add/create the property _random_ in the tracking doc as we use _random_ is used to emulate CAS. + +{ + "type": "user_plus_ntfys", + "id": 1, + "notifications": [{ + "nid": 4, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 5, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 8, + "doc": { + "somekey": "someValue" + } + }], + "random": 0.9071605464143964 +} + +NEW/OUTPUT: KEY user_plus_ntfys:2 + +{ + "type": "user_plus_ntfys", + "id": 2, + "notifications": [{ + "nid": 7, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 9, + "doc": { + "somekey": "someValue" + } + }, { + "nid": 10, + "doc": { + "somekey": "someValue" + } + }], + "random": 0.5637501636850883 +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-multiCollectionEventing.adoc b/modules/eventing/pages/eventing-handler-multiCollectionEventing.adoc new file mode 100644 index 000000000..1b3c017c8 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-multiCollectionEventing.adoc @@ -0,0 +1,164 @@ += Function: Multi Collection Eventing +:description: pass:q[Access the Data Service when Eventing is listening to multiple collections.] +:page-edition: Enterprise Edition + +{description} + +The `multiCollectionEventing` function: + +* Demonstrates how to access the Data Service when using `{asterisk}` wildcard bindings +* Requires 2 bindings of type `bucket alias` +* Requires the following 4 keyspaces in two buckets, `rr100` and source: +** `rr100.eventing.metadata` +** `source._default._default` +** `source.myscope.mycol1` +** `source.myscope.mycol2` +* Operates on 3 test documents +* Highlights the use of `meta.keyspace` + +For more information about the Advanced Self-Recursion Parameter, see xref:eventing-advanced-keyspace-accessors.adoc#multiple-collection-functions[Eventing Functions that Listen to Multiple Collections]. + +[tabs] +==== +multiCollectionEventing:: ++ +-- +[source, javascript] +---- +// Configure the settings for the multiCollectionEventing function as follows: +// +// Set up four (4) required keyspaces in two buckets "rr100" and "source" +// rr100.eventing.metadata +// source._default._default +// source.myscope.mycol1 +// source.myscope.mycol2 +// +// Version 7.1.1+ +// "Function Scope" +// *.* (or try source.* if non-privileged) +// "Listen to Location" +// source.*.* +// "Eventing Storage" +// rr100.eventing.metadata +// Create four (4) Bindings +// "binding type", "alias name...", "bucket.scope.collection", "Access" +// --------------------------------------------------------------------------- +// "bucket alias", "alias_ro", "source.myscope.*", "read only" +// "bucket alias", "alias_rw", "source.myscope.*", "read and write" +// Deploy the Function +// Create the following three (3) documents one at a time and inspect the Application log each time +// "bucket.scope.collection" KEY DATA +// --------------------------------------------------------------------------- +// source._default._default doc0 {"data": "doc0"} +// source.myscope.mycol1 doc1 {"data": "doc1"} +// source.myscope.mycol2 doc2 {"data": "doc2"} + +function OnUpdate(doc, meta) { + log('>>>A IN',doc, meta); + + // TEST GET with hardcode keyspace + var res1 = couchbase.get(alias_ro,{"id": "doc2", "keyspace": + {"bucket_name": "source","scope_name": "myscope","collection_name": "mycol2"}}); + log('>>>B fixed read',"res1", res1); + + // Protect against reading from something outside the alias + if (meta.keyspace.scope_name == "myscope") { + // TEST GET with keyspace from meta + var res2 = couchbase.get(alias_ro,meta); + log('>>>C read using passed meta (must be myscope)',"res2", res2); + + if (meta.keyspace.collection_name == "mycol2") { + // TEST UPSERT with hardcode keyspace + // Add a field to the document read in res1 + res1.doc.random1 = Math.random(); + var res3 = couchbase.upsert(alias_rw,{"id": "doc2", "keyspace": + {"bucket_name": "source","scope_name": "myscope","collection_name": "mycol2"}}, res1.doc) + log('>>>D upsert',"res3", res3); + + // TEST REPLACE with hardcode keyspace + res1.doc.random2 = Math.random(); + var res4 = couchbase.replace(alias_rw,{"id": "doc2", "keyspace": + {"bucket_name": "source","scope_name": "myscope","collection_name": "mycol2"}}, res1.doc) + log('>>>E replace',"res4", res4); + + // TEST GET with hardcode keyspace + var res5 = couchbase.get(alias_rw,meta); + log('>>>F get (show added fields)',"res5", res5); + + // TEST DELETE with hardcode keyspace (so the insert can be tested) + var res6 = couchbase.delete(alias_rw,{"id": "doc2", "keyspace": + {"bucket_name": "source","scope_name": "myscope","collection_name": "mycol2"}}) + log('>>>G delete',"res6", res6); + + // TEST INSERT with hardcode keyspace + // Remove the added items + delete res1.doc.random1; + delete res1.doc.random2; + var res7 = couchbase.insert(alias_rw,{"id": "doc2", "keyspace": + {"bucket_name": "source","scope_name": "myscope","collection_name": "mycol2"}}, res1.doc) + log('>>>H upsert',"res7", res7); + } + } +} +---- +-- + +Input data:: ++ +-- +Create a test document set of 3 documents using the Query Editor to insert the data items. +You do not need an Index. + +Add one test document at a time. + +[source,sqlpp] +---- + UPSERT INTO source._default._default (KEY,VALUE) VALUES ( "doc0", {"data": "doc0"} ); + + UPSERT INTO source.myscope.mycol1 (KEY,VALUE) VALUES ( "doc1", {"data": "doc1"} ); + + UPSERT INTO source.myscope.mycol2 (KEY,VALUE) VALUES ( "doc2", {"data": "doc2"} ); +---- +-- + +Output log in reverse order:: ++ +-- +[source,log] +---- +LOG/OUTPUT: KEY doc0 + +2022-07-28T17:02:04.599-07:00 [INFO] ">>>B fixed read" "res1" {"error":{"code":1,"name":"LCB_KEY_ENOENT","desc":"The document key does not exist on the server","key_not_found":true},"success":false} + +2022-07-28T17:02:04.597-07:00 [INFO] ">>>A IN" {"data":"doc0"} {"cas":"1659052924529868800","id":"doc0","expiration":0,"flags":0,"vb":642,"seq":6,"datatype":"json","keyspace":{"bucket_name":"source","scope_name":"_default","collection_name":"_default"},"cid":0} + +LOG/OUTPUT: KEY doc1 + +2022-07-28T17:03:52.902-07:00 [INFO] ">>>C read using passed meta (must be myscope)" "res2" {"doc":{"data":"doc1"},"meta":{"id":"doc1","cas":"1659053032885387264","datatype":"json"},"success":true} + +2022-07-28T17:03:52.901-07:00 [INFO] ">>>B fixed read" "res1" {"error":{"code":1,"name":"LCB_KEY_ENOENT","desc":"The document key does not exist on the server","key_not_found":true},"success":false} + +2022-07-28T17:03:52.898-07:00 [INFO] ">>>A IN" {"data":"doc1"} {"cas":"1659053032885387264","id":"doc1","expiration":0,"flags":0,"vb":389,"seq":9,"datatype":"json","keyspace":{"bucket_name":"source","scope_name":"myscope","collection_name":"mycol1"},"cid":8} + +LOG/OUTPUT: KEY doc2 + +Function Log - multiCollectionEventing +2022-07-28T17:04:37.807-07:00 [INFO] ">>>H upsert" "res7" {"meta":{"id":"doc2","cas":"1659053077807104000"},"success":true} + +2022-07-28T17:04:37.806-07:00 [INFO] ">>>G delete" "res6" {"meta":{"id":"doc2","cas":"1659053077806055424"},"success":true} + +2022-07-28T17:04:37.805-07:00 [INFO] ">>>F get (show added fields)" "res5" {"doc":{"data":"doc2","random1":0.7875783578859457,"random2":0.47914947531399843},"meta":{"id":"doc2","cas":"1659053077803827200","datatype":"json"},"success":true} + +2022-07-28T17:04:37.804-07:00 [INFO] ">>>E replace" "res4" {"meta":{"id":"doc2","cas":"1659053077803827200"},"success":true} + +2022-07-28T17:04:37.803-07:00 [INFO] ">>>D upsert" "res3" {"meta":{"id":"doc2","cas":"1659053077802516480"},"success":true} + +2022-07-28T17:04:37.800-07:00 [INFO] ">>>C read using passed meta (must be myscope)" "res2" {"doc":{"data":"doc2"},"meta":{"id":"doc2","cas":"1659053077704474624","datatype":"json"},"success":true} + +2022-07-28T17:04:37.799-07:00 [INFO] ">>>B fixed read" "res1" {"doc":{"data":"doc2"},"meta":{"id":"doc2","cas":"1659053077704474624","datatype":"json"},"success":true} + +2022-07-28T17:04:37.797-07:00 [INFO] ">>>A IN" {"data":"doc2"} {"cas":"1659053077704474624","id":"doc2","expiration":0,"flags":0,"vb":140,"seq":38,"datatype":"json","keyspace":{"bucket_name":"source","scope_name":"myscope","collection_name":"mycol2"},"cid":9} + +---- +-- +==== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-handler-redactSharedData.adoc b/modules/eventing/pages/eventing-handler-redactSharedData.adoc new file mode 100644 index 000000000..eacbe5c6e --- /dev/null +++ b/modules/eventing/pages/eventing-handler-redactSharedData.adoc @@ -0,0 +1,147 @@ += Function: redactSharedData +:description: pass:q[Redact Sensitive Data prior to sharing.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *redactSharedData* will remove sensitive data and write "safe" redacted records. +* Requires Eventing Storage (or metadata collection), a "source" collection, and a "destination" collection. +* Will operate on all documents where doc.type === "master_profile". +* Will create redacted documents in real-time of doc.type === "shared_profile". +* The "destination" collection can be shared (or replicated via XCDR to a business partner) too the cloud (AWS, Azure or GCP). + +[{tabs}] +==== +redactSharedData:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, redactSharedData, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "aws_col", "bulk.data.destination", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "aws_col", "destination", "read and write" + +function OnUpdate(doc, meta) { + // only process our profile documents + if (doc.type !== "master_profile") return; + // aws_col is a bucket alias to the target bucket to replicate to AWS via + // XCDR. Write the minimal (non-sensitive) profile doc to the bucket for AWS. + aws_col["shared_profile::"+doc.id] = { + "type": "shared_profile", + "first_name": doc.first_name, + "id": doc.id, + "basic_profile": doc.basic_profile, + "timezone": doc.timezone + }; +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY master_profile::80927079070 + +{ + "type": "master_profile", + "first_name": "Peter", + "last_name": "Chang", + "id": 80927079070, + "basic_profile": { + "partner_id": 80980221, + "services": [ + { + "music": true + }, + { + "games": true + }, + { + "video": false + } + ] + }, + "sensitive_profile": { + "ssn": "111-11-1111", + "credit_card": { + "number": "3333-333-3333-3333", + "expires": "01/09", + "ccv": "111" + } + }, + "address": { + "home": { + "street": "4032 Kenwood Drive", + "city": "Boston", + "zip": "02102" + }, + "billing": { + "street": "541 Bronx Street", + "city": "Boston", + "zip": "02102" + } + }, + "phone": { + "home": "800-555-9201", + "work": "877-123-8811", + "cell": "878-234-8171" + }, + "locale": "en_US", + "timezone": -7, + "gender": "M" +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY shared_profile::80927079070 + +{ + "type": "shared_profile", + "first_name": "Peter", + "id": 80927079070, + "basic_profile": { + "partner_id": 80980221, + "services": [ + { + "music": true + }, + { + "games": true + }, + { + "video": false + } + ] + }, + "timezone": -7 +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-removeNullsAndEmptys.adoc b/modules/eventing/pages/eventing-handler-removeNullsAndEmptys.adoc new file mode 100644 index 000000000..2b1a72fa1 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-removeNullsAndEmptys.adoc @@ -0,0 +1,239 @@ += Function: removeNullObjectsAndElements +:description: pass:q[Recursively remove all nulls and empty items from a document.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *removeNullObjectsAndElements* will recursively prune nulls and empty items from a given JSON document. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on all documents where doc.type === "my_data_to_prune". +* This function is a superset of the cleanup functionality found in the Scriptlet xref:eventing-handler-removeObjectStubs.adoc[removeObjectStubs]. + +[{tabs}] +==== +removeNullObjectsAndElements:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, removeNullObjectsAndElements, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function removeNullParts(obj) { + // remove any null Objects + Object.keys(obj).forEach(k => + (obj[k] && typeof obj[k] === 'object') && removeNullParts(obj[k]) || + (!obj[k] && obj[k] !== undefined) && delete(obj[k]) // 6.6+ can use "delete obj[k]"" + ); + Object.keys(obj).forEach(k => + (obj[k] && Array.isArray(obj[k])) && + (obj[k] = obj[k].filter(element => element !== null)) + ); + return obj; +} + +function removeEmptyParts(obj) { + if (obj !== null && typeof obj == "object") { + Object.entries(obj).forEach(([k, v]) => { + if (obj[k] && typeof obj[k] === 'object') { + // recurse + removeEmptyParts(obj[k]) + // collapse out null's in Array if any + if (obj[k] && Array.isArray(obj[k])) { + obj[k] = obj[k].filter(element => element !== null) + } + // remove empty [] array items and {} object items + if ( + (obj[k] && Array.isArray(obj[k]) && obj[k].length === 0) || + (obj[k] && !Array.isArray(obj[k]) && Object.keys(obj[k]).length === 0) + ) { + delete(obj[k]) // 6.6+ can use "delete obj" + } + } + }); + } else { + // obj is a number or a string + } + return obj; +} + +function OnUpdate(doc, meta) { + if (doc.type !== "my_data_to_prune") return; + + // make a new doc without any nulls + var newdoc = removeNullParts(doc); + // make a new doc without {} [] empties + newdoc = removeEmptyParts(newdoc); + + // alias src_col to our source collection. Since rev 6.5+ allowed to be in r/w mode + src_col[meta.id] = newdoc; +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY my_data_to_prune::1001 + +{ + "type": "my_data_to_prune", + "id": 1001, + "a_first_super_long_name_right_here": 111, + "b": "my object", + "c": "", + "d": null, + "f": { + "v": 1, + "x": "", + "y": null, + "m": { + "a": "asd" + } + }, + "f2": { + "v": 1, + "x": "", + "y": null, + "m": { + "a": "asd", + "b": null, + "c": null, + "a_second_super_long_name_right_here": 222, + "ary1": [ + null, + 1, + null, + 2, + null, + 3 + ], + "ary2": [ + [ + 1, + 2 + ], + [ + 3, + 4 + ], + [ + 5, + null, + 6 + ], + { + "a": 1 + }, + { + "b": 2 + }, + { + "c": 3, + "d": null + }, + { + "e": null + }, + [ + null, + null, + null, + null + ] + ] + } + }, + "a_third_super_long_name_right_here": { + "x": 1, + "y": 2, + "z": null + } +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY my_data_to_prune::1001 + +{ + "type": "my_data_to_prune", + "id": 1001, + "a_first_super_long_name_right_here": 111, + "b": "my object", + "f": { + "v": 1, + "m": { + "a": "asd" + } + }, + "f2": { + "v": 1, + "m": { + "a": "asd", + "a_second_super_long_name_right_here": 222, + "ary1": [ + 1, + 2, + 3 + ], + "ary2": [ + [ + 1, + 2 + ], + [ + 3, + 4 + ], + [ + 5, + 6 + ], + { + "a": 1 + }, + { + "b": 2 + }, + { + "c": 3 + } + ] + } + }, + "a_third_super_long_name_right_here": { + "x": 1, + "y": 2 + } +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-removeObjectStubs.adoc b/modules/eventing/pages/eventing-handler-removeObjectStubs.adoc new file mode 100644 index 000000000..ae84bbaff --- /dev/null +++ b/modules/eventing/pages/eventing-handler-removeObjectStubs.adoc @@ -0,0 +1,145 @@ += Function: removeObjectStubs +:description: pass:q[Recursively remove all empty object stubs from a document.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *removeObjectStubs* will recursively prune empty objects from a given JSON document. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on all documents where doc.type === "my_data_to_prune". +* The removeEmptyParts function returns two (2) values in an array the doc and a flag indicating if a change has occurred. +This flag ary_obj_upd[1] will increase the performance of subsequent runs where the Feed boundary is set to Everything on large document sets. +* This function is a subset of the cleanup functionality found in the Scriptlet xref:eventing-handler-removeNullsAndEmptys.adoc[removeNullsAndEmptys]. + +[{tabs}] +==== +removeObjectStubs:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, removeObjectStubs, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "src_col", "bulk.data.source", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "src_col", "source", "read and write" + +function removeEmptyParts(ary_obj_upd) { + if (ary_obj_upd[0] !== null && typeof ary_obj_upd[0] == "object") { + Object.entries(ary_obj_upd[0]).forEach(([k, v]) => { + if (ary_obj_upd[0][k] && typeof ary_obj_upd[0][k] === 'object') { + // recurse + if (removeEmptyParts( + [ary_obj_upd[0][k],ary_obj_upd[1]])[1] == true) { + ary_obj_upd[1] = true; + } + // remove stub {} object items + if (ary_obj_upd[0][k] && !Array.isArray(ary_obj_upd[0][k]) && + Object.keys(ary_obj_upd[0][k]).length === 0 + ) { + delete(ary_obj_upd[0][k]) // 6.6+ can use "delete obj" + ary_obj_upd[1] = true; + } + } + }); + } else { + // obj is a number or a string + } + // return [ary_obj_upd[0],ary_obj_upd[1]]; + return ary_obj_upd; +} + +function OnUpdate(doc, meta) { + // optional filter to specific types + if (doc.type !== "my_data_to_prune") return; + + // try make a new doc without {} stubs + var altered = false; + var ary_obj_upd = removeEmptyParts([doc,altered]); + if (ary_obj_upd[1]) { + // We actualy did an update so we need to write to KV + // Note, the alias src_col (mode r+w) references the + // handlers source collection (allowed version 6.5+). + src_col[meta.id] = ary_obj_upd[0]; + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY my_data_to_prune::1001 + +{ + "type": "my_data_to_prune", + "root": { + "field1a": {}, + "field1b": { + "field2a": { + "value": 2 + } + }, + "field1c": { + "field2c": { + "value": 3, + "field3c": { + "value": 4, + "field4c": {} + } + } + } + } +} + +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY my_data_to_prune::1001 + + { + "type": "my_data_to_prune", + "root": { + "field1b": { + "field2a": { + "value": 2 + } + }, + "field1c": { + "field2c": { + "value": 3, + "field3c": { + "value": 4 + } + } + } + } +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-shippingNotifier.adoc b/modules/eventing/pages/eventing-handler-shippingNotifier.adoc new file mode 100644 index 000000000..4b0bf8734 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-shippingNotifier.adoc @@ -0,0 +1,479 @@ += Function: Shipping Notifier +:description: pass:q[Send notifications when an order scheduled to arrive, when it is shipped, and when it is delivered.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *shippingNotifier* demonstrates a shipping workflow. +* Requires Eventing Storage (or metadata collection), and "active", "archive", "notify" collections. +* Requires four buckets metadata, active (the source), archive, and a notify. +** The "notify"collection can be used to integrate with SDK or Kafka to send notifications. +* Will operate on any doc with type === "ship". +* Will update the source document with key information on each notify. +* Delivered the shipping recored is archived. +* On each notify data is read from the "active" bucket for type === "cust" and type === "order" as needed to build the notification. + +Other: + +* Note we could have used curl() to send the notify messages instead of using our staging bucket called "notify". +* There are no try catch blocks and only limited error checking to highlight the functionality. +* It is expected that the application that processes the "notify" bucket will purge the notification documents. +* The notification history is stored in the shipping document and archived for all time. + +[{tabs}] +==== +shippingNotifier:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, shippingNotifier, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.active +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "act_col", "bulk.data.active", "read and write" +// "bucket alias", "arc_col", "bulk.data.archive", "read and write" +// "bucket alias", "snd_col", "bulk.data.notify", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "act_col", "active", "read and write" +// "bucket alias", "arc_col", "archive", "read and write" +// "bucket alias", "snd_col", "notify", "read and write" + +function sendNotifySchedDelivCallback(context) { + // This is a normal sceduled delivery notificaton + + // Look up the controlling ship: doc + var shipkey = context.id; + var shipdoc = act_col[shipkey]; + if (shipdoc === null) { + // stale timer + return; + } + + // Make sure we are active and still need to send + if (shipdoc.type != "ship" || !shipdoc.active || shipdoc.notifys[context.idx].notifySent) return; + + // Look up the realted order: doc + var orderkey = "order" + ":" + shipdoc.id; + var orderdoc = act_col[orderkey]; + + // Look up the realted cusomer: doc + var custkey = "cust" + ":" + orderdoc.cust_id; + var custdoc = act_col[custkey]; + var notifyId = "ntfy" + ":" + context.idx + ":" + shipkey; + + // log('shipdoc', shipdoc); + // log('orderdoc', orderdoc); + // log('custdoc', custdoc); + // log("notifyId",notifyId); + + var senddoc = { + "notifyReason": context.item.notifyReason, + "first_name": custdoc.first_name, + "last_name": custdoc.last_name, + "email": custdoc.email, + "phone": custdoc.phone, + "items": orderdoc.items, + "utcOffset": shipdoc.utcOffset + }; + + // Add any special details + if (context.item.notifyReason === "scheduled delivery") { + senddoc["schedDelivTs"] = shipdoc.schedDelivTs; + } else + if (context.item.notifyReason === "delivered") { + senddoc["deliveredTs"] = shipdoc.deliveredTs; + } else + if (context.item.notifyReason === "shipped") { + senddoc["shippedTs"] = shipdoc.shippedTs; + } + + // Write to send bucket -or- emit via cURL + snd_col[notifyId] = senddoc; + + // Mark as sent + shipdoc.notifys[context.idx].notifySent = true; + + // See if we are done and can archive this + if (shipdoc.delivered && context.item.notifyReason === "delivered") { + shipdoc.active = false; + // Yes we can archive write to archive bucket + arc_col[shipkey] = shipdoc; + // and remove + delete act_col[shipkey]; + } else { + // No just update in the source bucket + act_col[shipkey] = shipdoc; + } + + log("senddoc", senddoc); +} + +function OnUpdate(doc, meta) { + // Filter out non interesting items + if (doc.type != "ship" || !meta.id.startsWith("ship:") || !doc.active) return; + + var nowMs = Date.now(); // this instant or now in ms. + var nowSec = Math.trunc(nowMs / 1000); // this instant or now in sec. + + if (doc.shipped || doc.delivered) { + // these are events they do not need to be scheduled via a Timer + if (doc.shipped) { + if (doc.shippedTs === null) { + doc.shippedTs = nowSec; + } + var item = { + "notifyReason": 'shipped', + "notifyTs": nowSec, + "notifySent": false + }; + } + if (doc.delivered) { + if (doc.deliveredTs === null) { + doc.deliveredTs = nowSec; + } + var item = { + "notifyReason": 'delivered', + "notifyTs": nowSec, + "notifySent": false + }; + } + // Add to the notification array or history + doc.notifys.push(item); + // Write the source doc since we will sending an immediate notification + act_col[meta.id] = doc; + var context = { + "item": item, + "idx": doc.notifys.length - 1, + "id": meta.id + }; + // There no need for a timer we can do this now since it is an event + sendNotifySchedDelivCallback(context); + return; + } + + // Look for any needed notifications in the future + for (var idx = 0; idx < doc.notifys.length; idx++) { + var item = doc.notifys[idx]; + if (!item.notifySent) { + + // JavaScript works in ms. BUT the doc's fields are in sec. - so convert and make a Date() + var fireAt = new Date(item.notifyTs * 1000); + + // Make unique ref for this notification can overwrite/adjust or cancel + var notifyId = "ntfy" + ":" + idx + ":" + meta.id; + + // Pass minimal data in our context, the callback will look everything else up. + var context = { + "item": item, + "idx": idx, + "id": meta.id + }; + + // We will always 'overwrite' this timer(s) notification by the Timer's + // reference_id (6.6.0+ required for this) on every mutation + // log("create/overwrite notification "+ notifyId, item); + createTimer(sendNotifySchedDelivCallback, fireAt, notifyId, context); + } + } +} +---- +-- + +Input Data/Mutation:: ++ +-- + +We want to create a test set of three (3) documents. Use the Query Editor to insert the the data items (you do not need an index). + +NOTE: For key "ship:dea0fca2-e7b7-11ea-adc1-0242ac120002", you may want to adjust the timestamps as the times are in seconds since Unix epoch. Use a tool like https://www.dcode.fr/timestamp-converter or https://www.epochconverter.com/ . + +[source,sqlpp] +---- + UPSERT INTO `bulk`.`data`.`active` (KEY,VALUE) + VALUES ( "order:dea0fca2-e7b7-11ea-adc1-0242ac120002", { + "type": "order", + "id": "dea0fca2-e7b7-11ea-adc1-0242ac120002", + "cust_id": 108998, + "items": [ + { + "sku": "SK18768", + "descr": "Ticondorna pencils 12 pack", + "qty": 3 + }, + { + "sku": "SK89736", + "descr": "Sharpie large marker", + "qty": 1 + } + ] + }), + VALUES ( "cust:108998", { + "type": "cust", + "id": 108998, + "first_name": "John", + "last_name": "Smith", + "email": "jon.smith@gmail.com", + "addr1": "1010 E. 100th Ave.", + "addr2": "Apt 101B", + "city": "New York", + "state": "NY", + "zip": 10000, + "phone": "+1 714-222-2222" + }), + VALUES ( "ship:dea0fca2-e7b7-11ea-adc1-0242ac120002", { + "type": "ship", + "id": "dea0fca2-e7b7-11ea-adc1-0242ac120002", + "utcOffset": -420, + "orderTs": 1598214610, + "schedDelivTs": 1598486400, + "shippedTs": null, + "deliveredTs": null, + "notifys": [ + { + "notifyTs": 1598450400, + "notifyReason": "scheduled delivery", + "notifySent": false + } + ], + "exceptions": [], + "shipped": false, + "delivered": false, + "active": true + }); +---- +-- + +Output Data/Mutation:: ++ +-- + +To fully exercise the logic, run the following steps(to re-run flush the 'active', 'archive' and 'notify' collections and redo the UPSERT the data): + +* Deploy the Function with a Feed Boundary from "Everything". +** Wait for about 7-14 seconds (timers are high volume not wall clock accurate) and notice collection "notify" has our first notification (the timer was scheduled in the past). +** The shipping document will be modified in collection 'active' as follows: ++ +[source,json] +---- +UPDATED/OUTPUT: KEY ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "active" +{ + "active": true, + "delivered": false, + "deliveredTs": null, + "exceptions": [], + "id": "dea0fca2-e7b7-11ea-adc1-0242ac120002", + "notifys": [ + { + "notifyReason": "scheduled delivery", + "notifySent": true, + "notifyTs": 1598450400 + } + ], + "orderTs": 1598214610, + "schedDelivTs": 1598486400, + "shipped": false, + "shippedTs": null, + "type": "ship", + "utcOffset": -420 +} +---- ++ +** You will now have the first notificaton document in collection 'notify' as follows: ++ +[source,json] +---- +NEW/OUTPUT: KEY ntfy:0:ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "notify" +{ + "notifyReason": "scheduled delivery", + "first_name": "John", + "last_name": "Smith", + "email": "jon.smith@gmail.com", + "phone": "+1 714-222-2222", + "items": [ + { + "descr": "Ticondorna pencils 12 pack", + "qty": 3, + "sku": "SK18768" + }, + { + "descr": "Sharpie large marker", + "qty": 1, + "sku": "SK89736" + } + ], + "utcOffset": -420, + "schedDelivTs": 1598486400 +} +---- ++ +** The application log for the Eventing handler will show something like the following: ++ +2021-07-18T21:17:51.715-07:00 [INFO] "senddoc" {"notifyReason":"scheduled delivery","first_name":"John","last_name":"Smith","email":"jon.smith@gmail.com","phone":"+1 714-222-2222","items":[{"descr":"Ticondorna pencils 12 pack","qty":3,"sku":"SK18768"},{"descr":"Sharpie large marker","qty":1,"sku":"SK89736"}],"utcOffset":-420,"schedDelivTs":1598486400} + +* In collection "active" mutate ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 by setting "shipped" to true. +** The shiping document will be automatically modified in collection 'active' as follows: ++ +[source,json] +---- +UPDATED/OUTPUT: KEY ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "active" +{ + "active": true, + "delivered": false, + "deliveredTs": null, + "exceptions": [], + "id": "dea0fca2-e7b7-11ea-adc1-0242ac120002", + "notifys": [ + { + "notifyReason": "scheduled delivery", + "notifySent": true, + "notifyTs": 1598450400 + }, + { + "notifyReason": "shipped", + "notifyTs": 1626668498, + "notifySent": true + } + ], + "orderTs": 1598214610, + "schedDelivTs": 1598486400, + "shipped": true, + "shippedTs": 1626668498, + "type": "ship", + "utcOffset": -420 +} +---- ++ +** You will now have the second notificaton document in collection 'notify' as follows: ++ +[source,json] +---- +NEW/OUTPUT: KEY ntfy:1:ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "notify" +{ + "notifyReason": "shipped", + "first_name": "John", + "last_name": "Smith", + "email": "jon.smith@gmail.com", + "phone": "+1 714-222-2222", + "items": [ + { + "descr": "Ticondorna pencils 12 pack", + "qty": 3, + "sku": "SK18768" + }, + { + "descr": "Sharpie large marker", + "qty": 1, + "sku": "SK89736" + } + ], + "utcOffset": -420, + "shippedTs": 1626668498 +} +---- ++ +** The Application log for the Eventing handler will show something like the following ++ +2021-07-18T21:21:38.547-07:00 [INFO] "senddoc" {"notifyReason":"shipped","first_name":"John","last_name":"Smith","email":"jon.smith@gmail.com","phone":"+1 714-222-2222","items":[{"descr":"Ticondorna pencils 12 pack","qty":3,"sku":"SK18768"},{"descr":"Sharpie large marker","qty":1,"sku":"SK89736"}],"utcOffset":-420,"shippedTs":1626668498} + +* In collection "active", mutate ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 again by setting "delivered" to true. +** The shiping document will be removed from collections 'active' and archived to the collection 'archive' as follows: ++ +[source,json] +---- +DELETE/OUTPUT: KEY ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "active" + +NEW/OUTPUT: KEY ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "archive" +{ + "active": false, + "delivered": true, + "deliveredTs": 1626668622, + "exceptions": [], + "id": "dea0fca2-e7b7-11ea-adc1-0242ac120002", + "notifys": [ + { + "notifyReason": "scheduled delivery", + "notifySent": true, + "notifyTs": 1598450400 + }, + { + "notifyReason": "shipped", + "notifyTs": 1626668498, + "notifySent": true + }, + { + "notifyReason": "delivered", + "notifyTs": 1626668622, + "notifySent": true + } + ], + "orderTs": 1598214610, + "schedDelivTs": 1598486400, + "shipped": true, + "shippedTs": 1626668498, + "type": "ship", + "utcOffset": -420 +} +---- ++ +** You will now have the third and final notificaton document in collection 'notify' as follows: ++ +[source,json] +---- +NEW/OUTPUT: KEY ntfy:2:ship:dea0fca2-e7b7-11ea-adc1-0242ac120002 in collection "notify" +{ + "notifyReason": "delivered", + "first_name": "John", + "last_name": "Smith", + "email": "jon.smith@gmail.com", + "phone": "+1 714-222-2222", + "items": [ + { + "descr": "Ticondorna pencils 12 pack", + "qty": 3, + "sku": "SK18768" + }, + { + "descr": "Sharpie large marker", + "qty": 1, + "sku": "SK89736" + } + ], + "utcOffset": -420, + "deliveredTs": 1626668622 +} +---- ++ +** The Application log for the Eventing handler will show something like the following ++ +2021-07-18T21:23:42.248-07:00 [INFO] "senddoc" {"notifyReason":"delivered","first_name":"John","last_name":"Smith","email":"jon.smith@gmail.com","phone":"+1 714-222-2222","items":[{"descr":"Ticondorna pencils 12 pack","qty":3,"sku":"SK18768"},{"descr":"Sharpie large marker","qty":1,"sku":"SK89736"}],"utcOffset":-420,"deliveredTs":1626668622} + +Note that with respect to the notifications that were created: + +* index 0 created a Timer that was fired immediately as it used a timer and was in the past. ++ +notifyTs = 2020-08-26T14:00:00.000Z or Wed Aug 26 2020 07:00:00 GMT-0700 (Pacific Daylight Time) +* index 1 was an event e.g. shipped was mutated to true (it didn't need a Timer) and fired instantly. ++ +shippedTs = 2021-07-19T04:21:38.000Z or Sun Jul 18 2021 21:21:38 GMT-0700 (Pacific Daylight Time) +* index 2 was an event e.g. delivered was mutated to true (it didn't need a Timer) and fired instantly. ++ +deliveredTs = 2021-07-19T04:23:42.000Z or Sun Jul 18 2021 21:23:42 GMT-0700 (Pacific Daylight Time) +-- +==== diff --git a/modules/eventing/pages/eventing-handler-simpleFlatten.adoc b/modules/eventing/pages/eventing-handler-simpleFlatten.adoc new file mode 100644 index 000000000..e1c8e1183 --- /dev/null +++ b/modules/eventing/pages/eventing-handler-simpleFlatten.adoc @@ -0,0 +1,131 @@ += Function: simpleFlatten +:description: pass:q[Flatten a document for integration with a non-NOSQL RDBMS.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *simpleFlatten* shows how a document can be flattened into a RDBMS importable record. +* Requires Eventing Storage (or metadata collection), a "source" collection, and a "destination" collection. +* Will operate on all documents where doc.type === "tosync". +* Will write transformed or flattened documents to the destination bucket with the same type and id. +* Will also remove the flattened document in the destination bucket when the original source document is removed. +* The "destination" collection can be shared (or replicated via XCDR to a business partner) too the cloud (AWS, Azure or GCP). +* Note since the document is not available during an OnDelete we will filter by KEY prefix starting with `"tosync:".*`. This is a hard coded implementation. Refer to xref:eventing-handler-genericFlatten.adoc[genericFlatten] for a generic implementation. + +[{tabs}] +==== +simpleFlatten:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, simpleFlatten, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket.scope.collection", "Access" +// "bucket alias", "dst_col", "bulk.data.destination", "read and write" +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) +// 1. "binding type", "alias name...", "bucket", "Access" +// "bucket alias", "dst_col", "destination", "read and write" + +function OnUpdate(doc, meta) { + // filter + if (!doc.type || doc.type !== "tosync") return; + + log("OnUpdate IN id: "+meta.id+", doc: ",doc); + try { + // convert + var oracleDoc = { + // flatten items simple 1:1 map + "id": doc.id, "type":doc.type, + // flatten subdoc + "a_sub_aa": doc.a.aa, "a_sub_ab": doc.a.ab, "a_sub_ac": doc.a.ac, + // flatten array + "b_ary_0": doc.b[0], "b_ary_1": doc.b[1], "b_ary_2": doc.b[2] + } + // log + log("OnUpdate OUT id: "+meta.id+", oracleDoc:",oracleDoc); + } catch (e) { + log ("Error on convert: "+e+", id:",meta.id); + } + // save + try { + dst_col[meta.id] = oracleDoc; + } catch (e) { + log("Error on save: "+e+", id:", meta.id); + } +} + +function OnDelete(meta, options) { + // filter + if (!(meta.id.startsWith("tosync:"))) return; + + log("OnDelete expired=" + options.expired +" REM id: "+meta.id); + try { + delete dst_col[meta.id]; + } catch (e) { + log("Error on delete: "+e+", id:",meta.id); + } +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY tosync::1 + +{ + "id": 1, + "type": "tosync", + "a": { + "aa": 1, + "ab": 2, + "ac": 3 + }, + "b": [ + 1, + 3, + 7 + ] +} +---- +-- + +Output Data/Mutation:: ++ +-- +[source,json] +---- +UPDATED/OUTPUT: KEY tosync::1 + +{ + "id": 1, + "type": "tosync", + "a_sub_aa": 1, + "a_sub_ab": 2, + "a_sub_ac": 3, + "b_ary_0": 1, + "b_ary_1": 3, + "b_ary_2": 7 +} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-handler-simpleTimer.adoc b/modules/eventing/pages/eventing-handler-simpleTimer.adoc new file mode 100644 index 000000000..211a1971b --- /dev/null +++ b/modules/eventing/pages/eventing-handler-simpleTimer.adoc @@ -0,0 +1,91 @@ += Function: Simple Timer +:description: pass:q[Create a Simple Timer that triggers in the future on each mutation.] +:page-edition: Enterprise Edition +:tabs: + +*Goal*: {description} + +* This function *simpleTimer* merely demonstrates a basic Evening Timer. +* Requires Eventing Storage (or metadata collection) and a "source" collection. +* Will operate on any mutation where the KEY or meta.id starts with "simpletimer:". +* The result of processing the mutation is a Timer that will be executed approximately 30 seconds in the future. +* For more details on Timers refer to xref:eventing-timers.adoc[Timers]. +* For an example of a recurring Timer refer to: xref:eventing-examples-recurring-timer.adoc[Recurring Timer]. + +[{tabs}] +==== +simpleTimer:: ++ +-- +[source,javascript] +---- +// To run configure the settings for this Function, simpleTimer, as follows: +// +// Version 7.1+ +// "Function Scope" +// *.* (or try bulk.data if non-privileged) +// Version 7.0+ +// "Listen to Location" +// bulk.data.source +// "Eventing Storage" +// rr100.eventing.metadata +// Binding(s) - none +// +// Version 6.X +// "Source Bucket" +// source +// "MetaData Bucket" +// metadata +// Binding(s) - none + +function TimerCallback(context) { + log('From TimerCallback: timer fired with context', context); + // do any sort of recurring work here, just update a date_stamp in a doc +} + +function OnUpdate(doc, meta) { + // You would typically filter to mutations of interest + if (! meta.id.startsWith("simpletimer:")) return; + + // Make a Date 30 seconds in the future + var thirtySecFromNow = new Date(); // Get current time & add 30 sec. to it. + thirtySecFromNow.setSeconds(thirtySecFromNow.getSeconds() + 30); + + // Timers require an id + var timer_id = meta.id; + // Timers can access a context when they fire + var context = {"id": meta.id, "random": Math.random(), "sched": thirtySecFromNow, doc: doc} + + // crate the Timer + createTimer(TimerCallback, thirtySecFromNow, timer_id, context); + log("From OnUpdate createTimer(TimerCallback, "+thirtySecFromNow+","+ timer_id+",", context); +} +---- +-- + +Input Data/Mutation:: ++ +-- +[source,json] +---- +INPUT: KEY simpletimer:1 + +{ + "id": 1, + "type": "simpletimer", + "data": "ABCDEFG" +} +---- +-- + +Output Data/Logged:: ++ +-- +[source,json] +---- +2021-07-18T19:47:53.842-07:00 [INFO] "From TimerCallback: timer fired with context" {"id":"simpletimer:1","random":0.9470436283584234,"sched":"2021-07-19T02:47:48.405Z","doc":{"id":1,"type":"simpletimer","data":"ABCDEFG"}} + +2021-07-18T19:47:18.407-07:00 [INFO] "From OnUpdate createTimer(TimerCallback, Sun Jul 18 2021 19:47:48 GMT-0700 (Pacific Daylight Time),simpletimer:1," {"id":"simpletimer:1","random":0.9470436283584234,"sched":"2021-07-19T02:47:48.405Z","doc":{"id":1,"type":"simpletimer","data":"ABCDEFG"}} +---- +-- +==== diff --git a/modules/eventing/pages/eventing-language-constructs.adoc b/modules/eventing/pages/eventing-language-constructs.adoc new file mode 100644 index 000000000..4b491736c --- /dev/null +++ b/modules/eventing/pages/eventing-language-constructs.adoc @@ -0,0 +1,684 @@ += Language Constructs +:description: Language constructs are the fundamental units of a language. +:page-toclevels: 2 + +[abstract] +{description} + +This page describes which JavaScript constructs Eventing Functions do and do not support. + +NOTE: Couchbase functions inherit support for most ECMAScript constructs by using Google v8 as the execution container. +Certain capabilities have been removed and are not supported in order to handle the automatic sharding and scaling of functions. + +[#supported-lang-features] +== Supported Language Features + +Eventing Functions support the following features: + +* <> +* <> +* <> +* <> + +[#basic_bucket_accessors] +=== Basic Keyspace Accessors + +Buckets that are bound to an Eventing Function appear as a global JavaScript map. +Map operations like GET, SET, and DELETE are exposed to the GET, SET, and DELETE Data Service provider operations. + +If the bucket binding has a wildcard `*` for its scope or collection, you cannot use a Basic Keyspace Accessor to access the Data Service. Instead, you must use an <>. + +[cols="20,80",options="header"] + +|=== +|Operation +|Description + +|GET +|`operator[]` is applied on a bucket binding and used as a value expression. + +Fetches the object from the KV bucket that the variable is bound to. +Returns the parsed JSON value as a JavaScript object. + +Fetching a non-existent object from a bucket returns an undefined value. +This operation throws an exception if the underlying bucket GET operation fails with an unexpected error. + +|SET +|`operator[]` appears to the left of the `=` assignment statement. + +Sets the provided JavaScript value into the KV bucket that the variable is bound to. +Replaces any existing value with the specified key. + +This operation throws an exception if the underlying bucket SET operation fails with an unexpected error. + +|DELETE +|`operator[]` appears after the JavaScript delete keyword. + +Deletes the provided key from the KV bucket that the variable is bound to. +Returns a no-op if the object does not exist. + +This operation throws an exception if the underlying bucket DELETE operation fails with an unexpected error. + +|=== + +[source,javascript] +---- +function OnUpdate(doc, meta) { + // Assuming 'dest' is a bucket alias or binding to a keyspace + var val = dest[meta.id]; // this is a bucket GET operation + dest[meta.id] = {"status":3}; // this is a bucket SET operation + delete dest[meta.id]; // this is a bucket DEL operation +} +---- + +[#advanced_bucket_accessors] +=== Advanced Keyspace Accessors + +Advanced Keyspace Accessors expose a larger set of options and operators than <>. +They have non-trivial argument sets and return values. + +See xref:eventing-advanced-keyspace-accessors.adoc[] for more details. + +[#logging] +=== Logging + +The `log()` function allows Eventing Functions to log user-defined messages. +`log()` statements are logged in each Eventing Function's log file. + +`log()` does not throw exceptions. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + log("Now processing: " + meta.id); +} +---- + +The Eventing Service also creates a system log file named `eventing.log`. +This file exists in all Eventing Functions and captures management and lifecycle information. +The end-user cannot write to this file. + +ifdef::flag-devex-rest-api[] +See xref:eventing-debugging-and-diagnosability.adoc#logging-functions[Logging Functions] for more information. +endif::flag-devex-rest-api[] + +[#n1ql_statements] +=== {sqlpp} Statements + +You can use top-level {sqlpp} keywords like SELECT, UPDATE, INSERT, and DELETE as inline words in Eventing Functions. +These operations are accessible through the returned iterable handle. + +{sqlpp} Query results, through the SELECT operation, are streamed in batches to the iterable handle as the iteration progresses through the result set. + +NOTE: To avoid recursion, an Eventing Function can listen for mutations in a bucket. +{sqlpp} DML statements cannot manipulate documents in that same bucket. +To work around this, you can use the exposed data service KV map in your Eventing Function. + +The following Function has a feed boundary of *Everything*, which means the same {sqlpp} statement is executed 7,303 times. +To execute only one query, you can configure your feed boundary to be *From now* and to mutate only one document in the keyspace `beer-sample`.`_default`.`_default`. + +You can also use an optimal index, which makes your query performance 24 times faster. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + var strong = 70; + var results = + SELECT * /* SQL++ queries are embedded directly */ + FROM `beer-sample`._default._default /* Token escaping is standard SQL++ style */ + WHERE abv > $strong; // Local variable reference using $ syntax + for (var beer of results) { // Stream results using 'for' iterator + log(beer); + break; + } + results.close(); // End the query and free resources held +} +---- + +The embedded {sqlpp} call starts the query and returns a JavaScript iterable object that represents the result set of the query. You can iterate the returned handle using standard JavaScript mechanisms like `for...of` loops. + +The iterator is an input iterator, meaning the elements are read-only. +The variables created inside the iterator are local to it. +You cannot use the keyword `this` in the body of the iterator. + +You must close each result set with the `close()` method, which stops the underlying {sqlpp} query and releases associated resources. +In some cases like nested {sqlpp} lookups, failing to explicitly call `close()` can use too many {sqlpp} resources and lead to poor performance. + +==== Valid and Invalid Statements + +{sqlpp} is not syntactically part of the JavaScript language. +Eventing transpiles the Eventing Function code to identify {sqlpp} statements and convert them to a standard JavaScript function call. +This call then returns an iterable object with a `close()` method. + +To use a JavaScript variable in a query statement, you must use `$`. +This parameter is substituted in the query by the corresponding JavaScript variable's runtime value. + +You cannot use the `meta.id` expression in the query statement. +Instead, you must use `var id = meta.id`. + +The following is a valid statement: +[source, sqlpp] +---- +var id = meta.id; +DELETE FROM mybucket.myscope.transactions WHERE username = $id; +---- + +The following is an invalid statement: +[source, sqlpp] +---- +DELETE FROM mybucket.myscope.transactions WHERE username = $meta.id; +---- + +==== Escaped Identifiers + +When you use a {sqlpp} query inside an Eventing Function, you must also use an escaped identifier for keyspaces with special characters. To escape an identifier, enclose it in back ticks (``). + +If the bucket name is `beer-sample` and the scope and collection are both `_default`, you only need to escape the bucket in the {sqlpp} query: +[source, sqlpp] +---- +SELECT * FROM `beer-sample`._default._default WHERE type ... +---- + +If the bucket name is `beersample`, you do not need to escape the keyspace of the {sqlpp} query: +[source, sqlpp] +---- +SELECT * FROM beersample._default._default WHERE type ... +---- + +==== End of Line Comments + +In multiline {sqlpp} statements, you cannot use single line `// end of line comments` before the semicolon at the end of the statement. +This causes syntax errors in the transformation and compilation of the {sqlpp} statement. + +To include comments in multiline statements, use `/* this format */` instead. + + +[#unsupported-lang-features] +== Unsupported Language Features + +The following features are not supported by Eventing Functions: + +* <> +* <> +* <> +* <> + +[#global-state] +=== Global State + +Eventing Functions do not support global variables. +This restriction makes sure that the logic of Eventing Functions remains agnostic of rebalance operations. + +Instead of using global variables, you must save and retrieve all states from persistence providers like the Data Service. +You can use bindings to make all global states contained in Data Service buckets available to Eventing Functions. + +[source,javascript] +---- +var count = 0; // Not allowed - global variable. +function OnUpdate(doc, meta) { + count++; +} +---- + +You can use Constant alias bindings in your Function's settings to access global constants within a Function's JavaScript. +For example, a Constant alias of `debug` with a value of `true` or `false` behaves in the same way as the statement `const debug = true`. + +[#asynchrony] +=== Asynchrony + +Eventing Functions do not support asynchronous flows. + +Asynchrony creates a node-specific, long-running state that prevents persistence providers from capturing the entire state. +This limits Eventing Functions to executing short-running, straight-line code without sleep and wake-ups. + +You can use Timers to add limited asynchrony back into your Function. +Timers are designed specifically to prevent a state from being node-specific. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + setTimeout(function(){}, 300); // Not allowed - asynchronous flow. +} +---- + +[#browser_extensions] +=== Browser and Other Extensions + +Eventing Functions do not support browser extensions, like window methods and DOM events. + +You can use Timers instead of `setTimeout` and curl calls instead of `XMLHttpRequests`. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + var rpc = window.XMLHttpRequest(); // Not allowed - browser extension. +} +---- + +[#library_imports] +=== Library Imports + +The Eventing Service does not support importing libraries into Eventing Functions. + + +[#build-in-functions] +== Built-in Functions + +Eventing Functions support the following built-in functions: + +* <> +* <> +* <> +* <> +* <> +* <> +* <> + +[#n1ql_call] +=== `N1QL()` + +You cannot use the `N1QL()` function call directly because it bypasses the semantic and syntactic checks of the transpiler. + +NOTE: The `N1QL()` function has replaced the deprecated `N1qlQuery()`. + +The `N1QL()` function contains the following parameters: + +[cols="35,70",options="header"] + +|=== +|Parameter +|Description + +|`statement` +|The identified {sqlpp} statement. +This is passed to {sqlpp} through SDK to run as a prepared statement. + +All the JavaScript variables referenced in the statement using the `$` notation are treated as named parameters. + +|`params` +a|Can be a JavaScript array or a JavaScript map object. + +* `params` is a JavaScript array when the {sqlpp} statement executes positional parameters. +This array corresponds to the values bound to the positional parameters. + +* `params` is a JavaScript map object when the {sqlpp} statement executes named parameters. +This map object provides the name-value pairs that correspond to the variables used by the {sqlpp} statement. + +You cannot mix positional and named parameters. + +Example of an iterator using a positional `params` array: + +[source,javascript] +---- + // Using `travel-sample`._default._default to demonstrate params. + // a) Positional param 1 is field 'iata' from the input doc + // b) Positional param 2 from an Eventing Function variable: max_dist + // c) Will also prepare the statement for better performance + + if (doc.type !== "airline") return; // only process airline docs + + var max_dist = 120; + var results = N1QL( + "SELECT COUNT(*) AS cnt " + + "FROM `travel-sample`._default._default " + + "WHERE type = \"route\" " + + "AND airline = $1 AND distance <= $2", + [doc.iata,max_dist], + { 'isPrepared': true } + ); +---- + +Example of an iterator using a named `params` map object: + +[source,javascript] +---- + // Using `travel-sample`._default._default to demonstrate named params. + // a) Named param 1 '$mytype' is a hardcode + // b) Named param 2 '$myairline' is field 'iata' from the input doc + // c) Named param 3 '$mydistance' if from an Eventing Function variable max_dist + // d) Set the consistency in the options to none + + if (doc.type !== "airline") return; // only process airline docs + + var max_dist = 120; + var results = N1QL("SELECT COUNT(*) AS cnt " + + "FROM `travel-sample`._default._default " + + "WHERE type = $mytype " + + "AND airline = $myairline AND distance <= $mydistance", + { '$mytype': 'route', '$mydistance': max_dist, '$myairline': doc.iata }, + { 'consistency': 'none' } + ); +---- + +|`options` +a|A JSON object that has various query runtime options as keys. +The following settings are available: + +* `isPrepared` determines if the statement is prepared. +This setting defaults to `false`, but you can change it to `true` to increase the performance of any {sqlpp} query. + +* `consistency` determines the consistency level for the statement. +This setting defaults to the consistency level specified in your Eventing Function settings, but you can change it on any individual statement. +Valid values are `none` and `request`. + +|`return value (handle)` +|Returns a JavaScript iterable object that represents the result set of the query. +You can iterate the returned handle using standard JavaScript mechanisms like `for...of` loops. + +You can use the `close()` method on the handle object to release the resources held by the {sqlpp} query. +This method also cancels queries that are in the process of streaming results. + +|Exceptions thrown +|The `N1QL()` function throws an exception if the underlying {sqlpp} query fails to parse or does not start to execute. + +The returned iterable handle throws an exception if the underlying {sqlpp} query fails after it has started. + +The `close()` method on the iterable handle can throw an exception if the underlying {sqlpp} query cancellation finds an unexpected error. + +|=== + +[#analytics_call] +=== `couchbase.{zwsp}analyticsQuery({wj})` + +[.status]#Couchbase Server 7.6# + +The `couchbase.analyticsQuery()` function provides integration with {sqlpp} Analytics directly from the Eventing Service. + +Integrating Eventing with Analytics: + +* Allows Eventing to benefit from the high availability and load balancing of Analytics, where requests can take turns being submitted across nodes +* Simplifies Eventing code logic and improves code readability +* Eliminates security and network latency issues with the `curl()` function + +The following example assumes that the Analytics collection (dataset) called `default` already exists. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + var count = 0; + const limit = 4; + + let query = couchbase.analyticsQuery('SELECT * FROM default LIMIT $limit;', { + "limit": limit + }); + for (let row of query) { + ++count; + } + + if (count === limit) { + dst_bucket[meta.id] = 'yes'; + } +} +---- + +For more information about {sqlpp} Analytics, see xref:server:analytics:1_intro.adoc[]. + +[#crc64_call] +=== `crc64()` + +The `crc64()` function: + +* Calculates the CRC64 hash of an object using the ISO polynomial +* Suppresses double mutations + +The `crc64()` function takes the object to checksum as its only parameter. +The parameter can be any JavaScript object that can be encoded to JSON. + +The function returns the hash as a string. +The hash is sensitive to the order of the parameters in the case of map objects. + +If multiple Eventing Functions share the same `crc64` checksum documents as the Sync Gateway, real mutations can be suppressed and missed. +To prevent this from happening, you can make the checksum documents unique to each Eventing Function. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + var crc_str = crc64(doc); + /// Code goes here +} +---- + +You can also use the `crc64` function to suppress a double mutation. +A double mutation can happen when the Sync Gateway and the Eventing Function leverage the same bucket. + +The Sync Gateway updates the metadata of the document inside the bucket and generates an event for the Eventing Function to process. +The Eventing Function cannot differentiate between events from the Sync Gateway and events from SDKs, {sqlpp}, and other sources. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + // Ignore documents created by Sync Gateway + if(meta.id.startsWith("_sync") == true) return; + + // Ignore documents whose body has not changed since we last saw it + var prev_crc = checksum_bucket[meta.id]; + var curr_crc = crc64(doc); + if (prev_crc === curr_crc) return; + checksum_bucket[meta.id] = curr_crc; + + // Business logic goes in here +} +---- +.Translating strings +[NOTE] +==== +Bear in mind that using `crc64()` to convert strings will include any quotation marks as part of the conversion. +If you want to translate the string [.underline]#without# including the enclosing quotes, then use the <> instead. + +This does not apply to any other data type (e.g., numeric data or JSON data types). +==== + +[#crc_64_go_iso_call] +=== `crc_64_go_iso()` + +[.status]#Couchbase Server 7.6# + +`crc_64_go_iso()` performs the same function as <>, but does not include the enclosing quotation marks from the parameter in the translation if its parameter type is `string`. + +Other datatypes work the same as the `crc64()` call. + + +[source,javascript] +---- +function OnUpdate(doc, meta) { + var crc_iso_str = couchbase.crc_64_go_iso(doc); + /// Code goes here +} +---- + + +[#base64_call] +=== `base64()` + +[.status]#Couchbase Server 7.6# + +The `base64()` functions let you pack large-dimensional arrays of floats as base64 encoded strings when you use the Eventing Service to generate vector embeddings. +This encoding process stores and transmits arrays as text, ensuring data integrity and compatibility with text-based systems. + +The following `base64()` functions are available: + +* `base64Encode()`, which takes a JSON argument and returns a base64 string. ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + var base_str = couchbase.base64Encode(doc); + /// Code goes here +} +---- ++ +* `base64Decode()`, which takes a base64 encoded string and returns a value string. ++ +[source,javascript] +---- +function OnUpdate(doc, meta) { + var base_str = couchbase.base64Decode(doc); + /// Code goes here +} +---- ++ +* `couchbase.base64Float32ArrayEncode()`, which takes a float32 number array and returns a base64 string. +* `couchbase.base64Float32ArrayDecode()`, which takes a base64 encoded string and returns a float32 number array. +* `couchbase.base64Float64ArrayEncode()`, which takes a float64 number array and returns a base64 string. +* `couchbase.base64Float64ArrayDecode()`, which takes a base64 encoded string and returns a float64 number array. + +[#timers_general] +=== `createTimer()` and `cancelTimer()` + +Timers are asynchronously computed. +They allow Eventing Functions to execute in reference to wall-clock events. + +[#createtimer_call] +To create a Timer, call the `createTimer()` function using `createTimer(callback, date, reference, context)`. +This function executes at or close to a specified date. + +The reference is an identifier for the Timer that is scoped to an Eventing Function and callback. +The context must be serializable data that is available to the callback when the Timer is fired. + +[#canceltimer_call] +To cancel a Timer, you can do one of the following: + +* Call the `createTimer()` function again using a reference from the existing Timer you want to cancel. +* Call the `cancelTimer()` function using `cancelTimer(callback, reference)`. + +For more information about Timers, see xref:eventing-timers.adoc[]. + +[#curl_call] +=== `curl()` + +The `curl()` function lets you interact with external entities through a REST endpoint from Eventing Functions, using either HTTP or HTTPS. + +For more information about the `curl()` function, see xref:eventing-curl-spec.adoc[]. + + +[#handler-signatures] +== Handler Signatures + +The Eventing Service calls the following JavaScript functions on events like mutations and fired Timers: + +* <> +* <> +* <> + +[#onupdate_handler] +=== OnUpdate Handler + +The `OnUpdate` handler is called when you create or modify a document using an operation like insert or update. +The entry point `OnUpdate(doc, meta)` listens to mutations in the associated source bucket. + +The `OnUpdate` handler has the following limitations: + +* If a document is modified several times in a short period of time, the handler calls might be combined into a single event due to deduplication. +* You cannot distinguish between a Create and an Update operation. + +[source,javascript] +---- +function OnUpdate(doc, meta) { + if (doc.type === 'order' && doc.value > 5000) { + // ‘phoneverify’ is a bucket alias or binding to a keyspace + phoneverify[meta.id] = doc.customer; + } +} +---- + +[#ondelete_handler] +=== OnDelete Handler + +The `OnDelete` handler is called when a document is deleted or removed due to expiration. +The entry point `OnDelete(meta, options)` listens to mutations like deletions and expirations in the associated source bucket. + +To make sure that a document has been deleted or has expired, you can inspect the optional argument `options`. +The `options` argument is a JavaScript map object that contains the boolean property `expired`. + +You cannot get the value of a deleted or expired document. + +[source,javascript] +---- +function OnDelete(meta,options) { + if (options.expired) { + log("Document expired", meta.id); + } else { + log("Document deleted", meta.id); + } + var addr = meta.id; + var res = SELECT id from mybucket.myscope.orders WHERE shipaddr = $addr; + for (var id of res) { + log("Address invalidated for pending order: " + id); + } +} +---- + +In versions of Couchbase Server before version 6.6.0, the optional argument `options` is not present and the entry point for the handler is `OnDelete(meta)`. +The entry point is still supported, but using it means you're unable to differentiate deletion from expiration. + +[source,javascript] +---- +function OnDelete(meta) { + log("Document deleted or expired", meta.id); +} +---- + +[#timer_callback_handler] +=== Timer Callback Handler + +Timer callbacks are user-defined JavaScript functions passed as the callback argument in the built-in `createTimer(callback, date, reference, context)` function call. + +The Timer callback handler is an entry point for the event when a timer, created by the specific Eventing Function, matures and fires. + +[source,javascript] +---- +// Timer Callback Handler (user-defined entry point) +function DocTimerCallback(context) { + log("Timer fired running callback 'DocTimerCallback' with context: " + context); +} + +// Insert/Update Handler or entry point +function OnUpdate(doc, meta) { + // filter out docs of no interest + if (meta.id != 'make_timer:1') return; + // Create a Date value 60 seconds from now + var oneMinuteFromNow = new Date(); // Get current time & add 60 sec. to it + oneMinuteFromNow.setSeconds(oneMinuteFromNow.getSeconds() + 60); + // Create a doc to hold context to pass state to the callback function + var context = { docId: meta.id, random_text: "arbitrary text" }; + // Create a timer that will fire an event in the future + log("createTimer with callback 'DocTimerCallback'"); + createTimer(DocTimerCallback, oneMinuteFromNow, meta.id, context); +} +---- + +For more information about Timers, see xref:eventing-timers.adoc[]. + + +== Reserved Words + +You cannot use reserved words as variable names, function names, or JavaScript code properties in Eventing Functions. +If you use a reserved word, the Eventing Function returns a deployment error. + +The following reserved words are used by the transpiler to integrate {sqlpp} with Eventing: + +|=== +6+|{sqlpp} Reserved Words + +|ALTER +|BUILD +|CREATE +|DELETE +|DROP +|EXECUTE + +|EXPLAIN +|GRANT +|INFER +|INSERT +|MERGE +|PREPARE + +|RENAME +|REVOKE +|SELECT +|UPDATE +|UPSERT +| + +|=== diff --git a/modules/eventing/pages/eventing-lifecycle.adoc b/modules/eventing/pages/eventing-lifecycle.adoc new file mode 100644 index 000000000..25104c394 --- /dev/null +++ b/modules/eventing/pages/eventing-lifecycle.adoc @@ -0,0 +1,253 @@ += The Eventing Lifecycle +:description: This page shows how to add a new Eventing Function and briefly explores the Eventing Lifecycle. +:page-edition: Enterprise Edition +:page-aliases: eventing-adding-function + +[abstract] +{description} + +[#eventing_lifecycle_image] +image::lifecycle_overview_notitle.png[,%100] + +This is a quick introduction to Eventing via creating a simple Eventing Function and subsequently exercising the Eventing Function's operations across its typical lifecycle. For a deeper insight refer to the more detailed xref:eventing-examples.adoc[Eventing Examples]. + +== *Prerequisites*: + +In order to show the basic life cycle of an Eventing Function, we need a Function Scope (a RBAC grouping), a Listen To Location (a source keyspace) and a separate Eventing Storage keyspace. +You must have an Eventing storage keyspace, which should be typically 100% resident, and the collection is to be used solely by the Eventing Service. + +For the Function Scope or RBAC grouping, we will use the *+*+.+*+*, assuming you have the role of either "Full Admin" or "Eventing Full Admin". For standard or non-privileged users refer to xref:eventing-rbac.adoc[Eventing Role-Based Access Control]. + +For the Listen To Location or source keyspace we will use the *beer-sample._default._default* sample document set. + +If you don’t already have the sample document set *beer-sample* (it should have a scope of _default and a collection of _default) listed in the *Couchbase Web Console* > *Buckets* page you can load this sample data set as follows: + +** Access the *Couchbase Web Console* > *Settings* page +** Select the *Sample Buckets* in the upper right banner. +** Check *beer-sample* checkbox. +** Click *Load Sample Data*. + +For the Eventing Storage keyspace we need to create one if missing as follows: + +** Access the *Couchbase Web Console* > *Buckets* page +** Select the *Add Bucket* in the upper right banner. +** In the dialog set the "Name" of the bucket to *rr100* and set "Memory Quota" to *100* MiB. +** Click *Add Bucket*. + +At this point we could use the Eventing Storage keyspace of _rr100._default._default_, for all Eventing Functions but we might want to split this up by a logical grouping (or alternatively by tenants): + +** Select *Scopes & Collections* at the right of the new bucket information line. +** Select the *Add Scope* in the upper right banner. +** In the dialog set the "Name" of the Scope to *eventing*. +** Click *Save*. +** Select *Add Collection* at the right of the new scope information line. +** Click *Save*. + +If we return to the *Couchbase Web Console* > *Buckets* page you should see two (2) buckets. + +image::addfunc_00_prerq_bkts.png[,100%] + +If we now select *Scopes & Collections* at the right of the rr100 bucket information line, then expand eventing you should see the metadata collection. + +image::addfunc_00_prerq_bkts_s_c.png[,100%] + +[#eventing_examples_preparations] +== Create an Eventing Function: + +. From the Couchbase Web Console > *Eventing* page, click *ADD FUNCTION*. ++ +An empty *ADD FUNCTION* dialog is shown: ++ +image::addfunc_01_empty_settings.png[,484] ++ +The *ADD FUNCTION* dialog enables the developer to provide the following information: ++ +.Add a Function Dialog +[cols="50,173"] +|=== +| *Elements* | *Description* + + +Function Scope +| Function Scope (RBAC grouping) +| A bucket.scope combination used for identifying functions belonging to the same group. + +// TODO7X - need to check/fix this (buckets, scopes, collections) +The "Eventing Full Admin" role and also the "Full Admin" role can manage all Eventing Functions. Only these two privileged roles can set the bucket.scope to *+*+.+*+* and already have all the required RBAC privileges to both create and manage Eventing Functions. + +Typically, you should set Function Scope to the bucket.scope that holds the collection that is the source of your mutations. + +For complete details on how to set up the "Function Scope" and required RBAC privileges for standard or non-privileged users, refer to xref:eventing-rbac.adoc[Eventing Role-Based Access Control] and xref:manage:manage-security/manage-users-and-roles.adoc[Manage Users, Groups, and Roles] + +| Listen To Location (the source keyspace) +| The name of a collection currently defined on the cluster. +As of 7.1.1, Eventing Functions can listen to multiple collections via a wildcard of `{asterisk}` for the scope and/or the collection. + +// TODO7X - need to check/fix this (buckets, scopes, collections) +For complete details on how to set up your keyspaces refer to xref:manage:manage-buckets/create-bucket.adoc[creating buckets] and +xref:manage:manage-scopes-and-collections/manage-scopes-and-collections.adoc[creating scopes and collections]. + +| Eventing Storage (the Eventing metadata keyspace) +| The name of a collection currently defined on the cluster. +The Eventing Storage (or Metadata) collection, stores artifacts (or configuration documents) for your Function. A common Eventing Storage collection can be shared across all Eventing Functions for the same tenant. + +// TODO7X - need to check/fix this (buckets, scopes, collections) +For complete details on how to set up your keyspaces refer to xref:manage:manage-buckets/create-bucket.adoc[creating buckets] and +xref:manage:manage-scopes-and-collections/manage-scopes-and-collections.adoc[creating scopes and collections]. + +| Function Name +| A name, for the Function you are creating. +All Eventing Functions must have a unique name in a Couchbase cluster. + +| Deployment Feed Boundary +| Using the Feed Boundary drop down, you can either set an Eventing Function to deploy for all data mutations available in the cluster (Everything) or choose to deploy the Eventing Function to process only future data mutations, post deployment (From now). The Feed Boundary is a persistent setting in the +Function’s definition and can only be set or altered when a Function is created, undeployed or paused. + +| Description +| The Description is an optional text that can be added to the Function, typically to describe the purpose of the particular business logic. +This is optional. + +| Settings +a| +The available settings (by default hidden within a collapsible panel) for complete details refer to xref:eventing-Terminologies.adoc#function-settings[Terminologies - Function Settings]: + +* *System Log Level*: Determines the granularity at which messages are logged to the common system log messages across all Eventing Functions. The available choices are: `Info` (the default), `Error`, `Debug`, `Warning`, and `Trace`. Leave this alone unless asked by support to change it. + +* *Application log location* The directory path to the log file for the application or the Function specific log messages named <>.log. +The Function designer uses log() statements to write to this file in addition it will also record some Function specific system level errors. +In the UI when "Log" is selected these files are combined across all Eventing nodes and displayed. This path is set at node initialization. + +* *{sqlpp} Consistency*: The default consistency level of {sqlpp} statements in the Eventing Function. +This controls the consistency level for {sqlpp} statements, but can be set on a per statement basis. The valid values are `None` (the default) and `Request`. + +* *Workers*: Workers the number of worker processes to be started for the Eventing Function. +The minimum value is 1 (the default) and the recommended maximum is 64. + +* *Language compatibility*: The language version of the Eventing Function for backward compatibility. +If the semantics of a language construct change in any given release the “Language compatibility” setting will ensure an older Eventing Function will continue to see the runtime behavior that existed at the time it was authored, until such behavior is deprecated and removed. Note 6.0.0, 6.5.0, and 6.6.2 (the default) are the only currently defined versions. + +* *Script Timeout*: Script Timeout provides a timeout option to terminate a non-responsive Function. +The entry points into the Eventing Function, e.g. OnUpdate and OnDelete, processing for each mutation must complete from start to finish prior to this specified timeout duration. The default is 60 seconds. In addition an Timer callback must also complete within this period. + +* *Timer Context Max Size*: Timer Context Max Size limits the size of the context for any Timer created by the Function. +Eventing Timers can store and access a context which can be any JSON document, the context is used to store state when the timer is created and retrieve state when the timer fires. By default the size is 1024 bytes, but this can be adjusted on a per Function basis. + +| Bindings +a| +A binding is a construct that allows separating environment specific variables (example: bucket names, external endpoint URLs, constants) from the Eventing Function's JavaScript source code. Currently Eventing Functions support the following binding types: + +* *Bucket Bindings*: to access the Data Service or KV. + +* *URL Bindings*: to communicate externally via cURL. + +* *Constant Bindings*: to pass global settings/constants into the function. + +An Eventing Function can have no bindings, just one binding, or several bindings. For more information on Bindings, refer to xref:eventing-Terminologies.adoc#section_mzd_l1p_m2b[Terminologies - Bindings]. +|=== + +. In the *ADD FUNCTION* dialog, configure the following information: +** For the *Function Scope* drop-downs, select *+*+* for bucket, and *+*+* (we assume you have the role of either "Full Admin" or "Eventing Full Admin" otherwise you will need RBAC set up for your user to access the required resources). +** For the *Listen To Location* drop-downs, select *beer-sample* for bucket, *_default* for scope, and *_default* for collection. + ** For the *Eventing Storage* drop-downs, select *rr100* for bucket, *eventing* for scope, and *metadata* for collection. + ** Enter *my_evt_function* as the name of the Function you are creating in the *Function Name* text-box. + ** [Optional Step] Enter text *A simple Eventing Function only prints IDs*, in the *Description* text-box. + ** For the *Settings* option, use the default values, feel free to expand this section and inspect. + ** For the *Bindings* option, don't add any bindings (we will merely be logging messages). ++ +image::addfunc_02_settings.png[,484] ++ +Note, we left the Settings alone, however if you expanded the collapsible Settings control you can see the defaults that the Function will use: ++ +image::addfunc_02_adv_settings.png[,484] ++ +. After providing all the required information in the *ADD FUNCTION* dialog, click *Next: Add Code*. +The *my_evt_function* dialog appears. +** The *my_evt_function* dialog initially contains a placeholder code block. +You will accept the default for your *my_evt_function code*. ++ +image::addfunc_03_editor_with_default.png[,100%] +** You will need to click *Save and Return* if you modified the JavaScript source. +** To return to the Eventing screen, click the '*< back to Eventing*' link (above the editor) or just click the *Eventing* tab. + +[#exercise-the-eventing-lifecycle] +== Exercise the Eventing Lifecycle: + +. Click on the Function name. ++ +image::addfunc_04_newundeployed.png[,100%] +Additional controls are now displayed. The controls are: +** *Delete*: Deletes the Eventing Function from the system. +** *Export*: Exports the Eventing Function as a JSON document. +** *Deploy*: Deploys the Eventing Function, making it active across the cluster. +** *Pause*: Pauses the Eventing Function, making it paused across the cluster (only allowed if the Function is Deployed). If a Function is paused this button will be renamed *Resume*. +** *Edit JavaScript*: Allows edits to be made on the Eventing Function, in an edit dialog (only allowed when Paused or Undeployed). When deployed this button is renamed *View JavaScript*. + +. From the *Eventing* screen, click *Deploy*. ++ +image::addfunc_04a_deploy.png[,%100] ++ +** In the *Confirm Deploy Function* dialog, note that *Everything* is the preferred *Feed boundary*. ++ +The Feed Boundary determines whether documents previously in existence need to be included in the Function's activities: the options are *Everything* and *From now*. +The *Everything* option invokes a Function on all mutations available in the cluster from the *Listen To Location* keyspace. +The *From now* option invokes a Function during future instances of data mutation, post Function deployment or new changes to the *Listen To Location* keyspace. +The preferred Deployment Feed Boundary for the function can be changed under the function level settings when the Function is undeployed or paused. ++ +** Click *Deploy Function*. + +. While the Eventing function is bootstrapping it will display a status of "deploying..." in the UI. Once the bootstrapping is complete the defined Function's JavaScript code is executed on all existing documents and then on subsequent mutations. This function will only perform logging operations. ++ +image::input-output-overview-6.5.png[,%100] ++ +The deployment process typically takes about 15 seconds. Once the Eventing Function is fully deployed its status will change from *deploying...* to a status of *deployed*. At this point the Eventing service will quickly process all of the 7,303 items in the collection because the *Feed boundary* was set to *Everything* in the Function's settings. Finally the Function will await any new mutations and immediately process them in real-time as they occur. ++ +image::addfunc_05_deployed_done.png[,100%] ++ +Since the example only has a single log(....) statement in the *OnUpdate* handler (or entry point) it will merely list items in the collection 'beer-sample', i.e. 7,303 documents. ++ +You should see the success count at 7,303 in the Function's basic statistics. + +. Verify that the deployment and processing actually worked by clicking the *Log* link that appeared after you the Eventing Function reached a status of deployed. The *Log* link appears in the right hand side of the Function's controls. +** A dialog showing the *Function Log - my_evt_function* will appear with the most recent logging information (in reverse order with the most recent lines first). ++ +image::addfunc_06_logs_emitted.png[,100%] +** Click *Close*. + +. To pause a Function (you can then edit and update the function without missing a mutation) ++ +image::addfunc_07_pause.png[,%100] ++ +** Click *Pause*. +** In the *Confirm Pause Function* dialog +*** Click *Pause Function*. +** The Eventing function will now create a checkpoint of its progress and pause. +** Wait for the "paused" state. + +. To resume a function that has been paused ++ +image::addfunc_07_resume.png[,%100] ++ +** Click *Resume*. +** In the *Confirm Resume Function* dialog +*** Click *Resume Function*. +** The Eventing function will now resume from the previously created checkpoint (no mutations will be missed). + +. To undeploy the Eventing Function *my_evt_function* ++ +image::addfunc_07_undeploy.png[,%100] ++ +** Click *Undeploy*. +** In the *Confirm Undeploy Function* dialog +*** Click *Undeploy Function*. +** The Eventing function will now undeploy. +** Wait for the "undeployed" state. + +. To delete the Eventing Function *my_evt_function* ++ +image::addfunc_08_delete.png[,%100] ++ +** Click *Delete*. +** In the *Confirm Delete Function* dialog +*** Click *Delete Function*. + +NOTE: The Eventing Function lifecycle operations (deploying, undeploying, pausing, resuming, and deleting operations) and the Eventing rebalance operation *are mutually exclusive*. The Eventing rebalance operation fails when an Eventing Function lifecycle operation is currently in progress. Likewise, when the Eventing rebalance operation is in progress, you cannot perform an Eventing Function lifecycle operation. diff --git a/modules/eventing/pages/eventing-overview.adoc b/modules/eventing/pages/eventing-overview.adoc new file mode 100644 index 000000000..00cc98363 --- /dev/null +++ b/modules/eventing/pages/eventing-overview.adoc @@ -0,0 +1,74 @@ += Run a Function on Data Change +:description: Use the Eventing Service to handle data changes that happen when code is executed in response to document mutations or as scheduled by Timers. +:page-aliases: clusters:eventing-service/eventing-service.adoc + +[abstract] +{description} + + +== Eventing Service + +The Eventing Service executes user-defined business logic and responds in real time whenever applications interact and cause your data to change. +This change in data is known as a document mutation, and includes operations such as insert, delete, update, and expiration. + +You can use the Eventing Service to: + +* Monitor specific parameters in a document +* Set alerts in a document when a preconfigured threshold is breached +* Propagate data changes inside a database +* Enrich documents in real time +* Cascade deletes to avoid orphaned documents + + +== Eventing Functions + +The Eventing Service can run one or more Eventing Functions in your database to handle data changes according to a real-time Event-Condition-Action model. +Eventing Functions are standalone JavaScript fragments that trigger in real time as a response to document mutations. + +Eventing Functions allow you to: + +* Integrate with the Data Service to: +** Read, write, and delete documents +** Work with Atomic Counters, CAS, and TTLS +* Integrate with the Query Service to use inline {sqlpp} queries or statements +* Enable a Timer to schedule functions to run in the future +* Interact with external REST endpoints through cURL functionality + +You can access Eventing Functions by going to menu:Data Tools[Eventing]. +The Eventing Functions table includes the following: + +[#eventing-functions,cols="1,2",options="header"] +|=== + +|Feature +|Description + +|Function Name +|The name of the Function. + +|Source Bucket +|The source bucket of the events or mutations. + +|Source Scope +|The source scope of the events or mutations. + +|Source Collection +|The source collection of the events or mutations. + +|Log +|xref:manage-eventing-functions.adoc#function-logs[View and debug with Function Logs.] + +|View JavaScript +|xref:manage-eventing-functions.adoc#edit-javascript[View and edit the Function's JavaScript.] + +|Settings +|xref:manage-eventing-functions.adoc#edit-settings[View and edit the Function's settings.] + +|Status +|The status of the Function. +The status can be either in a stable state of *Deployed*, *Undeployed*, or *Paused*, or in a transitory state of *Deploying*, *Undeploying*, or *Pausing*. + +|More options (⋮) +|Used to xref:deploy-eventing-functions.adoc#deploy-function[deploy], xref:deploy-eventing-functions.adoc#undeploy-function[undeploy], xref:manage-eventing-functions.adoc#export-function[export], xref:manage-eventing-functions.adoc#pause-function[pause], or xref:manage-eventing-functions.adoc#delete-function[delete] a Function. + +|=== \ No newline at end of file diff --git a/modules/eventing/pages/eventing-rbac.adoc b/modules/eventing/pages/eventing-rbac.adoc new file mode 100644 index 000000000..65fcbd89a --- /dev/null +++ b/modules/eventing/pages/eventing-rbac.adoc @@ -0,0 +1,159 @@ += Eventing Role-Based Access Control (RBAC) +:description: pass:q[Full Administrators or users with proper _Role-Based Access Control_ (RBAC) roles can create and manage Eventing Functions.] + +[abstract] +{description} + +[#description] +== Description: What is RBAC + +Couchbase provides _Role-Based Access Control_ (RBAC), in which access privileges are assigned to fixed roles, which are in turn assigned to users, (each of which may be an administrator or an application) either _directly_ or _indirectly_, through _user-groups_. + +Couchbase Server Enterprise Edition provides RBAC with multiple roles for finer access control. +Community Edition provides multiple users that can be assigned to a limited set of roles. +There are three fixed roles in the community edition of Couchbase providing coarser access control: Bucket Full Access (`bucket_full_access[*]`), Admin (`admin`), and Read Only Admin (`ro_admin`). + +A Couchbase-Server _role_ permits one or more _resources_ to be accessed according to defined _privileges_. +Roles can be assigned to individual users, and to groups, by means of either the UI or the REST API. + +For a complete list of roles, see xref:learn:security/roles.adoc[Roles]. +Note that most roles can be assigned only on the _Enterprise Edition_ of Couchbase Server: on the _Community Edition_ of Couchbase Server, only the `bucket_full_access`, +`admin`, and `ro_admin` roles can be assigned. + +For more information, see xref:learn:security/authorization-overview.adoc[Authorization], and xref:manage:manage-security/manage-users-and-roles.adoc[Manage Users, Groups, and Roles]. + +== Function Scope + +A bucket.scope combination is used for identifying functions belonging to the same group. + +Only the "Eventing Full Admin" role and also the "Full Admin" role can set the bucket.scope to *+*+.+*+*; all other Eventing non-privileged users need to define a *Function Scope* for their Eventing functions that references an existing resource of bucket.scope. +This provides role-based isolation of Eventing functions between non-privileged users + +include::partial$rbac-warning.adoc[] + +Typically, you should set Function Scope to the `bucket.scope` +that holds the collection that is the source of your mutations to your Eventing Function. +This best practice ensures that you _do not_ inadvertently cause an Eventing Function to undeploy +by removing a *Function Scope* pointing to a resource that is not required for the function to run. + +NOTE: A user can be assigned multiple "Eventing / Manage Scope Function" RBAC roles. If any of these roles match an existing Eventing Function's *Function Scope*, then that user can manage, modify, or delete the Eventing Function, even if it was created or imported by someone else. + +== Privileged Users + +If a user role of either "Full Admin" or "Eventing Full Admin", then by default this user has all the necessary access to every resource in a cluster required to run the Eventing Service and create and manage Eventing Functions. + +When creating an Eventing Function, either of these roles can set the *Function Scope* to *+*+.+*+*; no other RBAC role is allowed to use this *Function Scope*. + +NOTE: When upgrading to 7.1, all Eventing Functions are assumed to be running as a privileged user and have their *Function Scope* set to *+*+.+*+* to ensure continuity of your Eventing Functions. + +=== Full Admin v. Eventing Full Admin + +Prior to 7.0.0, Eventing always runs as "Full Admin". This blocked some use cases and adoption as this role allowed creation of new users and the ability to escalate privilege sets. The "Eventing Full Admin" role introduced in 7.0 simply removes the capability of creating users and assigning/modifying RBAC credentials, thus providing more security. + +For the Function Scope or RBAC grouping, we will use the 'bulk.data' assuming you have the role of either "Full Admin" or "Eventing Full Admin". +For standard or non-privileged users, refer to Role-Based Access Control. + +== Eventing and RBAC for Non-privileged Users + +NOTE: If a user role of either "Full Admin" or "Eventing Full Admin", then this user, by default, has all the necessary access to every resource in a cluster required to run the Eventing Service and create and manage Eventing Functions. + +_In RBAC, although you can assign roles directly to a *USER*, it is generally more flexible to define a *GROUP* and assign that group or set of roles to a *USER*. +This allows reusing a *GROUP* across multiple users._ + +== Minimal Eventing RBAC role + +The following minimal resources are required for a non-privileged user to access the Eventing Service and create and manage Eventing Functions. + +* Data Reader +** Eventing Storage keyspace or Scratchpad +* Data Writer +** Eventing Storage keyspace or Scratchpad +* Data DCP reader +** Mutation Source +* Eventing / Manage Scope Function +** bucket.scope or bucket.* + +== Minimal Eventing RBAC role example + +* Access the Couchbase Web Console > Security and Select "ADD GROUP". ++ +image::rbac_min_add_add_group.png[,%100] + +* Configure the group as follows: + ** `Data Reader` and `Data Writer` are required for the Eventing Storage or scratchpad. + ** `Data DCP Reader` is required to fetch the mutations from DCP. ++ +NOTE: this item was defined as `bulk.data`. which would allow building Evening functions that can listen to any collection under `bulk.data`. ++ +image::rbac_min_a.png[,538,align=middle] ++ +The final item required is defining the *Function Scope* under "Eventing / Manage Scope Function". Since we will be listing to mutations in a collection under `bulk.data`, it makes sense to use this as our grouping. ++ +image::rbac_min_b.png[,538,align=middle] + +* Hit *Save* to store the GROUP to the system. + +* Access the Couchbase Web Console > Security and Select "ADD USER". ++ +image::rbac_min_add_add_user.png[,%100] + +* Associate the GROUP to the user so the user can inherit all the roles in the group. ++ +image::rbac_min_c.png[,538,align=middle] + +* Add your password and verify it in the lower two boxes + +* Hit *Save* to store the USER to the system. + +* Access the Couchbase Web Console > Security + +* Select GROUPS on the right, you should see your definition for GROUP "eventing_min" ++ +image::rbac_min_groups.png[,%100] + +* Select USERS on the right, you should see your definition for USER `user_min`. ++ +image::rbac_min_users.png[,%100] + +== Beyond a Minimal Eventing RBAC role + +You may consider adding + +* Data Reader +** Mutation Source +* Data Writer +** Mutation Source +* Data Monitor +** Mutation Source +** Eventing Storage keyspace or Scratchpad + +If you have any Bindings in your Eventing Function of type `Bucket Alias`, + you will need to have one or more additional settings if not already allowed. + +* Data Reader +** Bucket Alias +* Data Writer +** Bucket Alias + +If you plan to use {sqlpp} consider adding at lease SELECT privileges + +* Query & Index / Query Select +** Mutation Source + +== Multi-tenancy in Eventing + +The "Function Scope" in an Eventing Function works with the RBAC selection in "Eventing / Manage Scope Function" to limit access to between tenants in both the UI and the REST API. + +A tenant might be based on company departments such as administration, sales, production and support. + +Below we have two tenants example (an admin and a limited user) and four Eventing Functions each with a different *Function Scope*. +We logged into the UI with either an `Eventing Full Admin` or `Full Admin` role, and thus we can access all the Eventing Functions. + +image::rbac_admin_view.png[,%100] + +Now log out of the UI console and log back in as a non-privileged user, +(for example, we use the USER `user_min` as defined above). +Because of the privileges defined, we are only allowed access to Eventing Functions that have a *Function Scope* of 'bulk.data'. + +image::rbac_user_view.png[,%100] + diff --git a/modules/eventing/pages/eventing-statistics.adoc b/modules/eventing/pages/eventing-statistics.adoc new file mode 100644 index 000000000..301b93ce8 --- /dev/null +++ b/modules/eventing/pages/eventing-statistics.adoc @@ -0,0 +1,77 @@ += Statistics +:description: Eventing Statistics, for each deployed Function, can be fetched from an Eventing node using the Web Console or using the REST API. +:page-edition: Enterprise Edition +:page-embargo: EMBARGOED + +[abstract] +{description} + +*Via the Web Console's Eventing page* + +As of 7.0.0, Eventing Statistics can be displayed in the Eventing main UI page for each deployed Function by clicking on the Function name to expand the Function controls. These three key metrics or Deployment Statistics are updated every 10 seconds by default and displayed as numeric values: + +* *success* - displays the number of processed Functions and also Eventing timer callbacks. +* *failure* - displays the number of failures while processing the Eventing Function code. +* *timeout* - displays the number of Functions which have encountered a timeout condition. + +image::stats_00_counts.png[,100%] + +In addition to the per Function numeric statistics above as of 7.0.0 there are the rate charts that can be accessed from any deployed function. These charts are lagged by 30 seconds. + +* *success* - displays the rate of processed Functions and also Eventing timer callbacks. +* *failure* - displays the rate of failures while processing the Function Eventing Function code. +* *timeout* - displays the rate of Functions which have encountered a timeout condition. + +image::stats_01_counts_and_charts.png[,100%] + +In addition, per Function Statistics the Web Console or using the REST API. + +*Via the Web Console's custom Dashboards* + +Eventing Statistics, for each deployed Function, can be fetched from an Eventing node using the Web Console. + +You can make custom dashboards for a node or a cluster to get aggregated Eventing statistics. Access the *Couchbase Web Console* > *Dashboard* page. Then select "_new dashboard..._" from the *Choose Dashboard* dropdown, then "Add Group" and finally "Add a Chart" (you of course are interested in Eventing charts). + +There are six Eventing measures (three rates + three counts) these Dashboard statistics are NOT per bucket and are NOT per function. + +* Successful Function Invocations Rate +* Failed Function Invocations Rate +* Eventing Timeouts Rate +* Successful Function Invocations +* Failed Function Invocations +* Eventing Timeouts + +image::stats_02_add_charts.png[,100%] + +An example of all the possible dashboard charts is shown below: + +image::stats_02_system_charts.png[,100%] + +Note, you may click and expand any of the above graphs for any deployed Eventing Function or any Dashboard chart. + +*Via the REST API* + +NOTE: The Functions REST API endpoints on this page are fully supported, as long as the content of the Eventing Function body is not created or modified externally (as the internal format of the body is not yet standardized). + +Eventing statistics can be fetched from each eventing node using REST API bound to localhost. The resulting +JSON based responses are local to the node, and suitable for further aggregation across nodes of the cluster. + +You must have appropriate RBAC privileges to view an Eventing Function's Application log in the UI or via the REST API. +The role of either "Full Admin" or "Eventing Full Admin" can access any Eventing Function endpoint. For more information refer to xref:eventing-rbac.adoc[Eventing Role-Based Access Control]. + +The following REST endpoint could be used to get the full set of Eventing statistics: +[source,shell] +---- +curl http://user:pass@localhost:8096/api/v1/stats?type=full +---- +This will return the full statistics set inclusive of events processing, events remaining, execution, failure, latency, worker PIDs and sequence processed. + +Note, omitting the parameter `type=full` will exclude `dcp_event_backlog_per_vb`, `doc_timer_debug_stats`, `latency_stats`, `plasma_stats` and `seqs_processed` from the response. + +The above statistics can also be individually obtained through the following REST endpoints: +[source,shell] +---- +curl http://user:pass@localhost:8096/getExecutionStats?name=function_name +curl http://user:pass@localhost:8096/getLatencyStats?name=function_name +curl http://user:pass@localhost:8096/getFailureStats?name=function_name +---- diff --git a/modules/eventing/pages/eventing-timers.adoc b/modules/eventing/pages/eventing-timers.adoc new file mode 100644 index 000000000..6ea0184b2 --- /dev/null +++ b/modules/eventing/pages/eventing-timers.adoc @@ -0,0 +1,162 @@ += Timers +:description: Timers are asynchronous compute, which offers Eventing Functions the ability to execute in reference to wall-clock events. +:page-edition: Enterprise Edition + +{description} +Timers also measure and track the amount of elapsed time and can be used while archiving expired documents at a preconfigured time. + +NOTE: When using timers, it is required that all nodes of the cluster are synchronized at computer startup, and periodically afterwards using a clock synchronization tool like NTP. + +A few important aspects related to timers are listed below: + +* Timers follow the same timeout semantics as their Parent Functions. So, if an Eventing Function has an execution timeout of 60 seconds, each of the timers created from the Eventing Function inherits the same execution timeout value of 60 seconds. +* Timers may run on a different node than the one on which it was created. +* One execution of timers is guaranteed despite node failures and cluster rebalances. +* During Function backlogs, timers get eventually executed. +* The Eventing Storage (or Metadata) collection stores information about timers and its association with an Eventing Function's handler. +* Ensure that the Eventing Storage collection is not deleted or flushed, or the keys in Eventing Storage collection get updated. +* Each active timer an additional amount of space between 832 and 1856 bytes (832 bytes + sizeof(context)) is needed. Where the context by default is not larger than 1024 bytes. +* Timers are represented by two documents in KV plus a common tiny root document for that is shared among 1-N timers scheduled to fire in the same 7 second period of time.. Thus two or three inserts and then two or three deletes must be performed in KV for each timer (regardless if the timer is ultimately fired or canceled). +* The timer context size may be adjusted up or down on a per Function handler basis in the Function's settings. +* With an increase in the usage of timers, the Eventing Storage collection's space assignment must also be increased to accommodate all active timers and any potential backlog. If the use-case mandates large numbers of timers in the system, it is required that the space assigned to the Eventing Storage collection be suitably high as well. +* Due to runtime or programmatic errors in the Function handler code, if triggering of a timer fails, then timer execution may get permanently blocked. +* Bindings for Bucket aliases to keyspaces can be reused in timers. Bucket aliases, created during the Eventing Function definition, can be accessed by the timer constructs in the handler code. +* Timers get deleted (and thus all KV documents that define them) when the associated Function is deleted or undeployed. + +== The Timer Construct + +The Timers language construct is added to support requirements of Couchbase Eventing Functions. + +[#createtimer-function] +To create a timer use the below syntax: + +---- +createTimer(callback, date, reference, context) +---- +In the createTimer syntax: + +* callback - This function is called when the timer fires. The callback function must be a top-level function that takes a single argument, the context (see below). +* date - This is a JavaScript Date object representing the time for the timer to fire. The date of a timer must always be in future when the timer is created, otherwise the behavior is unspecified. +* reference - This is a unique string that must be passed in to help identify the timer that is being created. References are always scoped to the function and callback they are used with and need to be unique only within this scope. The call returns the reference string if timer was created successfully. If multiple timers are created with the same unique reference, old timers with the same unique reference are implicitly cancelled. If the reference parameter is set to JavaScript null value, a unique reference will be generated. +* context - This is any JavaScript object that can be serialized. The context specified when a timer is created is passed to the callback function when the timer fires. The default maximum size for Context objects is 1kB. Larger objects would typically be stored as keyspace objects, and document key can be passed as context. +* return value - If the reference parameter was null, this call returns the generated unique reference. Otherwise, the passed in reference parameter is the return value. +* Exceptions Thrown - The createTimer() function throws an exception if the timer creation fails for an unexpected reason, such as an error writing to the Eventing Storage collection. + +[#canceltimer-function] +To cancel a timer you can either use _createTimer()_ with the same reference of an existing timer or you can use the below syntax: + +---- +cancelTimer(callback, reference) +---- +In the cancelTimer syntax: + +* callback - This function that was scheduled to be called when the timer fires, as supplied to the _createTimer()_ call that is now being cancelled. +* reference - This is the reference that was either passed in to the createTimer() call, or generated and returned by the createTimer() call in response to a null value for the incoming reference parameter. +* return value - A boolean value indicating if the specified timer could be cancelled successfully. A false return value typically indicates the timer never existed or had already fired prior to the cancellation request. +* Exceptions Thrown - The _cancelTimer()_ function throws an exception if the timer cancellation fails for an unexpected reason, such as an error writing to the Eventing Storage collection. (Note that cancelling stale or non-existent timers will be treated as a no-op and will not throw an exception). +* The cancelTimer operation will only deletes one of the two or three documents that define the timer in KV, the other two documents will be cleaned up when the original timer (and any peer timers) was scheduled to fire. +* the cancelTimer operation will remove two of the possible three documents that define the timer in KV leaving only the tiny common root document that was shared among all timers scheduled to fire in a given seven second period. Again this final root document will be cleaned up when the original timer (and any peer timers) were initially scheduled to fire. + +*Example use of createTimer and cancelTimer:* +---- +createTimer(DocTimerCallback, oneMinuteFromNow, meta.id, context) +cancelTimer(DocTimerCallback, meta.id) +---- +In the sample function calls above: + +* DocTimerCallback is the name of the timer callback function used in the Function handler code. +* oneMinuteFromNow is a JavaScript Date object. +* meta.id is a generic reference string that can be used in the Couchbase cluster. +* context is the JavaScript object that is used in the Function handler code. + +Below we will show a control document and a working Eventing Function that creates a Timer scheduled to execute 60 seconds in the future. When the Timer fires the callback will create a document in the alias 'dst_col' (which must be a 'read and write' binding to an existing collection in the function). + +Create a document with KEY type_of_interest::1 and DATA + +---- +{ + "type": "type_of_interest", + "id": 1, + "needed_condition": true, + "cancel_timer": false +} +---- + +Create an Eventing Function and deploy it (optionally adjust "cancel_timer" to true to invoke cancelTimer before the Timer fires) + +---- +function DocTimerCallback(context) { + log('From DocTimerCallback: timer fired', context); + + // Create a new document as per our received context in another collection + dst_col[context.docId] = context.random_text; // upsert a portion of the context +} + +function OnUpdate(doc,meta) { + // You would typically filter to mutations of interest + if (doc.type != 'type_of_interest') return; + + // You would typically look at some key conditions to decide what to do + if (doc.needed_condition === true && doc.cancel_timer === false) { + log('From OnUpdate: creating timer', meta.id); + + // Create a timestamp 60 seconds from now + var oneMinuteFromNow = new Date(); // Get current time & add 60 sec. to it. + oneMinuteFromNow.setSeconds(oneMinuteFromNow.getSeconds() + 60); + + // Create a document to use as out for our context + var context = {docId : meta.id, random_text : "arbitrary text"}; + createTimer(DocTimerCallback, oneMinuteFromNow, meta.id, context); + } + if (doc.cancel_timer === true) { + // Cancel an existing timer (if it is active) by reference meta.id + if (cancelTimer(DocTimerCallback, meta.id)) { + log('From OnUpdate: cancel request, timer was canceled',meta.id); + } else { + log('From OnUpdate: cancel request, no such timer may have fired',meta.id); + } + } +} +---- + +== Sharding of Timers + +Timers get automatically sharded across Eventing nodes and therefore are elastically scalable. Triggering of timers at or after a specified time interval is guaranteed. However, triggering of timers may either be on the same node (where the timer was created), or on a different node. Relative ordering between two specific timers cannot be maintained. + +== Debugging and Logs + +Timers cannot be debugged using the Visual Debugger. For debugging, Couchbase recommends enclosing of timers in a try-catch block. When logging is enabled, timer related logs get captured as part of the Eventing Function's application logs. + +== Elapsed Timestamps + +During runtime, when a Function handler code contains a timestamp in the past (elapsed timestamp), the system executes the code in the next available time window, as soon as the required resources are available. + +== Handling Delays + +During Function backlogs, execution of timers may be delayed. To handle these delays, you need to program additional time window in your code. If your business logic is time-sensitive after this additional time window the code should refrain from its Function execution. + +The following is a sample code snippet, which performs a timestamp check (my_deadline) before code execution. + +---- +func callback(context) { + //context.my_deadline is the parameter in the timer payload + if (new Date().getTime() > context.my_deadline) { + // timestamp is back-dated, do not execute the rest of the timer + return; + } +} +---- + +== Wall-clock Accuracy + +Timers are not wall-clock accurate events. The timer implementation is designed to handle large numbers of distributed timers (i.e., millions of timers) and only promise to run timers as soon as possible, e.g. no timers lost in a healthy system without crashing nodes. + +Couchbase currently scans for active timers every 7 seconds this creates a maximum delay of 7 seconds + the time it takes too process timers ahead of the given timer on a given thread. Thus, in an Eventing system in a steady state you will typically experience an average timer firing delay of about 3-4 seconds after the scheduled time. + +However, if timer is created and scheduled too close the wall clock of the system, Couchbase may delay the actual scheduling by an additional 1 to 2 scan periods (up to a 14 second delay after the scheduled time) to avoid races. + +The additional overall delay is an implementation artifact and may change between releases. + +== Examples + +The xref:eventing-examples.adoc[Eventing Examples] section provides two examples that show the use of Timers. The first example xref:eventing-examples-docexpiry.adoc[Document Expiry] and second example is xref:eventing-examples-docarchive.adoc[Document Archive]. diff --git a/modules/eventing/pages/manage-eventing-functions.adoc b/modules/eventing/pages/manage-eventing-functions.adoc new file mode 100644 index 000000000..8e5a0be52 --- /dev/null +++ b/modules/eventing/pages/manage-eventing-functions.adoc @@ -0,0 +1,181 @@ += Manage Eventing Functions +:description: Use the Capella UI to manage the Eventing Functions in your cluster. +:page-aliases: clusters:eventing-service/manage-eventing-functions.adoc + +[abstract] +{description} + + +[#pause-function] +== Pause a Function + +You can pause an Eventing Function to checkpoint the Function and stop processing document mutations. +This checkpoint saves a specific point in the processing stream and helps you not miss any mutations when you resume the Function. + +You can edit the JavaScript code of a paused Function. + +[NOTE] +==== +You can only pause an Eventing Function when that Function has already been deployed. +==== + +To pause an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Next to the Function you want to pause, click *More Options (⋮)* . +. Click *Pause*. + + +[#resume-function] +== Resume a Function + +You can resume a paused Eventing Function to reactivate and continue processing the Function. + +When you resume a Function: + +* The Function starts running from the checkpoint that was saved when you previously paused the Function. This makes sure that no document mutations are missed. +* All backlogged mutations are processed. +* All backlogged Timers fire as soon as possible, making sure no Timers are lost. + +You cannot edit the JavaScript code of a resumed Function. + +To resume an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to the Function you want to resume. +. Click *Resume* to resume your Function. +A resumed Function enters a deployed state and resumes processing mutations. + + +[#export-function] +== Export a Function + +You can export an Eventing Function to open and edit the Function with your code editor. +The Function exports in JSON format. + +To export an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to the Function you want to export. +. Click *Export* to export your Function. +. Go to the *Downloads* folder on your computer. +. Open the exported JSON file with your code editor. + + +[#function-logs] +== Debug with Function Logs + +You can use Function logs to identify and capture activities and errors related to your business logic through user-defined messages specific to each Eventing Function. + +The content of the Function logs depends on the logic of the `log(...)` statements you added inside the Function handler's JavaScript code. + +To check the logs of your deployed Function: + +. Go to menu:Data Tools[Eventing]. +. Click the *Log* icon next to the Function you want to check the logs for. +. In the *Logs* page, you can: +* Filter the log content +* Reorder the log file +* Refresh the log data +* Copy the log data to your clipboard + + +[#edit-javascript] +== Edit a Function's JavaScript Code + +[NOTE] +==== +You can only edit the JavaScript code of an Eventing Function when that Function is paused or undeployed. +==== + +To edit the JavaScript code of an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *View JavaScript* next to the Function you want to edit. +. In the code editor page, edit your business logic. +. Click btn:[Save] to commit your changes. + + +[#edit-settings] +== Edit Function Settings + +To edit the settings of your Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *Settings* next to the Function you want to edit the settings for. +. Edit the available settings. You can also edit the Function's bindings and JavaScript code. +. Click *Save*. + +If your Eventing Function is in a deployed state, you can only edit some of its settings. +To edit a larger number of your Function's settings, undeploy or pause your Function. + +[#edit-function,cols="1,2",options="header"] + +|=== + +|Field +|Description + +|Name +|Cannot be edited. + +|Source Bucket +|Cannot be edited. + +|Source Scope +|Cannot be edited. + +|Source Collection +|Cannot be edited. + +|Metadata Bucket +|Cannot be edited. + +|Metadata Scope +|Cannot be edited. + +|Metadata Collection +|Cannot be edited. + +|Description +|Can be edited at any time. + +|N1QL Consistency +|Can be edited at any time. + +|Workers +|Can be edited at any time. + +|Script Timeout +|Can be edited at any time. + +|Deployment Feed Boundary +|Can only be edited when the Function is in an undeployed or paused state. + +|Timer Context Max Size +|Can only be edited when the Function is in an undeployed or paused state. + +|Language Compatibility +|Can only be edited when the Function is in an undeployed or paused state. + +|Enable App Services Compatibility +|Can only be edited when the Function does not share the same collection as an App Service. + +|=== + + +[#delete-function] +== Delete a Function + +[NOTE] +==== +You can only delete an Eventing Function if the Function is undeployed. +==== + +To delete an Eventing Function: + +. Go to menu:Data Tools[Eventing]. +. Click *More Options (⋮)* next to the Function you want to delete. +. Click btn:[Delete]. +. In the *Delete function* dialog, type delete to confirm your action. +. Click btn:[Delete]. diff --git a/modules/eventing/pages/troubleshooting-best-practices.adoc b/modules/eventing/pages/troubleshooting-best-practices.adoc new file mode 100644 index 000000000..f9625929f --- /dev/null +++ b/modules/eventing/pages/troubleshooting-best-practices.adoc @@ -0,0 +1,222 @@ += Troubleshooting and Best Practices +:page-edition: Enterprise Edition + +== Why do similar functions that I write seem to run slower in 7.0.0 than 6.6.2? + +The default number of workers per function was three (3) in 6.X and is now one (1) in 7.0.0. You can simply raise the number of workers to 3 to get back the expected performance. + +NOTE: all upgrades will carry forward the configured number of workers in an Eventing Function so you don't have to worry about a production system slowing down during an upgrade. + +Raising the worker counts should be down if you need higher levels of throughput, for example cURL functions access slow external REST endpoints need more workers to scale performance up (in this case you are IO bound and not CPU bound). + +== What is the Security role "Eventing Full Admin" for? + +Prior to 7.0.0 Eventing always run as "Full Admin" this blocked some use cases and adoption as this role allowed creation of new users and the ability to escalate privilege sets. The new "Eventing Full Admin" role removes the capability of creating users and modifying credentials thus providing a bit more security. + +== What happens when more Workers are allocated for a Function? + +Couchbase Server for a specific Function limits the maximum number of workers to 64 (note the default is 3 workers). This upper limit is configured for system optimization purposes. You cannot create a function with more than this upper bound. + +When deploying (or resuming a paused function) a threshold is dynamically calculated based on node's resources and if the number of workers exceeds this calculation, then the system automatically generates a warning message but does not prevent the Function deployment. An example follows: + +[.out]`There are 104 eventing workers configured to run on 24 cores. A sizing exercise is recommended.` + +Typically you shouldn’t configure more than 4 × the number of physical cores (or 2 × the number of vCPUS) across all your Eventing functions. +If you have a high throughput for every Eventing Function for best performance the total number of workers should not exceed the number of physical cores. +If you wish to support a high number of curl() calls to slow REST endpoints (> 20ms+) you may need to define more workers to increase parallelism. + +== When should developers use the try-catch block in Eventing Functions? + +As a best practice, while writing the Eventing Function's JavaScript code, for basic error handling and debugging operations, it is recommended that application developers use the try-catch block. + +Before deployment, Couchbase Server verifies the Eventing Function's code. +Only valid Functions get deployed. Using the _log()_ option within a _try-catch block(s)_, you can record errors. These error logs get stored in the Eventing function's application log file. Note the Eventing function's application log file on disk is specific to the node that processed the mutation and is not global across the cluster. By default, JavaScript runtime errors get stored in the system logs. Unlike system logs, troubleshooting and debugging operations are easy when you use the _try-catch_ block and application _log()_ options. + +During runtime, Application logs, by default, do not capture any Eventing Function code exceptions. To log exceptions, it is recommended to encapsulate your code in a _try-catch_ block. + +A sample _try-catch_ block is provided for reference: + +---- +function OnUpdate(doc, meta) { + log('document', doc); + try { + var time_rand = random_gen(); + dst_col[meta.id + time_rand] = doc; + } catch(e) { + log(e); + } +} +---- + +[#cyclicredun] +== What are bucket alias considerations during a Function definition? + +Eventing Functions can trigger data mutations. To avoid a cyclic generation of data changes, ensure that you carefully consider the below aspects while specifying source and destination collections: + +=== Infinite recursion protection + +* Avoid infinite recursions. +If you are using a series of Eventing Functions, ensure they do not cause cyclic mutations by triggering write operations that, in turn, trigger other Eventing Functions. +For example the following design demonstrates an infinite recursion: ++ +*functionA* with source collectionA target collectionB aliased as same. ++ +---- +function OnUpdate(doc, meta) { + collectionB[meta.id] = {"status":"updated by functionA"}; +} +---- ++ +*functionB* with source collectionB target collectionC aliased as same. ++ +---- +function OnUpdate(doc, meta) { + collectionC[meta.id] = {"status":"updated by functionB"}; +} +---- ++ +*functionC* with source collectionC target collectionA aliased as same. ++ +---- +function OnUpdate(doc, meta) { + collectionA[meta.id] = {"status":"updated by functionC"}; +} +---- ++ +In the example above a single mutation in "collectionA" will create an infinite loop updating a record in "collectionB", then in "collectionC", then back to "collectionA", over and over. ++ +One possible solution is to change the design above such that *functionC* updated collectionD (instead of collectionA) we would have no recursion as follows: ++ +*functionC* (modified to write to a different collection) with source collectionA target collectionD aliased as same. ++ +---- +function OnUpdate(doc, meta) { + collectionD[meta.id] = {"status":"updated by functionC"}; +} +---- ++ +Another possible solution to the design above is to change the design is changes such that *functionA* performs a check to ensure that if *functionC* has operated on the document to cease any new mutations as follows: ++ +*functionA* (modified to stop recursion) with source collectionA target collectionB aliased as same. ++ +---- +function OnUpdate(doc, meta) { + if (doc["status"] == "updated by functionC") return; + collectionB[meta.id] = {"status":"updated by functionA"}; +} +---- +* Although the Couchbase Server can flag simple infinite recursions a long chain of source and destination collections with a series of Eventing Functions, a complex infinite recursion condition may occur. The developer, carefully consider and avoid these cases. + +* As a best practice, ensure that collections to which the Eventing Function performs a write operation do not have other Eventing Functions configured for tracking data mutations. + +There is a special case of direct self-recursion, which is highly useful, when a Eventing Function chooses to create a Read-Write binding to its own source collection we can perform document enrichment operations. In this case the direct self-recursive mutations and detected and suppressed by the Eventing framework. However this capability is only supported for the aliased JavaScript map and is not supported for mutations generated via {sqlpp}. + +NOTE: Since the 6.5 release, the Eventing Function JavaScript code can directly mutate (or write back) to the source bucket (now in 7.0.0 the source collection), e.g. direct self-recursion. + +* For example the following design is taken from the xref:eventing:eventing-example-data-enrichment.adoc[Data Enrichment, Case: 2]: ++ +*functionDirectEnrich* with source collectionA target collectionA aliased as 'src' ++ +---- +function OnUpdate(doc, meta) { + log('document', doc); + doc["ip_num_start"] = get_numip_first_3_octets(doc["ip_start"]); + doc["ip_num_end"] = get_numip_first_3_octets(doc["ip_end"]); + // !!! write back to the source collection !!! + src[meta.id]=doc; +} +function get_numip_first_3_octets(ip) { + var return_val = 0; + if (ip) { + var parts = ip.split('.'); + //IP Number = A x (256*256*256) + B x (256*256) + C x 256 + D + return_val = (parts[0]*(256*256*256)) + (parts[1]*(256*256)) + (parts[2]*256) + parseInt(parts[3]); + return return_val; + } +} +---- + +[#recursionchecks] +=== Disabling infinite recursion checks + +Although not encouraged, in some cases a client may still require the creation of potentially recursive loops. + +For example trying to run xref:eventing:eventing-handler-ConvertBucketToCollections.adoc[ConvertBucketToCollections] in a single bucket (as both source and target) will emit an 'ERR_INTER_FUNCTION_RECURSION' error. + +To allow recursion and thus the above Function to run a special configuration flag may be toggled via a REST API call to any Eventing node as follows: + +To disable recursion checks (requires admin privileges): + +[source,console] +---- +curl -X POST -u Administrator:password http://192.168.1.5:8091/_p/event/api/v1/config -d '{"allow_interbucket_recursion":true}' +---- + +To re-enable recursion checks (requires admin privileges): + +[source,console] +---- +curl -X POST -u Administrator:password http://192.168.1.5:8091/_p/event/api/v1/config -d '{"allow_interbucket_recursion":false}' +---- + +== In the cluster, I notice a sharp increase in the Timeout Statistics. What are my next steps? + +When the Timeout Statistics shows a sharp increase, it may be due to two possible scenarios: + +* Increase in execution time: When the Eventing Function execution time increases, the Function execution latency gets affected, and this in turn, leads to Function backlog and failure conditions. +* Script timeout value: When the script timeout attribute value is not correctly configured, then you encounter timeout conditions frequently. + +As a workaround, it is recommended to increase the script timeout value. +Ensure that you configure the script timeout value after carefully evaluating the execution latency of the Function. + +As a best practice use a combination of try-catch block and the application log options. +This way you can monitor, debug and troubleshoot errors during the Function execution. + +== Why is it important that the Eventing Storage keyspace (metadata collection) be 100% memory resident? + +If the collection you chose to hold your meta data spills over to disk access is not 100% resident, your Eventing system can essentially stall and/or slow down by orders of magnitude and you can also experience failures and/or missed mutations. + +Always make sure that the memory quota on your metadata Eventing Storage keyspace (metadata collection) is sufficiently large to ensure a residency ratio of 100%. Additionally avoid using an Ephemeral bucket for your Eventing Storage keyspace (refer to next question for details). + +You should only use Buckets of type Couchbase for data persistence of the Eventing Storage or metadata (for details refer to next question). + +== Can I use Ephemeral Buckets with Eventing? + +Yes, Ephemeral are fine for user data but not for the Eventing Storage (metadata collection). + +The source bucket and any bucket (or keyspace) bindings of your Eventing Function can be Ephemeral. However, the Eventing Storage keyspace (metadata collection) should always be persistent. + +NOTE: The Eventing Storage keyspace must be in a Bucket of type Couchbase. If this keyspace is not persistent the Data Service, or KV, will evict timer and checkpoint documents on hitting quota and Eventing can lose track of both timers and mutations processed. Furthermore at any point, refrain from deleting the Eventing metadata collection. Also, ensure that your Eventing Function's JavaScript code or other services do not perform a write or delete operation on the Eventing metadata collection. + +== Eventing worked fine when application was first deployed but now I am getting LCB_ETMPFAIL failures. + +A low residency ratio for either the source or the destination collection (sometimes these two can be the same) can result in a system that's unable to keep up with rate of mutations and internal logic's required reads and writes to the data service. + +NOTE: Watch the number of documents in your collections (source, Eventing Storage, and destination(s)) and in particular pay close attention to the change in the resident ratio. Typically, this could be due to growth in your overall data set. + +For example, a high velocity Eventing function that is processing in excess of 12K mutations/sec with a source or destination collection residency ratio of 100% can easily start to experience issues if the residency ratio drops below 18% (_this percentage isn't hard and fast and may vary based on a variety of factors such as the number of mutations acted on, the storage type, and so on_). +---- +2020-03-13T11:46:32.383-07:00 [INFO] "Exception: " {"message":{"code":392,"desc": \ +"Temporary failure received from server. Try again later","name":"LCB_ETMPFAIL"}, \ +"stack":"Error\n at OnUpdate (MyEventingFunction.js:177:25)"} +---- + +The above error indicates that the system is under provisioned for the load. Under the hood, Eventing will try to access to the data store five (5) times with a 200ms pause between attempts. If all of the attempts fail, the Eventing Function, in this case _MyEventingFunction_, throws an *LCB_ETMPFAIL* message from libcouchbase. This is important to understand as trapping the above exception and retrying the same operation inside your Eventing Function will only exacerbate the issue and make things worse. Of course your Eventing Function can take other actions such as creating a notification. + +There are two solutions: + +. The first solution is to increase the memory quota of the collection's bucket in question (thus increasing the resident ration). + +. The second solution is to add more Data nodes, faster disk IO, and more memory to eliminate the resource bottleneck. + +== Always escape quotes in regular expressions in your Eventing Function. + +When using bare regular expressions you should always escape a single quote or a double quote with a backslash character. Although non-escaped quotes are legal in the JavaScript language they do not pass Eventing Service’s parser. +---- +mystring.match(/(\S+)[^=]=["']?((?:.(?!["']?\s+(?:\S+)[^=]=|[>"']))+.)["']?/g); +---- + +The above bare regular expression should be written with the quotes escaped via the \ character. +---- +mystring.match(/(\S+)[^=]=[\"\']?((?:.(?![\"\']?\s+(?:\S+)[^=]=|[>\"\']))+.)[\"\']?/g); +---- diff --git a/modules/eventing/partials/eventing-common.adoc b/modules/eventing/partials/eventing-common.adoc new file mode 100644 index 000000000..65fbaf6f0 --- /dev/null +++ b/modules/eventing/partials/eventing-common.adoc @@ -0,0 +1,11 @@ +// tag::keyspace-description[] + +The keyspace of the document to be used for the operation with the JavaScript format: ++ +[source] +---- +"keyspace":{"bucket_name":_string_,"scope_name":_string_,"collection_name":_string_} +---- ++ +This parameter is only required if you are using a _binding_ with a wildcard for the scope and/or the collection. +// end::keyspace-description[] \ No newline at end of file diff --git a/modules/eventing/partials/nav.adoc b/modules/eventing/partials/nav.adoc new file mode 100644 index 000000000..52bcd823d --- /dev/null +++ b/modules/eventing/partials/nav.adoc @@ -0,0 +1,75 @@ +* xref:eventing:eventing-overview.adoc[] + ** xref:eventing:add-eventing-functions.adoc[] + ** xref:eventing:deploy-eventing-functions.adoc[] + ** xref:eventing:manage-eventing-functions.adoc[] + ** xref:eventing:eventing-language-constructs.adoc[Language Constructs] + *** xref:eventing:eventing-advanced-keyspace-accessors.adoc[Advanced Keyspace Accessors] + *** xref:eventing:eventing-timers.adoc[Timers] + *** xref:eventing:eventing-curl-spec.adoc[cURL] + ** xref:eventing:eventing-buckets-to-collections.adoc[Buckets vs Collections] + ** xref:eventing:eventing-rbac.adoc[Eventing Role-Based Access Control] + ** xref:eventing:eventing-examples.adoc[Eventing Function Examples] + + + *** Step-by-Step Examples + **** xref:eventing:eventing-example-data-enrichment.adoc[] + **** xref:eventing:eventing-examples-cascade-delete.adoc[] + **** xref:eventing:eventing-examples-docexpiry.adoc[] + **** xref:eventing:eventing-examples-delete-v-expiry.adoc[] + **** xref:eventing:eventing-examples-docarchive.adoc[] + **** xref:eventing:eventing-examples-cancel-overwrite-timer.adoc[] + **** xref:eventing:eventing-examples-recurring-timer.adoc[] + **** xref:eventing:eventing-examples-rest-via-curl-get.adoc[] + **** xref:eventing:eventing-examples-high-risk.adoc[] + + + *** Basic Accessor Functions + **** xref:eventing:eventing-handler-basicBucketOps.adoc[basicBucketOps] + **** xref:eventing:eventing-handler-curl-get.adoc[basicCurlGet] + **** xref:eventing:eventing-handler-curl-post.adoc[basicCurlPost] + **** xref:eventing:eventing-handler-simpleTimer.adoc[simpleTimer] + **** xref:eventing:eventing-handler-cascadeKvDeleteWithDoc.adoc[cascadeKvDeleteWithDoc] + **** xref:eventing:eventing-handler-redactSharedData.adoc[redactSharedData] + **** xref:eventing:eventing-handler-simpleFlatten.adoc[simpleFlatten] + **** xref:eventing:eventing-handler-fixEmailDomains.adoc[fixEmailDomains] + **** xref:eventing:eventing-handler-keepLastN.adoc[keepLastN] + **** xref:eventing:eventing-handler-docControlledSelfExpiry.adoc[docControlledSelfExpiry] + **** xref:eventing:eventing-handler-shippingNotifier.adoc[shippingNotifier] + **** xref:eventing:eventing-handler-ConvertBucketToCollections.adoc[ConvertBucketToCollections] + *** Basic {sqlpp} Functions + **** xref:eventing:eventing-handler-basicN1qlSelectStmt.adoc[] + **** xref:eventing:eventing-handler-basicN1qlPreparedSelectStmt.adoc[] + *** Generic Manipulation Functions + **** xref:eventing:eventing-handler-dateToEpochConversion.adoc[dateToEpochConversion] + **** xref:eventing:eventing-handler-deepCloneAndModify.adoc[deepCloneAndModify] + **** xref:eventing:eventing-handler-removeObjectStubs.adoc[removeObjectStubs] + **** xref:eventing:eventing-handler-removeNullsAndEmptys.adoc[removeNullsAndEmptys] + **** xref:eventing:eventing-handler-genericRename.adoc[genericRename] + **** xref:eventing:eventing-handler-genericFlatten.adoc[genericFlatten] + **** xref:eventing:eventing-handler-convertXMLtoJSON.adoc[convertXMLtoJSON] + **** xref:eventing:eventing-handler-convertAdvXMLtoJSON.adoc[convertAdvXMLtoJSON] + *** Advanced Accessor Functions + **** xref:eventing:eventing-handler-advancedGetOp.adoc[advancedGetOp] + **** xref:eventing:eventing-handler-advancedGetOpWithCache.adoc[advancedGetOpWithCache] + **** xref:eventing:eventing-handler-advancedInsertOp.adoc[advancedInsertOp] + **** xref:eventing:eventing-handler-advancedUpsertOp.adoc[advancedUpsertOp] + **** xref:eventing:eventing-handler-advancedReplaceOp.adoc[advancedReplaceOp] + **** xref:eventing:eventing-handler-advancedDeleteOp.adoc[advancedDeleteOp] + **** xref:eventing:eventing-handler-advancedIncrementOp.adoc[advancedIncrementOp] + **** xref:eventing:eventing-handler-advancedDecrementOp.adoc[advancedDecrementOp] + **** xref:eventing:eventing-handler-advancedTouchOp.adoc[advancedTouchOp] + **** xref:eventing:eventing-handler-advanced-keepLastN.adoc[advancedKeepLastN] + **** xref:eventing:eventing-handler-advanced-docControlledSelfExpiry.adoc[advancedDocControlledSelfExpiry] + **** xref:eventing:eventing-handler-multiCollectionEventing.adoc[multiCollectionEventing] + **** xref:eventing:eventing-handler-advancedSelfRecursion.adoc[advancedSelfRecursion] + **** xref:eventing:eventing-handler-advancedMutateInField.adoc[advancedMutateInField] + **** xref:eventing:eventing-handler-advancedMutateInArray.adoc[advancedMutateInArray] + **** xref:eventing:eventing-handler-advancedLookupInOp.adoc[advancedLookupInField] + *** Binary Document Support + **** xref:eventing:eventing-handler-basicBinaryKV.adoc[basicBinaryKV] + **** xref:eventing:eventing-handler-advancedBinaryKV.adoc[advancedBinaryKV] + *** Performance Functions + **** xref:eventing:eventing-handler-fasterToLocalString.adoc[fasterToLocalString] + ** xref:eventing:eventing-Terminologies.adoc[Terminology] + ** xref:eventing:troubleshooting-best-practices.adoc[Troubleshooting and Best Practices] + ** xref:eventing:eventing-faq.adoc[Frequently Asked Questions] diff --git a/modules/eventing/partials/rbac-warning.adoc b/modules/eventing/partials/rbac-warning.adoc new file mode 100644 index 000000000..e9ef8db62 --- /dev/null +++ b/modules/eventing/partials/rbac-warning.adoc @@ -0,0 +1,7 @@ +[CAUTION] +==== +Changing the access role (i.e., +by revoking write permissions) could impact deployed eventing functions that have been assigned to this role. + +_This may result in the function being undeployed._ + +In this case, redeploy the function with the correctly assigned role to allow access. +==== diff --git a/modules/guides/assets/images/capella-copy-hostname.png b/modules/guides/assets/images/capella-copy-hostname.png new file mode 100644 index 000000000..a4c72c8ba Binary files /dev/null and b/modules/guides/assets/images/capella-copy-hostname.png differ diff --git a/modules/guides/assets/images/capella-login.png b/modules/guides/assets/images/capella-login.png new file mode 100644 index 000000000..29d62fc8d Binary files /dev/null and b/modules/guides/assets/images/capella-login.png differ diff --git a/modules/guides/assets/images/capella-security-cert.png b/modules/guides/assets/images/capella-security-cert.png new file mode 100644 index 000000000..52d6988e9 Binary files /dev/null and b/modules/guides/assets/images/capella-security-cert.png differ diff --git a/modules/guides/assets/images/capella-select-cluster.png b/modules/guides/assets/images/capella-select-cluster.png new file mode 100644 index 000000000..c363006d3 Binary files /dev/null and b/modules/guides/assets/images/capella-select-cluster.png differ diff --git a/modules/guides/assets/images/cbo-active.png b/modules/guides/assets/images/cbo-active.png new file mode 100644 index 000000000..13ffb60ac Binary files /dev/null and b/modules/guides/assets/images/cbo-active.png differ diff --git a/modules/guides/assets/images/cbo-inactive.png b/modules/guides/assets/images/cbo-inactive.png new file mode 100644 index 000000000..20f0ec594 Binary files /dev/null and b/modules/guides/assets/images/cbo-inactive.png differ diff --git a/modules/guides/assets/images/documents-kv-operations.png b/modules/guides/assets/images/documents-kv-operations.png new file mode 100644 index 000000000..8b1244d7d Binary files /dev/null and b/modules/guides/assets/images/documents-kv-operations.png differ diff --git a/modules/guides/assets/images/inner-join.png b/modules/guides/assets/images/inner-join.png new file mode 100644 index 000000000..88e5ba524 Binary files /dev/null and b/modules/guides/assets/images/inner-join.png differ diff --git a/modules/guides/assets/images/inner-nest.png b/modules/guides/assets/images/inner-nest.png new file mode 100644 index 000000000..ca6aa941a Binary files /dev/null and b/modules/guides/assets/images/inner-nest.png differ diff --git a/modules/guides/assets/images/javascript-udfs/add-function-dialog-switch-to-javascript.png b/modules/guides/assets/images/javascript-udfs/add-function-dialog-switch-to-javascript.png new file mode 100644 index 000000000..81a8eb2d9 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/add-function-dialog-switch-to-javascript.png differ diff --git a/modules/guides/assets/images/javascript-udfs/add-function-dialog.png b/modules/guides/assets/images/javascript-udfs/add-function-dialog.png new file mode 100644 index 000000000..797ea3544 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/add-function-dialog.png differ diff --git a/modules/guides/assets/images/javascript-udfs/add-library-screen.png b/modules/guides/assets/images/javascript-udfs/add-library-screen.png new file mode 100644 index 000000000..26e614016 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/add-library-screen.png differ diff --git a/modules/guides/assets/images/javascript-udfs/add-scoped-library.png b/modules/guides/assets/images/javascript-udfs/add-scoped-library.png new file mode 100644 index 000000000..09b8e1bbf Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/add-scoped-library.png differ diff --git a/modules/guides/assets/images/javascript-udfs/add-statement-in-editor.png b/modules/guides/assets/images/javascript-udfs/add-statement-in-editor.png new file mode 100644 index 000000000..8fdc724e6 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/add-statement-in-editor.png differ diff --git a/modules/guides/assets/images/javascript-udfs/added-get-business-days-function.png b/modules/guides/assets/images/javascript-udfs/added-get-business-days-function.png new file mode 100644 index 000000000..6268ae784 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/added-get-business-days-function.png differ diff --git a/modules/guides/assets/images/javascript-udfs/drop-library-from-ui.png b/modules/guides/assets/images/javascript-udfs/drop-library-from-ui.png new file mode 100644 index 000000000..dd7543e3a Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/drop-library-from-ui.png differ diff --git a/modules/guides/assets/images/javascript-udfs/drop-scoped-udf.png b/modules/guides/assets/images/javascript-udfs/drop-scoped-udf.png new file mode 100644 index 000000000..b715f7c08 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/drop-scoped-udf.png differ diff --git a/modules/guides/assets/images/javascript-udfs/drop-sqlpp-handler.png b/modules/guides/assets/images/javascript-udfs/drop-sqlpp-handler.png new file mode 100644 index 000000000..4c572c790 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/drop-sqlpp-handler.png differ diff --git a/modules/guides/assets/images/javascript-udfs/my-library-list-add-function-button.png b/modules/guides/assets/images/javascript-udfs/my-library-list-add-function-button.png new file mode 100644 index 000000000..8a3473897 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/my-library-list-add-function-button.png differ diff --git a/modules/guides/assets/images/javascript-udfs/navigate-to-udf-query.png b/modules/guides/assets/images/javascript-udfs/navigate-to-udf-query.png new file mode 100644 index 000000000..5a666cc53 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/navigate-to-udf-query.png differ diff --git a/modules/guides/assets/images/javascript-udfs/removing-javascript-function.png b/modules/guides/assets/images/javascript-udfs/removing-javascript-function.png new file mode 100644 index 000000000..2c770c6ed Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/removing-javascript-function.png differ diff --git a/modules/guides/assets/images/javascript-udfs/scope-library-list.png b/modules/guides/assets/images/javascript-udfs/scope-library-list.png new file mode 100644 index 000000000..7464ce20e Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/scope-library-list.png differ diff --git a/modules/guides/assets/images/javascript-udfs/select-query-tool-ui.png b/modules/guides/assets/images/javascript-udfs/select-query-tool-ui.png new file mode 100644 index 000000000..3129a3d6d Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/select-query-tool-ui.png differ diff --git a/modules/guides/assets/images/javascript-udfs/setting-context.png b/modules/guides/assets/images/javascript-udfs/setting-context.png new file mode 100644 index 000000000..d3e267041 Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/setting-context.png differ diff --git a/modules/guides/assets/images/javascript-udfs/switch-context-to-travel-sample.png b/modules/guides/assets/images/javascript-udfs/switch-context-to-travel-sample.png new file mode 100644 index 000000000..c7f9d125b Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/switch-context-to-travel-sample.png differ diff --git a/modules/guides/assets/images/javascript-udfs/workbench-menu-item.png b/modules/guides/assets/images/javascript-udfs/workbench-menu-item.png new file mode 100644 index 000000000..6675c6d0a Binary files /dev/null and b/modules/guides/assets/images/javascript-udfs/workbench-menu-item.png differ diff --git a/modules/guides/assets/images/left-join.png b/modules/guides/assets/images/left-join.png new file mode 100644 index 000000000..9049bf5ec Binary files /dev/null and b/modules/guides/assets/images/left-join.png differ diff --git a/modules/guides/assets/images/left-nest.png b/modules/guides/assets/images/left-nest.png new file mode 100644 index 000000000..1a4b5ceda Binary files /dev/null and b/modules/guides/assets/images/left-nest.png differ diff --git a/modules/guides/assets/images/login.png b/modules/guides/assets/images/login.png new file mode 100644 index 000000000..3eb01f9dc Binary files /dev/null and b/modules/guides/assets/images/login.png differ diff --git a/modules/guides/assets/images/query-workbench-context-unset.png b/modules/guides/assets/images/query-workbench-context-unset.png new file mode 100644 index 000000000..776475226 Binary files /dev/null and b/modules/guides/assets/images/query-workbench-context-unset.png differ diff --git a/modules/guides/assets/images/query-workbench-context.png b/modules/guides/assets/images/query-workbench-context.png new file mode 100644 index 000000000..b6382332e Binary files /dev/null and b/modules/guides/assets/images/query-workbench-context.png differ diff --git a/modules/guides/assets/images/right-join.png b/modules/guides/assets/images/right-join.png new file mode 100644 index 000000000..eb841dd2d Binary files /dev/null and b/modules/guides/assets/images/right-join.png differ diff --git a/modules/guides/assets/images/transactions-context.png b/modules/guides/assets/images/transactions-context.png new file mode 100644 index 000000000..ec9ddb086 Binary files /dev/null and b/modules/guides/assets/images/transactions-context.png differ diff --git a/modules/guides/assets/images/transactions-preferences.png b/modules/guides/assets/images/transactions-preferences.png new file mode 100644 index 000000000..a515057ee Binary files /dev/null and b/modules/guides/assets/images/transactions-preferences.png differ diff --git a/modules/guides/assets/images/unnest.png b/modules/guides/assets/images/unnest.png new file mode 100644 index 000000000..73c1c02c3 Binary files /dev/null and b/modules/guides/assets/images/unnest.png differ diff --git a/modules/guides/assets/source/inner-join.svg b/modules/guides/assets/source/inner-join.svg new file mode 100644 index 000000000..2dafd3bd7 --- /dev/null +++ b/modules/guides/assets/source/inner-join.svg @@ -0,0 +1,4 @@ + + + +Left Data Source
      abc
      abc
      mno
      mno
      jkl
      jkl
      ghi
      ghi
      def
      def
      Right Data Source
      2000
      2000
      1000
      1000
      4000
      4000
      3000
      3000
      5000
      5000
      8000
      8000
      7000
      7000
      6000
      6000
      Result
      ghi
      ghi
      abc
      abc
      abc
      abc
      abc
      abc
      ghi
      ghi
      1000
      1000
      6000
      6000
      5000
      5000
      3000
      3000
      2000
      2000
      Viewer does not support full SVG 1.1
      \ No newline at end of file diff --git a/modules/guides/assets/source/inner-nest.svg b/modules/guides/assets/source/inner-nest.svg new file mode 100644 index 000000000..dcf01677f --- /dev/null +++ b/modules/guides/assets/source/inner-nest.svg @@ -0,0 +1,4 @@ + + + +Left Data Source
      abc
      abc
      jkl
      jkl
      ghi
      ghi
      def
      def
      Right Data Source
      2000
      2000
      1000
      1000
      4000
      4000
      3000
      3000
      5000
      5000
      8000
      8000
      7000
      7000
      6000
      6000
      Result
      ghi
      ghi
      6000
      6000
      5000
      5000
      abc
      abc
      1000
      1000
      2000
      2000
      3000
      3000
      Viewer does not support full SVG 1.1
      \ No newline at end of file diff --git a/modules/guides/assets/source/left-join.svg b/modules/guides/assets/source/left-join.svg new file mode 100644 index 000000000..bc8615b35 --- /dev/null +++ b/modules/guides/assets/source/left-join.svg @@ -0,0 +1,4 @@ + + + +Left Data Source
      abc
      abc
      mno
      mno
      jkl
      jkl
      ghi
      ghi
      def
      def
      Right Data Source
      2000
      2000
      1000
      1000
      4000
      4000
      3000
      3000
      5000
      5000
      8000
      8000
      7000
      7000
      6000
      6000
      Result
      jkl
      jkl
      ghi
      ghi
      abc
      abc
      abc
      abc
      def
      def
      abc
      abc
      ghi
      ghi
      mno
      mno
      1000
      1000
      6000
      6000
      5000
      5000
      3000
      3000
      2000
      2000
      Viewer does not support full SVG 1.1
      \ No newline at end of file diff --git a/modules/guides/assets/source/left-nest.svg b/modules/guides/assets/source/left-nest.svg new file mode 100644 index 000000000..df0774b7e --- /dev/null +++ b/modules/guides/assets/source/left-nest.svg @@ -0,0 +1,4 @@ + + + +Left Data Source
      abc
      abc
      jkl
      jkl
      ghi
      ghi
      def
      def
      Right Data Source
      2000
      2000
      1000
      1000
      4000
      4000
      3000
      3000
      5000
      5000
      8000
      8000
      7000
      7000
      6000
      6000
      Result
      jkl
      jkl
      def
      def
      ghi
      ghi
      6000
      6000
      5000
      5000
      abc
      abc
      1000
      1000
      2000
      2000
      3000
      3000
      Viewer does not support full SVG 1.1
      \ No newline at end of file diff --git a/modules/guides/assets/source/right-join.svg b/modules/guides/assets/source/right-join.svg new file mode 100644 index 000000000..c1c14c9ba --- /dev/null +++ b/modules/guides/assets/source/right-join.svg @@ -0,0 +1,4 @@ + + + +Left Data Source
      abc
      abc
      mno
      mno
      jkl
      jkl
      ghi
      ghi
      def
      def
      Right Data Source
      2000
      2000
      1000
      1000
      4000
      4000
      3000
      3000
      5000
      5000
      8000
      8000
      7000
      7000
      6000
      6000
      Result
      ghi
      ghi
      abc
      abc
      abc
      abc
      abc
      abc
      ghi
      ghi
      1000
      1000
      8000
      8000
      7000
      7000
      6000
      6000
      5000
      5000
      4000
      4000
      3000
      3000
      2000
      2000
      Viewer does not support full SVG 1.1
      \ No newline at end of file diff --git a/modules/guides/assets/source/unnest.svg b/modules/guides/assets/source/unnest.svg new file mode 100644 index 000000000..d05524e12 --- /dev/null +++ b/modules/guides/assets/source/unnest.svg @@ -0,0 +1,4 @@ + + + +Result
      def
      def
      abc
      abc
      5000
      5000
      1000
      1000
      abc
      abc
      3000
      3000
      abc
      abc
      2000
      2000
      ghi
      ghi
      6000
      6000
      def
      def
      4000
      4000
      Data source
      def
      def
      5000
      5000
      4000
      4000
      abc
      abc
      1000
      1000
      2000
      2000
      3000
      3000
      ghi
      ghi
      6000
      6000
      Viewer does not support full SVG 1.1
      \ No newline at end of file diff --git a/modules/guides/examples/connect/connect-cbc.sh b/modules/guides/examples/connect/connect-cbc.sh new file mode 100644 index 000000000..21ed61dc8 --- /dev/null +++ b/modules/guides/examples/connect/connect-cbc.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# tag::cbc-connect[] +cbc ping -u Administrator -P password -U couchbase://localhost/travel-sample \ + --count=1 \ + --table +# end::cbc-connect[] + +# tag::cbc-connect-cert[] +cbc ping -v -U "couchbases://127.0.0.1/travel-sample?certpath=ca.pem" \ + --count=1 \ + --table +# end::cbc-connect-cert[] + +# tag::cbc-connect-capella[] +cbc ping -u username -P "passworD#1" \ + -U "couchbases://cb.oawlpi4audpc6jp5.cloud.couchbase.com/travel-sample?certpath=cert.pem" \ + --count=1 \ + --table +# end::cbc-connect-capella[] diff --git a/modules/guides/examples/javascript-udfs/create-javascript-function-with-rest.sh b/modules/guides/examples/javascript-udfs/create-javascript-function-with-rest.sh new file mode 100644 index 000000000..84830a496 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/create-javascript-function-with-rest.sh @@ -0,0 +1,15 @@ +curl -v POST http://localhost:8093/evaluator/v1/libraries/my-library \ + -u Administrator:password \ + -d 'function getBusinessDays(startDate, endDate) { + let count = 0; + const curDate = new Date(new Date(startDate).getTime()); + while (curDate <= new Date(endDate)) { + const dayOfWeek = curDate.getDay(); + if(dayOfWeek !== 0 && dayOfWeek !== 6) + count++; + curDate.setDate(curDate.getDate() + 1); + } + return count; + }' + + \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/create-scoped-javascript-function-with-rest.sh b/modules/guides/examples/javascript-udfs/create-scoped-javascript-function-with-rest.sh new file mode 100644 index 000000000..c599e2270 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/create-scoped-javascript-function-with-rest.sh @@ -0,0 +1,14 @@ +curl -v -X POST 'http://localhost:8093/evaluator/v1/libraries/my-library?bucket=travel-sample&scope=inventory' \ + -u Administrator:password \ + -d 'function getBusinessDays(startDate, endDate) { + let count = 0; + const curDate = new Date(new Date(startDate).getTime()); + while (curDate <= new Date(endDate)) { + const dayOfWeek = curDate.getDay(); + if(dayOfWeek !== 0 && dayOfWeek !== 6) + count++; + curDate.setDate(curDate.getDate() + 1); + } + return count; + }' + \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/create-scoped-n1ql-udf-with-rest.sh b/modules/guides/examples/javascript-udfs/create-scoped-n1ql-udf-with-rest.sh new file mode 100644 index 000000000..9e9943302 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/create-scoped-n1ql-udf-with-rest.sh @@ -0,0 +1,4 @@ +curl -v http://localhost:8093/query/service \ + -u Administrator:password \ + -d 'statement=CREATE FUNCTION default:`travel-sample`.inventory.GetBusinessDays(...) + LANGUAGE JAVASCRIPT as "getBusinessDays" AT "travel-sample/inventory/my-library"' diff --git a/modules/guides/examples/javascript-udfs/create-scoped-n1ql-udf.n1ql b/modules/guides/examples/javascript-udfs/create-scoped-n1ql-udf.n1ql new file mode 100644 index 000000000..6f8a55404 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/create-scoped-n1ql-udf.n1ql @@ -0,0 +1 @@ +CREATE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays(...) LANGUAGE JAVASCRIPT as "getBusinessDays" AT "travel-sample/inventory/my-library"; \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/drop-scoped-n1ql-udf.sh b/modules/guides/examples/javascript-udfs/drop-scoped-n1ql-udf.sh new file mode 100644 index 000000000..97478a510 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/drop-scoped-n1ql-udf.sh @@ -0,0 +1,3 @@ +curl -v http://localhost:8093/query/service \ + -u Administrator:password \ + -d 'statement=DROP FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays' \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/execute-get-business-days-response.jsonc b/modules/guides/examples/javascript-udfs/execute-get-business-days-response.jsonc new file mode 100644 index 000000000..07820afa5 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/execute-get-business-days-response.jsonc @@ -0,0 +1,5 @@ +[ + { + "$1": 45 + } +] \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/execute-javascript-function-rest-response.jsonc b/modules/guides/examples/javascript-udfs/execute-javascript-function-rest-response.jsonc new file mode 100644 index 000000000..0592288ac --- /dev/null +++ b/modules/guides/examples/javascript-udfs/execute-javascript-function-rest-response.jsonc @@ -0,0 +1,9 @@ +{ +"requestID": "72261909-4ba7-44b4-91c6-d02a58ee6b4f", +"signature": null, +"results": [ // <.> +45 +], +"status": "success", +"metrics": {"elapsedTime": "5.378419ms","executionTime": "5.336847ms","resultCount": 1,"resultSize": 2,"serviceLoad": 25} +} diff --git a/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql b/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql new file mode 100644 index 000000000..aea6b4586 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION GetBusinessDays("02/14/2022", "04/16/2022"); \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/execute-javascript-function.sh b/modules/guides/examples/javascript-udfs/execute-javascript-function.sh new file mode 100644 index 000000000..47560399c --- /dev/null +++ b/modules/guides/examples/javascript-udfs/execute-javascript-function.sh @@ -0,0 +1,3 @@ +curl -v http://localhost:8093/query/service \ + -u Administrator:password \ + -d 'statement=EXECUTE FUNCTION GetBusinessDays("02/14/2022", "04/16/2022")' \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql b/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql new file mode 100644 index 000000000..e7f1a0297 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays("03/10/2022", "05/10.2022"); \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/execute-scoped-function.sh b/modules/guides/examples/javascript-udfs/execute-scoped-function.sh new file mode 100644 index 000000000..863c0a5e8 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/execute-scoped-function.sh @@ -0,0 +1,3 @@ +curl -v http://localhost:8093/query/service \ + -u Administrator:password \ + -d 'statement=EXECUTE FUNCTION default:`travel-sample`.inventory.GetBusinessDays("03/10/2022", "05/10.2022")' \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/get-business-days.js b/modules/guides/examples/javascript-udfs/get-business-days.js new file mode 100644 index 000000000..c86274b22 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/get-business-days.js @@ -0,0 +1,11 @@ +function getBusinessDays(startDate, endDate) { + let count = 0; + const curDate = new Date(new Date(startDate).getTime()); + while (curDate <= new Date(endDate)) { + const dayOfWeek = curDate.getDay(); + if(dayOfWeek !== 0 && dayOfWeek !== 6) + count++; + curDate.setDate(curDate.getDate() + 1); + } + return count; +} diff --git a/modules/guides/examples/javascript-udfs/remove-library.sh b/modules/guides/examples/javascript-udfs/remove-library.sh new file mode 100644 index 000000000..cdb918fb5 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/remove-library.sh @@ -0,0 +1,2 @@ +curl -X DELETE 'http://localhost:8093/evaluator/v1/libraries/my-library?bucket=travel-sample&scope=inventory' \ +-u Administrator:password diff --git a/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql b/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql new file mode 100644 index 000000000..01e7f2f28 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql @@ -0,0 +1 @@ +SELECT GetBusinessDays("02/14/2022", "04/16/2022"); \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql b/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql new file mode 100644 index 000000000..875ecbc7e --- /dev/null +++ b/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql @@ -0,0 +1,5 @@ +SELECT CASE + WHEN GetBusinessDays('02/14/2022', '4/16/2022') > 44 THEN "true" + ELSE "false" + END + AS response; \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/start-up-cbq-shell.sh b/modules/guides/examples/javascript-udfs/start-up-cbq-shell.sh new file mode 100644 index 000000000..ab95d66f6 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/start-up-cbq-shell.sh @@ -0,0 +1 @@ +/opt/couchbase/bin/cbq -u Administrator \ No newline at end of file diff --git a/modules/guides/examples/kv/airport-123.json b/modules/guides/examples/kv/airport-123.json new file mode 100644 index 000000000..8f54850a8 --- /dev/null +++ b/modules/guides/examples/kv/airport-123.json @@ -0,0 +1,15 @@ +{ + "id": 123, + "type": "airport", + "airportname": "Santa Clara", + "city": "Santa Clara", + "country": "United States", + "faa": "SCC", + "geo": { + "alt": 62, + "lat": -121.928407, + "lon": 37.368792 + }, + "icao": "LFAX", + "tz": "America/Los_Angeles" +} diff --git a/modules/guides/examples/kv/airport-456.json b/modules/guides/examples/kv/airport-456.json new file mode 100644 index 000000000..8c3295a73 --- /dev/null +++ b/modules/guides/examples/kv/airport-456.json @@ -0,0 +1,15 @@ +{ + "id": 456, + "type": "airport", + "airportname": "Calais Dunkerque", + "city": "Calais", + "country": "France", + "faa": "CQF", + "geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + }, + "icao": "LFAC", + "tz": "Europe/Paris" +} diff --git a/modules/guides/examples/kv/hotel-123.json b/modules/guides/examples/kv/hotel-123.json new file mode 100644 index 000000000..cf4e51b8f --- /dev/null +++ b/modules/guides/examples/kv/hotel-123.json @@ -0,0 +1,23 @@ +{ + "id": 123, + "name": "Medway Youth Hostel", + "address": "Capstone Road, ME7 3JE", + "url": "http://www.yha.org.uk", + "geo": { + "lat": 51.35785, + "lon": 0.55818, + "accuracy": "RANGE_INTERPOLATED" + }, + "country": "United Kingdom", + "city": "Medway", + "state": null, + "reviews": [ + { + "content": "This was our 2nd trip here and we enjoyed it more than last year.", + "author": "Ozella Sipes", + "date": "2021-11-17T17:35:05.351Z" + } + ], + "vacancy": true, + "description": "40 bed summer hostel about 3 miles from Gillingham." +} diff --git a/modules/guides/examples/kv/hotel-456.json b/modules/guides/examples/kv/hotel-456.json new file mode 100644 index 000000000..4b8fc6522 --- /dev/null +++ b/modules/guides/examples/kv/hotel-456.json @@ -0,0 +1,12 @@ +{ + "id": 456, + "title": "Ardèche", + "name": "La Pradella", + "address": "rue du village, 07290 Preaux, France", + "phone": "+33 4 75 32 08 52", + "url": "http://www.lapradella.fr", + "country": "France", + "city": "Preaux", + "state": "Rhône-Alpes", + "vacancy": false +} diff --git a/modules/guides/examples/kv/kv-cbsh.nu b/modules/guides/examples/kv/kv-cbsh.nu new file mode 100755 index 000000000..9073e6251 --- /dev/null +++ b/modules/guides/examples/kv/kv-cbsh.nu @@ -0,0 +1,167 @@ +#!/usr/bin/env nu + +# tag::cbsh-kv-insert[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc insert hotel-123 { + "id": 123, + "name": "Medway Youth Hostel", + "address": "Capstone Road, ME7 3JE", + "url": "http://www.yha.org.uk", + "geo": { + "lat": 51.35785, + "lon": 0.55818, + "accuracy": "RANGE_INTERPOLATED" + }, + "country": "United Kingdom", + "city": "Medway", + "state": null, + "reviews": [ + { + "content": "This was our 2nd trip here and we enjoyed it more than last year.", + "author": "Ozella Sipes", + "date": "2021-11-17T17:35:05.351Z" + } + ], + "vacancy": true, + "description": "40 bed summer hostel about 3 miles from Gillingham." +} +# end::cbsh-kv-insert[] + +# tag::cbsh-kv-insert-expiry[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc insert --expiry 60 hotel-456 { + "id": 456, + "title": "Ardèche", + "name": "La Pradella", + "address": "rue du village, 07290 Preaux, France", + "phone": "+33 4 75 32 08 52", + "url": "http://www.lapradella.fr", + "country": "France", + "city": "Preaux", + "state": "Rhône-Alpes", + "vacancy": false +} +# end::cbsh-kv-insert-expiry[] + +# tag::cbsh-kv-get[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc get hotel-123 +# end::cbsh-kv-get[] + +# tag::cbsh-kv-get-with-opts[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc get hotel-123 | to json +# end::cbsh-kv-get-with-opts[] + +# tag::cbsh-kv-upsert[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc upsert hotel-123 { + "id": 123, + "name": "Medway Youth Hostel", + "address": "Capstone Road, ME7 3JE", + "url": "http://www.yha.org.uk", + "country": "United Kingdom", + "city": "Medway", + "state": null, + "vacancy": true, + "description": "40 bed summer hostel about 3 miles from Gillingham." +} +# end::cbsh-kv-upsert[] + +# tag::cbsh-kv-replace[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc replace hotel-123 { + "id": 123, + "name": "Medway Youth Hostel", + "address": "Capstone Road, ME7 3JE", + "url": "http://www.yha.org.uk", + "geo": { + "lat": 51.35785, + "lon": 0.55818, + "accuracy": "RANGE_INTERPOLATED" + }, + "country": "United Kingdom", + "city": "Medway", + "state": null, + "reviews": [ + { + "content": "This was our 2nd trip here and we enjoyed it more than last year.", + "author": "Ozella Sipes", + "date": "2021-12-13T17:38:02.935Z" + }, + { + "content": "This hotel was cozy, conveniently located and clean.", + "author": "Carmella O'Keefe", + "date": "2021-12-13T17:38:02.974Z" + } + ], + "vacancy": true, + "description": "40 bed summer hostel about 3 miles from Gillingham." +} +# end::cbsh-kv-replace[] + +# tag::cbsh-kv-delete[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc remove hotel-123 +# end::cbsh-kv-delete[] + +# tag::cbsh-bulk-insert[] +cb-env bucket travel-sample +cb-env scope tenant_agent_00 +cb-env collection users + +[ + {id: "user_111", email: "tom_the_cat@example.com"}, + {id: "user_222", email: "jerry_mouse@example.com"}, + {id: "user_333", email: "mickey_mouse@example.com"} +] | wrap content | insert id { |this| echo $this.content.id } | doc insert +# end::cbsh-bulk-insert[] + +# tag::cbsh-bulk-get[] +cb-env bucket travel-sample +cb-env scope tenant_agent_00 +cb-env collection users + +['0' '1'] | wrap id | doc get +# end::cbsh-bulk-get[] + +# tag::cbsh-bulk-upsert[] +cb-env bucket travel-sample +cb-env scope tenant_agent_00 +cb-env collection users + +[ + {id: "user_111", email: "tom@example.com"}, + {id: "user_222", email: "jerry@example.com"}, + {id: "user_333", email: "mickey@example.com"} +] | wrap content | insert id { |this| echo $this.content.id } | doc upsert +# end::cbsh-bulk-upsert[] + +# tag::cbsh-bulk-delete[] +cb-env bucket travel-sample +cb-env scope tenant_agent_00 +cb-env collection users + +[user_111 user_222 user_333] | wrap id | doc remove +# end::cbsh-bulk-delete[] diff --git a/modules/guides/examples/kv/kv-subdoc.nu b/modules/guides/examples/kv/kv-subdoc.nu new file mode 100644 index 000000000..a583d6e44 --- /dev/null +++ b/modules/guides/examples/kv/kv-subdoc.nu @@ -0,0 +1,25 @@ +#!/usr/bin/env nu + +# tag::cbsh-subdoc-get[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc get hotel-123 | get content.geo +# end::cbsh-subdoc-get[] + +# tag::cbsh-subdoc-upsert[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc get hotel-123 | upsert content.pets_ok true | doc replace +# end::cbsh-subdoc-upsert[] + +# tag::cbsh-subdoc-reject[] +cb-env bucket travel-sample +cb-env scope inventory +cb-env collection hotel + +doc get hotel-123 | reject content.url | doc replace +# end::cbsh-subdoc-reject[] diff --git a/modules/guides/examples/prepared/adhoc.cs b/modules/guides/examples/prepared/adhoc.cs new file mode 100644 index 000000000..156dc9231 --- /dev/null +++ b/modules/guides/examples/prepared/adhoc.cs @@ -0,0 +1,6 @@ +var result = await cluster.QueryAsync( + "select count(*) from `travel-sample`.inventory.airport where country = ?", + options => + options.Parameter("France") + .AdHoc(false); +); \ No newline at end of file diff --git a/modules/guides/examples/prepared/adhoc.js b/modules/guides/examples/prepared/adhoc.js new file mode 100644 index 000000000..d10a71666 --- /dev/null +++ b/modules/guides/examples/prepared/adhoc.js @@ -0,0 +1,15 @@ +async function queryNamed() { + const query = ` + SELECT airportname, city FROM \`travel-sample\`.inventory.airport + WHERE city=$1 + `; + var options = { adhoc: false, parameters: ['London'] } + + try { + let result = await cluster.query(query, options) + console.log("Result:", result) + return result + } catch (error) { + console.error('Query failed: ', error) + } +} \ No newline at end of file diff --git a/modules/guides/examples/prepared/adhoc.py b/modules/guides/examples/prepared/adhoc.py new file mode 100644 index 000000000..4a036b1f2 --- /dev/null +++ b/modules/guides/examples/prepared/adhoc.py @@ -0,0 +1,5 @@ +result = cluster.query( + """SELECT airportname, city + FROM \`travel-sample\`.inventory.airport + WHERE city=$1;""", + 'London', QueryOptions(adhoc=false)) \ No newline at end of file diff --git a/modules/guides/examples/query/ansi-join-example.n1ql b/modules/guides/examples/query/ansi-join-example.n1ql new file mode 100644 index 000000000..8c24fc479 --- /dev/null +++ b/modules/guides/examples/query/ansi-join-example.n1ql @@ -0,0 +1,5 @@ +SELECT * +FROM route r -- <.> +JOIN airline a -- <.> +ON r.airlineid = META(a).id -- <.> +LIMIT 1; \ No newline at end of file diff --git a/modules/guides/examples/query/ansi-nest-example.n1ql b/modules/guides/examples/query/ansi-nest-example.n1ql new file mode 100644 index 000000000..3590b3b2a --- /dev/null +++ b/modules/guides/examples/query/ansi-nest-example.n1ql @@ -0,0 +1,5 @@ +SELECT * +FROM route r -- <.> +NEST airline a -- <.> +ON r.airlineid = META(a).id -- <.> +LIMIT 1; \ No newline at end of file diff --git a/modules/guides/examples/query/context-set.n1ql b/modules/guides/examples/query/context-set.n1ql new file mode 100644 index 000000000..1c8ee6046 --- /dev/null +++ b/modules/guides/examples/query/context-set.n1ql @@ -0,0 +1 @@ +\SET -query_context travel-sample.inventory; \ No newline at end of file diff --git a/modules/guides/examples/query/context-unset.n1ql b/modules/guides/examples/query/context-unset.n1ql new file mode 100644 index 000000000..fe349fd60 --- /dev/null +++ b/modules/guides/examples/query/context-unset.n1ql @@ -0,0 +1 @@ +\UNSET -query_context; \ No newline at end of file diff --git a/modules/guides/examples/query/from-clause.jsonc b/modules/guides/examples/query/from-clause.jsonc new file mode 100644 index 000000000..a81836e39 --- /dev/null +++ b/modules/guides/examples/query/from-clause.jsonc @@ -0,0 +1,7881 @@ +// tag::extract[] +[ + { + "airportname": "Calais Dunkerque", + "city": "Calais" + }, + { + "airportname": "Peronne St Quentin", + "city": "Peronne" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "airportname": "Les Loges", + "city": "Nangis" + }, + { + "airportname": "Couterne", + "city": "Bagnole-de-l'orne" + }, + { + "airportname": "Bray", + "city": "Albert" + }, + { + "airportname": "Le Touquet Paris Plage", + "city": "Le Tourquet" + }, + { + "airportname": "Denain", + "city": "Valenciennes" + }, + { + "airportname": "Glisy", + "city": "Amiens" + }, + { + "airportname": "La Garenne", + "city": "Agen" + }, + { + "airportname": "Cazaux", + "city": "Cazaux" + }, + { + "airportname": "Merignac", + "city": "Bordeaux" + }, + { + "airportname": "Roumaniere", + "city": "Bergerac" + }, + { + "airportname": "Francazal", + "city": "Toulouse" + }, + { + "airportname": "Chateaubernard", + "city": "Cognac" + }, + { + "airportname": "Biard", + "city": "Poitiers" + }, + { + "airportname": "Montlucon Gueret", + "city": "Montlucon-gueret" + }, + { + "airportname": "Bellegarde", + "city": "Limoges" + }, + { + "airportname": "Mont De Marsan", + "city": "Mont-de-marsan" + }, + { + "airportname": "Souche", + "city": "Niort" + }, + { + "airportname": "Blagnac", + "city": "Toulouse" + }, + { + "airportname": "Pau Pyrenees", + "city": "Pau" + }, + { + "airportname": "Lherm", + "city": "La Rochelle" + }, + { + "airportname": "Lourdes", + "city": "Tarbes" + }, + { + "airportname": "Brie Champniers", + "city": "Angouleme" + }, + { + "airportname": "La Roche", + "city": "Brive" + }, + { + "airportname": "Bassillac", + "city": "Perigueux" + }, + { + "airportname": "Anglet", + "city": "Biarritz-bayonne" + }, + { + "airportname": "Lalbenque", + "city": "Cahors" + }, + { + "airportname": "Antichan", + "city": "St.-girons" + }, + { + "airportname": "La Teste De Buch", + "city": "Arcachon" + }, + { + "airportname": "Le Sequestre", + "city": "Albi" + }, + { + "airportname": "Mazamet", + "city": "Castres" + }, + { + "airportname": "Lasbordes", + "city": "Toulouse" + }, + { + "airportname": "Larzac", + "city": "Millau" + }, + { + "airportname": "Montdragon", + "city": "Graulhet" + }, + { + "airportname": "Marcillac", + "city": "Rodez" + }, + { + "airportname": "Thalamy", + "city": "Ussel" + }, + { + "airportname": "Villeneuve Sur Lot", + "city": "Villeneuve-sur-lot" + }, + { + "airportname": "Medis", + "city": "Royan" + }, + { + "airportname": "Mimizan", + "city": "Mimizan" + }, + { + "airportname": "Aire Sur L Adour", + "city": "Aire-sur-l'adour" + }, + { + "airportname": "Montauban", + "city": "Montauban" + }, + { + "airportname": "Lamothe", + "city": "Auch" + }, + { + "airportname": "Artigues De Lussac", + "city": "Libourne" + }, + { + "airportname": "Les Pujols", + "city": "Pamiers" + }, + { + "airportname": "Virazeil", + "city": "Marmande" + }, + { + "airportname": "St Agnant", + "city": "Rochefort" + }, + { + "airportname": "Pontivy", + "city": "Pontivy" + }, + { + "airportname": "Aubigny Sur Nere", + "city": "Aubigny-sur-nere" + }, + { + "airportname": "Scaer", + "city": "Guiscriff-scaer" + }, + { + "airportname": "Ancenis", + "city": "Ancenis" + }, + { + "airportname": "Brienne Le Chateau", + "city": "Brienne-le Chateau" + }, + { + "airportname": "Houssen", + "city": "Colmar" + }, + { + "airportname": "Challanges", + "city": "Beaune" + }, + { + "airportname": "Tavaux", + "city": "Dole" + }, + { + "airportname": "Joigny", + "city": "Joigny" + }, + { + "airportname": "Le Rozelier", + "city": "Verdun" + }, + { + "airportname": "Ardeche Meridionale", + "city": "Aubenas-vals-lanas" + }, + { + "airportname": "Loudes", + "city": "Le Puy" + }, + { + "airportname": "Coltines", + "city": "St.-flour" + }, + { + "airportname": "Ceyzeriat", + "city": "Bourg" + }, + { + "airportname": "Tarare", + "city": "Vilefrance" + }, + { + "airportname": "Montbeugny", + "city": "Moulins" + }, + { + "airportname": "Belmont", + "city": "St.-afrique-belmont" + }, + { + "airportname": "Cassagnes Begonhes", + "city": "Cassagnes-beghones" + }, + { + "airportname": "Metz Nancy Lorraine", + "city": "Metz" + }, + { + "airportname": "Poretta", + "city": "Bastia" + }, + { + "airportname": "Saint Catherine", + "city": "Calvi" + }, + { + "airportname": "Sud Corse", + "city": "Figari" + }, + { + "airportname": "Campo Dell Oro", + "city": "Ajaccio" + }, + { + "airportname": "Propriano", + "city": "Propriano" + }, + { + "airportname": "Solenzara", + "city": "Solenzara" + }, + { + "airportname": "Corte", + "city": "Corte" + }, + { + "airportname": "Branches", + "city": "Auxerre" + }, + { + "airportname": "Aix Les Bains", + "city": "Chambery" + }, + { + "airportname": "Auvergne", + "city": "Clermont-Ferrand" + }, + { + "airportname": "Bourges", + "city": "Bourges" + }, + { + "airportname": "Challes Les Eaux", + "city": "Chambery" + }, + { + "airportname": "Champforgeuil", + "city": "Chalon" + }, + { + "airportname": "Annemasse", + "city": "Annemasse" + }, + { + "airportname": "Saint Exupery", + "city": "Lyon" + }, + { + "airportname": "Charnay", + "city": "Macon" + }, + { + "airportname": "Saint Yan", + "city": "St.-yan" + }, + { + "airportname": "Renaison", + "city": "Roanne" + }, + { + "airportname": "Meythet", + "city": "Annecy" + }, + { + "airportname": "Saint Geoirs", + "city": "Grenoble" + }, + { + "airportname": "Domerat", + "city": "Montlucon" + }, + { + "airportname": "Chabeuil", + "city": "Valence" + }, + { + "airportname": "Charmeil", + "city": "Vichy" + }, + { + "airportname": "Aurillac", + "city": "Aurillac" + }, + { + "airportname": "Deols", + "city": "Chateauroux" + }, + { + "airportname": "Bron", + "city": "Lyon" + }, + { + "airportname": "Aix Les Milles", + "city": "Aix-les-milles" + }, + { + "airportname": "Le Cannet", + "city": "Le Luc" + }, + { + "airportname": "Mandelieu", + "city": "Cannes" + }, + { + "airportname": "Boutheon", + "city": "St-Etienne" + }, + { + "airportname": "Le Tube", + "city": "Istres" + }, + { + "airportname": "Salvaza", + "city": "Carcassonne" + }, + { + "airportname": "Provence", + "city": "Marseille" + }, + { + "airportname": "Cote D\\'Azur", + "city": "Nice" + }, + { + "airportname": "Caritat", + "city": "Orange" + }, + { + "airportname": "Rivesaltes", + "city": "Perpignan" + }, + { + "airportname": "Le Castellet", + "city": "Le Castellet" + }, + { + "airportname": "Deaux", + "city": "Ales" + }, + { + "airportname": "Mediterranee", + "city": "Montpellier" + }, + { + "airportname": "Vias", + "city": "Beziers" + }, + { + "airportname": "Caumont", + "city": "Avignon" + }, + { + "airportname": "Salon", + "city": "Salon" + }, + { + "airportname": "Lezignan Corbieres", + "city": "Lezignan-corbieres" + }, + { + "airportname": "Brenoux", + "city": "Mende" + }, + { + "airportname": "Carpentras", + "city": "Carpentras" + }, + { + "airportname": "Avord", + "city": "Avord" + }, + { + "airportname": "Tille", + "city": "Beauvais" + }, + { + "airportname": "Chateaudun", + "city": "Chateaudun" + }, + { + "airportname": "St Florent", + "city": "Saumur" + }, + { + "airportname": "Fauville", + "city": "Evreux" + }, + { + "airportname": "Octeville", + "city": "Le Havre" + }, + { + "airportname": "Abbeville", + "city": "Abbeville" + }, + { + "airportname": "Bricy", + "city": "Orleans" + }, + { + "airportname": "Vatry", + "city": "Chalons" + }, + { + "airportname": "Vallee De Seine", + "city": "Rouen" + }, + { + "airportname": "Val De Loire", + "city": "Tours" + }, + { + "airportname": "Le Pontreau", + "city": "Cholet" + }, + { + "airportname": "Entrammes", + "city": "Laval" + }, + { + "airportname": "St Denis De L Hotel", + "city": "Orleans" + }, + { + "airportname": "Le Bourget", + "city": "Paris" + }, + { + "airportname": "Creil", + "city": "Creil" + }, + { + "airportname": "Charles De Gaulle", + "city": "Paris" + }, + { + "airportname": "Voisins", + "city": "Coulommiers" + }, + { + "airportname": "Villaroche", + "city": "Melun" + }, + { + "airportname": "Toussus Le Noble", + "city": "Toussous-le-noble" + }, + { + "airportname": "Orly", + "city": "Paris" + }, + { + "airportname": "Cormeilles En Vexin", + "city": "Pontoise" + }, + { + "airportname": "Velizy", + "city": "Villacoublay" + }, + { + "airportname": "Prunay", + "city": "Reims" + }, + { + "airportname": "Barberey", + "city": "Troyes" + }, + { + "airportname": "Croismare", + "city": "Luneville" + }, + { + "airportname": "Rouvres", + "city": "Etain" + }, + { + "airportname": "Bellevue", + "city": "Autun" + }, + { + "airportname": "Fourchambault", + "city": "Nevers" + }, + { + "airportname": "Epinoy", + "city": "Cambrai" + }, + { + "airportname": "Elesmes", + "city": "Maubeuge" + }, + { + "airportname": "La Veze", + "city": "Besancon-la-veze" + }, + { + "airportname": "Bourscheid", + "city": "Phalsbourg" + }, + { + "airportname": "Lesquin", + "city": "Lille" + }, + { + "airportname": "Calonne", + "city": "Merville" + }, + { + "airportname": "Charleville Mezieres", + "city": "Charleville" + }, + { + "airportname": "Frotey", + "city": "Vesoul-frotey" + }, + { + "airportname": "Guipavas", + "city": "Brest" + }, + { + "airportname": "Maupertus", + "city": "Cherbourg" + }, + { + "airportname": "Pleurtuit", + "city": "Dinard" + }, + { + "airportname": "Escoublac", + "city": "La Baule" + }, + { + "airportname": "Granville", + "city": "Granville" + }, + { + "airportname": "St Gatien", + "city": "Deauville" + }, + { + "airportname": "Lann Bihoue", + "city": "Lorient" + }, + { + "airportname": "Les Ajoncs", + "city": "La Roche-sur-yon" + }, + { + "airportname": "Landivisiau", + "city": "Landivisiau" + }, + { + "airportname": "Carpiquet", + "city": "Caen" + }, + { + "airportname": "Poulmic", + "city": "Lanvedoc" + }, + { + "airportname": "Arnage", + "city": "Le Mans" + }, + { + "airportname": "St Jacques", + "city": "Rennes" + }, + { + "airportname": "Lannion", + "city": "Lannion" + }, + { + "airportname": "Pluguffan", + "city": "Quimper" + }, + { + "airportname": "Nantes Atlantique", + "city": "Nantes" + }, + { + "airportname": "Armor", + "city": "St.-brieuc Armor" + }, + { + "airportname": "Ploujean", + "city": "Morlaix" + }, + { + "airportname": "Meucon", + "city": "Vannes" + }, + { + "airportname": "Montoir", + "city": "St.-nazaire" + }, + { + "airportname": "Bale Mulhouse", + "city": "Mulhouse" + }, + { + "airportname": "Meyenheim", + "city": "Colmar" + }, + { + "airportname": "Longvic", + "city": "Dijon" + }, + { + "airportname": "Frescaty", + "city": "Metz" + }, + { + "airportname": "Mirecourt", + "city": "Epinal" + }, + { + "airportname": "Haguenau", + "city": "Haguenau" + }, + { + "airportname": "Robinson", + "city": "St.-dizier" + }, + { + "airportname": "Courcelles", + "city": "Montbeliard" + }, + { + "airportname": "Essey", + "city": "Nancy" + }, + { + "airportname": "Ochey", + "city": "Nancy" + }, + { + "airportname": "Pontarlier", + "city": "Pontarlier" + }, + { + "airportname": "Champagne", + "city": "Reims" + }, + { + "airportname": "Entzheim", + "city": "Strasbourg" + }, + { + "airportname": "Saint Sauveur", + "city": "Luxeuil" + }, + { + "airportname": "Pierrefeu", + "city": "Cuers" + }, + { + "airportname": "Le Palyvestre", + "city": "Hyeres" + }, + { + "airportname": "Garons", + "city": "Nimes" + }, + { + "airportname": "Amberieu", + "city": "Amberieu" + }, + { + "airportname": "Damblain", + "city": "Damblain" + }, + { + "airportname": "Barter Island Lrrs", + "city": "Barter Island" + }, + { + "airportname": "Wainwright As", + "city": "Fort Wainwright" + }, + { + "airportname": "Cape Lisburne Lrrs", + "city": "Cape Lisburne" + }, + { + "airportname": "Point Lay Lrrs", + "city": "Point Lay" + }, + { + "airportname": "Hilo Intl", + "city": "Hilo" + }, + { + "airportname": "Executive", + "city": "Orlando" + }, + { + "airportname": "Bettles", + "city": "Bettles" + }, + { + "airportname": "Clear", + "city": "Clear Mews" + }, + { + "airportname": "Indian Mountain Lrrs", + "city": "Indian Mountains" + }, + { + "airportname": "Fort Yukon", + "city": "Fort Yukon" + }, + { + "airportname": "Sparrevohn Lrrs", + "city": "Sparrevohn" + }, + { + "airportname": "Bryant Ahp", + "city": "Fort Richardson" + }, + { + "airportname": "Tatalina Lrrs", + "city": "Tatalina" + }, + { + "airportname": "Cape Romanzof Lrrs", + "city": "Cape Romanzof" + }, + { + "airportname": "Laurence G Hanscom Fld", + "city": "Bedford" + }, + { + "airportname": "St Paul Island", + "city": "St. Paul Island" + }, + { + "airportname": "Cape Newenham Lrrs", + "city": "Cape Newenham" + }, + { + "airportname": "St George", + "city": "Point Barrow" + }, + { + "airportname": "Iliamna", + "city": "Iliamna" + }, + { + "airportname": "Platinum", + "city": "Port Moller" + }, + { + "airportname": "Big Mountain Afs", + "city": "Big Mountain" + }, + { + "airportname": "Oscoda Wurtsmith", + "city": "Oscoda" + }, + { + "airportname": "Marina Muni", + "city": "Fort Ord" + }, + { + "airportname": "Sacramento Mather", + "city": "Sacramento" + }, + { + "airportname": "Bicycle Lake Aaf", + "city": "Fort Irwin" + }, + { + "airportname": "Twentynine Palms Eaf", + "city": "Twenty Nine Palms" + }, + { + "airportname": "Fort Smith Rgnl", + "city": "Fort Smith" + }, + { + "airportname": "Merrill Fld", + "city": "Anchorage" + }, + { + "airportname": "Grants Milan Muni", + "city": "Grants" + }, + { + "airportname": "Ponca City Rgnl", + "city": "Ponca City" + }, + { + "airportname": "Hunter Aaf", + "city": "Hunter Aaf" + }, + { + "airportname": "Grand Forks Intl", + "city": "Grand Forks" + }, + { + "airportname": "Grider Fld", + "city": "Pine Bluff" + }, + { + "airportname": "Whiting Fld Nas North", + "city": "Milton" + }, + { + "airportname": "Hana", + "city": "Hana" + }, + { + "airportname": "Ernest A Love Fld", + "city": "Prescott" + }, + { + "airportname": "Trenton Mercer", + "city": "Trenton" + }, + { + "airportname": "General Edward Lawrence Logan Intl", + "city": "Boston" + }, + { + "airportname": "Travis Afb", + "city": "Fairfield" + }, + { + "airportname": "Griffiss Afld", + "city": "Rome" + }, + { + "airportname": "Wendover", + "city": "Wendover" + }, + { + "airportname": "Mobile Downtown", + "city": "Mobile" + }, + { + "airportname": "Metropolitan Oakland Intl", + "city": "Oakland" + }, + { + "airportname": "Eppley Afld", + "city": "Omaha" + }, + { + "airportname": "Port Angeles Cgas", + "city": "Port Angeles" + }, + { + "airportname": "Kahului", + "city": "Kahului" + }, + { + "airportname": "Wichita Mid Continent", + "city": "Wichita" + }, + { + "airportname": "Kansas City Intl", + "city": "Kansas City" + }, + { + "airportname": "Dane Co Rgnl Truax Fld", + "city": "Madison" + }, + { + "airportname": "Dillingham", + "city": "Dillingham" + }, + { + "airportname": "Boone Co", + "city": "Harrison" + }, + { + "airportname": "Phoenix Sky Harbor Intl", + "city": "Phoenix" + }, + { + "airportname": "Bangor Intl", + "city": "Bangor" + }, + { + "airportname": "Fort Lauderdale Executive", + "city": "Fort Lauderdale" + }, + { + "airportname": "East Texas Rgnl", + "city": "Longview" + }, + { + "airportname": "Anderson Rgnl", + "city": "Andersen" + }, + { + "airportname": "Spokane Intl", + "city": "Spokane" + }, + { + "airportname": "North Perry", + "city": "Hollywood" + }, + { + "airportname": "San Francisco Intl", + "city": "San Francisco" + }, + { + "airportname": "Cut Bank Muni", + "city": "Cutbank" + }, + { + "airportname": "Acadiana Rgnl", + "city": "Louisiana" + }, + { + "airportname": "Gainesville Rgnl", + "city": "Gainesville" + }, + { + "airportname": "Memphis Intl", + "city": "Memphis" + }, + { + "airportname": "Bisbee Douglas Intl", + "city": "Douglas" + }, + { + "airportname": "Allen Aaf", + "city": "Delta Junction" + }, + { + "airportname": "Tstc Waco", + "city": "Waco" + }, + { + "airportname": "Annette Island", + "city": "Annette Island" + }, + { + "airportname": "Caribou Muni", + "city": "Caribou" + }, + { + "airportname": "Little Rock Afb", + "city": "Jacksonville" + }, + { + "airportname": "Redstone Aaf", + "city": "Redstone" + }, + { + "airportname": "Pope Field", + "city": "Fort Bragg" + }, + { + "airportname": "Dalhart Muni", + "city": "Dalhart" + }, + { + "airportname": "Laughlin Afb", + "city": "Del Rio" + }, + { + "airportname": "Los Angeles Intl", + "city": "Los Angeles" + }, + { + "airportname": "Anniston Metro", + "city": "Anniston" + }, + { + "airportname": "Cleveland Hopkins Intl", + "city": "Cleveland" + }, + { + "airportname": "Dover Afb", + "city": "Dover" + }, + { + "airportname": "Cincinnati Northern Kentucky Intl", + "city": "Cincinnati" + }, + { + "airportname": "Tipton", + "city": "Fort Meade" + }, + { + "airportname": "China Lake Naws", + "city": "China" + }, + { + "airportname": "Huron Rgnl", + "city": "Huron" + }, + { + "airportname": "Juneau Intl", + "city": "Juneau" + }, + { + "airportname": "Lafayette Rgnl", + "city": "Lafayette" + }, + { + "airportname": "Newark Liberty Intl", + "city": "Newark" + }, + { + "airportname": "Boise Air Terminal", + "city": "Boise" + }, + { + "airportname": "Creech Afb", + "city": "Indian Springs" + }, + { + "airportname": "Garden City Rgnl", + "city": "Garden City" + }, + { + "airportname": "Minot Intl", + "city": "Minot" + }, + { + "airportname": "Wheeler Aaf", + "city": "Wahiawa" + }, + { + "airportname": "Maxwell Afb", + "city": "Montgomery" + }, + { + "airportname": "Robinson Aaf", + "city": "Robinson" + }, + { + "airportname": "Dallas Love Fld", + "city": "Dallas" + }, + { + "airportname": "Butts Aaf", + "city": "Fort Carson" + }, + { + "airportname": "Helena Rgnl", + "city": "Helena" + }, + { + "airportname": "Miramar Mcas", + "city": "Miramar" + }, + { + "airportname": "Luke Afb", + "city": "Phoenix" + }, + { + "airportname": "Hurlburt Fld", + "city": "Mary Esther" + }, + { + "airportname": "Jack Northrop Fld Hawthorne Muni", + "city": "Hawthorne" + }, + { + "airportname": "Houlton Intl", + "city": "Houlton" + }, + { + "airportname": "Vance Afb", + "city": "Enid" + }, + { + "airportname": "Point Mugu Nas", + "city": "Point Mugu" + }, + { + "airportname": "Edwards Afb", + "city": "Edwards Afb" + }, + { + "airportname": "Lake Charles Rgnl", + "city": "Lake Charles" + }, + { + "airportname": "Kona Intl At Keahole", + "city": "Kona" + }, + { + "airportname": "Myrtle Beach Intl", + "city": "Myrtle Beach" + }, + { + "airportname": "Lemoore Nas", + "city": "Lemoore" + }, + { + "airportname": "Nantucket Mem", + "city": "Nantucket" + }, + { + "airportname": "Felker Aaf", + "city": "Fort Eustis" + }, + { + "airportname": "Campbell Aaf", + "city": "Hopkinsville" + }, + { + "airportname": "Ronald Reagan Washington Natl", + "city": "Washington" + }, + { + "airportname": "Patuxent River Nas", + "city": "Patuxent River" + }, + { + "airportname": "Palacios Muni", + "city": "Palacios" + }, + { + "airportname": "Arkansas Intl", + "city": "Blytheville" + }, + { + "airportname": "Atlantic City Intl", + "city": "Atlantic City" + }, + { + "airportname": "Tinker Afb", + "city": "Oklahoma City" + }, + { + "airportname": "Elizabeth City Cgas Rgnl", + "city": "Elizabeth City" + }, + { + "airportname": "Pueblo Memorial", + "city": "Pueblo" + }, + { + "airportname": "Northern Maine Rgnl At Presque Isle", + "city": "Presque Isle" + }, + { + "airportname": "Kirtland Air Force Base", + "city": "Kirtland A.f.b." + }, + { + "airportname": "Gray Aaf", + "city": "Fort Lewis" + }, + { + "airportname": "Kodiak", + "city": "Kodiak" + }, + { + "airportname": "Upolu", + "city": "Opolu" + }, + { + "airportname": "Fort Lauderdale Hollywood Intl", + "city": "Fort Lauderdale" + }, + { + "airportname": "Davis Fld", + "city": "Muskogee" + }, + { + "airportname": "Falls Intl", + "city": "International Falls" + }, + { + "airportname": "Salt Lake City Intl", + "city": "Salt Lake City" + }, + { + "airportname": "Childress Muni", + "city": "Childress" + }, + { + "airportname": "Keesler Afb", + "city": "Biloxi" + }, + { + "airportname": "Lawson Aaf", + "city": "Fort Benning" + }, + { + "airportname": "Kingsville Nas", + "city": "Kingsville" + }, + { + "airportname": "Marshall Aaf", + "city": "Fort Riley" + }, + { + "airportname": "Harrisburg Intl", + "city": "Harrisburg" + }, + { + "airportname": "Lincoln", + "city": "Lincoln" + }, + { + "airportname": "Capital City", + "city": "Lansing" + }, + { + "airportname": "Waimea Kohala", + "city": "Kamuela" + }, + { + "airportname": "Massena Intl Richards Fld", + "city": "Massena" + }, + { + "airportname": "Hickory Rgnl", + "city": "Hickory" + }, + { + "airportname": "Albert Whitted", + "city": "St. Petersburg" + }, + { + "airportname": "Page Fld", + "city": "Fort Myers" + }, + { + "airportname": "George Bush Intercontinental", + "city": "Houston" + }, + { + "airportname": "Millinocket Muni", + "city": "Millinocket" + }, + { + "airportname": "Andrews Afb", + "city": "Camp Springs" + }, + { + "airportname": "Smith Reynolds", + "city": "Winston-salem" + }, + { + "airportname": "Southern California Logistics", + "city": "Victorville" + }, + { + "airportname": "Bob Sikes", + "city": "Crestview" + }, + { + "airportname": "Wheeler Sack Aaf", + "city": "Fort Drum" + }, + { + "airportname": "St Clair Co Intl", + "city": "Port Huron" + }, + { + "airportname": "Meadows Fld", + "city": "Bakersfield" + }, + { + "airportname": "El Paso Intl", + "city": "El Paso" + }, + { + "airportname": "Valley Intl", + "city": "Harlingen" + }, + { + "airportname": "Columbia Metropolitan", + "city": "Columbia" + }, + { + "airportname": "Davis Monthan Afb", + "city": "Tucson" + }, + { + "airportname": "Pensacola Nas", + "city": "Pensacola" + }, + { + "airportname": "Pensacola Rgnl", + "city": "Pensacola" + }, + { + "airportname": "Grand Forks Afb", + "city": "Red River" + }, + { + "airportname": "William P Hobby", + "city": "Houston" + }, + { + "airportname": "Buckley Afb", + "city": "Buckley" + }, + { + "airportname": "Northway", + "city": "Northway" + }, + { + "airportname": "Palmer Muni", + "city": "Palmer" + }, + { + "airportname": "Pittsburgh Intl", + "city": "Pittsburgh" + }, + { + "airportname": "Wiley Post Will Rogers Mem", + "city": "Barrow" + }, + { + "airportname": "Ellington Fld", + "city": "Houston" + }, + { + "airportname": "Whidbey Island Nas", + "city": "Whidbey Island" + }, + { + "airportname": "Alice Intl", + "city": "Alice" + }, + { + "airportname": "Moody Afb", + "city": "Valdosta" + }, + { + "airportname": "Miami Intl", + "city": "Miami" + }, + { + "airportname": "Seattle Tacoma Intl", + "city": "Seattle" + }, + { + "airportname": "Lovell Fld", + "city": "Chattanooga" + }, + { + "airportname": "Igor I Sikorsky Mem", + "city": "Stratford" + }, + { + "airportname": "Jackson Evers Intl", + "city": "Jackson" + }, + { + "airportname": "Scholes Intl At Galveston", + "city": "Galveston" + }, + { + "airportname": "Long Beach", + "city": "Long Beach" + }, + { + "airportname": "Dillingham", + "city": "Dillingham" + }, + { + "airportname": "Williamsport Rgnl", + "city": "Williamsport" + }, + { + "airportname": "Indianapolis Intl", + "city": "Indianapolis" + }, + { + "airportname": "Whiteman Afb", + "city": "Knobnoster" + }, + { + "airportname": "Akron Fulton Intl", + "city": "Akron" + }, + { + "airportname": "Greenwood Leflore", + "city": "Greenwood" + }, + { + "airportname": "Westchester Co", + "city": "White Plains" + }, + { + "airportname": "Francis S Gabreski", + "city": "West Hampton Beach" + }, + { + "airportname": "Jonesboro Muni", + "city": "Jonesboro" + }, + { + "airportname": "Tonopah Test Range", + "city": "Tonopah" + }, + { + "airportname": "Palm Beach Co Park", + "city": "West Palm Beach" + }, + { + "airportname": "North Island Nas", + "city": "San Diego" + }, + { + "airportname": "Biggs Aaf", + "city": "El Paso" + }, + { + "airportname": "Yuma Mcas Yuma Intl", + "city": "Yuma" + }, + { + "airportname": "Cavern City Air Terminal", + "city": "Carlsbad" + }, + { + "airportname": "Duluth Intl", + "city": "Duluth" + }, + { + "airportname": "Bethel", + "city": "Bethel" + }, + { + "airportname": "Bowman Fld", + "city": "Louisville" + }, + { + "airportname": "Sierra Vista Muni Libby Aaf", + "city": "Fort Huachuca" + }, + { + "airportname": "Lihue", + "city": "Lihue" + }, + { + "airportname": "Terre Haute Intl Hulman Fld", + "city": "Terre Haute" + }, + { + "airportname": "Havre City Co", + "city": "Havre" + }, + { + "airportname": "Grant Co Intl", + "city": "Grant County Airport" + }, + { + "airportname": "Edward F Knapp State", + "city": "Montpelier" + }, + { + "airportname": "San Nicolas Island Nolf", + "city": "San Nicolas Island" + }, + { + "airportname": "Richmond Intl", + "city": "Richmond" + }, + { + "airportname": "Shreveport Rgnl", + "city": "Shreveport" + }, + { + "airportname": "Merle K Mudhole Smith", + "city": "Cordova" + }, + { + "airportname": "Norfolk Intl", + "city": "Norfolk" + }, + { + "airportname": "Southeast Texas Rgnl", + "city": "Beaumont" + }, + { + "airportname": "Savannah Hilton Head Intl", + "city": "Savannah" + }, + { + "airportname": "Hill Afb", + "city": "Ogden" + }, + { + "airportname": "Nome", + "city": "Nome" + }, + { + "airportname": "Scappoose Industrial Airpark", + "city": "San Luis" + }, + { + "airportname": "St Petersburg Clearwater Intl", + "city": "St. Petersburg" + }, + { + "airportname": "Menominee Marinette Twin Co", + "city": "Macon" + }, + { + "airportname": "Lone Star Executive", + "city": "Conroe" + }, + { + "airportname": "Deadhorse", + "city": "Deadhorse" + }, + { + "airportname": "San Antonio Intl", + "city": "San Antonio" + }, + { + "airportname": "Greater Rochester Intl", + "city": "Rochester" + }, + { + "airportname": "Patrick Afb", + "city": "Coco Beach" + }, + { + "airportname": "Teterboro", + "city": "Teterboro" + }, + { + "airportname": "Ellsworth Afb", + "city": "Rapid City" + }, + { + "airportname": "Raleigh Durham Intl", + "city": "Raleigh-durham" + }, + { + "airportname": "James M Cox Dayton Intl", + "city": "Dayton" + }, + { + "airportname": "Kenai Muni", + "city": "Kenai" + }, + { + "airportname": "Mc Alester Rgnl", + "city": "Mcalester" + }, + { + "airportname": "Niagara Falls Intl", + "city": "Niagara Falls" + }, + { + "airportname": "Coulter Fld", + "city": "Bryan" + }, + { + "airportname": "Wright Aaf", + "city": "Wright" + }, + { + "airportname": "Newport News Williamsburg Intl", + "city": "Newport News" + }, + { + "airportname": "Esler Rgnl", + "city": "Alexandria" + }, + { + "airportname": "Altus Afb", + "city": "Altus" + }, + { + "airportname": "Tucson Intl", + "city": "Tucson" + }, + { + "airportname": "Minot Afb", + "city": "Minot" + }, + { + "airportname": "Beale Afb", + "city": "Marysville" + }, + { + "airportname": "Greater Kankakee", + "city": "Kankakee" + }, + { + "airportname": "Seymour Johnson Afb", + "city": "Goldsboro" + }, + { + "airportname": "Theodore Francis Green State", + "city": "Providence" + }, + { + "airportname": "Salisbury Ocean City Wicomico Rgnl", + "city": "Salisbury" + }, + { + "airportname": "Rancho Murieta", + "city": "Rancho Murieta" + }, + { + "airportname": "Bob Hope", + "city": "Burbank" + }, + { + "airportname": "Detroit Metro Wayne Co", + "city": "Detroit" + }, + { + "airportname": "Tampa Intl", + "city": "Tampa" + }, + { + "airportname": "Pembina Muni", + "city": "Pembina" + }, + { + "airportname": "Polk Aaf", + "city": "Fort Polk" + }, + { + "airportname": "Eielson Afb", + "city": "Fairbanks" + }, + { + "airportname": "Chisholm Hibbing", + "city": "Hibbing" + }, + { + "airportname": "Angelina Co", + "city": "Lufkin" + }, + { + "airportname": "Midland Intl", + "city": "Midland" + }, + { + "airportname": "Austin Straubel Intl", + "city": "Green Bay" + }, + { + "airportname": "Ardmore Muni", + "city": "Ardmore" + }, + { + "airportname": "Mc Guire Afb", + "city": "Wrightstown" + }, + { + "airportname": "Cherry Point Mcas", + "city": "Cherry Point" + }, + { + "airportname": "Emanuel Co", + "city": "Santa Barbara" + }, + { + "airportname": "Augusta Rgnl At Bush Fld", + "city": "Bush Field" + }, + { + "airportname": "Sloulin Fld Intl", + "city": "Williston" + }, + { + "airportname": "Adams Fld", + "city": "Little Rock" + }, + { + "airportname": "Stewart Intl", + "city": "Newburgh" + }, + { + "airportname": "Baudette Intl", + "city": "Baudette" + }, + { + "airportname": "Sacramento Executive", + "city": "Sacramento" + }, + { + "airportname": "Homer", + "city": "Homer" + }, + { + "airportname": "Waynesville Rgnl Arpt At Forney Fld", + "city": "Fort Leonardwood" + }, + { + "airportname": "Dobbins Arb", + "city": "Marietta" + }, + { + "airportname": "Fairchild Afb", + "city": "Spokane" + }, + { + "airportname": "Roscommon Co", + "city": "Houghton Lake" + }, + { + "airportname": "Tyndall Afb", + "city": "Panama City" + }, + { + "airportname": "Dallas Fort Worth Intl", + "city": "Dallas-Fort Worth" + }, + { + "airportname": "Melbourne Intl", + "city": "Melbourne" + }, + { + "airportname": "Mc Chord Afb", + "city": "Tacoma" + }, + { + "airportname": "Austin Bergstrom Intl", + "city": "Austin" + }, + { + "airportname": "Rickenbacker Intl", + "city": "Columbus" + }, + { + "airportname": "Sawyer Intl", + "city": "Gwinn" + }, + { + "airportname": "Mc Ghee Tyson", + "city": "Knoxville" + }, + { + "airportname": "Hood Aaf", + "city": "Fort Hood" + }, + { + "airportname": "Lambert St Louis Intl", + "city": "St. Louis" + }, + { + "airportname": "Millville Muni", + "city": "Millville" + }, + { + "airportname": "Sheppard Afb Wichita Falls Muni", + "city": "Wichita Falls" + }, + { + "airportname": "Cincinnati Muni Lunken Fld", + "city": "Cincinnati" + }, + { + "airportname": "Hartsfield Jackson Atlanta Intl", + "city": "Atlanta" + }, + { + "airportname": "Castle", + "city": "Merced" + }, + { + "airportname": "Mc Clellan Afld", + "city": "Sacramento" + }, + { + "airportname": "Gerald R Ford Intl", + "city": "Grand Rapids" + }, + { + "airportname": "Winkler Co", + "city": "Wink" + }, + { + "airportname": "Fresno Yosemite Intl", + "city": "Fresno" + }, + { + "airportname": "Vero Beach Muni", + "city": "Vero Beach" + }, + { + "airportname": "Imperial Co", + "city": "Imperial" + }, + { + "airportname": "Nashville Intl", + "city": "Nashville" + }, + { + "airportname": "Laredo Intl", + "city": "Laredo" + }, + { + "airportname": "Elmendorf Afb", + "city": "Anchorage" + }, + { + "airportname": "Ralph Wien Mem", + "city": "Kotzebue" + }, + { + "airportname": "Altoona Blair Co", + "city": "Altoona" + }, + { + "airportname": "Dyess Afb", + "city": "Abilene" + }, + { + "airportname": "South Arkansas Rgnl At Goodwin Fld", + "city": "El Dorado" + }, + { + "airportname": "La Guardia", + "city": "New York" + }, + { + "airportname": "Tallahassee Rgnl", + "city": "Tallahassee" + }, + { + "airportname": "Dupage", + "city": "West Chicago" + }, + { + "airportname": "Waco Rgnl", + "city": "Waco" + }, + { + "airportname": "Augusta State", + "city": "Augusta" + }, + { + "airportname": "Hillsboro Muni", + "city": "Hillsboro" + }, + { + "airportname": "Jacksonville Nas", + "city": "Jacksonville" + }, + { + "airportname": "Mc Kellar Sipes Rgnl", + "city": "Jackson" + }, + { + "airportname": "Molokai", + "city": "Molokai" + }, + { + "airportname": "Godman Aaf", + "city": "Fort Knox" + }, + { + "airportname": "New River Mcas", + "city": "Jacksonville" + }, + { + "airportname": "San Angelo Rgnl Mathis Fld", + "city": "San Angelo" + }, + { + "airportname": "Calexico Intl", + "city": "Calexico" + }, + { + "airportname": "Chico Muni", + "city": "Chico" + }, + { + "airportname": "Burlington Intl", + "city": "Burlington" + }, + { + "airportname": "Jacksonville Intl", + "city": "Jacksonville" + }, + { + "airportname": "Durango La Plata Co", + "city": "Durango" + }, + { + "airportname": "Washington Dulles Intl", + "city": "Washington" + }, + { + "airportname": "Easterwood Fld", + "city": "College Station" + }, + { + "airportname": "Felts Fld", + "city": "Spokane" + }, + { + "airportname": "General Mitchell Intl", + "city": "Milwaukee" + }, + { + "airportname": "Abilene Rgnl", + "city": "Abilene" + }, + { + "airportname": "Columbia Rgnl", + "city": "Columbia" + }, + { + "airportname": "Portland Intl", + "city": "Portland" + }, + { + "airportname": "Dade Collier Training And Transition", + "city": "Miami" + }, + { + "airportname": "Palm Beach Intl", + "city": "West Palm Beach" + }, + { + "airportname": "Fort Worth Meacham Intl", + "city": "Fort Worth" + }, + { + "airportname": "Ogdensburg Intl", + "city": "Ogdensburg" + }, + { + "airportname": "Otis Angb", + "city": "Falmouth" + }, + { + "airportname": "Boeing Fld King Co Intl", + "city": "Seattle" + }, + { + "airportname": "Lackland Afb Kelly Fld Annex", + "city": "San Antonio" + }, + { + "airportname": "Honolulu Intl", + "city": "Honolulu" + }, + { + "airportname": "Des Moines Intl", + "city": "Des Moines" + }, + { + "airportname": "Craven Co Rgnl", + "city": "New Bern" + }, + { + "airportname": "San Diego Intl", + "city": "San Diego" + }, + { + "airportname": "Monroe Rgnl", + "city": "Monroe" + }, + { + "airportname": "Shaw Afb", + "city": "Sumter" + }, + { + "airportname": "Ontario Intl", + "city": "Ontario" + }, + { + "airportname": "Majors", + "city": "Greenvile" + }, + { + "airportname": "Roswell Intl Air Center", + "city": "Roswell" + }, + { + "airportname": "Coleman A Young Muni", + "city": "Detroit" + }, + { + "airportname": "Brownsville South Padre Island Intl", + "city": "Brownsville" + }, + { + "airportname": "Dothan Rgnl", + "city": "Dothan" + }, + { + "airportname": "Cape May Co", + "city": "Wildwood" + }, + { + "airportname": "Fallon Nas", + "city": "Fallon" + }, + { + "airportname": "Selfridge Angb", + "city": "Mount Clemens" + }, + { + "airportname": "Four Corners Rgnl", + "city": "Farmington" + }, + { + "airportname": "Corpus Christi Intl", + "city": "Corpus Christi" + }, + { + "airportname": "Syracuse Hancock Intl", + "city": "Syracuse" + }, + { + "airportname": "Key West Nas", + "city": "Key West" + }, + { + "airportname": "Chicago Midway Intl", + "city": "Chicago" + }, + { + "airportname": "Norman Y Mineta San Jose Intl", + "city": "San Jose" + }, + { + "airportname": "Lea Co Rgnl", + "city": "Hobbs" + }, + { + "airportname": "Northeast Philadelphia", + "city": "Philadelphia" + }, + { + "airportname": "Denver Intl", + "city": "Denver" + }, + { + "airportname": "Philadelphia Intl", + "city": "Philadelphia" + }, + { + "airportname": "Sioux Gateway Col Bud Day Fld", + "city": "Sioux City" + }, + { + "airportname": "Middle Georgia Rgnl", + "city": "Macon" + }, + { + "airportname": "Truth Or Consequences Muni", + "city": "Truth Or Consequences" + }, + { + "airportname": "Palmdale Rgnl Usaf Plt 42", + "city": "Palmdale" + }, + { + "airportname": "Randolph Afb", + "city": "San Antonio" + }, + { + "airportname": "El Centro Naf", + "city": "El Centro" + }, + { + "airportname": "Port Columbus Intl", + "city": "Columbus" + }, + { + "airportname": "Drake Fld", + "city": "Fayetteville" + }, + { + "airportname": "Henry Post Aaf", + "city": "Fort Sill" + }, + { + "airportname": "Princeton Muni", + "city": "Princeton" + }, + { + "airportname": "Wright Patterson Afb", + "city": "Dayton" + }, + { + "airportname": "Edward G Pitka Sr", + "city": "Galena" + }, + { + "airportname": "Chandler Muni", + "city": "Chandler" + }, + { + "airportname": "Mineral Wells", + "city": "Mineral Wells" + }, + { + "airportname": "Mc Connell Afb", + "city": "Wichita" + }, + { + "airportname": "New Orleans Nas Jrb", + "city": "New Orleans" + }, + { + "airportname": "Beaufort", + "city": "Beaufort" + }, + { + "airportname": "Texarkana Rgnl Webb Fld", + "city": "Texarkana" + }, + { + "airportname": "Plattsburgh Intl", + "city": "Plattsburgh" + }, + { + "airportname": "Phillips Aaf", + "city": "Aberdeen" + }, + { + "airportname": "Tucumcari Muni", + "city": "Tucumcari" + }, + { + "airportname": "Ted Stevens Anchorage Intl", + "city": "Anchorage" + }, + { + "airportname": "Robert Gray Aaf", + "city": "Killeen" + }, + { + "airportname": "Black Rock", + "city": "Zuni Pueblo" + }, + { + "airportname": "Bellingham Intl", + "city": "Bellingham" + }, + { + "airportname": "Millington Rgnl Jetport", + "city": "Millington" + }, + { + "airportname": "Elkins Randolph Co Jennings Randolph", + "city": "Elkins" + }, + { + "airportname": "Hartford Brainard", + "city": "Hartford" + }, + { + "airportname": "North Central State", + "city": "Smithfield" + }, + { + "airportname": "Mobile Rgnl", + "city": "Mobile" + }, + { + "airportname": "Moffett Federal Afld", + "city": "Mountain View" + }, + { + "airportname": "Santa Fe Muni", + "city": "Santa Fe" + }, + { + "airportname": "Barking Sands Pmrf", + "city": "Barking Sands" + }, + { + "airportname": "Beauregard Rgnl", + "city": "Deridder" + }, + { + "airportname": "Bradshaw Aaf", + "city": "Bradshaw Field" + }, + { + "airportname": "Nogales Intl", + "city": "Nogales" + }, + { + "airportname": "Macdill Afb", + "city": "Tampa" + }, + { + "airportname": "Scott Afb Midamerica", + "city": "Belleville" + }, + { + "airportname": "Opa Locka", + "city": "Miami" + }, + { + "airportname": "Del Rio Intl", + "city": "Del Rio" + }, + { + "airportname": "Southwest Florida Intl", + "city": "Fort Myers" + }, + { + "airportname": "King Salmon", + "city": "King Salmon" + }, + { + "airportname": "Muir Aaf", + "city": "Muir" + }, + { + "airportname": "Kapalua", + "city": "Lahania-kapalua" + }, + { + "airportname": "John F Kennedy Intl", + "city": "New York" + }, + { + "airportname": "Homestead Arb", + "city": "Homestead" + }, + { + "airportname": "Riverside Muni", + "city": "Riverside" + }, + { + "airportname": "Sherman Aaf", + "city": "Fort Leavenworth" + }, + { + "airportname": "Wallops Flight Facility", + "city": "Wallops Island" + }, + { + "airportname": "Holloman Afb", + "city": "Alamogordo" + }, + { + "airportname": "Willow Grove Nas Jrb", + "city": "Willow Grove" + }, + { + "airportname": "Cheyenne Rgnl Jerry Olson Fld", + "city": "Cheyenne" + }, + { + "airportname": "Stockton Metropolitan", + "city": "Stockton" + }, + { + "airportname": "Charleston Afb Intl", + "city": "Charleston" + }, + { + "airportname": "Reno Tahoe Intl", + "city": "Reno" + }, + { + "airportname": "Ketchikan Intl", + "city": "Ketchikan" + }, + { + "airportname": "Willow Run", + "city": "Detroit" + }, + { + "airportname": "Vandenberg Afb", + "city": "Lompoc" + }, + { + "airportname": "Birmingham Intl", + "city": "Birmingham" + }, + { + "airportname": "Lakehurst Naes", + "city": "Lakehurst" + }, + { + "airportname": "Eareckson As", + "city": "Shemya" + }, + { + "airportname": "Nellis Afb", + "city": "Las Vegas" + }, + { + "airportname": "March Arb", + "city": "Riverside" + }, + { + "airportname": "Modesto City Co Harry Sham", + "city": "Modesto" + }, + { + "airportname": "Sacramento Intl", + "city": "Sacramento" + }, + { + "airportname": "Waukegan Rgnl", + "city": "Chicago" + }, + { + "airportname": "City Of Colorado Springs Muni", + "city": "Colorado Springs" + }, + { + "airportname": "Buffalo Niagara Intl", + "city": "Buffalo" + }, + { + "airportname": "Griffing Sandusky", + "city": "Sandusky" + }, + { + "airportname": "Snohomish Co", + "city": "Everett" + }, + { + "airportname": "Mountain Home Afb", + "city": "Mountain Home" + }, + { + "airportname": "Cedar City Rgnl", + "city": "Cedar City" + }, + { + "airportname": "Bradley Intl", + "city": "Windsor Locks" + }, + { + "airportname": "Mc Allen Miller Intl", + "city": "Mcallen" + }, + { + "airportname": "Norfolk Ns", + "city": "Norfolk" + }, + { + "airportname": "Westover Arb Metropolitan", + "city": "Chicopee Falls" + }, + { + "airportname": "Lubbock Preston Smith Intl", + "city": "Lubbock" + }, + { + "airportname": "Chicago Ohare Intl", + "city": "Chicago" + }, + { + "airportname": "Boca Raton", + "city": "Boca Raton" + }, + { + "airportname": "Fairbanks Intl", + "city": "Fairbanks" + }, + { + "airportname": "Quantico Mcaf", + "city": "Quantico" + }, + { + "airportname": "Cannon Afb", + "city": "Clovis" + }, + { + "airportname": "Kaneohe Bay Mcaf", + "city": "Kaneohe Bay" + }, + { + "airportname": "Offutt Afb", + "city": "Omaha" + }, + { + "airportname": "Gulkana", + "city": "Gulkana" + }, + { + "airportname": "Watertown Intl", + "city": "Watertown" + }, + { + "airportname": "Palm Springs Intl", + "city": "Palm Springs" + }, + { + "airportname": "Rick Husband Amarillo Intl", + "city": "Amarillo" + }, + { + "airportname": "Fort Dodge Rgnl", + "city": "Fort Dodge" + }, + { + "airportname": "Barksdale Afb", + "city": "Shreveport" + }, + { + "airportname": "Forbes Fld", + "city": "Topeka" + }, + { + "airportname": "Cotulla Lasalle Co", + "city": "Cotulla" + }, + { + "airportname": "Wilmington Intl", + "city": "Wilmington" + }, + { + "airportname": "Baton Rouge Metro Ryan Fld", + "city": "Baton Rouge" + }, + { + "airportname": "Meridian Nas", + "city": "Meridian" + }, + { + "airportname": "Tyler Pounds Rgnl", + "city": "Tyler" + }, + { + "airportname": "Baltimore Washington Intl", + "city": "Baltimore" + }, + { + "airportname": "Hobart Muni", + "city": "Hobart" + }, + { + "airportname": "Lanai", + "city": "Lanai" + }, + { + "airportname": "Alexandria Intl-US", + "city": "Alexandria" + }, + { + "airportname": "Condron Aaf", + "city": "White Sands" + }, + { + "airportname": "Cold Bay", + "city": "Cold Bay" + }, + { + "airportname": "Tulsa Intl", + "city": "Tulsa" + }, + { + "airportname": "Sitka Rocky Gutierrez", + "city": "Sitka" + }, + { + "airportname": "Long Island Mac Arthur", + "city": "Islip" + }, + { + "airportname": "Minneapolis St Paul Intl", + "city": "Minneapolis" + }, + { + "airportname": "New Castle", + "city": "Wilmington" + }, + { + "airportname": "Unalaska", + "city": "Unalaska" + }, + { + "airportname": "Louis Armstrong New Orleans Intl", + "city": "New Orleans" + }, + { + "airportname": "Portland Intl Jetport", + "city": "Portland" + }, + { + "airportname": "Will Rogers World", + "city": "Oklahoma City" + }, + { + "airportname": "Albany Intl", + "city": "Albany" + }, + { + "airportname": "Valdez Pioneer Fld", + "city": "Valdez" + }, + { + "airportname": "Langley Afb", + "city": "Hampton" + }, + { + "airportname": "John Wayne Arpt Orange Co", + "city": "Santa Ana" + }, + { + "airportname": "Columbus Afb", + "city": "Colombus" + }, + { + "airportname": "Kendall Tamiami Executive", + "city": "Kendall-tamiami" + }, + { + "airportname": "Oceana Nas", + "city": "Oceana" + }, + { + "airportname": "Grissom Arb", + "city": "Peru" + }, + { + "airportname": "Natrona Co Intl", + "city": "Casper" + }, + { + "airportname": "Eglin Afb", + "city": "Valparaiso" + }, + { + "airportname": "Craig Fld", + "city": "Selma" + }, + { + "airportname": "Key West Intl", + "city": "Key West" + }, + { + "airportname": "Charlotte Douglas Intl", + "city": "Charlotte" + }, + { + "airportname": "Mc Carran Intl", + "city": "Las Vegas" + }, + { + "airportname": "Orlando Intl", + "city": "Orlando" + }, + { + "airportname": "Florence Rgnl", + "city": "Florence" + }, + { + "airportname": "Great Falls Intl", + "city": "Great Falls" + }, + { + "airportname": "Youngstown Warren Rgnl", + "city": "Youngstown" + }, + { + "airportname": "Ladd Aaf", + "city": "Fort Wainwright" + }, + { + "airportname": "Mc Minnville Muni", + "city": "Mackminnville" + }, + { + "airportname": "Robins Afb", + "city": "Macon" + }, + { + "airportname": "Pullman-Moscow Rgnl", + "city": "Pullman" + }, + { + "airportname": "Lewiston Nez Perce Co", + "city": "Lewiston" + }, + { + "airportname": "Elmira Corning Rgnl", + "city": "Elmira" + }, + { + "airportname": "Ithaca Tompkins Rgnl", + "city": "Ithaca" + }, + { + "airportname": "Monterey Peninsula", + "city": "Monterey" + }, + { + "airportname": "Santa Barbara Muni", + "city": "Santa Barbara" + }, + { + "airportname": "Daytona Beach Intl", + "city": "Daytona Beach" + }, + { + "airportname": "Wall Street Heliport", + "city": "New York" + }, + { + "airportname": "Talkeetna", + "city": "Talkeetna" + }, + { + "airportname": "Tweed-New Haven Airport", + "city": "New Haven" + }, + { + "airportname": "Asheville Regional Airport", + "city": "Asheville" + }, + { + "airportname": "Piedmont Triad", + "city": "Greensboro" + }, + { + "airportname": "Sioux Falls", + "city": "Sioux Falls" + }, + { + "airportname": "Manchester Regional Airport", + "city": "Manchester NH" + }, + { + "airportname": "Naples Muni", + "city": "Naples" + }, + { + "airportname": "Louisville International Airport", + "city": "Louisville" + }, + { + "airportname": "Charlottesville-Albemarle", + "city": "Charlottesville VA" + }, + { + "airportname": "Roanoke Regional", + "city": "Roanoke VA" + }, + { + "airportname": "Blue Grass", + "city": "Lexington KY" + }, + { + "airportname": "Evansville Regional", + "city": "Evansville" + }, + { + "airportname": "Albuquerque International Sunport", + "city": "Albuquerque" + }, + { + "airportname": "Gallatin Field", + "city": "Bozeman" + }, + { + "airportname": "Billings Logan International Airport", + "city": "Billings" + }, + { + "airportname": "Bert Mooney Airport", + "city": "Butte" + }, + { + "airportname": "Cherry Capital Airport", + "city": "Traverse City" + }, + { + "airportname": "Hancock County - Bar Harbor", + "city": "Bar Harbor" + }, + { + "airportname": "Knox County Regional Airport", + "city": "Rockland" + }, + { + "airportname": "Jackson Hole Airport", + "city": "Jacksn Hole" + }, + { + "airportname": "Chicago Rockford International Airport ", + "city": "Rockford" + }, + { + "airportname": "East 34th Street Heliport", + "city": "New York" + }, + { + "airportname": "Greenville-Spartanburg International", + "city": "Greenville" + }, + { + "airportname": "Central Illinois Rgnl", + "city": "Bloomington" + }, + { + "airportname": "Gulfport-Biloxi", + "city": "Gulfport" + }, + { + "airportname": "Kalamazoo", + "city": "Kalamazoo" + }, + { + "airportname": "Toledo", + "city": "Toledo" + }, + { + "airportname": "Fort Wayne", + "city": "Fort Wayne" + }, + { + "airportname": "Decatur", + "city": "Decatur" + }, + { + "airportname": "Cedar Rapids", + "city": "Cedar Rapids" + }, + { + "airportname": "La Crosse Municipal", + "city": "La Crosse" + }, + { + "airportname": "Central Wisconsin", + "city": "Wassau" + }, + { + "airportname": "Peoria Regional", + "city": "Peoria" + }, + { + "airportname": "Appleton", + "city": "Appleton" + }, + { + "airportname": "Rochester", + "city": "Rochester" + }, + { + "airportname": "Champaign", + "city": "Champaign" + }, + { + "airportname": "Manhattan Reigonal", + "city": "Manhattan" + }, + { + "airportname": "Franklin", + "city": "Franklin" + }, + { + "airportname": "Grand Junction Regional", + "city": "Grand Junction" + }, + { + "airportname": "St George Muni", + "city": "Saint George" + }, + { + "airportname": "David Wayne Hooks Field", + "city": "Houston" + }, + { + "airportname": "Port O\\'Connor Airfield", + "city": "Port O\\'Connor" + }, + { + "airportname": "Sarasota Bradenton Intl", + "city": "Sarasota" + }, + { + "airportname": "Arthur Dunn Airpark", + "city": "Titusville" + }, + { + "airportname": "Van Nuys", + "city": "Van Nuys" + }, + { + "airportname": "Quad City Intl", + "city": "Moline" + }, + { + "airportname": "Panama City Bay Co Intl", + "city": "Panama City" + }, + { + "airportname": "Orlando", + "city": "Orlando" + }, + { + "airportname": "Bismarck Municipal Airport", + "city": "Bismarck" + }, + { + "airportname": "Telluride", + "city": "Telluride" + }, + { + "airportname": "Rapid City Regional Airport", + "city": "Rapid City" + }, + { + "airportname": "McClellan-Palomar Airport", + "city": "Carlsbad" + }, + { + "airportname": "Bishop International", + "city": "Flint" + }, + { + "airportname": "Redding Muni", + "city": "Redding" + }, + { + "airportname": "Mahlon Sweet Fld", + "city": "Eugene" + }, + { + "airportname": "Idaho Falls Rgnl", + "city": "Idaho Falls" + }, + { + "airportname": "Rogue Valley Intl Medford", + "city": "Medford" + }, + { + "airportname": "Roberts Fld", + "city": "Redmond-Bend" + }, + { + "airportname": "Akron Canton Regional Airport", + "city": "Akron" + }, + { + "airportname": "Huntsville International Airport-Carl T Jones Field", + "city": "Huntsville" + }, + { + "airportname": "Mid-Ohio Valley Regional Airport", + "city": "PARKERSBURG" + }, + { + "airportname": "Montgomery Regional Airport ", + "city": "MONTGOMERY" + }, + { + "airportname": "Tri-Cities Regional Airport", + "city": "BRISTOL" + }, + { + "airportname": "Barkley Regional Airport", + "city": "PADUCAH" + }, + { + "airportname": "Page Municipal Airport", + "city": "Page" + }, + { + "airportname": "Glacier Park Intl", + "city": "Kalispell" + }, + { + "airportname": "Mbs Intl", + "city": "Saginaw" + }, + { + "airportname": "Greater Binghamton Edwin A Link Fld", + "city": "Binghamton" + }, + { + "airportname": "Blythe Airport", + "city": "Blythe" + }, + { + "airportname": "Petersburg James A. Johnson", + "city": "Petersburg" + }, + { + "airportname": "Orlando Sanford Intl", + "city": "Sanford" + }, + { + "airportname": "John Murtha Johnstown-Cambria County Airport", + "city": "Johnstown" + }, + { + "airportname": "Missoula Intl", + "city": "Missoula" + }, + { + "airportname": "Grand Canyon National Park Airport", + "city": "Grand Canyon" + }, + { + "airportname": "Sugar Land Regional Airport", + "city": "Sugar Land" + }, + { + "airportname": "Centennial", + "city": "Denver" + }, + { + "airportname": "Clovis Muni", + "city": "Clovis" + }, + { + "airportname": "Fort Stockton Pecos Co", + "city": "Fort Stockton" + }, + { + "airportname": "Las Vegas Muni", + "city": "Las Vegas" + }, + { + "airportname": "West Houston", + "city": "Houston" + }, + { + "airportname": "La Junta Muni", + "city": "La Junta" + }, + { + "airportname": "Las Cruces Intl", + "city": "Las Cruces" + }, + { + "airportname": "Stephens Co", + "city": "Breckenridge" + }, + { + "airportname": "Draughon Miller Central Texas Rgnl", + "city": "Temple" + }, + { + "airportname": "Ozona Muni", + "city": "Ozona" + }, + { + "airportname": "Eagle Co Rgnl", + "city": "Vail" + }, + { + "airportname": "Cuyahoga County", + "city": "Richmond Heights" + }, + { + "airportname": "Mansfield Lahm Regional", + "city": "Mansfield" + }, + { + "airportname": "Columbus Metropolitan Airport", + "city": "Columbus" + }, + { + "airportname": "Lawton-Fort Sill Regional Airport", + "city": "Lawton" + }, + { + "airportname": "Fort Collins Loveland Muni", + "city": "Fort Collins" + }, + { + "airportname": "Flagstaff Pulliam Airport", + "city": "Flagstaff" + }, + { + "airportname": "Lake Tahoe Airport", + "city": "South Lake Tahoe" + }, + { + "airportname": "Magic Valley Regional Airport", + "city": "Twin Falls" + }, + { + "airportname": "Martha\\'s Vineyard", + "city": "Vineyard Haven MA" + }, + { + "airportname": "Newport State", + "city": "Newport RI" + }, + { + "airportname": "Hartness State", + "city": "Springfield VT" + }, + { + "airportname": "Concord Municipal", + "city": "Concord NH" + }, + { + "airportname": "Sanford Regional", + "city": "Sanford ME" + }, + { + "airportname": "Groton New London", + "city": "Groton CT" + }, + { + "airportname": "Saint Cloud Regional Airport", + "city": "Saint Cloud" + }, + { + "airportname": "Golden Triangle Regional Airport", + "city": "Columbus Mississippi" + }, + { + "airportname": "Bowerman Field", + "city": "Hoquiam" + }, + { + "airportname": "Erie Intl Tom Ridge Fld", + "city": "Erie" + }, + { + "airportname": "Barnstable Muni Boardman Polando Fld", + "city": "Barnstable" + }, + { + "airportname": "Sedona", + "city": "Sedona" + }, + { + "airportname": "Morgantown Muni Walter L Bill Hart Fld", + "city": "Morgantown" + }, + { + "airportname": "Yeager", + "city": "Charleston" + }, + { + "airportname": "Wilkes Barre Scranton Intl", + "city": "Scranton" + }, + { + "airportname": "Bemidji Regional Airport", + "city": "Bemidji" + }, + { + "airportname": "Hector International Airport", + "city": "Fargo" + }, + { + "airportname": "Downtown", + "city": "Kansas City" + }, + { + "airportname": "Gillette-Campbell County Airport", + "city": "Gillette" + }, + { + "airportname": "El Toro", + "city": "Santa Ana" + }, + { + "airportname": "University Park Airport", + "city": "State College Pennsylvania" + }, + { + "airportname": "Key Field", + "city": "Meridian" + }, + { + "airportname": "Abraham Lincoln Capital", + "city": "Springfield" + }, + { + "airportname": "Cortez Muni", + "city": "Cortez" + }, + { + "airportname": "Yampa Valley", + "city": "Hayden" + }, + { + "airportname": "Gallup Muni", + "city": "Gallup" + }, + { + "airportname": "Liberal Muni", + "city": "Liberal" + }, + { + "airportname": "Lamar Muni", + "city": "Lamar" + }, + { + "airportname": "Renner Fld", + "city": "Goodland" + }, + { + "airportname": "Yellowstone Rgnl", + "city": "Cody" + }, + { + "airportname": "RNAS WATTON", + "city": "WATTON" + }, + { + "airportname": "ISLES OF SCILLY", + "city": "ST MARY\\'S" + }, + { + "airportname": "Springfield Branson Natl", + "city": "Springfield" + }, + { + "airportname": "Joplin Rgnl", + "city": "Joplin" + }, + { + "airportname": "Lehigh Valley Intl", + "city": "Allentown" + }, + { + "airportname": "NW Arkansas Regional", + "city": "Bentonville" + }, + { + "airportname": "South Bend Rgnl", + "city": "South Bend" + }, + { + "airportname": "Smith Fld", + "city": "Fort Wayne IN" + }, + { + "airportname": "Arcata", + "city": "Arcata CA" + }, + { + "airportname": "Camp Mabry Austin City", + "city": "Austin TX" + }, + { + "airportname": "Albert J Ellis", + "city": "Jacksonville NC" + }, + { + "airportname": "Tuscaloosa Rgnl", + "city": "Tuscaloosa AL" + }, + { + "airportname": "Dubuque Rgnl", + "city": "Dubuque IA" + }, + { + "airportname": "Belfast Intl", + "city": "Belfast" + }, + { + "airportname": "St Angelo", + "city": "Enniskillen" + }, + { + "airportname": "Belfast City", + "city": "Belfast" + }, + { + "airportname": "City of Derry", + "city": "Londonderry" + }, + { + "airportname": "Birmingham", + "city": "Birmingham" + }, + { + "airportname": "Coventry", + "city": "Coventry" + }, + { + "airportname": "Leicester", + "city": "Leicester" + }, + { + "airportname": "Gloucestershire", + "city": "Golouchestershire" + }, + { + "airportname": "Wolverhampton", + "city": "Halfpenny Green" + }, + { + "airportname": "Kemble", + "city": "Pailton" + }, + { + "airportname": "Turweston", + "city": "Turweston" + }, + { + "airportname": "Wellesbourne Mountford", + "city": "Wellesbourne" + }, + { + "airportname": "Manchester", + "city": "Manchester" + }, + { + "airportname": "Manchester Woodford", + "city": "Woodfort" + }, + { + "airportname": "Chivenor", + "city": "Chivenor" + }, + { + "airportname": "St Mawgan", + "city": "Newquai" + }, + { + "airportname": "Lyneham", + "city": "Lyneham" + }, + { + "airportname": "Boscombe Down", + "city": "Boscombe Down" + }, + { + "airportname": "Culdrose", + "city": "Culdrose" + }, + { + "airportname": "St Athan", + "city": "St. Athan" + }, + { + "airportname": "Yeovilton", + "city": "Yeovilton" + }, + { + "airportname": "Haverfordwest", + "city": "Haverfordwest" + }, + { + "airportname": "Cardiff", + "city": "Cardiff" + }, + { + "airportname": "Swansea", + "city": "Swansea" + }, + { + "airportname": "Bristol", + "city": "Bristol" + }, + { + "airportname": "Liverpool", + "city": "Liverpool" + }, + { + "airportname": "Luton", + "city": "London" + }, + { + "airportname": "Plymouth", + "city": "Plymouth" + }, + { + "airportname": "Bournemouth", + "city": "Bournemouth" + }, + { + "airportname": "Southampton", + "city": "Southampton" + }, + { + "airportname": "Lasham", + "city": "Lasham" + }, + { + "airportname": "Shoreham", + "city": "Shoreham By Sea" + }, + { + "airportname": "Biggin Hill", + "city": "Biggin Hill" + }, + { + "airportname": "Gatwick", + "city": "London" + }, + { + "airportname": "City", + "city": "London" + }, + { + "airportname": "Farnborough", + "city": "Farnborough" + }, + { + "airportname": "Chalgrove", + "city": "Chalsgrove" + }, + { + "airportname": "Blackbushe", + "city": "Blackbushe" + }, + { + "airportname": "Heathrow", + "city": "London" + }, + { + "airportname": "Southend", + "city": "Southend" + }, + { + "airportname": "Lydd", + "city": "Lydd" + }, + { + "airportname": "Manston", + "city": "Manston" + }, + { + "airportname": "Brough", + "city": "Brough" + }, + { + "airportname": "Carlisle", + "city": "Carlisle" + }, + { + "airportname": "Gamston", + "city": "Repton" + }, + { + "airportname": "Blackpool", + "city": "Blackpool" + }, + { + "airportname": "Humberside", + "city": "Humberside" + }, + { + "airportname": "Walney Island", + "city": "Barrow Island" + }, + { + "airportname": "Leeds Bradford", + "city": "Leeds" + }, + { + "airportname": "Warton", + "city": "Warton" + }, + { + "airportname": "Hawarden", + "city": "Hawarden" + }, + { + "airportname": "Newcastle", + "city": "Newcastle" + }, + { + "airportname": "Durham Tees Valley Airport", + "city": "Teesside" + }, + { + "airportname": "Nottingham East Midlands", + "city": "East Midlands" + }, + { + "airportname": "Llanbedr", + "city": "Llanbedr" + }, + { + "airportname": "Ternhill", + "city": "Ternhill" + }, + { + "airportname": "Shawbury", + "city": "Shawbury" + }, + { + "airportname": "Woodvale", + "city": "Woodvale" + }, + { + "airportname": "Kirkwall", + "city": "Kirkwall" + }, + { + "airportname": "Sumburgh", + "city": "Sumburgh" + }, + { + "airportname": "Wick", + "city": "Wick" + }, + { + "airportname": "Dyce", + "city": "Aberdeen" + }, + { + "airportname": "Inverness", + "city": "Inverness" + }, + { + "airportname": "Glasgow", + "city": "Glasgow" + }, + { + "airportname": "Edinburgh", + "city": "Edinburgh" + }, + { + "airportname": "Islay", + "city": "Islay" + }, + { + "airportname": "Prestwick", + "city": "Prestwick" + }, + { + "airportname": "Benbecula", + "city": "Benbecula" + }, + { + "airportname": "Scatsta", + "city": "Scatsta" + }, + { + "airportname": "Dundee", + "city": "Dundee" + }, + { + "airportname": "Stornoway", + "city": "Stornoway" + }, + { + "airportname": "Tiree", + "city": "Tiree" + }, + { + "airportname": "Leuchars", + "city": "Leuchars" + }, + { + "airportname": "Lossiemouth", + "city": "Lossiemouth" + }, + { + "airportname": "Cambridge", + "city": "Cambridge" + }, + { + "airportname": "Conington", + "city": "Peterborough" + }, + { + "airportname": "Norwich", + "city": "Norwich" + }, + { + "airportname": "Stansted", + "city": "London" + }, + { + "airportname": "North Weald", + "city": "North Weald" + }, + { + "airportname": "Sheffield City", + "city": "Fowlmere" + }, + { + "airportname": "Cranfield", + "city": "Cranfield" + }, + { + "airportname": "Exeter", + "city": "Exeter" + }, + { + "airportname": "Bristol Filton", + "city": "Bristol" + }, + { + "airportname": "Kidlington", + "city": "Oxford" + }, + { + "airportname": "Benson", + "city": "Benson" + }, + { + "airportname": "Lakenheath", + "city": "Lakenheath" + }, + { + "airportname": "Nottingham Airport", + "city": "Nottingham" + }, + { + "airportname": "Robin Hood Doncaster Sheffield Airport", + "city": "Doncaster, Sheffield" + }, + { + "airportname": "Campbeltown Airport", + "city": "Campbeltown" + }, + { + "airportname": "Eday Airport", + "city": "Eday" + }, + { + "airportname": "Fair Isle Airport", + "city": "Fair Isle" + }, + { + "airportname": "North Ronaldsay Airport", + "city": "North Ronaldsay" + }, + { + "airportname": "Papa Westray Airport", + "city": "Papa Westray" + }, + { + "airportname": "Stronsay Airport", + "city": "Stronsay" + }, + { + "airportname": "Sanday Airport", + "city": "Sanday" + }, + { + "airportname": "Mildenhall", + "city": "Mildenhall" + }, + { + "airportname": "Lerwick / Tingwall Airport", + "city": "Lerwick" + }, + { + "airportname": "Westray Airport", + "city": "Westray" + }, + { + "airportname": "Land's End / St. Just Airport", + "city": "Land's End" + }, + { + "airportname": "Penzance Heliport", + "city": "Penzance" + }, + { + "airportname": "Anglesey Airport", + "city": "Angelsey" + }, + { + "airportname": "Barra Airport", + "city": "Barra" + }, + { + "airportname": "Wattisham", + "city": "Wattisham" + }, + { + "airportname": "Wyton", + "city": "Wyton" + }, + { + "airportname": "Fairford", + "city": "Fairford" + }, + { + "airportname": "Brize Norton", + "city": "Brize Norton" + }, + { + "airportname": "Odiham", + "city": "Odiham" + }, + { + "airportname": "Cosford", + "city": "Cosford" + }, + { + "airportname": "Croisette Heliport", + "city": "Cannes" + }, + { + "airportname": "Northolt", + "city": "Northolt" + }, + { + "airportname": "Coningsby", + "city": "Coningsby" + }, + { + "airportname": "Foula Airport", + "city": "Foula" + }, + { + "airportname": "Outer Skerries Airport", + "city": "Outer Skerries" + }, + { + "airportname": "Papa Stour Airport", + "city": "Papa Stour" + }, + { + "airportname": "Dishforth", + "city": "Dishforth" + }, + { + "airportname": "Leeming", + "city": "Leeming" + }, + { + "airportname": "Church Fenton", + "city": "Church Fenton" + }, + { + "airportname": "Honington", + "city": "Honington" + }, + { + "airportname": "Cottesmore", + "city": "Cottesmore" + }, + { + "airportname": "Scampton", + "city": "Scampton" + }, + { + "airportname": "Aberdeen Regional Airport", + "city": "Aberdeen" + }, + { + "airportname": "Southwest Georgia Regional Airport", + "city": "Albany" + }, + { + "airportname": "Athens Ben Epps Airport", + "city": "Athens" + }, + { + "airportname": "Alamogordo White Sands Regional Airport", + "city": "Alamogordo" + }, + { + "airportname": "Waterloo Regional Airport", + "city": "Waterloo" + }, + { + "airportname": "Walla Walla Regional Airport", + "city": "Walla Walla" + }, + { + "airportname": "Wittering", + "city": "Wittering" + }, + { + "airportname": "Alpena County Regional Airport", + "city": "Alpena" + }, + { + "airportname": "Watertown Regional Airport", + "city": "Watertown" + }, + { + "airportname": "Bradford Regional Airport", + "city": "Bradford" + }, + { + "airportname": "Western Nebraska Regional Airport", + "city": "Scottsbluff" + }, + { + "airportname": "Raleigh County Memorial Airport", + "city": "Beckley" + }, + { + "airportname": "Brunswick Golden Isles Airport", + "city": "Brunswick" + }, + { + "airportname": "Southeast Iowa Regional Airport", + "city": "Burlington" + }, + { + "airportname": "Del Norte County Airport", + "city": "Crescent City" + }, + { + "airportname": "Cape Girardeau Regional Airport", + "city": "Cape Girardeau" + }, + { + "airportname": "Chippewa County International Airport", + "city": "Sault Ste Marie" + }, + { + "airportname": "Linton On Ouse", + "city": "Linton-on-ouse" + }, + { + "airportname": "Harrison Marion Regional Airport", + "city": "Clarksburg" + }, + { + "airportname": "William R Fairchild International Airport", + "city": "Port Angeles" + }, + { + "airportname": "Houghton County Memorial Airport", + "city": "Hancock" + }, + { + "airportname": "Dodge City Regional Airport", + "city": "Dodge City" + }, + { + "airportname": "DuBois Regional Airport", + "city": "Du Bois" + }, + { + "airportname": "Chippewa Valley Regional Airport", + "city": "Eau Claire" + }, + { + "airportname": "Elko Regional Airport", + "city": "Elko" + }, + { + "airportname": "New Bedford Regional Airport", + "city": "New Bedford" + }, + { + "airportname": "Fayetteville Regional Grannis Field", + "city": "Fayetteville" + }, + { + "airportname": "Wokal Field Glasgow International Airport", + "city": "Glasgow" + }, + { + "airportname": "Waddington", + "city": "Waddington" + }, + { + "airportname": "Central Nebraska Regional Airport", + "city": "Grand Island" + }, + { + "airportname": "Memorial Field", + "city": "Hot Springs" + }, + { + "airportname": "Tri State Milton J Ferguson Field", + "city": "Huntington" + }, + { + "airportname": "Kirksville Regional Airport", + "city": "Kirksville" + }, + { + "airportname": "Jamestown Regional Airport", + "city": "Jamestown" + }, + { + "airportname": "Laramie Regional Airport", + "city": "Laramie" + }, + { + "airportname": "Arnold Palmer Regional Airport", + "city": "Latrobe" + }, + { + "airportname": "North Platte Regional Airport Lee Bird Field", + "city": "North Platte" + }, + { + "airportname": "Lebanon Municipal Airport", + "city": "Lebanon" + }, + { + "airportname": "Topcliffe", + "city": "Topcliffe" + }, + { + "airportname": "Klamath Falls Airport", + "city": "Klamath Falls" + }, + { + "airportname": "Lancaster Airport", + "city": "Lancaster" + }, + { + "airportname": "Lewistown Municipal Airport", + "city": "Lewistown" + }, + { + "airportname": "Lynchburg Regional Preston Glenn Field", + "city": "Lynchburg" + }, + { + "airportname": "Muskegon County Airport", + "city": "Muskegon" + }, + { + "airportname": "Frank Wiley Field", + "city": "Miles City" + }, + { + "airportname": "Northwest Alabama Regional Airport", + "city": "Muscle Shoals" + }, + { + "airportname": "Southwest Oregon Regional Airport", + "city": "North Bend" + }, + { + "airportname": "Owensboro Daviess County Airport", + "city": "Owensboro" + }, + { + "airportname": "Hattiesburg Laurel Regional Airport", + "city": "Hattiesburg/Laurel" + }, + { + "airportname": "Cranwell", + "city": "Cranwell" + }, + { + "airportname": "Pocatello Regional Airport", + "city": "Pocatello" + }, + { + "airportname": "Pierre Regional Airport", + "city": "Pierre" + }, + { + "airportname": "Pellston Regional Airport of Emmet County Airport", + "city": "Pellston" + }, + { + "airportname": "Pease International Tradeport", + "city": "Portsmouth" + }, + { + "airportname": "Reading Regional Carl A Spaatz Field", + "city": "Reading" + }, + { + "airportname": "Rhinelander Oneida County Airport", + "city": "Rhinelander" + }, + { + "airportname": "Rock Springs Sweetwater County Airport", + "city": "Rock Springs" + }, + { + "airportname": "Rutland State Airport", + "city": "Rutland" + }, + { + "airportname": "San Luis County Regional Airport", + "city": "San Luis Obispo" + }, + { + "airportname": "Sheridan County Airport", + "city": "Sheridan" + }, + { + "airportname": "Barkston Heath", + "city": "Barkston Heath" + }, + { + "airportname": "Adirondack Regional Airport", + "city": "Saranac Lake" + }, + { + "airportname": "Salina Municipal Airport", + "city": "Salina" + }, + { + "airportname": "Santa Maria Pub Cpt G Allan Hancock Airport", + "city": "Santa Maria" + }, + { + "airportname": "Tupelo Regional Airport", + "city": "Tupelo" + }, + { + "airportname": "Quincy Regional Baldwin Field", + "city": "Quincy" + }, + { + "airportname": "Victoria Regional Airport", + "city": "Victoria" + }, + { + "airportname": "Valdosta Regional Airport", + "city": "Valdosta" + }, + { + "airportname": "Worland Municipal Airport", + "city": "Worland" + }, + { + "airportname": "Yakima Air Terminal McAllister Field", + "city": "Yakima" + }, + { + "airportname": "Marham", + "city": "Marham" + }, + { + "airportname": "√éle d'Yeu Airport", + "city": "√éle d'Yeu" + }, + { + "airportname": "Angers-Loire Airport", + "city": "Angers/Marc√©" + }, + { + "airportname": "La M√¥le Airport", + "city": "La M√¥le" + }, + { + "airportname": "Adak Airport", + "city": "Adak Island" + }, + { + "airportname": "Gustavus Airport", + "city": "Gustavus" + }, + { + "airportname": "Skagway Airport", + "city": "Skagway" + }, + { + "airportname": "Holy Cross Airport", + "city": "Holy Cross" + }, + { + "airportname": "Haines Airport", + "city": "Haines" + }, + { + "airportname": "Kalskag Airport", + "city": "Kalskag" + }, + { + "airportname": "McGrath Airport", + "city": "Mcgrath" + }, + { + "airportname": "Mountain Village Airport", + "city": "Mountain Village" + }, + { + "airportname": "Aniak Airport", + "city": "Aniak" + }, + { + "airportname": "Chevak Airport", + "city": "Chevak" + }, + { + "airportname": "Wrangell Airport", + "city": "Wrangell" + }, + { + "airportname": "Kalaupapa Airport", + "city": "Molokai" + }, + { + "airportname": "Aleknagik Airport", + "city": "Aleknagik" + }, + { + "airportname": "Brookings Regional Airport", + "city": "Brookings" + }, + { + "airportname": "Mercer County Airport", + "city": "Bluefield" + }, + { + "airportname": "Kearney Municipal Airport", + "city": "Kearney" + }, + { + "airportname": "Mid Delta Regional Airport", + "city": "Greenville" + }, + { + "airportname": "Laughlin-Bullhead Intl", + "city": "Bullhead" + }, + { + "airportname": "Kingman Airport", + "city": "Kingman" + }, + { + "airportname": "Tri Cities Airport", + "city": "Pasco" + }, + { + "airportname": "Akutan Seaplane Base", + "city": "Akutan" + }, + { + "airportname": "Grant County Airport", + "city": "Silver City" + }, + { + "airportname": "Lopez Island Airport", + "city": "Lopez" + }, + { + "airportname": "Waikoloa Heliport", + "city": "Waikoloa Village" + }, + { + "airportname": "Worcester Regional Airport", + "city": "Worcester" + }, + { + "airportname": "New Haven Rail Station", + "city": "New Haven" + }, + { + "airportname": "Bremerton National", + "city": "Bremerton" + }, + { + "airportname": "Spencer Muni", + "city": "Spencer" + }, + { + "airportname": "Jefferson City Memorial Airport", + "city": "Jefferson City" + }, + { + "airportname": "Grand Canyon West Airport", + "city": "Grand Canyon West" + }, + { + "airportname": "Boulder City Municipal Airport", + "city": "Boulder City" + }, + { + "airportname": "Unst Airport", + "city": "Unst" + }, + { + "airportname": "Provincetown Muni", + "city": "Provincetown" + }, + { + "airportname": "Kenmore Air Harbor Seaplane Base", + "city": "Seattle" + }, + { + "airportname": "Saint Barthelemy", + "city": "Gustavia" + }, + { + "airportname": "Oban Airport", + "city": "North Connel" + }, + { + "airportname": "Courchevel Airport", + "city": "Courcheval" + }, + { + "airportname": "Fullerton Municipal Airport", + "city": "Fullerton" + }, + { + "airportname": "Concord Rgnl", + "city": "Concord" + }, + { + "airportname": "Sandown", + "city": "Isle Of Wight" + }, + { + "airportname": "Fort William Heliport", + "city": "Fort William" + }, + { + "airportname": "La Defense Heliport", + "city": "Paris" + }, + { + "airportname": "Andernos-Les-Bains", + "city": "Andernos-Les-Bains" + }, + { + "airportname": "La Rochelle-Ile de Re", + "city": "La Rochelle" + }, + { + "airportname": "Friedman Mem", + "city": "Hailey" + }, + { + "airportname": "Portsmouth Airport", + "city": "Portsmouth" + }, + { + "airportname": "Mason City Municipal", + "city": "Mason City" + }, + { + "airportname": "Phoenix-Mesa Gateway", + "city": "Mesa" + }, + { + "airportname": "Washington Union Station", + "city": "Washington" + }, + { + "airportname": "Anaktuvuk Pass Airport", + "city": "Anaktuvuk Pass" + }, + { + "airportname": "Anvik Airport", + "city": "Anvik" + }, + { + "airportname": "Atqasuk Edward Burnell Sr Memorial Airport", + "city": "Atqasuk" + }, + { + "airportname": "Gambell Airport", + "city": "Gambell" + }, + { + "airportname": "Hooper Bay Airport", + "city": "Hooper Bay" + }, + { + "airportname": "Kaltag Airport", + "city": "Kaltag" + }, + { + "airportname": "St Marys Airport", + "city": "St Mary's" + }, + { + "airportname": "Kivalina Airport", + "city": "Kivalina" + }, + { + "airportname": "Mekoryuk Airport", + "city": "Mekoryuk" + }, + { + "airportname": "Point Hope Airport", + "city": "Point Hope" + }, + { + "airportname": "Ruby Airport", + "city": "Ruby" + }, + { + "airportname": "Shishmaref Airport", + "city": "Shishmaref" + }, + { + "airportname": "Savoonga Airport", + "city": "Savoonga" + }, + { + "airportname": "Noatak Airport", + "city": "Noatak" + }, + { + "airportname": "Arctic Village Airport", + "city": "Arctic Village" + }, + { + "airportname": "Port Clarence Coast Guard Station", + "city": "Port Clarence" + }, + { + "airportname": "Hagerstown Regional Richard A Henson Field", + "city": "Hagerstown" + }, + { + "airportname": "Sand Point Airport", + "city": "Sand Point" + }, + { + "airportname": "Deering Airport", + "city": "Deering" + }, + { + "airportname": "Igiugig Airport", + "city": "Igiugig" + }, + { + "airportname": "New Stuyahok Airport", + "city": "New Stuyahok" + }, + { + "airportname": "King Cove Airport", + "city": "King Cove" + }, + { + "airportname": "Port Heiden Airport", + "city": "Port Heiden" + }, + { + "airportname": "Togiak Airport", + "city": "Togiak Village" + }, + { + "airportname": "Delta County Airport", + "city": "Escanaba" + }, + { + "airportname": "Yakutat", + "city": "Yakutat" + }, + { + "airportname": "EuroAirport", + "city": "Mulhouse" + }, + { + "airportname": "Williamson Country Regional Airport", + "city": "Marion" + }, + { + "airportname": "Ford Airport", + "city": "Iron Mountain" + }, + { + "airportname": "Sawyer International Airport", + "city": "Marquette" + }, + { + "airportname": "Allakaket Airport", + "city": "Allakaket" + }, + { + "airportname": "Michigan City Municipal Airport", + "city": "Michigan City" + }, + { + "airportname": "Seward Airport", + "city": "Seward" + }, + { + "airportname": "McCarthy Airport", + "city": "McCarthy" + }, + { + "airportname": "Porter County Municipal Airport", + "city": "Valparaiso" + }, + { + "airportname": "Grand Marais Cook County Airport", + "city": "Grand Marais" + }, + { + "airportname": "Mackinac Island Airport", + "city": "Mackinac Island" + }, + { + "airportname": "Gogebic Iron County Airport", + "city": "Ironwood" + }, + { + "airportname": "Portage Municipal Airport", + "city": "Portage" + }, + { + "airportname": "Wausau Downtown Airport", + "city": "Wausau" + }, + { + "airportname": "Macomb Municipal Airport", + "city": "Macomb" + }, + { + "airportname": "Point Roberts Airpark", + "city": "Point Roberts" + }, + { + "airportname": "Lyon Part-Dieu Railway", + "city": "Lyon" + }, + { + "airportname": "Delaware County Airport", + "city": "Muncie" + }, + { + "airportname": "Miami University Airport", + "city": "Oxford" + }, + { + "airportname": "Purude University Airport", + "city": "Lafayette" + }, + { + "airportname": "De Kalb Taylor Municipal Airport", + "city": "De Kalb" + }, + { + "airportname": "Grand Geneva Resort Airport", + "city": "Lake Geneva" + }, + { + "airportname": "Brown County Airport", + "city": "Georgetown" + }, + { + "airportname": "North Las Vegas Airport", + "city": "Las Vegas" + }, + { + "airportname": "Kenosha Regional Airport", + "city": "Kenosha" + }, + { + "airportname": "Clow International Airport", + "city": "Bolingbrook" + }, + { + "airportname": "Montrose Regional Airport", + "city": "Montrose CO" + }, + { + "airportname": "Riverton Regional", + "city": "Riverton WY" + }, + { + "airportname": "Tyonek Airport", + "city": "Tyonek" + }, + { + "airportname": "Eastern Oregon Regional Airport", + "city": "Pendleton" + }, + { + "airportname": "Shoestring Aviation Airfield", + "city": "Stewartstown" + }, + { + "airportname": "Door County Cherryland Airport", + "city": "Sturgeon Bay" + }, + { + "airportname": "Ashford", + "city": "Lympne" + }, + { + "airportname": "Cambridge Municipal Airport", + "city": "Cambridge" + }, + { + "airportname": "Dowagiac Municipal Airport", + "city": "Dowagiac" + }, + { + "airportname": "Putnam County Airport", + "city": "Greencastle" + }, + { + "airportname": "Everglades Airpark", + "city": "Everglades" + }, + { + "airportname": "Galt Field Airport", + "city": "Greenwood" + }, + { + "airportname": "Waukesha County Airport", + "city": "Waukesha" + }, + { + "airportname": "Southwest Michigan Regional Airport", + "city": "Benton Harbor" + }, + { + "airportname": "Wittman Regional Airport", + "city": "Oshkosh" + }, + { + "airportname": "Pangborn Field", + "city": "Wenatchee" + }, + { + "airportname": "Fortman Airport", + "city": "St. Marys" + }, + { + "airportname": "Fort Worth NAS", + "city": "Dallas" + }, + { + "airportname": "Gary Chicago International Airport", + "city": "Gary" + }, + { + "airportname": "Brainerd Lakes Rgnl", + "city": "Brainerd" + }, + { + "airportname": "Greenbrier Valley Airport", + "city": "Lewisburg" + }, + { + "airportname": "Pitt-Greenville Airport", + "city": "Greenville" + }, + { + "airportname": "Chefornak Airport", + "city": "Chefornak" + }, + { + "airportname": "Oxnard - Ventura County", + "city": "Oxnard" + }, + { + "airportname": "Branson LLC", + "city": "Branson" + }, + { + "airportname": "Penn Station", + "city": "Baltimore" + }, + { + "airportname": "Penn Station", + "city": "New York" + }, + { + "airportname": "Stratton ANGB - Schenectady County Airpor", + "city": "Scotia NY" + }, + { + "airportname": "St. Augustine Airport", + "city": "St. Augustine Airport" + }, + { + "airportname": "Charles M Schulz Sonoma Co", + "city": "Santa Rosa" + }, + { + "airportname": "Kissimmee Gateway Airport", + "city": "Kissimmee" + }, + { + "airportname": "Lake City Municipal Airport", + "city": "Lake City" + }, + { + "airportname": "DeLand Municipal Airport", + "city": "DeLand" + }, + { + "airportname": "Haller Airpark Airport", + "city": "Green Cove Springs" + }, + { + "airportname": "Logan-Cache", + "city": "Logan" + }, + { + "airportname": "Brigham City", + "city": "Brigham City" + }, + { + "airportname": "Malad City", + "city": "Malad City" + }, + { + "airportname": "Aspen Pitkin County Sardy Field", + "city": "Aspen" + }, + { + "airportname": "Hilton Head", + "city": "Hilton Head" + }, + { + "airportname": "Philadelphia 30th St Station", + "city": "Philadelphia" + }, + { + "airportname": "KBWD", + "city": "Brownwood" + }, + { + "airportname": "Mexia - Limestone County Airport", + "city": "Mexia" + }, + { + "airportname": "Kerrville Municipal Airport", + "city": "Kerrville" + }, + { + "airportname": "Sussex Co", + "city": "Georgetown" + }, + { + "airportname": "Great Bend Municipal", + "city": "Great Bend" + }, + { + "airportname": "Hays Regional Airport", + "city": "Hays" + }, + { + "airportname": "Spirit Of St Louis", + "city": "Null" + }, + { + "airportname": "Ely Municipal", + "city": "Ely" + }, + { + "airportname": "Grand Rapids Itasca County", + "city": "Grand Rapids MN" + }, + { + "airportname": "Thief River Falls", + "city": "Thief River Falls" + }, + { + "airportname": "Eagle River", + "city": "Eagle River" + }, + { + "airportname": "Lakeland", + "city": "Minocqua - Woodruff" + }, + { + "airportname": "Ankeny Regl Airport", + "city": "Ankeny" + }, + { + "airportname": "Corpus Christi NAS", + "city": "Corpus Christi" + }, + { + "airportname": "Avalon-US", + "city": "Catalina Island" + }, + { + "airportname": "Mojave", + "city": "Mojave" + }, + { + "airportname": "Kenmore Air Harbor Inc Seaplane Base", + "city": "Kenmore" + }, + { + "airportname": "Hutchinson Municipal Airport", + "city": "Hutchinson" + }, + { + "airportname": "Eagle County Airport", + "city": "Eagle" + }, + { + "airportname": "Rosecrans Mem", + "city": "Rosecrans" + }, + { + "airportname": "Hartford Union Station", + "city": "Hartford" + }, + { + "airportname": "Stamford Amtrak Station", + "city": "Stamford" + }, + { + "airportname": "Newark Penn Station", + "city": "Newark" + }, + { + "airportname": "Volk Fld", + "city": "Camp Douglas" + }, + { + "airportname": "BFT County Airport", + "city": "Beauford" + }, + { + "airportname": "Gunnison - Crested Butte", + "city": "Gunnison" + }, + { + "airportname": "Zamperini Field Airport", + "city": "Torrance" + }, + { + "airportname": "Manistee County-Blacker Airport", + "city": "Manistee" + }, + { + "airportname": "Hickam Air Force Base", + "city": "Honolulu" + }, + { + "airportname": "Charlotte County-Punta Gorda Airport", + "city": "Punta Gorda" + }, + { + "airportname": "Grand Canyon Heliport", + "city": "Grand Canyon" + }, + { + "airportname": "Northern Aroostook Regional Airport", + "city": "Frenchville" + }, + { + "airportname": "Chautauqua County-Jamestown", + "city": "Jamestown" + }, + { + "airportname": "Lake Cumberland Regional Airport", + "city": "Somerset" + }, + { + "airportname": "Shenandoah Valley Regional Airport", + "city": "Weyers Cave" + }, + { + "airportname": "Devils Lake Regional Airport", + "city": "Devils Lake" + }, + { + "airportname": "Dickinson Theodore Roosevelt Regional Airport", + "city": "Dickinson" + }, + { + "airportname": "Sidney-Richland Municipal Airport", + "city": "Sidney" + }, + { + "airportname": "Chadron Municipal Airport", + "city": "Chadron" + }, + { + "airportname": "Alliance Municipal Airport", + "city": "Alliance" + }, + { + "airportname": "McCook Regional Airport", + "city": "McCook" + }, + { + "airportname": "Florida Keys Marathon Airport", + "city": "Marathon" + }, + { + "airportname": "Dawson Community Airport", + "city": "Glendive" + }, + { + "airportname": "LM Clayton Airport", + "city": "Wolf Point" + }, + { + "airportname": "Yellowstone Airport", + "city": "West Yellowstone" + }, + { + "airportname": "San Luis Valley Regional Airport", + "city": "Alamosa" + }, + { + "airportname": "Canyonlands Field", + "city": "Moab" + }, + { + "airportname": "Ely Airport", + "city": "Ely" + }, + { + "airportname": "Vernal Regional Airport", + "city": "Vernal" + }, + { + "airportname": "Sierra Blanca Regional Airport", + "city": "Ruidoso" + }, + { + "airportname": "Show Low Regional Airport", + "city": "Show Low" + }, + { + "airportname": "McCall Municipal Airport", + "city": "McCall" + }, + { + "airportname": "Lemhi County Airport", + "city": "Salmon" + }, + { + "airportname": "Mammoth Yosemite Airport", + "city": "Mammoth Lakes" + }, + { + "airportname": "Friday Harbor Airport", + "city": "Friday Harbor" + }, + { + "airportname": "Orcas Island Airport", + "city": "Eastsound" + }, + { + "airportname": "Anacortes Airport", + "city": "Anacortes" + }, + { + "airportname": "Astoria Regional Airport", + "city": "Astoria" + }, + { + "airportname": "Newport Municipal Airport", + "city": "Newport" + }, + { + "airportname": "Emmonak Airport", + "city": "Emmonak" + }, + { + "airportname": "Unalakleet Airport", + "city": "Unalakleet" + }, + { + "airportname": "Ugnu-Kuparuk Airport", + "city": "Kuparuk" + }, + { + "airportname": "Shageluk Airport", + "city": "Shageluk" + }, + { + "airportname": "Chuathbaluk Airport", + "city": "Chuathbaluk" + }, + { + "airportname": "Nuiqsut Airport", + "city": "Nuiqsut" + }, + { + "airportname": "Eek Airport", + "city": "Eek" + }, + { + "airportname": "Kasigluk Airport", + "city": "Kasigluk" + }, + { + "airportname": "Kwethluk Airport", + "city": "Kwethluk" + }, + { + "airportname": "Kwigillingok Airport", + "city": "Kwigillingok" + }, + { + "airportname": "Marshall Don Hunter Sr. Airport", + "city": "Marshall" + }, + { + "airportname": "Russian Mission Airport", + "city": "Russian Mission" + }, + { + "airportname": "Tuntutuliak Airport", + "city": "Tuntutuliak" + }, + { + "airportname": "Ekwok Airport", + "city": "Ekwok" + }, + { + "airportname": "Koliganek Airport", + "city": "Koliganek" + }, + { + "airportname": "Levelock Airport", + "city": "Levelock" + }, + { + "airportname": "Manokotak Airport", + "city": "Manokotak" + }, + { + "airportname": "Twin Hills Airport", + "city": "Twin Hills" + }, + { + "airportname": "Chalkyitsik Airport", + "city": "Chalkyitsik" + }, + { + "airportname": "Eagle Airport", + "city": "Eagle" + }, + { + "airportname": "Hughes Airport", + "city": "Hughes" + }, + { + "airportname": "Huslia Airport", + "city": "Huslia" + }, + { + "airportname": "Livingood Airport", + "city": "Livingood" + }, + { + "airportname": "Minto Airport", + "city": "Minto" + }, + { + "airportname": "Nulato Airport", + "city": "Nulato" + }, + { + "airportname": "Rampart Airport", + "city": "Rampart" + }, + { + "airportname": "Tanana Airport", + "city": "Tanana" + }, + { + "airportname": "Venetie Airport", + "city": "Venetie" + }, + { + "airportname": "Beaver Airport", + "city": "Beaver" + }, + { + "airportname": "Central Airport", + "city": "Central" + }, + { + "airportname": "Shungnak Airport", + "city": "Shungnak" + }, + { + "airportname": "Birch Creek Airport", + "city": "Brich Creek" + }, + { + "airportname": "Coldfoot Airport", + "city": "Coldfoot" + }, + { + "airportname": "Inyokern Airport", + "city": "Inyokern" + }, + { + "airportname": "Visalia Municipal Airport", + "city": "Visalia" + }, + { + "airportname": "Merced Municipal Airport", + "city": "Merced" + }, + { + "airportname": "Phoenix Goodyear", + "city": "Goodyear" + }, + { + "airportname": "Angoon Seaplane Base", + "city": "Angoon" + }, + { + "airportname": "Elfin Cove Seaplane Base", + "city": "Elfin Cove" + }, + { + "airportname": "Tenakee Seaplane Base", + "city": "Tenakee Springs" + }, + { + "airportname": "Pelican Seaplane Base", + "city": "Pelican" + }, + { + "airportname": "Chatham Seaplane Base", + "city": "Sitka" + }, + { + "airportname": "Funter Bay Seaplane Base", + "city": "Funter Bay" + }, + { + "airportname": "Excursion Inlet Seaplane Base", + "city": "Excursion Inlet" + }, + { + "airportname": "Hoonah Airport", + "city": "Hoonah" + }, + { + "airportname": "Kake Airport", + "city": "Kake" + }, + { + "airportname": "Craig Seaplane Base", + "city": "Craig" + }, + { + "airportname": "Hollis Seaplane Base", + "city": "Hollis" + }, + { + "airportname": "Metlakatla Seaplane Base", + "city": "Metakatla" + }, + { + "airportname": "Thorne Bay Seaplane Base", + "city": "Thorne Bay" + }, + { + "airportname": "Hydaburg Seaplane Base", + "city": "Hydaburg" + }, + { + "airportname": "Hyder Seaplane Base", + "city": "Hyder" + }, + { + "airportname": "Point Baker Seaplane Base", + "city": "Point Baker" + }, + { + "airportname": "Port Protection Seaplane Base", + "city": "Port Protection" + }, + { + "airportname": "North Whale Seaplane Base", + "city": "North Whale Pass" + }, + { + "airportname": "Chignik Lake Airport", + "city": "Chignik Lake" + }, + { + "airportname": "Egegik Airport", + "city": "Egegik" + }, + { + "airportname": "Chignik Lagoon Airport", + "city": "Chignik Lagoon" + }, + { + "airportname": "Chignik Bay Seaplane Base", + "city": "Chignik" + }, + { + "airportname": "Perryville Airport", + "city": "Perryville" + }, + { + "airportname": "Pilot Point Airport", + "city": "Pilot Point" + }, + { + "airportname": "South Naknek Airport", + "city": "South Naknek" + }, + { + "airportname": "Akhiok Airport", + "city": "Akhiok" + }, + { + "airportname": "Karuluk Airport", + "city": "Karluk" + }, + { + "airportname": "Larsen Bay Airport", + "city": "Larsen Bay" + }, + { + "airportname": "Old Harbor Airport", + "city": "Old Harbor" + }, + { + "airportname": "Ouzinkie Airport", + "city": "Ouzinkie" + }, + { + "airportname": "Port Lions Airport", + "city": "Port Lions" + }, + { + "airportname": "Alitak Seaplane Base", + "city": "Lazy Bay" + }, + { + "airportname": "Amook Bay Seaplane Base", + "city": "Amook Bay" + }, + { + "airportname": "Kitoi Bay Seaplane Base", + "city": "Kitoi Bay" + }, + { + "airportname": "Moser Bay Seaplane Base", + "city": "Moser Bay" + }, + { + "airportname": "Olga Bay Seaplane Base", + "city": "Olga Bay" + }, + { + "airportname": "Port Bailey Seaplane Base", + "city": "Port Bailey" + }, + { + "airportname": "Port Williams Seaplane Base", + "city": "Port Williams" + }, + { + "airportname": "Seal Bay Seaplane Base", + "city": "Seal Bay" + }, + { + "airportname": "San Juan - Uganik Seaplane Base", + "city": "San Juan" + }, + { + "airportname": "West Point Village Seaplane Base", + "city": "West Point" + }, + { + "airportname": "Zachar Bay Seaplane Base", + "city": "Zachar Bay" + }, + { + "airportname": "Ambler Airport", + "city": "Ambler" + }, + { + "airportname": "Buckland Airport", + "city": "Buckland" + }, + { + "airportname": "Bob Baker Memorial Airport", + "city": "Kiana" + }, + { + "airportname": "Kobuk Airport", + "city": "Kobuk" + }, + { + "airportname": "Robert Curtis Memorial Airport", + "city": "Noorvik" + }, + { + "airportname": "Selawik Airport", + "city": "Selawik" + }, + { + "airportname": "Brevig Mission Airport", + "city": "Brevig Mission" + }, + { + "airportname": "Elim Airport", + "city": "Elim" + }, + { + "airportname": "Golovin Airport", + "city": "Golovin" + }, + { + "airportname": "Teller Airport", + "city": "Teller" + }, + { + "airportname": "Wales Airport", + "city": "Wales" + }, + { + "airportname": "White Mountain Airport", + "city": "White Mountain" + }, + { + "airportname": "Council Airport", + "city": "Council" + }, + { + "airportname": "Koyuk Alfred Adams Airport", + "city": "Koyuk" + }, + { + "airportname": "St. Michael Airport", + "city": "St. Michael" + }, + { + "airportname": "Shaktoolik Airport", + "city": "Shaktoolik" + }, + { + "airportname": "Stebbins Airport", + "city": "Stebbins" + }, + { + "airportname": "Tin City LRRS Airport", + "city": "Tin City" + }, + { + "airportname": "Atka Airport", + "city": "Atka" + }, + { + "airportname": "Nikolski Air Station", + "city": "Nikolski" + }, + { + "airportname": "Icy Bay Airport", + "city": "Icy Bay" + }, + { + "airportname": "Yakataga Airport", + "city": "Yakataga" + }, + { + "airportname": "Alakanuk Airport", + "city": "Alakanuk" + }, + { + "airportname": "Sheldon Point Airport", + "city": "Nunam Iqua" + }, + { + "airportname": "Kipnuk Airport", + "city": "Kipnuk" + }, + { + "airportname": "False Pass Airport", + "city": "False Pass" + }, + { + "airportname": "Nelson Lagoon", + "city": "Nelson Lagoon" + }, + { + "airportname": "Port Moller Airport", + "city": "Cold Bay" + }, + { + "airportname": "Klawock Airport", + "city": "Klawock" + }, + { + "airportname": "Quinhagak Airport", + "city": "Quinhagak" + }, + { + "airportname": "Kotlik Airport", + "city": "Kotlik" + }, + { + "airportname": "Koyukuk Airport", + "city": "Koyukuk" + }, + { + "airportname": "Scammon Bay Airport", + "city": "Scammon Bay" + }, + { + "airportname": "Nondalton Airport", + "city": "Nondalton" + }, + { + "airportname": "Pedro Bay Airport", + "city": "Pedro Bay" + }, + { + "airportname": "Nunapitchuk Airport", + "city": "Nunapitchuk" + }, + { + "airportname": "Kongiganak Airport", + "city": "Kongiganak" + }, + { + "airportname": "Nikolai Airport", + "city": "Nikolai" + }, + { + "airportname": "Takotna Airport", + "city": "Takotna" + }, + { + "airportname": "Pilot Station Airport", + "city": "Pilot Station" + }, + { + "airportname": "Akiak Airport", + "city": "Akiak" + }, + { + "airportname": "Tuluksak Airport", + "city": "Tuluksak" + }, + { + "airportname": "Grayling Airport", + "city": "Grayling" + }, + { + "airportname": "Wainwright Airport", + "city": "Wainwright" + }, + { + "airportname": "Chenega Bay Airport", + "city": "Chenega" + }, + { + "airportname": "Chisana Airport", + "city": "Chisana" + }, + { + "airportname": "Tok Junction Airport", + "city": "Tok" + }, + { + "airportname": "Circle City Airport", + "city": "Circle" + }, + { + "airportname": "Coffman Cove Seaplane Base", + "city": "Coffman Cove" + }, + { + "airportname": "Crooked Creek Airport", + "city": "Crooked Creek" + }, + { + "airportname": "Red Devil Airport", + "city": "Red Devil" + }, + { + "airportname": "Sleetmute Airport", + "city": "Sleetmute" + }, + { + "airportname": "Stony River 2 Airport", + "city": "Stony River" + }, + { + "airportname": "Healy River Airport", + "city": "Healy" + }, + { + "airportname": "Kake Seaplane Base", + "city": "Kake" + }, + { + "airportname": "Klawock Seaplane Base", + "city": "Klawock" + }, + { + "airportname": "Minchumina Airport", + "city": "Lake Minchumina" + }, + { + "airportname": "Manley Hot Springs Airport", + "city": "Manley Hot Springs" + }, + { + "airportname": "St. George Airport", + "city": "St. George" + }, + { + "airportname": "Tatitlek Airport", + "city": "Tatitlek" + }, + { + "airportname": "Ketchikan harbor Seaplane Base", + "city": "Ketchikan" + }, + { + "airportname": "St. Louis Downtown Airport", + "city": "East St. Louis" + }, + { + "airportname": "Edinburgh Waverly Station", + "city": "Edinburgh" + }, + { + "airportname": "Eastern WV Regional Airport", + "city": "Martinsburg" + }, + { + "airportname": "Ouessant Airport", + "city": "Ouessant" + }, + { + "airportname": "Lille", + "city": "Lille" + }, + { + "airportname": "Colonsay Airport", + "city": "Colonsay" + }, + { + "airportname": "Coll Airport", + "city": "Coll" + }, + { + "airportname": "Rock Hill York Co Bryant Airport", + "city": "Rock Hill" + }, + { + "airportname": "Allegheny County Airport", + "city": "Pittsburgh" + }, + { + "airportname": "Cecil Field", + "city": "Jacksonville" + }, + { + "airportname": "Fulton County Airport Brown Field", + "city": "Atlanta" + }, + { + "airportname": "Tresco Heliport", + "city": "Tresco" + }, + { + "airportname": "Ocean Isle Beach Airport", + "city": "Ocean Isle Beach" + }, + { + "airportname": "Ohio State University Airport", + "city": "Columbus" + }, + { + "airportname": "Addison", + "city": "Addison" + }, + { + "airportname": "Destin", + "city": "Destin" + }, + { + "airportname": "Fort Jefferson", + "city": "Fort Jefferson - Dry Tortugas" + }, + { + "airportname": "Kinston Regional Jetport", + "city": "Kinston" + }, + { + "airportname": "First Flight Airport", + "city": "Kill Devil Hills" + }, + { + "airportname": "Provo Municipal Airport", + "city": "Provo" + }, + { + "airportname": "Steamboat Springs Airport-Bob Adams Field", + "city": "Steamboat Springs" + }, + { + "airportname": "Delta Municipal Airport", + "city": "Delta" + }, + { + "airportname": "Richfield Minicipal Airport", + "city": "Richfield" + }, + { + "airportname": "Carbon County Regional-Buck Davis Field", + "city": "Price" + }, + { + "airportname": "Los Alamos Airport", + "city": "Los Alamos" + }, + { + "airportname": "Borrego Valley Airport", + "city": "Borrego Springs" + }, + { + "airportname": "Lake Havasu City Airport", + "city": "Lake Havasu City" + }, + { + "airportname": "Winslow-Lindbergh Regional Airport", + "city": "Winslow" + }, + { + "airportname": "Douglas Municipal Airport", + "city": "Douglas" + }, + { + "airportname": "Bartow Municipal Airport", + "city": "Bartow" + }, + { + "airportname": "Livermore Municipal", + "city": "Livermore" + }, + { + "airportname": "MariposaYosemite", + "city": "Mariposa" + }, + { + "airportname": "Paddington Station", + "city": "London" + }, + { + "airportname": "Jacqueline Cochran Regional Airport", + "city": "Palm Springs" + }, + { + "airportname": "Santa Monica Municipal Airport", + "city": "Santa Monica" + }, + { + "airportname": "Bermuda Dunes Airport", + "city": "Palm Springs" + }, + { + "airportname": "Scottsdale Airport", + "city": "Scottsdale" + }, + { + "airportname": "Olympia Regional Airpor", + "city": "Olympia" + }, + { + "airportname": "Yolo County Airport", + "city": "Davis-Woodland-Winters" + }, + { + "airportname": "Garfield County Regional Airport", + "city": "Rifle" + }, + { + "airportname": "Shively Field Airport", + "city": "SARATOGA" + }, + { + "airportname": "Dekalb-Peachtree Airport", + "city": "Atlanta" + }, + { + "airportname": "Monroe County Airport", + "city": "Bloomington" + }, + { + "airportname": "Witham Field Airport", + "city": "Stuart" + }, + { + "airportname": "Morristown Municipal Airport", + "city": "Morristown" + }, + { + "airportname": "Napa County Airport", + "city": "Napa" + }, + { + "airportname": "Brown Field Municipal Airport", + "city": "San Diego" + }, + { + "airportname": "Pahokee Airport", + "city": "Pahokee" + }, + { + "airportname": "Venice Municipal", + "city": "Venice" + }, + { + "airportname": "Pahokee", + "city": "Pahokee" + }, + { + "airportname": "Panama City-NW Florida Bea.", + "city": "Panama City" + }, + { + "airportname": "San Bernardino International Airport", + "city": "San Bernardino" + }, + { + "airportname": "Gare du Nord", + "city": "Paris" + }, + { + "airportname": "Gare Montparnasse", + "city": "Paris" + }, + { + "airportname": "Saint-Pierre-des-Corps", + "city": "Tours" + }, + { + "airportname": "San Carlos Airport", + "city": "San Carlos" + }, + { + "airportname": "Rocky Mount Wilson Regional Airport", + "city": "Rocky Mount" + }, + { + "airportname": "Whittier Airport", + "city": "Whittier" + }, + { + "airportname": "Soldotna Airport", + "city": "Soldotna" + }, + { + "airportname": "Gillespie", + "city": "El Cajon" + }, + { + "airportname": "San Clemente Island Nalf", + "city": "San Clemente Island" + }, + { + "airportname": "London St Pancras", + "city": "London" + }, + { + "airportname": "Truckee-Tahoe Airport", + "city": "Truckee" + }, + { + "airportname": "Frejus Saint Raphael", + "city": "Frejus" + }, + { + "airportname": "Cobb County Airport-Mc Collum Field", + "city": "Atlanta" + }, + { + "airportname": "Oneonta Municipal Airport", + "city": "Oneonta" + }, + { + "airportname": "Wideawake Field", + "city": "Georgetown Acension Island Santa Helena" + }, + { + "airportname": "Dell Flight Strip", + "city": "Dell" + }, + { + "airportname": "Mission Field Airport", + "city": "Livingston-Montana" + }, + { + "airportname": "Big Timber Airport", + "city": "Big Timber" + }, + { + "airportname": "Tulip City Airport", + "city": "Holland" + }, + { + "airportname": "London Heliport", + "city": "London" + }, + { + "airportname": "Monument Valley Airport", + "city": "Monument Valley" + }, + { + "airportname": "West 30th St. Heliport", + "city": "New York" + }, + { + "airportname": "Lakeland Linder Regional Airport", + "city": "Lakeland" + }, + { + "airportname": "Idlewild Intl", + "city": "New York" + }, + { + "airportname": "French Valley Airport", + "city": "Murrieta-Temecula" + }, + { + "airportname": "White Waltham Airfield", + "city": "Maidenhead" + }, + { + "airportname": "Erie-Ottawa Regional Airport", + "city": "Port Clinton" + }, + { + "airportname": "Dayton-Wright Brothers Airport", + "city": "Dayton" + }, + { + "airportname": "Richmond Municipal Airport", + "city": "Richmond" + }, + { + "airportname": "Findlay Airport", + "city": "Findley" + }, + { + "airportname": "Booker", + "city": "Wycombe" + }, + { + "airportname": "Bembridge", + "city": "Bembridge" + }, + { + "airportname": "Black Hills Airport-Clyde Ice Field", + "city": "Spearfish-South Dakota" + }, + { + "airportname": "Olive Branch Muni", + "city": "Olive Branch" + }, + { + "airportname": "Rocky Mountain Metropolitan Airport", + "city": "Broomfield-CO" + }, + { + "airportname": "McNary Field", + "city": "Salem" + }, + { + "airportname": "Tunica Municipal Airport", + "city": "Tunica" + }, + { + "airportname": "Saint-Cyr-l-Ecole Airport", + "city": "Saint-Cyr" + }, + { + "airportname": "Lawrence J Timmerman Airport", + "city": "Milwaukee" + }, + { + "airportname": "Southern Wisconsin Regional Airport", + "city": "Janesville" + }, + { + "airportname": "Hatfield", + "city": "Hatfield" + }, + { + "airportname": "Arlington Municipal", + "city": "Arlington" + }, + { + "airportname": "Gwinnett County Airport-Briscoe Field", + "city": "Lawrenceville" + }, + { + "airportname": "Bowling Green-Warren County Regional Airport", + "city": "Bowling Green" + }, + { + "airportname": "Richard Lloyd Jones Jr Airport", + "city": "Tulsa" + }, + { + "airportname": "Bryce Canyon", + "city": "Bryce Canyon" + }, + { + "airportname": "Burlington-Alamance Regional Airport", + "city": "Burlington" + }, + { + "airportname": "New Century AirCenter Airport", + "city": "Olathe" + }, + { + "airportname": "Easton-Newnam Field Airport", + "city": "Easton" + }, + { + "airportname": "Ferry County Airport", + "city": "Republic" + }, + { + "airportname": "Yuba County Airport", + "city": "Yuba City" + }, + { + "airportname": "Halliburton Field Airport", + "city": "Duncan" + }, + { + "airportname": "Port Authority Bus Terminal", + "city": "New York" + }, + { + "airportname": "Chinle Municipal Airport", + "city": "Chinle" + }, + { + "airportname": "Garner Field", + "city": "Uvalde" + }, + { + "airportname": "Lewis University Airport", + "city": "Lockport" + }, + { + "airportname": "Frasca Field", + "city": "Urbana" + }, + { + "airportname": "Buchanan Field Airport", + "city": "Concord" + }, + { + "airportname": "Key Largo", + "city": "Ocean Reef Club Airport" + }, + { + "airportname": "Polygone", + "city": "Strasbourg Neudorf" + }, + { + "airportname": "Ohio University Airport", + "city": "Athens" + }, + { + "airportname": "Springfield-Beckly Municipal Airport", + "city": "Springfield" + }, + { + "airportname": "Miami Seaplane Base", + "city": "Miami" + }, + { + "airportname": "Philip Billard Muni", + "city": "Topeka" + }, + { + "airportname": "Emporia Municipal Airport", + "city": "Emporia" + }, + { + "airportname": "Benson Airstrip", + "city": "Uvalde" + }, + { + "airportname": "Rough River State Park", + "city": "Null" + }, + { + "airportname": "Smyrna Airport", + "city": "Smyrna" + }, + { + "airportname": "Franklin County Airport", + "city": "Sewanee" + }, + { + "airportname": "Collin County Regional Airport at Mc Kinney", + "city": "DALLAS" + }, + { + "airportname": "Chicago Executive", + "city": "Chicago-Wheeling" + }, + { + "airportname": "Kelso Longview", + "city": "Kelso" + }, + { + "airportname": "Put-in-Bay Airport", + "city": "Put-in-Bay" + }, + { + "airportname": "Jefferson County Intl", + "city": "Port Townsend" + }, + { + "airportname": "Lynden Airport", + "city": "Lynden" + }, + { + "airportname": "Jefferson County Intl", + "city": "Port Townsend" + }, + { + "airportname": "Boston South Station", + "city": "Boston" + }, + { + "airportname": "Train Station", + "city": "Richmond" + }, + { + "airportname": "Wilmington Airborne Airpark", + "city": "Wilmington" + }, + { + "airportname": "Marana Regional", + "city": "Tucson" + }, + { + "airportname": "Casa Grande Municipal Airport", + "city": "Casa Grande" + }, + { + "airportname": "Mobile", + "city": "Mobile" + }, + { + "airportname": "Buckeye Municipal Airport", + "city": "Buckeye" + }, + { + "airportname": "Gila Bend Municipal Airport", + "city": "Gila Bend" + }, + { + "airportname": "McMinn Co", + "city": "Athens" + }, + { + "airportname": "Sterling Municipal Airport", + "city": "Sterling" + }, + { + "airportname": "Rawlins Municipal Airport-Harvey Field", + "city": "Rawlins" + }, + { + "airportname": "Caldwell Essex County Airport", + "city": "Caldwell" + }, + { + "airportname": "Lee C Fine Memorial Airport", + "city": "Kaiser Lake Ozark" + }, + { + "airportname": "Big Bear City", + "city": "Big Bear" + }, + { + "airportname": "Thomasville Regional Airport", + "city": "Thomasville" + }, + { + "airportname": "Henderson Executive Airport", + "city": "Henderson" + }, + { + "airportname": "Henry Tift Myers Airport", + "city": "Tifton" + }, + { + "airportname": "St Pancras Railway Station", + "city": "London" + }, + { + "airportname": "Deer Valley Municipal Airport", + "city": "Phoenix " + }, + { + "airportname": "Republic Airport", + "city": "Farmingdale" + }, + { + "airportname": "Hondo Municipal Airport", + "city": "Hondo" + }, + { + "airportname": "McKinley National Park Airport", + "city": "McKinley Park" + }, + { + "airportname": "Lake Hood Seaplane Base", + "city": "Anchorage" + }, + { + "airportname": "Prospect Creek Airport", + "city": "Prospect Creek" + }, + { + "airportname": "Columbia County", + "city": "Hudson NY" + }, + { + "airportname": "Wheeling Ohio County Airport", + "city": "Wheeling" + }, + { + "airportname": "Fitzgerald Municipal Airport", + "city": "Fitzgerald" + }, + { + "airportname": "Perry-Foley Airport", + "city": "Perry" + }, + { + "airportname": "Cairo-Grady County Airport", + "city": "Cairo" + }, + { + "airportname": "Aransas County Airport", + "city": "Rockport" + }, + { + "airportname": "Megeve Airport", + "city": "Verdun" + }, + { + "airportname": "Meribel Airport", + "city": "Ajaccio" + }, + { + "airportname": "Crisp County Cordele Airport", + "city": "Cordele" + }, + { + "airportname": "Ormond Beach municipal Airport", + "city": "Ormond Beach" + }, + { + "airportname": "Portland Troutdale", + "city": "Troutdale" + }, + { + "airportname": "Portland Hillsboro", + "city": "Hillsboro" + }, + { + "airportname": "One Police Plaza Heliport", + "city": "New York" + }, + { + "airportname": "Suwannee County Airport", + "city": "Live Oak" + }, + { + "airportname": "Bend Municipal Airport", + "city": "Bend" + }, + { + "airportname": "Christmas Valley Airport", + "city": "Christmas Valley" + }, + { + "airportname": "Burns Municipal Airport", + "city": "Burns" + }, + { + "airportname": "Prineville Airport", + "city": "Prineville" + }, + { + "airportname": "Red Bluff Municipal Airport", + "city": "Red Bluff" + }, + { + "airportname": "Gnoss Field Airport", + "city": "Novato" + }, + { + "airportname": "Lake County Airport", + "city": "Lakeview" + }, + { + "airportname": "Tillamook Airport", + "city": "Tillamook" + }, + { + "airportname": "Ontario Municipal Airport", + "city": "Ontario" + }, + { + "airportname": "Columbia Gorge Regional - The Dalles Municipal Airport", + "city": "The Dalles" + }, + { + "airportname": "Montgomery County Airpark", + "city": "Gaithersburg" + }, + { + "airportname": "Cleveland Clinic", + "city": "Cleveland" + }, + { + "airportname": "Charlevoix Municipal Airport", + "city": "Charelvoix" + }, + { + "airportname": "Quincy Municipal Airport", + "city": "Quincy" + }, + { + "airportname": "Moultrie Municipal Airport", + "city": "Moultrie" + }, + { + "airportname": "Roche Harbor Seaplane Base", + "city": "Roche Harbor" + }, + { + "airportname": "Blakely Island Airport", + "city": "Blakely Island" + }, + { + "airportname": "Rosario Seaplane Base", + "city": "Rosario" + }, + { + "airportname": "Westsound Seaplane Base", + "city": "Westsound" + }, + { + "airportname": "Friday Harbor Seaplane Base", + "city": "Friday Harbor" + }, + { + "airportname": "Furnace Creek", + "city": "Death Valley National Park" + }, + { + "airportname": "Flagler County Airport", + "city": "Flagler" + }, + { + "airportname": "Morrisville Stowe State Airport", + "city": "Morrisville" + }, + { + "airportname": "Dallas Executive Airport", + "city": "Dallas" + }, + { + "airportname": "Welke Airport", + "city": "Beaver Island" + }, + { + "airportname": "Westerly State Airport", + "city": "Washington County" + }, + { + "airportname": "Block Island State Airport", + "city": "Block Island" + }, + { + "airportname": "Atmautluak Airport", + "city": "Atmautluak" + }, + { + "airportname": "Nightmute Airport", + "city": "Nightmute" + }, + { + "airportname": "Toksook Bay Airport", + "city": "Toksook Bay" + }, + { + "airportname": "Tununak Airport", + "city": "Tununak" + }, + { + "airportname": "Goodnews Airport", + "city": "Goodnews Bay" + }, + { + "airportname": "Newtok Airport", + "city": "Newtok" + }, + { + "airportname": "Angers St Laud", + "city": "Angers" + }, + { + "airportname": "Decatur County Industrial Air Park", + "city": "Bainbridge" + }, + { + "airportname": "Silver Springs Airport", + "city": "Silver Springs" + }, + { + "airportname": "Whiteman Airport", + "city": "Los Angeles" + }, + { + "airportname": "Madera Municipal Airport", + "city": "Madera" + }, + { + "airportname": "Mountain Home Municipal Airport", + "city": "Mountain Home" + }, + { + "airportname": "Jackson County Airport", + "city": "Jefferson" + }, + { + "airportname": "Apalachicola Regional Airport", + "city": "Apalachicola" + }, + { + "airportname": "St. Augustine Airport", + "city": "St. Augustine" + }, + { + "airportname": "Douglas Municipal Airport", + "city": "Douglas" + }, + { + "airportname": "St Lucie County International Airport", + "city": "Fort Pierce" + }, + { + "airportname": "Alexandria-US", + "city": "Alexandria" + }, + { + "airportname": "Taunton Municipal Airport - King Field", + "city": "Taunton" + }, + { + "airportname": "Plymouth Municipal Airport", + "city": "Plymouth" + }, + { + "airportname": "Quonset State Airport", + "city": "North Kingstown" + }, + { + "airportname": "Mansfield Municipal", + "city": "Mansfield" + }, + { + "airportname": "Norwood Memorial Airport", + "city": "Norwood" + }, + { + "airportname": "Barnes Municipal", + "city": "Westfield" + }, + { + "airportname": "Windham Airport", + "city": "Willimantic" + }, + { + "airportname": "Orange County Airport", + "city": "Montgomery" + }, + { + "airportname": "Capital City Airport Harrisburg", + "city": "Harrisburg" + }, + { + "airportname": "Marshfield Municipal Airport", + "city": "Marshfield" + }, + { + "airportname": "Danbury Municipal Airport", + "city": "Danbury" + }, + { + "airportname": "Boire Field Airport", + "city": "Nashua" + }, + { + "airportname": "Lawrence Municipal Airport", + "city": "Lawrence" + }, + { + "airportname": "Waterbury-Oxford Airport", + "city": "Oxford" + }, + { + "airportname": "Fitchburg Municipal Airport", + "city": "Fitchburg" + }, + { + "airportname": "Stockmar Airport", + "city": "Villa Rica" + }, + { + "airportname": "Cartersville Airport", + "city": "Cartersville" + }, + { + "airportname": "Centre-Piedmont-Cherokee County Regional Airport", + "city": "Centre" + }, + { + "airportname": "Richard B Russell Airport", + "city": "Rome" + }, + { + "airportname": "Northeast Alabama Regional Airport", + "city": "Gadsden" + }, + { + "airportname": "Knoxville Downtown Island Airport", + "city": "Knoxville" + }, + { + "airportname": "Barrow County Airport", + "city": "Winder" + }, + { + "airportname": "Plantation Airpark", + "city": "Sylvania" + }, + { + "airportname": "Dalton Municipal Airport", + "city": "Dalton" + }, + { + "airportname": "West Georgia Regional Airport - O V Gray Field", + "city": "Carrollton" + }, + { + "airportname": "Isbell Field Airport", + "city": "Fort Payne" + }, + { + "airportname": "LaGrange-Callaway Airport", + "city": "LaGrange" + }, + { + "airportname": "Baldwin County Airport", + "city": "Milledgeville" + }, + { + "airportname": "Polk County Airport - Cornelius Moore Field", + "city": "Cedartown" + }, + { + "airportname": "Harris County Airport", + "city": "Pine Mountain" + }, + { + "airportname": "Atlanta Regional Airport - Falcon Field", + "city": "Atlanta" + }, + { + "airportname": "Covington Municipal Airport", + "city": "Covington" + }, + { + "airportname": "Lee Gilmer Memorial Airport", + "city": "Gainesville" + }, + { + "airportname": "Cherokee County Airport", + "city": "Canton" + }, + { + "airportname": "DeFuniak Springs Airport", + "city": "DeFuniak Springs" + }, + { + "airportname": "Barwick Lafayette Airport", + "city": "LaFayette" + }, + { + "airportname": "Harry Clever Field Airport", + "city": "New Philadelpha" + }, + { + "airportname": "Darlington County Jetport", + "city": "Darlington" + }, + { + "airportname": "Hilton Head Airport", + "city": "Hilton Head Island" + }, + { + "airportname": "Gilmer County Airport", + "city": "Ellijay" + }, + { + "airportname": "Elizabethton Municipal Airport", + "city": "Elizabethton" + }, + { + "airportname": "Moton Field Municipal Airport", + "city": "Tuskegee" + }, + { + "airportname": "Daniel Field Airport", + "city": "Augusta" + }, + { + "airportname": "Foothills Regional Airport", + "city": "Morganton" + }, + { + "airportname": "Pike County Airport - Hatcher Field", + "city": "Pikeville" + }, + { + "airportname": "Mallards Landing Airport", + "city": "Locust Grove" + }, + { + "airportname": "Toccoa RG Letourneau Field Airport", + "city": "Toccoa" + }, + { + "airportname": "Shaftesbury-Compton Abbas Aerodrome", + "city": "Shaftesbury" + }, + { + "airportname": "Tampa Executive Airport", + "city": "Tampa" + }, + { + "airportname": "Fort Worth Alliance Airport", + "city": "Fort Worth" + }, + { + "airportname": "East Troy Municipal Airport", + "city": "East Troy" + }, + { + "airportname": "Montgomery Field", + "city": "San Diego" + }, + { + "airportname": "Lawrence Municipal", + "city": "Lawrence" + }, + { + "airportname": "Wellington Municipal", + "city": "Wellington" + }, + { + "airportname": "Griffin-Spalding County Airport", + "city": "Griffin" + }, + { + "airportname": "Pompano Beach Airpark", + "city": "Pompano Beach" + }, + { + "airportname": "Greyhound Station", + "city": "Washington DC" + }, + { + "airportname": "Shelby County Airport", + "city": "Alabaster" + }, + { + "airportname": "Gare de Strasbourg", + "city": "Strasbourg" + }, + { + "airportname": "Sky Ranch at Carefree", + "city": "Carefree" + }, + { + "airportname": "Glasgow City Heliport", + "city": "Glasgow" + }, + { + "airportname": "Indianapolis Metropolitan Airport", + "city": "Indianapolis" + }, + { + "airportname": "London-Corbin Airport-MaGee Field", + "city": "London" + }, + { + "airportname": "Fredericksburg Amtrak Station", + "city": "Fredericksburg" + }, + { + "airportname": "Buffalo Bus Terminal", + "city": "Buffalo" + }, + { + "airportname": "King St Station", + "city": "Seattle" + }, + { + "airportname": "John H. Batten Airport", + "city": "Racine" + }, + { + "airportname": "Redlands Municipal Airport", + "city": "Redlands" + }, + { + "airportname": "Chemehuevi Valley", + "city": "Chemehuevi Valley" + }, + { + "airportname": "Flabob Airport", + "city": "Riverside" + }, + { + "airportname": "Tacoma Narrows Airport", + "city": "Tacoma" + }, + { + "airportname": "Tampa North Aero Park", + "city": "Tampa" + }, + { + "airportname": "Jack Edwards Airport", + "city": "Gulf Shores" + }, + { + "airportname": "Annapolis", + "city": "Annapolis" + }, + { + "airportname": "Hazleton Municipal", + "city": "Hazleton" + }, + { + "airportname": "Greater Cumberland Rgnl.", + "city": "Cumberland" + }, + { + "airportname": "Sugar Loaf Shores Airport", + "city": "Key West" + }, + { + "airportname": "Tri-County Regional Airport", + "city": "Lone Rock" + }, + { + "airportname": "Price County Airport", + "city": "Phillips" + }, + { + "airportname": "Municipal Monroe", + "city": "Monroe" + }, + { + "airportname": "Regional Airport", + "city": "Joliet" + }, + { + "airportname": "Illinois Valley Regional", + "city": "Peru" + }, + { + "airportname": "Reynolds Field", + "city": "Jackson" + }, + { + "airportname": "Joseph A. Hardy Airport", + "city": "Connellsville" + }, + { + "airportname": "Bedford County", + "city": "Bedford" + }, + { + "airportname": "Wings Field", + "city": "Philadelphia" + }, + { + "airportname": "County", + "city": "Okeechobee" + }, + { + "airportname": "Regional - Hendricks AAF", + "city": "Sebring" + }, + { + "airportname": "Executive", + "city": "Avon Park" + }, + { + "airportname": "Gilbert Airport", + "city": "Winter Haven" + }, + { + "airportname": "Municipal Airport Zephyrhills", + "city": "Zephyrhills" + }, + { + "airportname": "International Airport", + "city": "Ocala" + }, + { + "airportname": "Jesup-Wayne County Airport", + "city": "Jesup" + }, + { + "airportname": "Madison GA Municipal Airport", + "city": "Madison" + }, + { + "airportname": "Coweta County Airport", + "city": "Newnan" + }, + { + "airportname": "McDuffie County Airport", + "city": "Thomson" + }, + { + "airportname": "Municipal Airport Aiken", + "city": "Aiken" + }, + { + "airportname": "Woodward Field", + "city": "Camden" + }, + { + "airportname": "Municipal Airport Lumberton", + "city": "Lumberton" + }, + { + "airportname": "Ridgeland Airport", + "city": "Ridgeland" + }, + { + "airportname": "Moore County Airport", + "city": "Pinehurst-Southern Pines" + }, + { + "airportname": "Richmond County Airport", + "city": "Rockingham" + }, + { + "airportname": "Bamberg County Airport", + "city": "Bamberg" + }, + { + "airportname": "Richland Airport", + "city": "Richland Center" + }, + { + "airportname": "Municipal Airport Viroqua", + "city": "Viroqua" + }, + { + "airportname": "Baraboo Wisconsin Dells Airport", + "city": "Baraboo" + }, + { + "airportname": "Foster Field", + "city": "Apple River" + }, + { + "airportname": "Regional Airport", + "city": "Statesville" + }, + { + "airportname": "Sylvania Airport", + "city": "Sturtevant" + }, + { + "airportname": "Municipal Airport Burlington", + "city": "Burlington" + }, + { + "airportname": "Stroudsburg-Pocono Airport", + "city": "East Stroudsburg" + }, + { + "airportname": "Spring Hill Airport", + "city": "Sterling" + }, + { + "airportname": "Randall Airport", + "city": "Middletown" + }, + { + "airportname": "William T. Piper Mem.", + "city": "Lock Haven" + }, + { + "airportname": "Grove City Airport", + "city": "Grove City" + }, + { + "airportname": "Lansdowne Airport", + "city": "Youngstown" + }, + { + "airportname": "Wadsworth Municipal", + "city": "Wadsworth" + }, + { + "airportname": "Ashland County Airport", + "city": "Ashland" + }, + { + "airportname": "Pittsburgh-Monroeville Airport", + "city": "Monroeville" + }, + { + "airportname": "Zelienople Municipal Airport", + "city": "Zelienople" + }, + { + "airportname": "Somerset County Airport", + "city": "Somerset" + }, + { + "airportname": "Youngstown Elser Metro Airport", + "city": "Youngstown" + }, + { + "airportname": "Braceville Airport", + "city": "Braceville" + }, + { + "airportname": "Lorain County Regional Airport", + "city": "Lorain-Elyria" + }, + { + "airportname": "Germack Airport", + "city": "Geneva" + }, + { + "airportname": "Burke Lakefront Airport", + "city": "Cleveland" + }, + { + "airportname": "Chautauqua County-Dunkirk Airport", + "city": "Dunkirk" + }, + { + "airportname": "Hamburg Inc Airport", + "city": "Hamburg" + }, + { + "airportname": "Trenton-Robbinsville Airport", + "city": "Trenton" + }, + { + "airportname": "South Jersey Regional Airport", + "city": "Mount Holly" + }, + { + "airportname": "Spitfire Aerodrome", + "city": "Pedricktown" + }, + { + "airportname": "Linden Airport", + "city": "Linden" + }, + { + "airportname": "Morgantown Airport", + "city": "Morgantown" + }, + { + "airportname": "Harford County Airport", + "city": "Churchville" + }, + { + "airportname": "Tri-State Steuben County Airport", + "city": "Angola" + }, + { + "airportname": "Plymouth Municipal Airport", + "city": "Plymouth" + }, + { + "airportname": "Warsaw Municipal Airport", + "city": "Warsaw" + }, + { + "airportname": "Van Wert County Airport", + "city": "Van Wert" + }, + { + "airportname": "Port Bucyrus-Crawford County Airport", + "city": "Bucyrus" + }, + { + "airportname": "Lake Wales Municipal Airport", + "city": "Lake Wales" + }, + { + "airportname": "Brooks Field Airport", + "city": "Marshall" + }, + { + "airportname": "Genesee County Airport", + "city": "Batavia" + }, + { + "airportname": "Finger Lakes Regional Airport", + "city": "Seneca Falls" + }, + { + "airportname": "Stormville Airport", + "city": "Stormville" + }, + { + "airportname": "Robertson Field", + "city": "Plainville" + }, + { + "airportname": "Williams County Airport", + "city": "Bryan" + }, + { + "airportname": "Clearwater Air Park", + "city": "Clearwater" + }, + { + "airportname": "South Lakeland Airport", + "city": "Lakeland" + }, + { + "airportname": "Scatsta Airport", + "city": "Scatsta" + }, + { + "airportname": "North Sea", + "city": "Claymore" + }, + { + "airportname": "North Sea", + "city": "FPSO Anasuria" + }, + { + "airportname": "North Sea", + "city": "BP Bruce" + }, + { + "airportname": "North Sea", + "city": "Buchan Alpha" + }, + { + "airportname": "North Sea", + "city": "Buzzard" + }, + { + "airportname": "North Sea", + "city": "Clyde" + }, + { + "airportname": "North Sea", + "city": "Cormorant Alpha" + }, + { + "airportname": "North Sea", + "city": "Forties Alpha" + }, + { + "airportname": "North Sea", + "city": "Forties Charlie" + }, + { + "airportname": "North Sea", + "city": "Fulmar" + }, + { + "airportname": "North Sea", + "city": "Gannet Alpha" + }, + { + "airportname": "North Sea", + "city": "Montrose Alpha" + }, + { + "airportname": "North Sea", + "city": "Tern" + }, + { + "airportname": "Gare de Lyon", + "city": "Paris" + }, + { + "airportname": "Gare de LEst", + "city": "Paris" + }, + { + "airportname": "All Airports", + "city": "Paris" + }, + { + "airportname": "All Airports", + "city": "London" + }, + { + "airportname": "All Airports", + "city": "New York" + }, + { + "airportname": "All Airports", + "city": "Chicago" + }, + { + "airportname": "Meigs Field", + "city": "Chicago" + }, + { + "airportname": "All Airports", + "city": "Washington" + }, + { + "airportname": "Pickens County Airport", + "city": "Jasper" + }, + { + "airportname": "Grand Strand Airport", + "city": "North Myrtle Beach" + }, + { + "airportname": "Lansing Municipal", + "city": "Lansing" + }, + { + "airportname": "Bloyer Field", + "city": "Tomah" + }, + { + "airportname": "Ramona Airport", + "city": "Ramona" + }, + { + "airportname": "Dole-Pont Sur Yonne Airport", + "city": "Pont Sur Yonne" + }, + { + "airportname": "Dole-St Florentin Cheu Airport", + "city": "St Florentin Cheu" + }, + { + "airportname": "Guiscriff-Saulieu Liernais Airport", + "city": "Saulieu" + }, + { + "airportname": "Creil-Meaux Esbly Airport", + "city": "Meaux" + }, + { + "airportname": "Belleau Airport", + "city": "Chateau-Thierry" + }, + { + "airportname": "Branch County Memorial Airport", + "city": "Coldwater" + }, + { + "airportname": "Wilkes-Barre Wyoming Valley Airport", + "city": "Wilkes-Barre" + }, + { + "airportname": "Lost Nation Municipal Airport", + "city": "Willoughby" + }, + { + "airportname": "Capital City Airport Franfort", + "city": "Frankfort" + }, + { + "airportname": "Lewiston Maine", + "city": "Lewiston" + }, + { + "airportname": "Florence", + "city": "Florence" + }, + { + "airportname": "Martin Campbell Field Airport", + "city": "Copperhead" + }, + { + "airportname": "Naval Air Station", + "city": "Glenview" + }, + { + "airportname": "Bloyer Field", + "city": "Tomah" + }, + { + "airportname": "Marco Islands", + "city": "Marco Island Airport" + }, + { + "airportname": "Drummond Island Airport", + "city": "Drummond Island" + }, + { + "airportname": "Garland Airport", + "city": "Lewiston" + }, + { + "airportname": "Gladwin Zettel Memorial Airport", + "city": "Gladwin" + }, + { + "airportname": "Lowell City Airport", + "city": "Lowell" + }, + { + "airportname": "South Haven Area Regional Airport", + "city": "South Haven" + }, + { + "airportname": "Schaumburg Regional", + "city": "Schaumburg" + }, + { + "airportname": "Marshfield Municipal Airport", + "city": "Marshfield" + }, + { + "airportname": "Alexander Field South Wood County Airport", + "city": "Wisconsin Rapids" + }, + { + "airportname": "Clinton Municipal", + "city": "Clinton" + }, + { + "airportname": "Beverly Municipal Airport", + "city": "Beverly" + }, + { + "airportname": "Oakdale Airport", + "city": "Oakdale" + }, + { + "airportname": "Poplar Bluff Municipal Airport", + "city": "Poplar Bluff" + }, + { + "airportname": "Somerset Airport", + "city": "Somerville" + }, + { + "airportname": "Eastport Municipal Airport", + "city": "Eastport" + }, + { + "airportname": "Keokuk Municipal Airport", + "city": "Keokuk" + }, + { + "airportname": "Banks Airport", + "city": "Swans Island" + }, + { + "airportname": "Perth Scone Airport", + "city": "Perth" + }, + { + "airportname": "Caernarfon Airport", + "city": "Caernarfon" + }, + { + "airportname": "St. Paul Downtown Airport - Holman Field", + "city": "St. Paul" + }, + { + "airportname": "Bagdad Airport", + "city": "Bagdad" + }, + { + "airportname": "Oconomowoc Airport", + "city": "Oconomowoc" + }, + { + "airportname": "Ocean Ridge Airport", + "city": "Gualala" + }, + { + "airportname": "Kent State Airport", + "city": "Kent" + }, + { + "airportname": "Bulter County Regional Airport", + "city": "Hamilton" + }, + { + "airportname": "Atlantic City Rail Terminal", + "city": "Atlantic City NJ" + }, + { + "airportname": "Springfield Amtrak Station", + "city": "Springfield MA" + }, + { + "airportname": "Amherst Amtrak Station AMM", + "city": "Amherst MA" + }, + { + "airportname": "London - Kings Cross", + "city": "London" + }, + { + "airportname": "Stevenage Railway Station", + "city": "Stevenage" + }, + { + "airportname": "Peterborough Railway Station", + "city": "Peterborough" + }, + { + "airportname": "Whittlesford Parkway Rail Station", + "city": "Whittlesford" + }, + { + "airportname": "Fond Du Lac County Airport", + "city": "Fond du Lac" + }, + { + "airportname": "Waupaca Municipal Airport", + "city": "Waupaca" + }, + { + "airportname": "Stevens Point Municipal Airport", + "city": "Stevens Point" + }, + { + "airportname": "Luce County Airport", + "city": "Newberry" + }, + { + "airportname": "Forest Lake Airport", + "city": "Forest Lake" + }, + { + "airportname": "Galion Municipal Airport", + "city": "Galion" + }, + { + "airportname": "Clarksville-Montgomery County Regional Airport", + "city": "Clarksville" + }, + { + "airportname": "Lompoc Airport", + "city": "Lompoc" + }, + { + "airportname": "Chester County G O Carlson Airport", + "city": "Coatesville" + }, + { + "airportname": "Lake Placid Airport", + "city": "Lake Placid" + }, + { + "airportname": "Long Lake", + "city": "Long Lake" + }, + { + "airportname": "Wishram Amtrak Station", + "city": "Wishram" + }, + { + "airportname": "Lima Allen County Airport", + "city": "Lima" + }, + { + "airportname": "McKinnon Airport", + "city": "Brunswick" + }, + { + "airportname": "Beaver Falls", + "city": "Beaver Falls" + }, + { + "airportname": "Seaplane Base", + "city": "Winterhaven" + }, + { + "airportname": "Georgetown County Airport", + "city": "Georgetown" + }, + { + "airportname": "Hardwick Field Airport", + "city": "Cleveland" + }, + { + "airportname": "Mark Anton Airport", + "city": "Dayton" + }, + { + "airportname": "Jefferson County Airpark", + "city": "Steubenville" + }, + { + "airportname": "Renton", + "city": "Renton" + }, + { + "airportname": "Brackett Field", + "city": "La Verne" + }, + { + "airportname": "Jekyll Island Airport", + "city": "Jekyll Island" + }, + { + "airportname": "CedarKey", + "city": "Cedar Key" + }, + { + "airportname": "Cross City", + "city": "Cross City" + }, + { + "airportname": "Clemson", + "city": "Clemson" + }, + { + "airportname": "Heber City Municipal Airport", + "city": "Heber" + }, + { + "airportname": "Beech Factory Airport", + "city": "Wichita" + }, + { + "airportname": "Cherokee County Airport", + "city": "Canton" + }, + { + "airportname": "Fernandina Beach Municipal Airport", + "city": "Fernandina Beach" + }, + { + "airportname": "Tom B. David Field Airport", + "city": "Calhoun" + }, + { + "airportname": "Habersham County Airport", + "city": "Cornelia" + }, + { + "airportname": "Georgetown Municipal Airport", + "city": "Georgetown" + }, + { + "airportname": "Old Rhinebeck Airport", + "city": "Rhinebeck" + }, + { + "airportname": "Duxford Aerodrome", + "city": "Duxford" + }, + { + "airportname": "Sidney Muni Airport", + "city": "Sidney" + }, + { + "airportname": "Luray Caverns Airport", + "city": "Luray" + }, + { + "airportname": "Eagle's Nest Airport", + "city": "Waynesboro" + }, + { + "airportname": "Kalaeloa", + "city": "Kapolei" + }, + { + "airportname": "Iosco County", + "city": "East Tawas" + }, + { + "airportname": "Madison County Executive Airport", + "city": "Huntsville" + }, + { + "airportname": "Leesburg Executive Airport", + "city": "Leesburg" + }, + { + "airportname": "Anoka County Blaine Airport", + "city": "Anoka" + }, + { + "airportname": "Williamson-Sodus Airport", + "city": "Williamson" + }, + { + "airportname": "Clear Lake Metroport", + "city": "Clear Lake City" + }, + { + "airportname": "Woking", + "city": "Fairoaks" + }, + { + "airportname": "Boulder Municipal", + "city": "Boulder" + }, + { + "airportname": "Palo Alto Airport of Santa Clara County", + "city": "Palo Alto" + }, + { + "airportname": "Mesa Falcon Field", + "city": "Mesa" + }, + { + "airportname": "Coolidge Municipal Airport", + "city": "Cooldige" + }, + { + "airportname": "Cottonwood Airport", + "city": "Cottonwood" + }, + { + "airportname": "Phoenix Regional Airport", + "city": "Phoenix" + }, + { + "airportname": "Wickenburg Municipal Airport", + "city": "Wickenburg" + }, + { + "airportname": "Oakland Co. Intl", + "city": "Pontiac" + }, + { + "airportname": "Dillant Hopkins Airport", + "city": "Keene" + }, + { + "airportname": "Glasgow Industrial", + "city": "Glasgow" + }, + { + "airportname": "Rochester Airport", + "city": "Rochester" + }, + { + "airportname": "Monroe Reqional Airport", + "city": "Charlotte" + }, + { + "airportname": "Iowa City Municipal Airport", + "city": "Iowa City" + }, + { + "airportname": "Windom Municipal Airport", + "city": "Windom" + }, + { + "airportname": "Longview Ranch Airport", + "city": "Longview" + }, + { + "airportname": "Rothera Research Station", + "city": "Rothera Research Station" + }, + { + "airportname": "Lee Airport", + "city": "Annapolis" + }, + { + "airportname": "Pecos Municipal Airport", + "city": "Pecos" + }, + { + "airportname": "Hattiesburg Bobby L. Chain Municipal Airport", + "city": "Hattiesburg" + }, + { + "airportname": "Chan Gurney", + "city": "Yankton" + }, + { + "airportname": "Selfield Airport", + "city": "Selma Alabama" + }, + { + "airportname": "Ellough", + "city": "Beccles" + }, + { + "airportname": "Brawdy RAF Airport", + "city": "Brawdy" + }, + { + "airportname": "Redhill Aerodrome", + "city": "Redhill" + }, + { + "airportname": "Frazier Lake Airpark", + "city": "Hollister" + }, + { + "airportname": "Hayward Executive Airport", + "city": "Hayward" + }, + { + "airportname": "Enstone", + "city": "Enstone" + }, + { + "airportname": "Ann Arbor Municipal Airport", + "city": "Ann Arbor" + }, + { + "airportname": "North Sea", + "city": "Gryphon FPSO" + }, + { + "airportname": "Boston Back Bay Station", + "city": "Boston" + }, + { + "airportname": "Clayton County Tara Field", + "city": "Hampton" + }, + { + "airportname": "Stapleton International Airport", + "city": "Denver" + }, + { + "airportname": "NAS Alameda", + "city": "Alameda" + }, + { + "airportname": "Wilmington Amtrak Station", + "city": "Wilmington" + }, + { + "airportname": "Elkhart Municipal", + "city": "Elkhart" + }, + { + "airportname": "Salt Lake City Intermodal Hub", + "city": "Salt Lake City" + }, + { + "airportname": "Immokalee ", + "city": "Immokalee " + }, + { + "airportname": "Rancho San Simeon Airport", + "city": "Cambria" + }, + { + "airportname": "New Carrollton Rail Station", + "city": "New Carrollton" + }, + { + "airportname": "Dinwiddie County Airport", + "city": "Petersburg" + }, + { + "airportname": "Sheboygan County Memorial Airport", + "city": "Sheboygan" + }, + { + "airportname": "Ephraim-Gibraltar Airport", + "city": "Ephraim" + }, + { + "airportname": "Pinal Airpark", + "city": "Marana" + }, + { + "airportname": "Glendale Municipal Airport", + "city": "Glendale" + }, + { + "airportname": "Safford Regional Airport", + "city": "Safford" + }, + { + "airportname": "Sikeston Memorial Municipal", + "city": "Sikeston" + }, + { + "airportname": "Port of Belfast", + "city": "Belfast" + }, + { + "airportname": "Stranraer Ferry Port", + "city": "Stranraer" + }, + { + "airportname": "Oceano County Airport", + "city": "Oceano" + }, + { + "airportname": "Floyd Bennett Memorial Airport", + "city": "Queensbury" + }, + { + "airportname": "Saratoga County Airport", + "city": "Ballston Spa" + }, + { + "airportname": "Burrello-Mechanicville Airport", + "city": "Mechanicville" + }, + { + "airportname": "Crystal River", + "city": "Crystal River" + }, + { + "airportname": "Martin State", + "city": "Baltimore" + }, + { + "airportname": "Lincoln Regional Airport Karl Harder Field", + "city": "Lincoln" + }, + { + "airportname": "Fostoria Metropolitan Airport", + "city": "Fostoria" + }, + { + "airportname": "Eastern Slopes Regional", + "city": "Fryeburg" + }, + { + "airportname": "Coral Creek", + "city": "Placida" + }, + { + "airportname": "Lakefront", + "city": "New Orleans" + }, + { + "airportname": "Pappy Boyington", + "city": "Coeur d'Alene" + }, + { + "airportname": "Beaumont Municipal", + "city": "Beaumont" + }, + { + "airportname": "Vermilion Regional", + "city": "Danville" + }, + { + "airportname": "Merritt Island Airport", + "city": "Cocoa" + }, + { + "airportname": "Valkaria Municipal", + "city": "Valkaria" + }, + { + "airportname": "Space Coast Reg'l Airport", + "city": "Titusville" + }, + { + "airportname": "Sebastian Municipal", + "city": "Sebastian" + }, + { + "airportname": "Effingham Memorial Airport", + "city": "Effingham" + }, + { + "airportname": "Andrau Airport", + "city": "Houston" + }, + { + "airportname": "Flying Cloud Airport", + "city": "Eden Prairie" + }, + { + "airportname": "Johnson County Airport", + "city": "Olathe" + }, + { + "airportname": "Apopka", + "city": "Orlando" + }, + { + "airportname": "Brandywine Airport", + "city": "West Goshen Township" + }, + { + "airportname": "Manassas", + "city": "Manassas" + }, + { + "airportname": "Texas Gulf Coast Regional", + "city": "Angleton" + }, + { + "airportname": "Elstree", + "city": "Elstree" + }, + { + "airportname": "Sandtoft Airfield", + "city": "Sandtoft" + }, + { + "airportname": "Hite Airport", + "city": "Hanksville" + }, + { + "airportname": "Queen Street Station", + "city": "Glasgow" + }, + { + "airportname": "Shelby County Airport", + "city": "Shelbyville" + }, + { + "airportname": "Grand Canyon West Airport", + "city": "Peach Springs" + }, + { + "airportname": "Enumclaw Airport", + "city": "Enumclaw" + }, + { + "airportname": "Rock Airport", + "city": "Tarentum" + }, + { + "airportname": "Plum Island Airport", + "city": "Newburyport" + }, + { + "airportname": "Kulik Lake Airport", + "city": "Kulik Lake" + }, + { + "airportname": "Central Station", + "city": "Glasgow" + }, + { + "airportname": "Euston Station", + "city": "London" + }, + { + "airportname": "Waterloo International", + "city": "London" + }, + { + "airportname": "Port Alsworth Airport", + "city": "Port alsworth" + }, + { + "airportname": "Fontaine Airport", + "city": "Belfort" + }, + { + "airportname": "Fairfield County Airport", + "city": "Winnsboro" + }, + { + "airportname": "Skyhaven Airport", + "city": "Rochester" + }, + { + "airportname": "Port Oceanic Airport", + "city": "Port Oceanic" + }, + { + "airportname": "Newton City-County Airport", + "city": "Newton" + }, + { + "airportname": "La Ferte Alais Airport", + "city": "La Ferte Alais" + }, + { + "airportname": "Bolton Field", + "city": "Columbus" + }, + { + "airportname": "Ocean Shores Municipal", + "city": "Ocean Shores" + }, + { + "airportname": "Packwood", + "city": "Packwood" + }, + { + "airportname": "Fort Bridger", + "city": "Fort Bridger" + }, + { + "airportname": "Prosser", + "city": "Prosser" + }, + { + "airportname": "Chehalis-Centralia", + "city": "Chehalis" + }, + { + "airportname": "Desert Aire", + "city": "Mattawa" + }, + { + "airportname": "Lebanon State", + "city": "Lebanon" + }, + { + "airportname": "Evanston-Uinta CO Burns Fld", + "city": "Evanston" + }, + { + "airportname": "Sabetha Municipal", + "city": "Sabetha" + }, + { + "airportname": "Mount Pleasant Regional-Faison Field", + "city": "Mount Pleasant" + }, + { + "airportname": "Jimmy Carter Regional", + "city": "Americus" + }, + { + "airportname": "Weedon Field", + "city": "Eufala" + }, + { + "airportname": "Saluda County", + "city": "Saluda" + }, + { + "airportname": "Dare County Regional", + "city": "Manteo" + }, + { + "airportname": "Auburn University Regional", + "city": "Auburn" + }, + { + "airportname": "Tri-Cities", + "city": "Endicott" + }, + { + "airportname": "Bessemer", + "city": "Bessemer" + }, + { + "airportname": "Colorado Springs East", + "city": "Ellicott" + }, + { + "airportname": "Crystal Airport", + "city": "Crystal" + }, + { + "airportname": "Clarke CO", + "city": "Quitman" + }, + { + "airportname": "W H Barron Field", + "city": "Dublin" + }, + { + "airportname": "Bus Stop Allentown", + "city": "Allentown" + }, + { + "airportname": "Binghamton Bus Terminal", + "city": "Binghamton" + }, + { + "airportname": "William F. Walsh Regional Transportation Center", + "city": "Syracuse" + }, + { + "airportname": "Union Station", + "city": "Utica" + }, + { + "airportname": "Clinton Bus Stop", + "city": "Clinton" + }, + { + "airportname": "Susquehanna Trailways Terminal", + "city": "Williamsport" + }, + { + "airportname": "Martz Trailways Bus Terminal", + "city": "Wilkes-Barre" + }, + { + "airportname": "Hazelton Bus Station", + "city": "Hazelton" + }, + { + "airportname": "Lewisburg Bus Stop", + "city": "Lewisburg" + }, + { + "airportname": "Madison NJT Station", + "city": "Madison" + }, + { + "airportname": "Maplewood NJT Station", + "city": "Maplewood" + }, + { + "airportname": "Harrisburg Transportation Center", + "city": "Harrisburg" + }, + { + "airportname": "Metro-North Station", + "city": "Poughkeepsie" + }, + { + "airportname": "Port Everglades", + "city": "Fort Lauderdale" + }, + { + "airportname": "Marigot Bus Stop", + "city": "Marigot" + }, + { + "airportname": "Summit NJT Station", + "city": "Summit" + }, + { + "airportname": "Corvallis Muni", + "city": "Corvallis" + }, + { + "airportname": "Martz Trailways", + "city": "Scranton" + }, + { + "airportname": "New Brunswick Station", + "city": "New Brunswick" + }, + { + "airportname": "Trenton Transit Center", + "city": "Trenton" + }, + { + "airportname": "Holmesburg Jct Station", + "city": "Philadelphia" + }, + { + "airportname": "White Plains", + "city": "White Plains" + }, + { + "airportname": "Southeast", + "city": "Southeast" + }, + { + "airportname": "B Street Cruise Terminal", + "city": "San Diego" + }, + { + "airportname": "Ferry Terminal Anacortes", + "city": "Anacortes" + }, + { + "airportname": "Ferry Dock", + "city": "Friday Harbor" + }, + { + "airportname": "Morristown Station", + "city": "Morristown" + }, + { + "airportname": "Port of Seattle", + "city": "Seattle" + }, + { + "airportname": "Ferry Terminal Whittier", + "city": "Whittier" + }, + { + "airportname": "Ferry Terminal Valdez", + "city": "Valdez" + }, + { + "airportname": "Ferry Dock", + "city": "Bainbridge Island" + }, + { + "airportname": "Chatsworth Station", + "city": "Chatsworth" + }, + { + "airportname": "Deer Harbor Seaplane", + "city": "Deer Harbor" + }, + { + "airportname": "San Diego Old Town Transit Center", + "city": "San Diego" + } +// tag::extract[] +] +// end::extract[] \ No newline at end of file diff --git a/modules/guides/examples/query/from-clause.n1ql b/modules/guides/examples/query/from-clause.n1ql new file mode 100644 index 000000000..cd9759d0d --- /dev/null +++ b/modules/guides/examples/query/from-clause.n1ql @@ -0,0 +1,2 @@ +SELECT airportname, city +FROM `travel-sample`.inventory.airport; \ No newline at end of file diff --git a/modules/guides/examples/query/select-clause.jsonc b/modules/guides/examples/query/select-clause.jsonc new file mode 100644 index 000000000..245c769d0 --- /dev/null +++ b/modules/guides/examples/query/select-clause.jsonc @@ -0,0 +1,5 @@ +[ + { + "greeting": "Hello world" + } +] \ No newline at end of file diff --git a/modules/guides/examples/query/select-clause.n1ql b/modules/guides/examples/query/select-clause.n1ql new file mode 100644 index 000000000..f2f901ec2 --- /dev/null +++ b/modules/guides/examples/query/select-clause.n1ql @@ -0,0 +1 @@ +SELECT "Hello world" AS greeting; \ No newline at end of file diff --git a/modules/guides/pages/.call-user-defined-function.adoc b/modules/guides/pages/.call-user-defined-function.adoc new file mode 100644 index 000000000..a92ef220a --- /dev/null +++ b/modules/guides/pages/.call-user-defined-function.adoc @@ -0,0 +1,84 @@ += Calling a User-Defined Function +:description: How to call a user-defined function from {sqlpp} statements. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-pagination: prev +:page-topic-type: guide +:page-toclevels: 2 +:imagesdir: ../assets/images +:no-escape-hatch: + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +A user-defined function can be called like any other {sqlpp} function. + +== Calling the {sqlpp} User-Defined Function + +An {sqlpp} user-defined function can be called from anywhere that a standard {sqlpp} function can be called. + +[tabs] +==== +Query Workbench:: ++ +-- +. Access the Query Workbench UI from the Administration Console. ++ +image::javascript-udfs/select-query-tool-ui.png[,500, alt="accessing the query tool"] + +. Set the context to match the namespace of the function you are calling. ++ +image::javascript-udfs/switch-context-to-travel-sample.png[] + +. Enter the {sqlpp} statement in the query editor to run your function: ++ +[source, sqlpp] +---- +include::example$javascript-udfs/execute-javascript-function.n1ql[] +---- +-- + +REST API:: ++ +-- +. Open up a shell session. +. Execute a `curl` command to run the function: ++ +[source, console] +---- +include::example$javascript-udfs/execute-scoped-function.sh[] +---- +-- + +{sqlpp}:: ++ +-- + +Run the `EXECUTE FUNCTION` function in the CBQ Shell. + +[source, sqlpp] +---- +include::example$javascript-udfs/execute-scoped-function.n1ql[] +---- + +[NOTE] +===== +The {sqlpp} user-defined function can be used in any {sqlpp} statement in exactly the same way as a standard built-in function. + +[source, sqlpp] +---- +include::example$javascript-udfs/select-true-alias-get-business-days.n1ql[] +---- +===== +-- +==== + + +== Related Links + +include::partial$javascript-udfs/further-reading.adoc[tags="create-function;user-defined-functions"] \ No newline at end of file diff --git a/modules/guides/pages/.connect.adoc b/modules/guides/pages/.connect.adoc new file mode 100644 index 000000000..44b12466e --- /dev/null +++ b/modules/guides/pages/.connect.adoc @@ -0,0 +1,188 @@ += Connecting to Couchbase Capella +:description: How to connect to a Couchbase Database. +:page-topic-type: guide +:page-toclevels: 2 +:tabs: +:github: Click the icon:github[] View button to see this code in context. +:imagesdir: ../assets/images + +include::partial$example-attributes.adoc[] + +[abstract] +-- +{description} + +include::partial$other-guide.adoc[] +-- + +== Introduction + +Connecting to Couchbase can be done in several ways. +This guide will take you through some of the most common methods used to access a Couchbase cluster with an SDK client or CLI tool. + +A Couchbase xref:server:learn:clusters-and-availability/clusters-and-availability.adoc[Cluster] is a combination of multiple server nodes, which can be accessed by users or applications with a xref:server:learn:security/usernames-and-passwords.adoc[username and password]. +Each server node can also be its own cluster or join an existing multi-node setup. + +Couchbase uses xref:server:learn:security/roles.adoc[Role Based Access Control (RBAC)] to control access to its various xref:server:learn:services-and-indexes/services/services.adoc[services]. +A user or application can connect to a cluster and use these services, assuming that valid credentials with relevant access roles are provided. + +include::partial$before-you-begin.adoc[] + +include::partial$clients.adoc[tags=!refs-ui] + +== Connecting to Couchbase Capella + +To connect to the database via Couchbase Capella, create a valid account and set up some xref:cloud:clusters:manage-database-users.adoc[database credentials]. + +=== Connecting via the Web Console + +Navigate to https://cloud.couchbase.com/sign-in[^] to access the Capella Web Console. + +image::clouds:capella-login.png["The Couchbase Capella Login"] + +See xref:cloud:organizations:ui-auth/capella-ui-auth.adoc[] for more information. + +=== Connecting via Client + +To connect an SDK or CLI client to Couchbase Capella: + +. If necessary, download a xref:get-started:create-account.adoc#next-steps[security certificate]. +(Note that the security certificate is provided with most SDKs.) + +. Use the appropriate SDK call to connect to Couchbase Capella. + +[{tabs}] +==== +ifdef::flag-devex-command-line[] +cbc:: ++ +-- +. To connect to Couchbase Capella using `cbc`, pass `-u` for the username, `-P` for the password and `-U` for the connection URL immediately after a sub-command. + +. Provide the bucket name required in the connection URL (i.e., cb..dp.cloud.couchbase.com/). + +''' + +The example below connects to a bucket on Couchbase Capella with a client certificate, and performs a `ping` to check what services are running. + +[source,sh] +---- +include::example$connect/connect-cbc.sh[tag=cbc-connect-capella] +---- + +.Result +[source,console] +---- +----------------------------------------------------------------------------------------------------------------------------------- +| type | id | status | latency, us | remote | local | +----------------------------------------------------------------------------------------------------------------------------------- +| fts | 0x7fecf9407a70 | ok | 198657 | evb8loulphaibjnn.oawlpi4audpc6jp5.cloud.couchbase.com:18094 | 172.20.10.6:54394 | +| kv | 0x7fecfb00d110 | ok | 69737 | evb8loulphaibjnn.oawlpi4audpc6jp5.cloud.couchbase.com:11207 | 172.20.10.6:54391 | +| n1ql | 0x7fecfb0110f0 | ok | 210735 | evb8loulphaibjnn.oawlpi4audpc6jp5.cloud.couchbase.com:18093 | 172.20.10.6:54392 | +| views | 0x7fecf961e2e0 | ok | 330057 | evb8loulphaibjnn.oawlpi4audpc6jp5.cloud.couchbase.com:18092 | 172.20.10.6:54393 | +----------------------------------------------------------------------------------------------------------------------------------- +---- + +{cbc-api-url} +-- +endif::flag-devex-command-line[] + +pass:[.NET]:: ++ +-- +Call the `Cluster.ConnectAsync()` method with a Couchbase Capella endpoint, username, password, and client certificate. + +''' + +{connect-cloud-example} + +[source,csharp] +---- +include::dotnet-sdk:devguide:example$dotnet/Cloud.cs[] +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.Cluster.html[Cluster^]. +-- + +Java:: ++ +-- +Call the `Cluster.connect()` method method with a Couchbase Capella endpoint, username, password, and client certificate. + +''' + +{connect-cloud-example} + +[source,java] +---- +include::java-sdk:devguide:example$Cloud.java[] +---- + +{github} + +For further details, refer to {java-api-url}/Cluster.html[Cluster^]. +-- + +Node.js:: ++ +-- +Call the `connect()` function with a Couchbase Capella endpoint, and a `ConnectOptions` object containing the username, password and client certificate. + +''' + +{connect-cloud-example} + +[source,nodejs] +---- +include::nodejs-sdk:devguide:example$nodejs/cloud.js[] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Cluster.html[Cluster^]. +-- + +Python:: ++ +-- +. Call the `Cluster.connect()` function with a Couchbase Capella endpoint, and a `ClusterOptions` object containing a `PasswordAutheticator`. + +. Provide a username and password to the `PasswordAutheticator`. + +. Provide a client certificate path to the `PasswordAutheticator`. + +''' + +{connect-cloud-example} + +[source,python] +---- +include::python-sdk:hello-world:example$cloud.py[] +---- + +{github} + +For further details, refer to {python-api-url}#cluster-object[Cluster^]. +-- +==== + +== Related Links + +Reference and explanation: + +* xref:cloud:security:security.adoc[] +* xref:cloud:organizations:organization-projects-overview.adoc[Organizations and Access] +* xref:cloud:clouds:connect-an-sdk.adoc[] + +Connecting with SDKs: + +* xref:c-sdk:howtos:managing-connections.adoc[C] +| xref:dotnet-sdk:howtos:managing-connections.adoc[.NET] +| xref:go-sdk:howtos:managing-connections.adoc[Go] +| xref:java-sdk:howtos:managing-connections.adoc[Java] +| xref:nodejs-sdk:howtos:managing-connections.adoc[Node.js] +| xref:php-sdk:howtos:managing-connections.adoc[PHP] +| xref:python-sdk:howtos:managing-connections.adoc[Python] +| xref:ruby-sdk:howtos:managing-connections.adoc[Ruby] +| xref:scala-sdk:howtos:managing-connections.adoc[Scala] diff --git a/modules/guides/pages/.create-javascript-library.adoc b/modules/guides/pages/.create-javascript-library.adoc new file mode 100644 index 000000000..d10a710f9 --- /dev/null +++ b/modules/guides/pages/.create-javascript-library.adoc @@ -0,0 +1,100 @@ += Creating a JavaScript Library +:description: How to create a JavaScript library. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-pagination: +:page-topic-type: guide +:page-toclevels: 2 +:imagesdir: ../assets/images +:no-escape-hatch: + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +You can create an external library for storing JavaScript functions. +When you create a new library you can add a new JavaScript function to the library at the same time. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +[#creating-the-library-and-adding-your-first-function] +== Creating the Library and Adding JavaScript Code + +You can use the Query Workbench UI or the REST API to create a library. +The process for creating the library is as follows: + +include::partial$javascript-udfs/diagrams.adoc[tags=javascript-udf-library-creation-sequence] + +*(1) Create library*:: Create the library by creating the logical storage for the library. + +*(2) Add the JavaScript function to the library*:: Edit the library to add your JavaScript function. + +*(3) Create {sqlpp} User-Defined Function*:: The {sqlpp} User Defined Function is needed so that it can be called as part of {sqlpp} statements (such as `SELECT` and `EXECUTE FUNCTION`). +Creating the {sqlpp} User-Defined Function is covered in xref:create-user-defined-function.adoc[]. + +As shown in xref:create-library-udf-sequence[xrefstyle=short], the library is created and the first function is added in the same step. + +[tabs] +==== +Query Workbench:: ++ +-- + +. Select btn:[Query] to access the Query Workbench, then select btn:[UDF] Query Workbench menu. ++ +image::javascript-udfs/navigate-to-udf-query.png[alt="route to the user-defined functions screen"] + +. Click on the *{plus} add function library* link in the `JavaScript Function Libraries` table to show the `Add Library` screen. + +. Select your `Namespace` from the drop-down lists. +In this example, the namespace has been set to the `inventory` scope inside the `travel-sample` bucket. +You also have the option of leaving the Namespace unset, which will the library accessible at the cluster level. ++ +image::javascript-udfs/add-scoped-library.png[,500] ++ +.A Note on Namespaces +[sidebar] +**** +The `Namespace` defines the `scope` of the library within the containing bucket. +(You can read about scopes xref:clusters:data-service/scopes-collections.adoc[here].) +Setting the namespace means that functions in the library can only be called users who have their context set to the same scope. +**** + +. Enter a name for the library in the `Library Name` field. + +. Add your own function to the library, for example: ++ +[source, javascript] +---- +include::example$javascript-udfs/get-business-days.js[] +---- +. Save the library by pressing the btn:[Save] button. ++ +TIP: You can, of course, create an empty library and add functions to it later. +-- + + +REST API:: ++ +-- +. Start a shell session. +. Run a `curl` command to create a JavaScript library within a desired scope. ++ +[source, console] +---- +include::example$javascript-udfs/create-scoped-javascript-function-with-rest.sh[] +---- +The parameters in the URL denote that the function should reside in the `travel-sample` bucket, under the `inventory` scope within that bucket. +-- +==== + +When you have created an external library and added JavaScript code, you must create an {sqlpp} user-defined function to reference the JavaScript code in the library, so it can be called as part of any {sqlpp} statement. + +== Related Links + +include::partial$javascript-udfs/further-reading.adoc[tags="user-defined-functions-ui;rest-create-library-call"] diff --git a/modules/guides/pages/.create-user-defined-function.adoc b/modules/guides/pages/.create-user-defined-function.adoc new file mode 100644 index 000000000..4aae487e3 --- /dev/null +++ b/modules/guides/pages/.create-user-defined-function.adoc @@ -0,0 +1,87 @@ += Creating a User-Defined Function +:description: How to create a user-defined function to call external JavaScript code. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-pagination: +:page-topic-type: guide +:page-toclevels: 2 +:keywords: N1QL, UDF, user-defined function, SQL++ +:imagesdir: ../assets/images +:no-escape-hatch: + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +You cannot call external JavaScript code directly from a {sqlpp} query. +You must create a {sqlpp} user-defined function to reference the external JavaScript code. + +If you have created a JavaScript function in an external library (see xref:create-javascript-library.adoc[]), you must create a {sqlpp} user-defined function to reference it. + +You can also create a {sqlpp} user-defined function and the external JavaScript code in a single operation. +In this case, the JavaScript code is not stored in an external library. + +[#creating-the-n1ql-udf-function] +== Creating a {sqlpp} User-Defined Function to Reference an External Library + +To create a {sqlpp} user-defined function to reference an external library, do one of the following: + +* Use the xref:tools:udfs-ui.adoc[UDF UI] in the Query Workbench. +* Use the {sqlpp} xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] statement, and reference the external library and JavaScript function. + +[tabs] +==== +Query Workbench:: ++ +-- +. Access the *UDF* screen from the administration console. ++ +image::javascript-udfs/navigate-to-udf-query.png[] + +. Click on the *{plus}{nbsp}add function* link. ++ +image::javascript-udfs/my-library-list-add-function-button.png[alt="library list"] ++ +The *Add Function* dialog is displayed. ++ +image::javascript-udfs/add-function-dialog.png[ ,400] + +. Use the *Namespace* drop-down lists to select the bucket and scope where your JavaScript function resides. + +. Fill in the *Function Name* of your {sqlpp} user-defined function. + +. Specify *Parameters* for the function. ++ +NOTE: The `...` in the parameters box denotes a variable length list of parameters. + +. Select *JavaScript* for the function type. +A field appears in the dialog with a list of available libraries in the namespace you selected. ++ +image::javascript-udfs/add-function-dialog-switch-to-javascript.png[] ++ +From this list select the library containing your function. + +. Enter the name of the JavaScript function in the `Library Function Name` field. +-- + +{sqlpp}:: ++ +-- +Execute the `CREATE FUNCTION` in the CBQ Shell to create the {sqlpp} user-defined function: + +[source, sqlpp] +---- +include::example$javascript-udfs/create-scoped-n1ql-udf.n1ql[] +---- +-- +==== + +NOTE: The {sqlpp} user-defined function will take the same scope as the JavaScript UDF it is referencing. + +== Related Links + +* To create a {sqlpp} user-defined function and the external JavaScript code in a single operation, see xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. diff --git a/modules/guides/pages/.javascript-udfs.adoc b/modules/guides/pages/.javascript-udfs.adoc new file mode 100644 index 000000000..012a2a00f --- /dev/null +++ b/modules/guides/pages/.javascript-udfs.adoc @@ -0,0 +1,45 @@ += User-Defined Functions with JavaScript +:description: How to extend the {sqlpp} query language by adding your own functions written in JavaScript. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-pagination: next +:page-topic-type: guide +:page-toclevels: 2 +:xrefstyle: short +:no-escape-hatch: + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +{sqlpp} includes a large number of built-in operations and functions that cover every aspect of data manipulation. +User-defined functions enable you to create your own extensions to the language. + +Using user-defined functions, you can: + +* Create reuseable, domain-specific functions for use in your applications. +* Execute complex logic that may be difficult to do in {sqlpp}. +* Migrate from RDBMS stored procedures. + +== User-Defined Functions with JavaScript + +JavaScript supported in Couchbase shares the same constructs of the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript]. However, you should be aware of the restrictions and extensions that come with the Couchbase implementation. +These are covered in xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] + +== Next Steps + +If you're looking to create your own JavaScript libraries, then there are a number of guides to get you started. + +* xref:create-javascript-library.adoc[] +* xref:call-user-defined-function.adoc[] + +If you wish to look into the constructs and available in the language itself, then you can have a look through the following pages: + +* xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] +* xref:javascript-udfs:calling-javascript-from-n1ql.adoc[] +* xref:javascript-udfs:calling-n1ql-from-javascript.adoc[] +* xref:javascript-udfs:handling-errors-javascript-udf.adoc[] diff --git a/modules/guides/pages/bulk-operations.adoc b/modules/guides/pages/bulk-operations.adoc new file mode 100644 index 000000000..accf7ffe9 --- /dev/null +++ b/modules/guides/pages/bulk-operations.adoc @@ -0,0 +1,581 @@ += Work with Documents in Bulk +:description: How to perform bulk CRUD operations with a command line tool or an SDK. +:page-pagination: prev +:page-topic-type: guide +:github: Click the icon:github[] View button to see this code in context. + +include::partial$example-attributes.adoc[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Performing bulk operations with Couchbase Capella can be done in several ways, depending on the SDK or command line tool used to perform them. +This guide contains basic procedures for performing bulk CRUD operations on documents. + +include::partial$clients.adoc[tag=refs] + +include::partial$data-warning.adoc[] + +== Creating Multiple Documents + +To create multiple documents, perform a bulk insert operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection in which to store the documents. + +. Create an array of structured documents to insert. + +. Pipe each item through the `wrap` filter to wrap it in a `content` field. + +. Pipe each item through the `insert` filter to add an `id` field with a unique value: for example, by copying a unique field from the content. + +. Pipe the output through the `doc insert` command to create the documents. + +''' + +{kv-bulk-insert-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-bulk-insert] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 3 │ 3 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_mutating[Mutating^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Create some structured JSON documents to insert. + +. Initialize a list of `IMutationResult` tasks. + +. Perform an insert operation on each document and store the result in the tasks list. + +. Wait for all the tasks to complete before accessing the results. + +''' + +{kv-bulk-insert-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-users,indent=0] + +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-bulk-insert,indent=0] + +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Create some structured JSON documents to insert. + +. Using the `reactor.core.publisher.Flux` reactive library, call the `fromIterable()` method to perform multiple insert operations. + +{kv-bulk-insert-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-users,indent=0] + +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-bulk-insert,indent=0] + +---- + +NOTE: A `JsonDocument` class is used to supplement the example. + +[source,java] +---- +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-bulk-class,indent=0] +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^] and https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html[Project Reactor^]. +-- + +Node.js:: ++ +-- +. Create some structured JSON documents to insert. + +. Perform an insert operation on each document and wait for all the promises to complete before accessing the results. + +''' + +{kv-bulk-insert-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-bulk-hello-world.js[tags=kv-users;kv-bulk-insert,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Create a dictionary of structured JSON documents. + +. Pass the dictionary to the `insert_multi()` function. This will insert all the documents in the database. + +A dictionary of `MutationResult` objects is returned. + +CAUTION: `CBCollection.insert_multi` is a xref:python-sdk:project-docs:compatibility.adoc#interface-stability[volatile] API call that is still in flux and may likely be changed. + +''' + +{kv-bulk-insert-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_bulk_hello_world.py[tags=kv-users;kv-bulk-insert,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Reading Multiple Documents + +To read multiple documents, perform a bulk `get` operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the documents are stored. + +. Create an array of document IDs. + +. Pipe each document ID through the `wrap` filter to wrap it in an `id` field. + +. Pipe the output through the `doc get` command to retrieve multiple documents by their IDs. + +''' + +{kv-bulk-get-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-bulk-get] +---- + +.Result +[source,console] +---- +╭───┬────┬────────────────────┬─────────────────────┬───────┬─────────╮ +│ # │ id │ content │ cas │ error │ cluster │ +├───┼────┼────────────────────┼─────────────────────┼───────┼─────────┤ +│ 0 │ 1 │ {record 11 fields} │ 1717505682500419584 │ │ capella │ +│ 1 │ 0 │ {record 11 fields} │ 1717505682774949888 │ │ capella │ +╰───┴────┴────────────────────┴─────────────────────┴───────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_reading[Reading^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Initialize a list of `IGetResult` tasks. + +. Perform a `get` operation on each document and store the results in the tasks list. + +. Wait for all the tasks to complete before accessing the results. + +''' + +{kv-bulk-get-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-users,indent=0] + +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-bulk-get,indent=0] + +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +Using the `reactor.core.publisher.Flux` reactive library, call the `fromIterable()` method to perform multiple `get` operations. + +''' + +{kv-bulk-get-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-users,indent=0] + +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-bulk-get,indent=0] + +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^] and https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html[Project Reactor^]. +-- + +Node.js:: ++ +-- +Perform a `get` operation on each document and wait for all the promises to complete before accessing the results. + +''' + +{kv-bulk-get-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-bulk-hello-world.js[tags=kv-users;kv-bulk-get,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +Pass some document IDs to fetch to the `get_multi()` function. This will fetch the documents from the database. + +A dictionary of `GetResult` objects is returned. + +CAUTION: `CBCollection.get_multi` is a xref:python-sdk:project-docs:compatibility.adoc#interface-stability[volatile] API call that is still in flux and may likely be changed. + +''' + +{kv-bulk-get-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_bulk_hello_world.py[tags=kv-users;kv-bulk-get,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Updating Multiple Documents + +To update multiple documents, perform a bulk upsert or replace operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the documents are stored. + +. Create an array of updated structured documents. + +. Pipe each item through the `wrap` filter to wrap it in a `content` field. + +. Pipe each item through the `insert` filter to add an `id` field with a unique value: for example, by copying a unique field from the content. + +. Pipe the output through the `doc upsert` or `doc replace` command to update the documents. + +''' + +{kv-bulk-update-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-bulk-upsert] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 3 │ 3 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_mutating[Mutating^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Add new data to update some existing JSON documents. + +. Initialize a list of `IMutationResult` tasks. + +. Perform an upsert or replace operation on each document and store the results in the tasks list. + +. Wait for all the tasks to complete before accessing the results. + +''' + +{kv-bulk-insert-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-users,indent=0] + +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-bulk-insert,indent=0] + +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Add new data to update some existing JSON documents. + +. Using the `reactor.core.publisher.Flux` reactive library, call the `fromIterable()` method to perform multiple upsert or replace operations. + +''' + +{kv-bulk-update-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-users,indent=0] + +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-bulk-upsert,indent=0] + +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^] and https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html[Project Reactor^]. +-- + +Node.js:: ++ +-- +. Add new data to update some existing JSON documents. + +. Perform an upsert operation on each document and wait for all the promises to complete before accessing the results. + +''' + +{kv-bulk-update-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-bulk-hello-world.js[tags=kv-users;kv-bulk-upsert,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Add new data to update some existing JSON documents. + +. Pass the new document data to `upsert_multi()`. This will update all the documents in the database. + +A dictionary of `MutationResult` objects is returned. + +CAUTION: `CBCollection.upsert_multi` is a xref:python-sdk:project-docs:compatibility.adoc#interface-stability[volatile] API call that is still in flux and may likely be changed. + +''' + +{kv-bulk-update-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_bulk_hello_world.py[tags=kv-users;kv-bulk-upsert,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Deleting Multiple Documents + +To delete multiple documents, perform a bulk remove operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the documents are stored. + +. Create an array of document IDs. + +. Pipe each document ID through the `wrap` filter to wrap it in an `id` field. + +. Pipe the output through the `doc remove` command to delete multiple documents by their IDs. + +''' + +{kv-bulk-delete-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-bulk-delete] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 3 │ 3 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_removing[Removing^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Initialize a list of tasks. + +. Perform a remove operation on each document and store the results in the tasks list. + +. Wait for all the tasks to complete. + +''' + +{kv-bulk-delete-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-users,indent=0] + +include::dotnet-sdk:hello-world:example$KvBulkHelloWorld.csx[tag=kv-bulk-remove,indent=0] + +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +Using the `reactor.core.publisher.Flux` reactive library, call the `fromIterable()` method to perform multiple remove operations. + +''' + +{kv-bulk-delete-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-users,indent=0] + +include::java-sdk:devguide:example$java/KvBulkHelloWorld.java[tag=kv-bulk-remove,indent=0] + +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^] and https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html[Project Reactor^]. +-- + +Node.js:: ++ +-- +Perform a remove operation on each document and wait for all the promises to complete before accessing the results. + +''' + +{kv-bulk-delete-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-bulk-hello-world.js[tags=kv-users;kv-bulk-remove,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +Pass the document IDs to remove to the `remove_multi()` function. This will delete the documents from the database. + +A dictionary of `MutationResult` objects is returned. + +CAUTION: `CBCollection.remove_multi` is a xref:python-sdk:project-docs:compatibility.adoc#interface-stability[volatile] API call that is still in flux and may likely be changed. + +''' + +{kv-bulk-delete-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_bulk_hello_world.py[tags=kv-users;kv-bulk-remove,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Related Links + +Bulk Operations with SDKs: + +* xref:c-sdk:howtos:concurrent-async-apis.adoc[C] +| xref:dotnet-sdk:howtos:concurrent-async-apis.adoc[.NET] +| xref:go-sdk:howtos:concurrent-async-apis.adoc[Go] +| xref:java-sdk:howtos:concurrent-async-apis.adoc[Java] +| xref:nodejs-sdk:howtos:concurrent-async-apis.adoc[Node.js] +| xref:php-sdk:howtos:concurrent-async-apis.adoc[PHP] +| xref:python-sdk:howtos:concurrent-async-apis.adoc[Python] +| xref:ruby-sdk:howtos:concurrent-async-apis.adoc[Ruby] +| xref:scala-sdk:howtos:concurrent-async-apis.adoc[Scala] diff --git a/modules/guides/pages/cbo.adoc b/modules/guides/pages/cbo.adoc new file mode 100644 index 000000000..9a44efef0 --- /dev/null +++ b/modules/guides/pages/cbo.adoc @@ -0,0 +1,238 @@ += Use the Cost-Based Optimizer with Queries +:page-topic-type: guide +:page-partial: +:page-pagination: prev +:imagesdir: ../assets/images +:description: How to use the Cost-Based Optimizer and manage optimizer statistics. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +The Cost-Based Optimizer enables the Query service to create the most efficient plan to execute a query. +// end::intro[] +The Cost-Based Optimizer analyzes keyspace statistics, index statistics, and distribution statistics to select the optimal indexes and create the query execution plan. + +The Cost-Based Optimizer can generate a query plan for +xref:n1ql:n1ql-language-reference/selectintro.adoc[SELECT], +xref:n1ql:n1ql-language-reference/update.adoc[UPDATE], +xref:n1ql:n1ql-language-reference/delete.adoc[DELETE], +xref:n1ql:n1ql-language-reference/merge.adoc[MERGE], and +xref:n1ql:n1ql-language-reference/insert.adoc[INSERT INTO with SELECT] queries. + +NOTE: If the Cost-Based Optimizer is unavailable or inactive, or if statistics are not available, the Query service falls back on the legacy _rules-based optimizer_ to generate the query execution plan. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Activating the Cost-Based Optimizer + +The Cost-Based Optimizer is active by default. +This section shows how to activate or deactivate the Cost-Based Optimizer for a request. +You can also activate or deactivate the Cost-Based Optimizer for a query node, or for all the query nodes in the cluster. + +[tabs] +==== +Query Tab:: ++ +-- +To activate or deactivate the Cost-Based Optimizer for a request, use the Query Options window. + +. Click *Query Options* to display the Query Options window. + +. Check or uncheck the *Use Cost-Based Optimizer* box as required. + +. Choose btn:[Save] to save the preferences and return to the Query tab. + +''' + +The following setting deactivates the Cost-Based Optimizer for subsequent requests on this Query node. + +image::cbo-inactive.png['The Run-Time Preferences dialog, with Use Cost-Based Optimizer unchecked'] + +The following setting activates the Cost-Based Optimizer for subsequent requests on this Query node. + +image::cbo-active.png['The Run-Time Preferences dialog, with Use Cost-Based Optimizer checked'] +-- + +CBQ Shell:: ++ +-- +To activate or deactivate the Cost-Based Optimizer for a request, use `\SET` command with the `use_cbo` parameter. + +NOTE: The parameter name must be prefixed by a hyphen. +The parameter is set to `true` by default. + +''' + +For example, the following code deactivates the Cost-Based Optimizer for subsequent requests on this Query node. + +[source,sqlpp] +---- +\SET -use_cbo false; +---- + +The following code activates the Cost-Based Optimizer for subsequent requests on this Query node. + +[source,sqlpp] +---- +\SET -use_cbo true; +---- +-- +==== + +For more information and examples, refer to xref:n1ql:n1ql-manage/query-settings.adoc[]. + +== Updating Statistics + +Before you can use the Cost-Based Optimizer with a query, you must first gather the statistics that it needs. +The Query service automatically gathers statistics whenever an index is created or built, and you can update statistics at any time. + +include::n1ql:page$n1ql-language-reference/statistics-expressions.adoc[tags=overview] + +=== Updating Statistics for Expressions + +To gather statistics for specified expressions, use the `UPDATE STATISTICS` command. + +==== +The following example creates two indexes, gathers statistics for the index key expressions _and_ for predicate required by the query, and then runs the query. + +.Context +include::partial$query-context.adoc[tag=step] + +.Create indexes +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-expr.n1ql[tag=indexes] +---- + +.Update statistics +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-expr-predicate.n1ql[tag=update] +---- + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-expr-predicate.n1ql[tag=query] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/statistics-expressions.adoc[Update Statistics for Index Expressions]. + +=== Updating Statistics for an Index + +To gather statistics for all the index key expressions used by an index, use the `UPDATE STATISTICS` command with the `INDEX` clause. + +==== +For example, the following query gathers statistics for all the index expressions used by the specified index. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-index.n1ql[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/statistics-index.adoc[Update Statistics for a Single Index]. + +=== Updating Statistics for Multiple Indexes + +To gather statistics for all the index key expressions used by multiple indexes, use the `UPDATE STATISTICS` command with the `INDEX` clause and a list of index names. + +==== +For example, the following query gathers statistics for the index expressions used by the specified indexes. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-indexes.n1ql[] +---- + +''' + +The following query gathers statistics for the index expressions used by all indexes in the specified keyspace. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-indexes-all.n1ql[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/statistics-indexes.adoc[Update Statistics for Multiple Indexes]. + +=== Deleting Statistics + +To delete statistics, use the `UPDATE STATISTICS` command with the `DELETE` clause. + +NOTE: Deleting statistics for a set of index expressions effectively turns off the Cost-Based Optimizer for queries which use predicates on those expressions. + +==== +For example, the following query deletes statistics for the specified index expressions. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-delete.n1ql[] +---- + +''' + +The following query deletes statistics for the index expressions used by all indexes in the specified keyspace. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/statistics-delete-all.n1ql[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/statistics-delete.adoc[Delete Statistics]. + +== Related Links + +Explanation: + +* xref:n1ql:n1ql-language-reference/cost-based-optimizer.adoc[Cost-Based Optimizer] + +Reference: + +* xref:n1ql:n1ql-language-reference/updatestatistics.adoc[UPDATE STATISTICS] + +Administrator guides: + +* xref:clusters:query-service/query-workbench.adoc#query-settings[Modify Query Settings] +* xref:n1ql:n1ql-intro/sysinfo.adoc#sys-dictionary[Monitor Statistics] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/create-index.adoc b/modules/guides/pages/create-index.adoc new file mode 100644 index 000000000..3e71edb76 --- /dev/null +++ b/modules/guides/pages/create-index.adoc @@ -0,0 +1,568 @@ += Create Indexes +:page-topic-type: guide +:imagesdir: ../assets/images +:page-partial: +:page-pagination: +:github: Click the icon:github[] View button to see this code in context. +:work-with: create +:primary-name: pass:q[If you don't specify a name, the index is called `#primary`.] +:description: How to create primary indexes and secondary indexes. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +You don't need to create an index to query a keyspace. +However, an index can help you to query a keyspace more efficiently. +The Index service enables you to create two types of index: primary indexes and secondary indexes. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Creating a Primary Index + +A primary index is an index of document keys. +Primary indexes are optional. +They may improve the efficiency of ad-hoc queries that are not supported by a secondary index. + +You can create a primary index using a {sqlpp} statement or an SDK call. + +[tabs] +==== +{sqlpp}:: ++ +-- +To create a primary index, use the `CREATE PRIMARY INDEX` command. + +1. If required, specify a name for the primary index. +{primary-name} + +2. Use the `ON` keyword to specify the keyspace on which to create the index. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query creates an unnamed primary index on the `airline` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-pri-nameless.n1ql[tag=query] +---- + +The following query creates a primary index named `travel_primary` on the `airline` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-pri-name.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/createprimaryindex.adoc[CREATE PRIMARY INDEX]. +-- + +.NET:: ++ +-- +To create a primary index, use the task `CreatePrimaryIndexAsync()` on the interface `IQueryIndexManager`. + +1. Specify the keyspace on which to create the index. + +2. If you want to specify a name for the index: + + a. Use `CreatePrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, use the `IndexName` method to specify the index name. + ++ +{primary-name} + +''' + +The following example creates an unnamed primary index. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=primary,indent=0] +---- + +The following example creates a named primary index on the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.IQueryIndexManager.html[IQueryIndexManager^]. +-- + +Java:: ++ +-- +To create a primary index, use the `createPrimaryIndex` method. + +1. Specify the keyspace on which to create the index. + +2. If you want to specify a name for the index: + + a. Use `CreatePrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, use the `IndexName` method to specify the index name. + ++ +{primary-name} + +''' + +The following example creates an unnamed primary index. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=primary,indent=0] +---- + +The following example creates a named primary index on the specified keyspace. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/QueryIndexManager.html[QueryIndexManager^]. +-- + +Node.js:: ++ +-- +To create a primary index, use the `createPrimaryIndex` function on a `QueryIndexManager` object. + +1. Specify the keyspace on which to create the index. + +2. If you want to specify a name for the index: + + a. Use `CreatePrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, use the `name` property to specify the index name. + ++ +{primary-name} + +''' + +The following example creates an unnamed primary index. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=primary,indent=0] +---- + +The following example creates a named primary index on the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/classes/QueryIndexManager.html[QueryIndexManager^]. +-- + +Python:: ++ +-- +To create a primary index, use the `create_primary_index` function on a `QueryIndexManager` object. + +1. Specify the keyspace on which to create the index. + +2. If you want to specify a name for the index: + + a. Use `CreatePrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, use the `index_name` property to specify the index name. + ++ +{primary-name} + +''' + +The following example creates an unnamed primary index. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=primary,indent=0] +---- + +The following example creates a named primary index on the specified keyspace. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +== Creating a Secondary Index + +A secondary index is actually the main type of index that queries use. +For this reason, they are also known as Global Secondary Indexes or GSIs. +You can create a secondary index on any fields or expressions necessary to support your queries. + +You can create a secondary index using a {sqlpp} statement or an SDK call. + +[tabs] +==== +{sqlpp}:: ++ +-- +To create a secondary index, use the `CREATE INDEX` statement. + +1. Specify a name for the index. + +2. Use the `ON` keyword to specify the keyspace on which to create the index. + +3. Specify the index key (the expression or expressions to index) in parentheses `()`. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query creates a secondary index on the `name` field in the `airline` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-name.n1ql[] +---- + +The following query creates a secondary index on an expression using the `name` field in the `airline` keyspace. + +[source,sqlpp] +---- +include::learn:example$services-and-indexes/indexes/create-idx-expr.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/createindex.adoc[CREATE INDEX]. +-- + +.NET:: ++ +-- +To create a secondary index, use the task `CreateIndexAsync()` on the interface `IQueryIndexManager`. + +1. Specify the keyspace on which to create the index. + +2. Specify a name for the index. + +3. Specify the field to index. + +''' + +The following example creates a secondary index on the `name` field in the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.IQueryIndexManager.html[IQueryIndexManager^]. +-- + +Java:: ++ +-- +To create a secondary index, use the `createIndex` method. + +1. Specify the keyspace on which to create the index. + +2. Specify a name for the index. + +3. Specify the field to index. + +''' + +The following example creates a secondary index on the `name` field in the specified keyspace. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/QueryIndexManager.html[QueryIndexManager^]. +-- + +Node.js:: ++ +-- +To create a secondary index, use the `createIndex` function on a `QueryIndexManager` object. + +1. Specify the keyspace on which to create the index. + +2. Specify a name for the index. + +3. Specify the field to index. + +''' + +The following example creates a secondary index on the `name` field in the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/classes/QueryIndexManager.html[QueryIndexManager^]. +-- + +Python:: ++ +-- +To create a secondary index, use the `create_index` function on a `QueryIndexManager` object. + +1. Specify the keyspace on which to create the index. + +2. Specify a name for the index. + +3. Specify the field to index. + +''' + +The following example creates a secondary index on the `name` field in the specified keyspace. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +=== Creating a Composite Index + +A _composite index_ is a secondary index which contains multiple index keys. + +You can create a composite index using a {sqlpp} statement or an SDK call. + +[tabs] +==== +{sqlpp}:: ++ +-- +To create a composite index, specify multiple index keys in the index definition, separated by commas. + +''' + +The following example creates a secondary index on the `name`, `id`, `icao`, and `iata` fields in the `airline` keyspace. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::learn:example$services-and-indexes/indexes/create-idx-composite.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/createindex.adoc[CREATE INDEX]. +-- + +.NET:: ++ +-- +To create a composite index, specify multiple fields in the index definition. + +''' + +The following example creates a secondary index on the `name`, `id`, `icao`, and `iata` fields in the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=composite,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.IQueryIndexManager.html[IQueryIndexManager^]. +-- + +Java:: ++ +-- +To create a composite index, specify multiple fields in the index definition. + +''' + +The following example creates a secondary index on the `name`, `id`, `icao`, and `iata` fields in the specified keyspace. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=composite,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/QueryIndexManager.html[QueryIndexManager^]. +-- + +Node.js:: ++ +-- +To create a composite index, specify multiple fields in the index definition. + +''' + +The following example creates a secondary index on the `name`, `id`, `icao`, and `iata` fields in the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=composite,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/classes/QueryIndexManager.html[QueryIndexManager^]. +-- + +Python:: ++ +-- +To create a composite index, specify multiple fields in the index definition. + +''' + +The following example creates a secondary index on the `name`, `id`, `icao`, and `iata` fields in the specified keyspace. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=composite,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +=== Creating an Index on Metadata + +You can also create a secondary index using document metadata. + +To index metadata information, use the xref:n1ql:n1ql-language-reference/metafun.adoc#meta[META()] function in the index key. + +==== +The following example creates a secondary index on the document key. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/meta-idx-id.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/indexing-meta-info.adoc[Indexing Metadata Information]. + +=== Creating an Index on an Array + +You can use an _array index_ to optimize queries on fields which are nested within array elements. + +To create an array index, specify the index key as follows: + +1. Use the `ALL` keyword to index all values in the specified fields, or `DISTINCT` to index only distinct values. + +2. Use a field name to index the entire array, or use an xref:n1ql:n1ql-language-reference/collectionops.adoc#array[ARRAY] operator to index nested fields within the array. + +==== +The following example creates an index on distinct values of the `day` field within the `schedule` field. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::server:learn:example$services-and-indexes/indexes/create-idx-array.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/indexing-arrays.adoc[Array Indexing]. + +=== Creating a Partial Index + +A _partial index_ is an index on a subset of documents within a keyspace -- for example, just the documents which have a specific schema. + +To create an index on a subset of documents, use the WHERE clause to specify the distinguishing field(s) for that subset. + +==== +The following example creates an index on documents in which the value of the `activity` field is `eat`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::server:learn:example$services-and-indexes/indexes/create-idx-partial.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/indexing-and-query-perf.adoc#partial-index[Partial Index]. + +=== Creating a Covering Index + +A _covering index_ is an index which contains all the fields in the query projection, not just the fields that are required for joins or filtering. +A covering index is therefore usually a composite index. +If a query uses a covering index, the query can get all the data it needs from the index, and the Query service does not have to make a fetch request to the Data service. + +To create a covering index, make sure the index includes all the fields and expressions required by the query. + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/covering-indexes.adoc[Covering Indexes]. + +== Related Links + +Reference and explanation: + +* xref:server:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes] + +Administrator guides: + +* xref:cloud:clusters:index-service/manage-indexes.adoc[Manage Indexes] +* xref:cloud:clusters:index-service/manage-indexes.adoc#accessing-indexes-in-the-capella-ui[Monitor Indexes] + +Indexes with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#indexes[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#indexes[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#indexes[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#indexes[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#indexes[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#indexes[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#indexes[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#indexes[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#indexes[Scala] diff --git a/modules/guides/pages/creating-data.adoc b/modules/guides/pages/creating-data.adoc new file mode 100644 index 000000000..d90eb92ce --- /dev/null +++ b/modules/guides/pages/creating-data.adoc @@ -0,0 +1,306 @@ += Create Documents +:description: How to create documents with a command line tool or an SDK. +:page-pagination: full +:page-topic-type: guide +:page-toclevels: 2 +:github: Click the icon:github[] View button to see this code in context. + +include::partial$example-attributes.adoc[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Couchbase stores its xref:server:learn:data/data.adoc[data] as either JSON or Binary [.term]#documents# with unique IDs (primary keys) by which they can be located. + +Documents are organized and grouped in [.term]#buckets# using xref:clusters:data-service/about-buckets-scopes-collections.adoc[scopes and collections]. +If a scope or collection is not provided when creating a document, Couchbase will automatically store data in the `_default` collection or `_default` scope. + +include::partial$clients.adoc[tag=refs] + +include::partial$data-warning.adoc[] + +== Inserting a Document + +To create a single document, perform an insert operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection in which to store the document. + +. Create a structured JSON object containing your data. + +. Use `doc insert` to create the document. + +''' + +{kv-insert-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-insert] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +NOTE: If the document already exists, Couchbase Shell returns a `Key already exists` error. + +For further details, refer to {cbsh-api-url}/#_mutating[Mutating^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Create a structured document object containing your data. + +. Use the `InsertAsync()` method to insert the document in a given keyspace. + +A `MutationResult` object is returned containing the result and metadata relevant to the insert operation. + +''' + +{kv-insert-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-insert,indent=0] +---- + +NOTE: If the document already exists, the SDK returns a `DocumentExistsException` error. + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Create a structured document object containing your data. + +. Use the `insert()` method to insert the document in a given keyspace. + +A `MutationResult` object is returned containing the result and metadata relevant to the insert operation. + +''' + +{kv-insert-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-insert,indent=0] +---- + +NOTE: If the document already exists, the SDK returns a `DocumentExistsException` error. + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +. Create a structured document object containing your data. + +. Use the `insert()` method to insert the document in a given keyspace. + +A `MutationResult` promise is returned containing the result and metadata relevant to the insert operation. + +''' + +{kv-insert-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-insert,indent=0] +---- + +NOTE: If the document already exists, the SDK returns a `DocumentExistsError` error. + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Create a structured document object containing your data. + +. Use the `insert()` function to insert the document in a given keyspace. + +A `MutationResult` object is returned containing the result and metadata relevant to the insert operation. + +''' + +{kv-insert-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-insert,indent=0] +---- + +NOTE: If the document already exists, the SDK returns a `DocumentExistsException` error. + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +When a document is created, Couchbase assigns it a xref:java-sdk:howtos:concurrent-document-mutations.adoc[CAS (Compare And Swap)] value to keep track of the document's state within the database. +Each time a document is mutated the CAS will change accordingly. +This unique value allows the database to protect against concurrent updates to the same document. + +=== Inserting with Options + +To specify further parameters for the inserted document, such as expiry, add the options to the insert operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection in which to store the document. + +. Create a structured JSON object containing your data. + +. Use `doc insert` to create the document. + +. Pass any required options, such as `--expiry`. + +''' + +{kv-insert-with-options-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-insert-expiry] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_mutating[Mutating^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Create a structured document object containing your data. + +. Use the `InsertAsync()` method to insert the document with a given option parameter. + +''' + +{kv-insert-with-options-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-insert-with-opts,indent=0] +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Create a structured document object containing your data. + +. Use the `insert()` method to insert the document with a given option parameter. + +''' + +{kv-insert-with-options-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-insert-with-opts,indent=0] +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +. Create a structured document object containing your data. + +. Use the `insert()` function to insert the document with a given option parameter. + +''' + +{kv-insert-with-options-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-insert-with-opts,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Create a structured document object containing your data. + +. Use the `insert()` function to insert the document with a given option parameter. + +''' + +{kv-insert-with-options-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-insert-with-opts,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Related Links + +Key-Value Operations with SDKs: + +* xref:c-sdk:howtos:kv-operations.adoc[C] +| xref:dotnet-sdk:howtos:kv-operations.adoc[.NET] +| xref:go-sdk:howtos:kv-operations.adoc[Go] +| xref:java-sdk:howtos:kv-operations.adoc[Java] +| xref:nodejs-sdk:howtos:kv-operations.adoc[Node.js] +| xref:php-sdk:howtos:kv-operations.adoc[PHP] +| xref:python-sdk:howtos:kv-operations.adoc[Python] +| xref:ruby-sdk:howtos:kv-operations.adoc[Ruby] +| xref:scala-sdk:howtos:kv-operations.adoc[Scala] diff --git a/modules/guides/pages/data.adoc b/modules/guides/pages/data.adoc new file mode 100644 index 000000000..faa5b0cba --- /dev/null +++ b/modules/guides/pages/data.adoc @@ -0,0 +1,44 @@ += Work with Your Data +:page-role: tiles -toc +:description: The Data Service offers Couchbase clients the fastest and simplest way to create, retrieve, or mutate data. +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Key-Value Operations + +Use the Couchbase Capella UI or an SDK to create, read, update, or delete data. + +* xref:kv-operations.adoc[] + +== Import and Export + +Use the Couchbase Capella UI, an SDK, or a command-line tool to import data. +Use a command-line tool to export data. + +* xref:load.adoc[] + +== Related Links + +Refer to the following for information on the Data Service. + +* xref:clusters:data-service/data-service.adoc[] \ No newline at end of file diff --git a/modules/guides/pages/defer-index.adoc b/modules/guides/pages/defer-index.adoc new file mode 100644 index 000000000..0763c898a --- /dev/null +++ b/modules/guides/pages/defer-index.adoc @@ -0,0 +1,322 @@ += Defer Indexes +:page-topic-type: guide +:imagesdir: ../assets/images +:page-partial: +:page-pagination: +:github: Click the icon:github[] View button to see this code in context. +:work-with: create +:description: How to create deferred indexes and build them later. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +When you create a primary or secondary index, you can mark it as _deferred_. +This means the index is not built at once; you can build the deferred index later. +This enables you to build multiple indexes more efficiently. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Deferring an Index + +You can defer an index to be built later using a {sqlpp} statement or an SDK call. + +include::partial$index-context.adoc[] + +[tabs] +==== +{sqlpp}:: ++ +-- +To defer a primary or secondary index to be built later: + +1. Use the `WITH` clause to specify the index options. + +2. In the index options, set the `defer_build` attribute to `true`. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following queries create a set of primary and secondary indexes in the `landmark` keyspace, with build deferred until later. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-defer-1.n1ql[] +---- + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-defer-2.n1ql[] +---- + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-defer-3.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/createprimaryindex.adoc[CREATE PRIMARY INDEX] and xref:n1ql:n1ql-language-reference/createindex.adoc[CREATE INDEX]. +-- + +.NET:: ++ +-- +To defer a primary or secondary index to be built later: + +1. Use `CreatePrimaryQueryIndexOptions` or `CreateQueryIndexOptions` to specify the index options. + +2. In the index options, invoke the `Deferred` method with the argument `true`. + +''' + +The following examples create a set of primary and secondary indexes in the specified keyspace, with build deferred until later. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=defer-create-primary,indent=0] +---- + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=defer-create-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.CreatePrimaryQueryIndexOptions.html[CreatePrimaryQueryIndexOptions^] and https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.CreateQueryIndexOptions.html[CreateQueryIndexOptions^]. +-- + +Java:: ++ +-- +To defer a primary or secondary index to be built later: + +1. Use `CreatePrimaryQueryIndexOptions` or `CreateQueryIndexOptions` to specify the index options. + +2. In the index options, invoke the `deferred` method with the argument `true`. + +''' + +The following examples create a set of primary and secondary indexes in the specified keyspace, with build deferred until later. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=defer-create-primary,indent=0] +---- + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=defer-create-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/CreatePrimaryQueryIndexOptions.html[CreatePrimaryQueryIndexOptions^] and https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/CreateQueryIndexOptions.html[CreateQueryIndexOptions^]. +-- + +Node.js:: ++ +-- +To defer a primary or secondary index to be built later: + +1. Use `CreatePrimaryQueryIndexOptions` or `CreateQueryIndexOptions` to specify the index options. + +2. In the index options, set the `deferred` property to `true`. + +''' + +The following examples create a set of primary and secondary indexes in the specified keyspace, with build deferred until later. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=defer-create-primary,indent=0] +---- + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=defer-create-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/CreatePrimaryQueryIndexOptions.html[CreatePrimaryQueryIndexOptions^] and https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/CreateQueryIndexOptions.html[CreateQueryIndexOptions^]. +-- + +Python:: ++ +-- +To defer a primary or secondary index to be built later: + +1. Use `CreatePrimaryQueryIndexOptions` or `CreateQueryIndexOptions` to specify the index options. + +2. In the index options, set the `deferred` property to `True`. + +''' + +The following examples create a set of primary and secondary indexes in the specified keyspace, with build deferred until later. + +[source,python] +---- +include::python-sdk:hello-world:example$index_hello_world.py[tag=defer-create-primary,indent=0] +---- + +[source,python] +---- +include::python-sdk:hello-world:example$index_hello_world.py[tag=defer-create-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +== Building a Deferred Index +:work-with: build + +You can build one or more deferred primary or secondary indexes using a {sqlpp} statement. +You can also build all deferred indexes in a keyspace using an SDK call. + +include::partial$index-context.adoc[] + +[tabs] +==== +{sqlpp}:: ++ +-- +To build one or more deferred indexes, use the `BUILD INDEX` statement: + +1. Use the `ON` keyword to specify the keyspace which contains the index or indexes. + +2. Specify the index or indexes that you want to build in parentheses `()`. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query builds a single deferred index. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/build-idx-single.n1ql[] +---- + +The following query builds multiple deferred indexes. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/build-idx-multiple.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/build-index.adoc[BUILD INDEX]. +-- + +.NET:: ++ +-- +To build all deferred indexes in a keyspace, use the task `BuildDeferredIndexesAsync` on the interface `IQueryIndexManager`. + +''' + +The following example builds all deferred indexes in the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=defer-build,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.IQueryIndexManager.html[IQueryIndexManager()^]. +-- + +Java:: ++ +-- +To build all deferred indexes in a keyspace, use the `buildDeferredIndexes` method. + +''' + +The following example builds all deferred indexes in the specified keyspace. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=defer-build,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/QueryIndexManager.html[QueryIndexManager^]. +-- + +Node.js:: ++ +-- +To build all deferred indexes in a keyspace, use the `buildDeferredIndexes` function on a `QueryIndexManager` object. + +''' + +The following example builds all deferred indexes in the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=defer-build,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/classes/QueryIndexManager.html[QueryIndexManager^]. +-- + +Python:: ++ +-- +To build all deferred indexes in a keyspace, use the `build_deferred_indexes` function on a `QueryIndexManager` object. + +''' + +The following example builds all deferred indexes in the specified keyspace. + +[source,python] +---- +include::python-sdk:hello-world:example$index_hello_world.py[tag=defer-build,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +== Related Links + +Reference and explanation: + +* xref:cloud:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes] + +Administrator guides: + +* xref:cloud:clusters:index-service/manage-indexes.adoc[Manage Indexes] +* xref:cloud:clusters:index-service/manage-indexes.adoc#accessing-indexes-in-the-capella-ui[Monitor Indexes] + +Indexes with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#indexes[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#indexes[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#indexes[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#indexes[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#indexes[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#indexes[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#indexes[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#indexes[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#indexes[Scala] diff --git a/modules/guides/pages/delete.adoc b/modules/guides/pages/delete.adoc new file mode 100644 index 000000000..d9ab6a1a8 --- /dev/null +++ b/modules/guides/pages/delete.adoc @@ -0,0 +1,172 @@ += Delete Data with a Query +:page-topic-type: guide +:imagesdir: ../assets/images +:tabs: +:page-partial: +:page-pagination: prev +:description: How to delete documents using {sqlpp}. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +To delete documents from a keyspace, you can use the DELETE statement or the MERGE statement. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +include::partial$data-warning.adoc[] + +== Deleting Documents by Key + +To delete one or more documents by key, use the DELETE statement with the USE KEYS hint: + +. Use the FROM keyword to specify the keyspace which contains the documents to be deleted. +. Use the USE KEYS hint to specify a document keys or array of document keys. +. If required, use the RETURNING clause to specify what should be returned when the documents are deleted. + +You can combine this approach with the WHERE clause if necessary. + +==== +The following query deletes a document with the key `"airline_4444"` and returns the deleted document. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/delete-key.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/delete-key.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/delete.adoc[DELETE]. + +== Deleting Documents by Filter + +To delete documents by filter, use the DELETE statement with the WHERE clause: + +. Use the FROM keyword to specify the keyspace which contains the documents to be deleted. +. Use the WHERE clause to specify the condition that needs to be met for documents to be deleted. +. If required, use the LIMIT clause to specify the greatest number of documents that may be deleted. +. If required, use the RETURNING clause to specify what should be returned when the documents are deleted. + +You can combine this approach with the USE KEYS hint if necessary. + +==== +The following query deletes any airline whose callsign is `"AIR-X"`, returning the content of the airline's `id` field. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/delete-filter.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/delete-filter.jsonc[] +---- +==== + +== Deleting Documents by Subquery + +To delete documents based on the results returned by a SELECT query, use a subquery in the filter. + +==== +The following query finds the last city in alphanumeric order in the `airport` keyspace, and deletes any airports in that city. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/delete-sub-same.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/delete-sub-same.jsonc[] +---- +==== + +== Merging and Deleting Documents + +You can also delete documents by merging: that is, by joining one keyspace to another, and deleting any documents that match. + +To delete documents using a merge, use the MERGE statement with the DELETE action: + +. Use the INTO keyword to specify the target. +This is the data source containing the documents to delete. + +. Use the USING keyword to specify the source. +This is the data source to check against the target. + +. Use the ON keyword to specify the merge predicate. +This is a condition that must be met to match an object in the source with an object in the target. + +. Use WHEN MATCHED THEN DELETE to specify that when a document in the source matches a document in the target, the document in the target should be deleted. + +. If necessary, use the WHERE clause to specify any further conditions that must be met for documents to be deleted. + +. If required, use the LIMIT clause to specify the greatest number of documents that may be deleted. + +. If required, use the RETURNING clause to specify what should be returned when the documents are deleted. + +==== +The following query finds all BA routes whose source airport is in France. +If any flights are using equipment 319, they are updated to use 797. +If any flights are using equipment 757, they are deleted. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/ansi-merge-keyspace.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/ansi-merge-keyspace.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/merge.adoc[MERGE]. + +== Related Links + +Reference and explanation: + +* xref:n1ql:n1ql-language-reference/delete.adoc[DELETE] +* xref:n1ql:n1ql-language-reference/merge.adoc[MERGE] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/deleting-data.adoc b/modules/guides/pages/deleting-data.adoc new file mode 100644 index 000000000..d5de60652 --- /dev/null +++ b/modules/guides/pages/deleting-data.adoc @@ -0,0 +1,308 @@ += Delete Documents +:description: How to delete documents with a command line tool or an SDK. +:page-pagination: full +:page-topic-type: guide +:github: Click the icon:github[] View button to see this code in context. + +include::partial$example-attributes.adoc[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +In situations where data is no longer needed, Couchbase Capella provides a remove operation to delete a document from the database permanently. + +include::partial$clients.adoc[tag=refs] + +include::partial$data-warning.adoc[] + +== Deleting a Document + +To delete a document, perform a remove operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Use the `doc remove` command to delete the document by ID. + +''' + +{kv-delete-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-delete] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_removing[Removing^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +Use the `RemoveAsync()` method to delete a document from the database. + +''' + +{kv-delete-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-remove,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +Use the `remove()` method to delete a document from the database. + +''' + +{kv-delete-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-remove,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +Use the `remove()` function to delete a document from the database. + +''' + +{kv-delete-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-remove,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundError` error. + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +Use the `remove()` function to delete a document from the database. + +''' + +{kv-delete-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-remove,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Deleting a Sub-Document + +To delete a specific field within a document you can perform a sub-document remove operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Use the `doc get` command to retrieve a document by ID. + +. Pipe the document through the `reject` filter to remove the field containing the sub-document. + +. Pipe the output, including the `id` and `content` fields, through the `doc replace` command to update the document. + +''' + +{kv-subdoc-delete-example} + +[source,sh] +---- +include::example$kv/kv-subdoc.nu[tag=cbsh-subdoc-reject] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +NOTE: If the field containing the sub-document cannot be found, the `reject` command returns a `Cannot find column` error. + +For further details, refer to {nushell-api-url}/reject.html[reject for filters^] in the Nushell documentation. +-- + +pass:[.NET]:: ++ +-- +. Call the `MutateInAsync()` method, which takes a document ID and an IEnumerable containing `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned containing the result and metadata relevant to the sub-document remove operation. + +''' + +{kv-subdoc-delete-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-remove-subdoc,indent=0] +---- + +NOTE: If the path doesn't exist, the SDK will return a `PathNotFoundException` error. + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Call the `mutateIn()` method, which takes a document ID and an array of `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document remove operation. + +''' + +{kv-subdoc-delete-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-remove-subdoc,indent=0] +---- + +NOTE: If the path doesn't exist, the SDK will return a `PathNotFoundException` error. + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +. Call the `mutateIn()` method, which takes a document ID and an array of `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document remove operation. + +''' + +{kv-subdoc-delete-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-remove-subdoc,indent=0] +---- + +NOTE: If the path doesn't exist, the SDK will return a `PathNotFoundError` error. + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Call the `lookup_in()` function, which takes a document ID and a list of `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document remove operation. + +''' + +{kv-subdoc-delete-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-remove-subdoc,indent=0] +---- + +NOTE: If the path doesn't exist, the SDK will return a `PathNotFoundException` error. + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Related Links + +Key-Value Operations with SDKs: + +* xref:c-sdk:howtos:kv-operations.adoc[C] +| xref:dotnet-sdk:howtos:kv-operations.adoc[.NET] +| xref:go-sdk:howtos:kv-operations.adoc[Go] +| xref:java-sdk:howtos:kv-operations.adoc[Java] +| xref:nodejs-sdk:howtos:kv-operations.adoc[Node.js] +| xref:php-sdk:howtos:kv-operations.adoc[PHP] +| xref:python-sdk:howtos:kv-operations.adoc[Python] +| xref:ruby-sdk:howtos:kv-operations.adoc[Ruby] +| xref:scala-sdk:howtos:kv-operations.adoc[Scala] + +Sub-Document operations with SDKs: + +* xref:c-sdk:howtos:subdocument-operations.adoc[C] +| xref:dotnet-sdk:howtos:subdocument-operations.adoc[.NET] +| xref:go-sdk:howtos:subdocument-operations.adoc[Go] +| xref:java-sdk:howtos:subdocument-operations.adoc[Java] +| xref:nodejs-sdk:howtos:subdocument-operations.adoc[Node.js] +| xref:php-sdk:howtos:subdocument-operations.adoc[PHP] +| xref:python-sdk:howtos:subdocument-operations.adoc[Python] +| xref:ruby-sdk:howtos:subdocument-operations.adoc[Ruby] +| xref:scala-sdk:howtos:subdocument-operations.adoc[Scala] diff --git a/modules/guides/pages/drop-index.adoc b/modules/guides/pages/drop-index.adoc new file mode 100644 index 000000000..68eec898f --- /dev/null +++ b/modules/guides/pages/drop-index.adoc @@ -0,0 +1,355 @@ += Drop Indexes +:page-topic-type: guide +:imagesdir: ../assets/images +:page-partial: +:page-pagination: +:github: Click the icon:github[] View button to see this code in context. +:work-with: drop +:description: How to drop primary and secondary indexes. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +You can drop primary and secondary indexes when you do not need them any more. +// end::intro[] +Dropping an index that has replicas will also drop all of the replica indexes too. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Dropping a Primary Index + +You can drop a primary index using a {sqlpp} statement or an SDK call. + +include::partial$index-context.adoc[] + +[tabs] +==== +{sqlpp}:: ++ +-- +To drop an unnamed primary index, use the `DROP PRIMARY INDEX` statement. + +To drop a named primary index, use the `DROP INDEX` statement. +There are two possible syntaxes: + +* Specify the index name, then use the `ON` keyword to specify the keyspace which contains the index. + +* Specify the keyspace and index name using dotted notation. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query drops an unnamed primary index from the `airline` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/drop-pri-nameless.n1ql[tag=query] +---- + +The following query drops a named primary index from the `airline` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/drop-pri-name.n1ql[] +---- + +The following query drops the index in exactly the same way, but uses alternative syntax. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/drop-pri-alt.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/dropprimaryindex.adoc[DROP PRIMARY INDEX] and xref:n1ql:n1ql-language-reference/dropindex.adoc[DROP INDEX]. +-- + +.NET:: ++ +-- +To drop a primary index, use the task `DropPrimaryIndexAsync()` on the interface `IQueryIndexManager`. + +1. Specify the keyspace which contains the index. + +2. If the index has a name: + + a. Use `DropPrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, invoke the `IndexName` method. + +''' + +The following example drops an unnamed primary index from the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=drop-primary,indent=0] +---- + +The following example drops a named primary index from the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=drop-named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.IQueryIndexManager.html[IQueryIndexManager()^]. +-- + +Java:: ++ +-- +To drop a primary index, use the `dropPrimaryIndex` method and specify the keyspace which contains the index. + +NOTE: The Java SDK does not provide a call for dropping a named primary index. +To drop a named primary index, use a {sqlpp} query. + +''' + +The following example drops an unnamed primary index from the specified keyspace. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=drop-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/QueryIndexManager.html[QueryIndexManager^]. +-- + +Node.js:: ++ +-- +To drop a primary index, use the `dropPrimaryIndex` function on a `QueryIndexManager` object. + +1. Specify the keyspace which contains the index. + +2. If the index has a name: + + a. Use `DropPrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, use the `name` property to specify the index name. + +''' + +The following example drops an unnamed primary index from the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=drop-primary,indent=0] +---- + +The following example drops a named primary index from the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=drop-named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/classes/QueryIndexManager.html[QueryIndexManager^]. +-- + +Python:: ++ +-- +To drop a primary index, use the `drop_primary_index` function on a `QueryIndexManager` object. + +1. Specify the keyspace which contains the index. + +2. If the index has a name: + + a. Use `DropPrimaryQueryIndexOptions` to specify the index options. + + b. In the index options, use the `index_name` property to specify the index name. + +''' + +The following example drops an unnamed primary index from the specified keyspace. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=drop-primary,indent=0] +---- + +The following example drops a named primary index from the specified keyspace. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=drop-named-primary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +== Dropping a Secondary Index + +You can drop a secondary index using a {sqlpp} statement or an SDK call. + +include::partial$index-context.adoc[] + +[tabs] +==== +{sqlpp}:: ++ +-- +To drop a a secondary index, use the `DROP INDEX` statement. +There are two possible syntaxes: + +* Specify the index name, then use the `ON` keyword to specify the keyspace which contains the index. + +* Specify the keyspace and index name using dotted notation. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query drops a named index from the `airline` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/drop-idx-name.n1ql[] +---- + +The following query drops the index in exactly the same way, but uses alternative syntax. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/drop-idx-alt.n1ql[] +---- + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/dropindex.adoc[DROP INDEX]. +-- + +.NET:: ++ +-- +To drop a secondary index, use the task `DropIndexAsync()` on the interface `IQueryIndexManager`. + +1. Specify the keyspace which contains the index. + +2. Specify the name of the index. + +''' + +The following example drops a named index from the specified keyspace. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$IndexHelloWorld.csx[tag=drop-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Management.Query.IQueryIndexManager.html[IQueryIndexManager()^]. +-- + +Java:: ++ +-- +To drop a secondary index, use the `dropIndex` method. + +1. Specify the keyspace which contains the index. + +2. Specify the name of the index. + +''' + +The following example drops a named index from the specified keyspace. + +[source,java] +---- +include::java-sdk:devguide:example$java/IndexHelloWorld.java[tag=drop-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/manager/query/QueryIndexManager.html[QueryIndexManager^]. +-- + +Node.js:: ++ +-- +To drop a secondary index, use the `dropIndex` function on a `QueryIndexManager` object. + +1. Specify the keyspace which contains the index. + +2. Specify the name of the index. + +''' + +The following example drops a named index from the specified keyspace. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$index-hello-world.js[tag=drop-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/classes/QueryIndexManager.html[QueryIndexManager^]. +-- + +Python:: ++ +-- +To drop a secondary index, use the `drop_index` function on a `QueryIndexManager` object. + +1. Specify the keyspace which contains the index. + +2. Specify the name of the index. + +''' + +The following example drops a named index from the specified keyspace. + +[source,python] +---- +include::python-sdk:devguide:example$python/index_hello_world.py[tag=drop-secondary,indent=0] +---- + +{github} + +For further details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html#n1ql-index-management[{sqlpp} Index Management^]. +-- +==== + +== Related Links + +Reference and explanation: + +* xref:server:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes] + +Administrator guides: + +* xref:cloud:clusters:index-service/manage-indexes.adoc[Manage Indexes] +* xref:cloud:clusters:index-service/manage-indexes.adoc#accessing-indexes-in-the-capella-ui[Monitor Indexes] + +Indexes with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#indexes[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#indexes[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#indexes[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#indexes[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#indexes[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#indexes[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#indexes[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#indexes[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#indexes[Scala] diff --git a/modules/guides/pages/group-agg.adoc b/modules/guides/pages/group-agg.adoc new file mode 100644 index 000000000..dfe03cb8e --- /dev/null +++ b/modules/guides/pages/group-agg.adoc @@ -0,0 +1,228 @@ += Calculate Aggregates and Group Results +:page-topic-type: guide +:page-partial: +:page-pagination: +:imagesdir: ../assets/images +:tabs: +:description: How to calculate aggregates and group the results. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +You can use aggregate functions to perform calculations over multiple values. +Grouping enables you to display the results in groups. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Aggregate Functions + +To take multiple values from documents, perform calculations, and return a single value as the result, use an aggregate function, such as +xref:n1ql:n1ql-language-reference/aggregatefun.adoc#avg[AVG()], +xref:n1ql:n1ql-language-reference/aggregatefun.adoc#count[COUNT()], +xref:n1ql:n1ql-language-reference/aggregatefun.adoc#min[MIN()], +xref:n1ql:n1ql-language-reference/aggregatefun.adoc#max[MAX()], or +xref:n1ql:n1ql-language-reference/aggregatefun.adoc#sum[SUM()]. + +==== +For example, the following query finds the average altitude of airports in the airport keyspace. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/avg.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$functions/avg.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/aggregatefun.adoc[Aggregate Functions]. + +=== Aggregating Distinct Values + +To aggregate all values, omit the aggregate quantifier, or optionally include the `ALL` keyword before the function arguments. + +==== +For example, the following query finds the average number of stops per route. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/avg-all.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$functions/avg-all.jsonc[] +---- + +Results in 0.0002 since nearly all routes have 0 stops. +==== + +To aggregate distinct values only, include the `DISTINCT` keyword before the function arguments. + +==== +For example, the following query finds the average of the distinct numbers of stops. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/avg-distinct.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$functions/avg-distinct.jsonc[] +---- + +Results in 0.5 since the routes contain only 1 or 0 stops. +==== + +For more information, refer to xref:n1ql:n1ql-language-reference/aggregatefun.adoc#aggregate-quantifier[Aggregate Quantifier]. + +=== Filtering the Aggregates + +To filter the values used by an aggregate function, use the FILTER clause after the function. + +==== +For example, the following query finds the minimum value of a string field, only including strings that start with `"A"` or greater. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/min-filter.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$functions/min-filter.jsonc[] +---- +==== + +For more information, refer to xref:n1ql:n1ql-language-reference/aggregatefun.adoc#filter-clause[FILTER Clause]. + +== Grouping the Results + +By default, an aggregate function returns a single result for all the documents that the query selects. +It is often more useful to group the documents (by a different field) and return the aggregate result for each group. + +To group the results of an aggregate query, use the GROUP BY clause. + +==== +For example, the following query groups unique landmarks by city. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/group-by.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/group-by.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/groupby.adoc[GROUP BY Clause]. + +=== Filtering the Groups + +To filter the groups by an aggregate function, use the HAVING clause within the GROUP BY clause. + +==== +For example, the following query groups unique landmarks by city, and specifies cities that have more than 180 landmarks. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/group-by-having.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/group-by-having.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/groupby.adoc#having-clause[HAVING Clause]. + +=== Defining an Expression within the GROUP BY Clause + +To define an expression for use within the GROUP BY clause, use the LETTING clause before the HAVING clause. + +==== +For example, the following clause uses an expression to define the minimum number of landmarks for each city. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/group-by-letting.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/group-by-letting.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/groupby.adoc#letting-clause[LETTING Clause]. + +== Related Links + +Reference and explanation: + +* xref:n1ql:n1ql-language-reference/aggregatefun.adoc[Aggregate Functions] +* xref:n1ql:n1ql-language-reference/groupby.adoc[GROUP BY Clause] + +Tutorials: + +* https://query-tutorial.couchbase.com/tutorial/#1[{sqlpp} Query Language Tutorial^] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/import.adoc b/modules/guides/pages/import.adoc new file mode 100644 index 000000000..1c109c673 --- /dev/null +++ b/modules/guides/pages/import.adoc @@ -0,0 +1,706 @@ += Import Data with an SDK +:page-topic-type: guide +:imagesdir: ../assets/images +:page-toclevels: 2 +:page-pagination: +:description: How to import documents into Couchbase with an SDK. +:github: Click the icon:github[] View button to see any code sample in context. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Importing data can be done from the Couchbase Capella UI, +ifdef::flag-devex-command-line[] +via the xref:server:tools:cbimport.adoc[cbimport] command-line tool, +endif::flag-devex-command-line[] +or using the SDK to script the process. + +Data load essentially consists of the following steps: + +. Prepare data in some well known format such as Comma Separated Values (.csv) or JSON documents. + +. Parse this data, and iterate over each document. + +. Connect to your Couchbase instance. + +. Connect to the appropriate bucket, scope, and collection. + +. Decide on the key for this document (could be an ID, a sequence number, or some combination of fields). + +. Do any additional processing if required. + +. Insert the document. + +// tag::clients_section[] +// include::partial$clients.adoc[] +// following section copied/tweaked from above +// differences: cbc vs cbimport, topic, etc. +=== Couchbase Clients + +Clients access data by connecting to a Couchbase cluster over the network. +The most common type of client is a Couchbase SDK, which is a full programmatic API that enables applications to take the best advantage of Couchbase. +This developer guide focuses on the most commonly-used SDKs, but full explanations and reference documentation for all SDKs is available. + +ifdef::flag-devex-command-line[] +The command line clients also provide a quick and streamlined interface for simple access and are suitable if you just want to access an item without writing any code. +For this guide, we are especially interested in the `cbimport` tool. + +[NOTE] +==== +With some editions, the command line clients are provided as part of the installation of Couchbase Server. +Assuming a default installation, you can find them in the following location, depending on your operating system: + +[horizontal] +Linux:: `/opt/couchbase/bin` +Windows:: `C:\Program Files\Couchbase\Server\bin` +macOS:: `/Applications/Couchbase Server.app/Contents/Resources/couchbase-core/bin` +==== +endif::flag-devex-command-line[] + +The Couchbase Capella UI also offers a graphical interface for import. + +Read the following for further information about the clients available for importing data: + +ifdef::flag-devex-command-line[] +* xref:server:tools:cbimport.adoc[cbimport] +endif::flag-devex-command-line[] + +* xref:home::sdk.adoc[SDK Clients] + +* xref:cloud:clusters:data-service/import-data-documents.adoc[Couchbase Capella UI] +// end::clients_section[] + +== Preparing the Data + +To prepare the data, extract or generate your data in an appropriate data format. + +The following are well supported for export, as well as by Couchbase Capella and the module ecosystems of all Couchbase SDKs. + +[tabs] +==== +CSV:: ++ +-- +Comma Separated Values (.csv) are easily exported from many spreadsheet and database applications. + +Ensure that the first row is a header row containing the names of the columns within the document. + +[source,csv] +---- +include::nodejs-sdk:howtos:example$import.csv[] +---- +-- + +TSV:: ++ +-- +Tab Separated Values (.tsv) are a common variant of CSV files. + +[source,tsv] +---- +include::nodejs-sdk:howtos:example$import.tsv[] +---- +-- + +JSON:: ++ +-- +JSON (.json) files are especially well suited to import into Couchbase, as it is the default native datatype. + +A .json file contains only one single value, so to give flexibility to import one or many values, format this as an *array* of the values you want to store. + +[source,json] +---- +include::nodejs-sdk:howtos:example$import.json[] +---- +-- + +JSONL:: ++ +-- +JSON Lines (.json) also known as NDJSON is a common format for streaming JSON, with one JSON object per line of text. + +// "jsonl" not currently supported by highlighter +[source,json] +---- +include::nodejs-sdk:howtos:example$import.jsonl[] +---- +-- +==== + +ifdef::flag-devex-command-line[] +== Using `cbimport` + +Using xref:server:tools:cbimport.adoc[cbimport] is straightforward. +Ensure you have the path to the command line clients in Couchbase Server in your path. + +You can import all of the data formats described above. + +[tabs] +==== +CSV:: ++ +-- +To import a CSV file using `cbimport csv`: + +. Use the `--dataset` argument to specify the CSV file. + +. Use the `--cluster`, `--username`, and `--password` arguments to specify your connection details. + +. Use the `--bucket` and `--scope-collection-exp` arguments to specify the bucket, scope, and collection as required. + +. Use the `--generate-key` argument to specify an ID for the imported documents. + +''' + +The following example imports a local CSV file, generating IDs such as `airline_1234`. + +[source,sh] +---- +cbimport csv \ + --dataset file://./import.csv \ + --cluster localhost --username Administrator --password password \ + --bucket travel-sample --scope-collection-exp inventory.airline \ + --generate-key %type%_%id% +---- +-- + +TSV:: ++ +-- +To import a TSV file using `cbimport csv`: + +. Use the `--dataset` argument to specify the TSV file. + +. Use the `--field-separator` argument to specify the field separation character, such as `"\t"` for tab. + +. Use the `--cluster`, `--username`, and `--password` arguments to specify your connection details. + +. Use the `--bucket` and `--scope-collection-exp` arguments to specify the bucket, scope, and collection as required. + +. Use the `--generate-key` argument to specify an ID for the imported documents. + +''' + +The following example imports a local TSV file, generating IDs such as `airline_1234`. + +[source,sh] +---- +cbimport csv \ + --dataset file://./import.tsv --field-separator "\t" \ + --cluster localhost --username Administrator --password password \ + --bucket travel-sample --scope-collection-exp inventory.airline \ + --generate-key %type%_%id% +---- +-- + +JSON:: ++ +-- +To import a JSON file using `cbimport json`: + +. Use the `--dataset` argument to specify the JSON file. + +. Set the `--format` argument to `list`. + +. Use the `--cluster`, `--username`, and `--password` arguments to specify your connection details. + +. Use the `--bucket` and `--scope-collection-exp` arguments to specify the bucket, scope, and collection as required. + +. Use the `--generate-key` argument to specify an ID for the imported documents. + +''' + +The following example imports a local JSON file, generating IDs such as `airline_1234`. + +[source,sh] +---- +cbimport json \ + --dataset file://./import.json --format list \ + --cluster localhost --username Administrator --password password \ + --bucket travel-sample --scope-collection-exp inventory.airline \ + --generate-key %type%_%id% +---- +-- + +JSONL:: ++ +-- +To import a CSV file using `cbimport json`: + +. Use the `--dataset` argument to specify the JSONL file. + +. Set the `--format` argument to `lines`. + +. Use the `--cluster`, `--username`, and `--password` arguments to specify your connection details. + +. Use the `--bucket` and `--scope-collection-exp` arguments to specify the bucket, scope, and collection as required. + +. Use the `--generate-key` argument to specify an ID for the imported documents. + +''' + +The following example imports a local JSONL file, generating IDs such as `airline_1234`. + +[source,sh] +---- +cbimport json \ + --dataset file://./import.jsonl --format lines \ + --cluster localhost --username Administrator --password password \ + --bucket travel-sample --scope-collection-exp inventory.airline \ + --generate-key %type%_%id% +---- +-- +==== +endif::flag-devex-command-line[] + +== Importing Using an SDK + +Using an SDK gives you flexibility and control over the import process. +You can import all of the data formats described above. + +=== Parsing the Import into an Array or Stream of Records + +The details of how to parse the import data vary depending on the chosen input format, and the most appropriate library for your SDK. + +==== Parsing CSV and TSV Data + +[tabs] +==== +pass:[.NET]:: ++ +-- +To parse CSV and TSV data, use the https://joshclose.github.io/CsvHelper/[CsvHelper^] library. + +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=csv-tsv-import,indent=0] +---- + +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=importCSV,indent=0] +---- + +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=importTSV,indent=0] +---- + +{github} +-- + +Java:: ++ +-- +To parse CSV and TSV data, use the http://opencsv.sourceforge.net/[opencsv^] library. + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=csv-tsv-import,indent=0] +---- + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importCSV,indent=0] +---- + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importTSV;!omit,indent=0] +---- + +If you are using the *Reactor API* then, as OpenCSV doesn't have a built-in converter, +use the https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#generate-java.util.concurrent.Callable-java.util.function.BiFunction-java.util.function.Consumer-[`Flux::generate`] method to convert the CSV or TSV file into a stream: + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importCSV_batch;!omit,indent=0] +---- + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importTSV_batch;!omit,indent=0] +---- + +{github} +-- + +Node.js:: ++ +-- +To parse CSV and TSV data, use the https://csv.js.org/parse/[csv-parse^] library. + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=csv-tsv-import,indent=0] +---- + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=csvStream,indent=0] +---- + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=tsvStream,indent=0] +---- + +{github} +-- + +Python:: ++ +-- +To parse CSV and TSV data, use the https://docs.python.org/3/library/csv.html[csv^] library. + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=csv-tsv-import,indent=0] +---- + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=csvImport,indent=0] +---- + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=tsvImport,indent=0] +---- + + +{github} +-- +==== + +==== Parsing JSON and JSONL Data + +[tabs] +==== +pass:[.NET]:: ++ +-- +To parse JSON and JSONL data, use https://www.newtonsoft.com/json[Newtonsoft^]. + +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=json-jsonl-import,indent=0] +---- +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=importJSON,indent=0] +---- + +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=importJSONL,indent=0] +---- + +{github} +-- + +Java:: ++ +-- +To parse *JSON* data, read the file as a string, then use the built-in Couchbase xref:java-sdk:howtos:json.adoc[JSON] handling to parse the result into an array of JSON objects. + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=json-jsonl-import,indent=0] +---- + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importJSON,indent=0] +---- + +If you are using the *Reactor API* then, once you've read the JSON array, use the https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#fromIterable-java.lang.Iterable-[`Flux::fromIterable`] method to convert it into streams: + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importJSON_batch;!omit,indent=0] +---- + +To parse *JSONL* data: do the same, but read the file line-by-line. + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importJSONL;!omit,indent=0] +---- + +If you are using the *Reactor API* then open the JSONL file as a stream using the https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#using-java.util.concurrent.Callable-java.util.function.Function-java.util.function.Consumer-[`Flux::using`] method. + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=importJSONL_batch;!omit,indent=0] +---- + +{github} +-- + +Node.js:: ++ +-- +Use the https://github.com/uhop/stream-json[stream-json^] library. + +NOTE: stream-json formats its output with a `{ key: ..., value: ...}` wrapper, so we need to map the stream into the expected format. + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=json-jsonl-import,indent=0] +---- + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=jsonStream,indent=0] +---- + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=jsonlStream,indent=0] +---- + +{github} +-- + +Python:: ++ +-- +Use the https://docs.python.org/3/library/json.html[json^] library: + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=json-jsonl-import,indent=0] +---- + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=jsonImport,indent=0] +---- + +[source,python] +---- + +include::python-sdk:devguide:example$python/import.py[tags=jsonlImport,indent=0] +---- + +{github} +-- +==== + +=== Connecting to Couchbase Capella + +First, you need the connection details for Couchbase Capella. + +Now decide which bucket and xref:clusters:data-service/scopes-collections.adoc[scope and collection] you want to import to, and create them if they don't already exist. + +[tabs] +==== +pass:[.NET]:: ++ +-- +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=connect,indent=0] +---- + +{github} + +For more information, refer to xref:dotnet-sdk:howtos:managing-connections.adoc[]. +-- + +Java:: ++ +-- +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=connect,indent=0] +---- + +If you are using the xref:java-sdk:howtos:concurrent-async-apis.adoc#reactive-programming-with-reactor[Reactive API], then use the reactive collection instead: + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=reactiveCollection,indent=0] +---- + +{github} + +For more information, refer to xref:java-sdk:howtos:managing-connections.adoc[]. +-- + +Node.js:: ++ +-- +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=connect,indent=0] +---- + +{github} + +For more information, refer to xref:nodejs-sdk:howtos:managing-connections.adoc[]. +-- + +Python:: ++ +-- +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=connect,indent=0] +---- + +{github} + +For more information, refer to xref:python-sdk:howtos:managing-connections.adoc[]. +-- +==== + +=== Inserting the Documents + +Having processed each imported document, you can insert it into the keyspace. +Couchbase is a key-value store, and the document is the value, so before you can insert the document, you need to determine the key. + +To insert an imported document into the keyspace: + +. Specify the key. This could be as simple as extracting the `id` field from the document, or using an incrementing sequence number. + +. Do any additional processing, for example calculating fields, or adding metadata about the importer. + +. Finally, use an upsert operation to the store the document. + +TIP: Use `upsert` rather than `insert` to upload the document even if the target key already has a value. +This means that in the case of any error, it is easy to make any required tweaks to the import file and re-run the whole import. + +[tabs] +==== +pass:[.NET]:: ++ +-- +To store the data, hook the prepared data into an `upsert` routine. + +NOTE: As CsvHelper and Newtonsoft generate different outputs, we've provided some overloaded options that work for either. + +[source,csharp] +---- +include::dotnet-sdk:howtos:example$Import.csx[tags=upsertDocument,indent=0] +---- + +{github} + +For more information, refer to xref:dotnet-sdk:howtos:kv-operations.adoc[]. +-- + +Java:: ++ +-- +To store the data, hook the prepared data into an `upsert` routine. +For the blocking API, use the method below. + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=upsertDocument,indent=0] +---- + +The *Reactive API* examples above already include a call to `ReactiveCollection::upsert`. + +In both cases, you must provide a preprocess routine which returns a key-value tuple object: + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=JsonDocument,indent=0] +---- + +[source,java] +---- +include::java-sdk:howtos:example$Import.java[tags=preprocess,indent=0] +---- + +{github} + +For more information, refer to xref:java-sdk:howtos:kv-operations.adoc[]. +-- + +Node.js:: ++ +-- +To iterate the prepared data stream, use a simple `for` loop in the same way as an array. + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=importStream,indent=0] +---- + +Hook the prepared stream in to an `upsertDocument` routine: + +[source,nodejs] +---- +include::nodejs-sdk:howtos:example$import.js[tags=upsertDocument,indent=0] +---- + +{github} + +For more information, refer to xref:nodejs-sdk:howtos:kv-operations.adoc[]. +-- + +Python:: ++ +-- +// extracted to functions as there's a multi example below +To store the data, define functions to determine the key, and process the value. + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=key,indent=0] +---- +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=process,indent=0] +---- + +Hook the prepared data into an `upsertDocument` routine which uses these functions. + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=upsertDocument,indent=0] +---- + +For more information, refer to xref:python-sdk:howtos:kv-operations.adoc[]. + +Note that the Python SDK offers a set of batch operations which are marked as _volatile_ as of SDK 3.2.3, which may be more efficient. Here's a brief example for CSV: + +[source,python] +---- +include::python-sdk:devguide:example$python/import.py[tags=csvImportMulti,indent=0] +---- + +{github} +-- +==== + +== Related Links + +Reference and information: + +* The xref:cloud:clusters:data-service/import-data-documents.adoc[Couchbase Capella UI] offers a graphical view of documents, to check your imports interactively. + +How-to guides: + +* The xref:guides:kv-operations.adoc[] guide shows how to read and update the data you have imported. + +Key-Value Operations with SDKs: + +* xref:c-sdk:howtos:kv-operations.adoc[C] +| xref:dotnet-sdk:howtos:kv-operations.adoc[.NET] +| xref:go-sdk:howtos:kv-operations.adoc[Go] +| xref:java-sdk:howtos:kv-operations.adoc[Java] +| xref:nodejs-sdk:howtos:kv-operations.adoc[Node.js] +| xref:php-sdk:howtos:kv-operations.adoc[PHP] +| xref:python-sdk:howtos:kv-operations.adoc[Python] +| xref:ruby-sdk:howtos:kv-operations.adoc[Ruby] +| xref:scala-sdk:howtos:kv-operations.adoc[Scala] diff --git a/modules/guides/pages/index-advisor.adoc b/modules/guides/pages/index-advisor.adoc new file mode 100644 index 000000000..125c4cc36 --- /dev/null +++ b/modules/guides/pages/index-advisor.adoc @@ -0,0 +1,251 @@ += Get Index Advice +:page-topic-type: guide +:page-partial: +:page-pagination: prev +:imagesdir: ../assets/images +:description: How to use the Index Advisor to recommend indexes for your queries. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +You don't need to create an index to query a keyspace. +However, you can improve the performance of your query by using a well-designed index. +// tag::intro[] +The Index Advisor can analyze your queries and provide recommended indexes to optimize response times. +// end::intro[] + +The Index Advisor works with +xref:n1ql:n1ql-language-reference/selectintro.adoc[SELECT], +xref:n1ql:n1ql-language-reference/update.adoc[UPDATE], +xref:n1ql:n1ql-language-reference/delete.adoc[DELETE], or +xref:n1ql:n1ql-language-reference/merge.adoc[MERGE] queries. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +[[advice-single]] +== Advice for a Single Query + +To get index recommendations for a single query, you can use the Index Advisor in the Query tab, the `ADVISE` statement, or the `ADVISOR()` function. + +[tabs] +==== +Query Tab:: ++ +-- +To get index recommendations for a single query, enter the query in the Query tab and click btn:[Run]. + +The *Index Advice* area displays the details of any current indexes used by the query, and any indexes that the Index Advisor recommends. + +* To hide or display the *Index Advice* area, click btn:[Index Advice]. + +* If there are any recommended indexes or covering indexes, click btn:[Build Suggested] to create them. + +* If the query has been updated, click btn:[Update Advice] to update the advice. + +For more details, refer to xref:cloud:clusters:query-service/query-workbench.adoc#index-advice[Index Advice]. +-- + +ADVISE Statement:: ++ +-- +To get index recommendations for a single query, use the `ADVISE` statement, followed by the query for which you want advice. + +The `ADVISE` statement returns a JSON object containing the details of any current indexes used by the query, and any indexes that the Index Advisor recommends, along with the reasons for recommendation. +For each index, a {sqlpp} statement is provided: you can copy and run this index statement to create the recommended index. + +''' + +The following example gets index advice for a single query. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$utility/advise-indexes.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$utility/advise-indexes.jsonc[] +---- + +For more details, refer to xref:n1ql:n1ql-language-reference/advise.adoc[ADVISE]. +-- + +ADVISOR() Function:: ++ +-- +To get index recommendations for a single query, use the `ADVISOR()` function with a string argument, representing the query. + +The `ADVISOR()` function returns a JSON object containing the details of any current indexes used by each query, and any indexes that the Index Advisor recommends. +For each index, a {sqlpp} statement is provided: you can copy and run this index statement to create the recommended index. + +''' + +The following example gets index advice for a single query. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/advisor-single.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$functions/advisor-single.jsonc[] +---- + +For more details, refer to xref:n1ql:n1ql-language-reference/advisor.adoc#advisor-string[ADVISOR(string)]. +-- +==== + +[[advisor-function-multiple]] +== Advice for Multiple Queries + +The `ADVISOR()` function also enables you to get index recommendations for multiple queries. + +To get advice for multiple queries, use the `ADVISOR()` function with an array argument containing strings which represent each query. + +TIP: You can query the xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc#sys-completed-req[system:completed_requests] catalog to get a list of recently-completed queries. + +==== +The following example gets index advice for recently-completed queries. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/advisor-recent.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$functions/advisor-recent.jsonc[tags=current;recommended;ellipsis] +---- +==== + +For more details, refer to xref:n1ql:n1ql-language-reference/advisor.adoc#advisor-array[ADVISOR(array)]. + +[[advisor-function-session]] +== Advice for a Session + +The `ADVISOR()` function also enables you to get index recommendations for all the queries that you run in an Index Advisor session. + +To run an Index Advisor session: + +. Use the `ADVISOR()` function with a start object argument to start the session. +The object argument must contain the property `"action": "start"`, and must also contain a `"duration"` property, specifying the duration of the session. ++ +The query returns a session ID, which you must use to get the results for this session, and to perform other actions on this session. + +. Run all the queries for which you require index recommendations. + +. If you want to stop the session early, use the `ADVISOR()` function with a stop object argument. +The object argument must contain the property `"action": "stop"`, and must also contain a `"session"` property, specifying the session ID. + +. When the session is complete, use the `ADVISOR()` function with a get object argument to get the index recommendations. +The object argument must contain the property `"action": "get"`, and must also contain a `"session"` property, specifying the session ID. + +NOTE: You can also use the `ADVISOR()` function to abandon a session without recording any results; to list active and completed sessions; and to purge the results of an Index Advisor session. + +==== +The following example starts an Index Advisor session with a duration of 1 hour. +All queries taking longer than 0 seconds will be collected. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/advisor-start.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$functions/advisor-start.jsonc[] +---- + +''' + +The following example stops the Index Advisor session early and saves the results. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/advisor-stop.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$functions/advisor-stop.jsonc[] +---- + +''' + +The following example returns index recommendations for the queries in the Index Advisor session. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$functions/advisor-get.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$functions/advisor-get.jsonc[tags=current;covering;recommended;ellipsis] +---- +==== + +For more details, refer to xref:n1ql:n1ql-language-reference/advisor.adoc#advisor-session-start[ADVISOR(start_obj)]. + +== Related Links + +Reference and explanation: + +* xref:server:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes] + +Administrator guides: + +* xref:cloud:clusters:index-service/manage-indexes.adoc[Manage Indexes] +* xref:cloud:clusters:index-service/manage-indexes.adoc#accessing-indexes-in-the-capella-ui[Monitor Indexes] + +Online Index Advisor tool: + +* https://index-advisor.couchbase.com/indexadvisor/#1[Couchbase {sqlpp} Index Advisor^] + +Indexes with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#indexes[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#indexes[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#indexes[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#indexes[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#indexes[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#indexes[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#indexes[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#indexes[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#indexes[Scala] diff --git a/modules/guides/pages/indexes.adoc b/modules/guides/pages/indexes.adoc new file mode 100644 index 000000000..d1d836aa8 --- /dev/null +++ b/modules/guides/pages/indexes.adoc @@ -0,0 +1,61 @@ += Use Primary and Secondary Indexes +:page-role: tiles -toc +:page-pagination: next +:description: These guides explain how to create and use primary and secondary indexes for {sqlpp} queries. +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Create Indexes + +include::create-index.adoc[tags=intro] + +* xref:create-index.adoc[Creating Indexes] + +== Place Indexes + +include::place-index.adoc[tags=intro] + +* xref:place-index.adoc[Index Placement] + +== Defer Indexes + +include::defer-index.adoc[tags=intro] + +* xref:defer-index.adoc[Deferring Indexes] + +== Select Indexes + +include::select-index.adoc[tags=intro] + +* xref:select-index.adoc[Selecting Indexes] + +== Drop Indexes + +include::drop-index.adoc[tags=intro] + +* xref:drop-index.adoc[Dropping Indexes] + +== Get Index Advice + +include::index-advisor.adoc[tags=intro] + +* xref:index-advisor.adoc[] diff --git a/modules/guides/pages/insert.adoc b/modules/guides/pages/insert.adoc new file mode 100644 index 000000000..5657638c2 --- /dev/null +++ b/modules/guides/pages/insert.adoc @@ -0,0 +1,216 @@ += Insert Data with a Query +:page-topic-type: guide +:imagesdir: ../assets/images +:tabs: +:page-partial: +:page-pagination: +:description: How to insert documents using {sqlpp}. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +To insert documents in a keyspace, you can use the INSERT statement, the UPSERT statement, or the MERGE statement. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +include::partial$data-warning.adoc[] + +== Inserting a Document + +To insert a document by providing the value, use the INSERT statement with the VALUES clause: + +. Use the INTO keyword to specify the keyspace into which the document is inserted. + +. Optionally, use the bracketed KEY and VALUE keywords to specify that you're inserting a document key and body. + +. Use the VALUES clause to specify the document key and the body of the document. + +. If required, use the RETURNING clause specifies what the query returns when the document is inserted. + +==== +The following query creates a document in the `airline` keyspace. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/insert-doc.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/insert-doc.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/insert.adoc[INSERT]. + +=== Inserting Documents in Bulk + +To insert several documents at once, use multiple VALUES clauses. +The VALUES keyword itself is optional in the second and later iterations of the clause. + +==== +The following query creates two documents in the `airline` keyspace. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/insert-batch.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/insert-batch.jsonc[] +---- +==== + +=== Inserting the Results of a Query + +To insert documents using a query, use the INSERT statement with a SELECT statement. + +. Use the bracketed KEY keyword to specify the document key. + +. Use the optional VALUE keyword to specify the body of the document to insert. +The body of the inserted document is usually based on the result returned by the SELECT statement. + +. Use the SELECT statement to return a resultset which is used as a basis for the inserted documents. +The INSERT statement inserts a document for every result returned by the SELECT statement. + +. If required, use the RETURNING clause specifies what the query returns when the document is inserted. + +[NOTE] +The document key that you specify must be unique for every document that you insert. +For example, you can use the xref:n1ql:n1ql-language-reference/metafun.adoc#uuid[UUID()] function to generate a unique key for each document. + +==== +The following query creates a copy in the `airport` keyspace of any document whose `airportname` is "Heathrow". + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/insert-select.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/insert-select.jsonc[] +---- +==== + +== Replacing Existing Documents + +The INSERT statement fails if a document with the same document key already exists in the keyspace. + +To insert documents into a keyspace and replace any existing documents with the same key, use the UPSERT statement. +This has the same syntax as the INSERT statement. + +==== +The following query creates two documents in the `landmark` keyspace. +If documents with the same keys already exist, the existing documents are replaced. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/upsert-batch.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/upsert-batch.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/upsert.adoc[UPSERT]. + +== Merging and Inserting Documents + +You can also insert documents by merging: that is, by joining one data source to another, and inserting documents any documents that do not match. + +To insert documents using a merge, use the MERGE statement with the INSERT action: + +. Use the INTO keyword to specify the target data source. +This is the data source into which documents will be inserted. + +. Use the USING keyword to specify the source. +This is the data source to check against the target. + +. Use the ON keyword to specify the merge predicate. +This is a condition that must be met to match an object in the source with an object in the target. + +. Use WHEN NOT MATCHED THEN INSERT to specify that when a document in the source does not match a document in the target, the document should be inserted in the target. + + .. If necessary, use the bracketed KEY keyword to specify the document key. + + .. If necessary, use the bracketed VALUE keyword to specify the body of the document to insert. + + .. If necessary, use the WHERE clause to specify any further conditions that must be met for documents to be inserted. + +. If required, use the LIMIT clause to specify the greatest number of documents that may be inserted. + +. If required, use the RETURNING clause to specify what should be returned when the documents are inserted. + +==== +The following query compares a source set of airport data with the target `airport` keyspace. +If the airport already exists in the `airport` keyspace, the record is updated. +If the airport does not exist in the `airport` keyspace, a new record is inserted. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/ansi-merge-else.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/ansi-merge-else.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/merge.adoc[MERGE]. + +== Related Links + +Reference and explanation: + +* xref:n1ql:n1ql-language-reference/insert.adoc[INSERT] +* xref:n1ql:n1ql-language-reference/upsert.adoc[UPSERT] +* xref:n1ql:n1ql-language-reference/merge.adoc[MERGE] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/join.adoc b/modules/guides/pages/join.adoc new file mode 100644 index 000000000..9d5f6417c --- /dev/null +++ b/modules/guides/pages/join.adoc @@ -0,0 +1,184 @@ += Query Across Relationships +:page-topic-type: guide +:page-partial: +:page-pagination: +:imagesdir: ../assets/images +:clauses: Joins +:tabs: +:description: How to join data sources for a {sqlpp} selection query. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +You can use a _join_ to read objects from one data source, combine them with corresponding objects from another data source, and return the joined objects. +// end::intro[] +The first data source is said to be on the _left-hand side_ of the join and the second is said to be on the _right-hand side_ of the join. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Creating a Join + +{sqlpp} offers several types of join syntax. +This guide focuses on ANSI join, which is the recommended join syntax. +It enables you to join one data source to another using arbitrary fields. + +To create a join: + +1. Use the FROM clause to specify the data source on the left-hand side of the join. +This may be a keyspace identifier, a subquery, or a generic expression. + +2. Use the JOIN clause to specify the data source on the right-hand side of the join. +For ANSI joins, this may be a keyspace identifier, a subquery, or a generic expression. + +3. Use the ON keyword to specify the join predicate. +This is a condition that must be met to join an object on the right-hand side to an object on the left-hand side. + +TIP: To use a xref:server:learn:data/data.adoc#keys[document key] in the join predicate, use the xref:n1ql:n1ql-language-reference/metafun.adoc#meta[META()] function to return the `id` field from the document metadata. + +==== +For example, the following query selects a route and the associated airline. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::example$query/ansi-join-example.n1ql[] +---- + +<.> The `route` keyspace is the left-hand side of the join. +<.> The `airline` keyspace is the right-hand side of the join. +<.> The `airlineid` field on the left-hand side must be equal to the document key on the right-hand side. +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/join.adoc#section_ek1_jnx_1db[ANSI JOIN Clause]. + +== Join Types + +ANSI joins support three types of join: _inner joins_, _left outer joins_, and _right outer joins_. + +=== Inner Joins + +The default join is an inner join. +An inner join returns joined objects _only_ where a source object from the left-hand side of the join matches a source object from the right-hand side of the join. + +image::inner-join.png['Inner join: the result contains only matching objects from the left-hand side and right-hand side'] + +To create an inner join, omit the join type, or optionally include the `INNER` keyword before the JOIN clause. + +==== +For example, the following query lists all the source airports and airlines that fly into San Francisco. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/ansi-join-inner.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/ansi-join-inner.jsonc[tags=extract;ellipsis] +---- +==== + +=== Left Outer Joins + +A left outer join returns joined objects using all the source objects from the left-hand side of the join, but only including source objects from the right-hand side of the join if they match. + +image::left-join.png['Left outer join: the result contains all objects from the left-hand side, and only matching objects from the right-hand side'] + +To create a left outer join, include the `LEFT` or `LEFT OUTER` keywords before the JOIN clause. + +==== +For example, the following query lists all airports in the United States, and for each airport gives the first listed landmark in the same city, if any. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/ansi-join-left.n1ql[] +---- + +<.> The `airport` keyspace is on the left-hand side of the join. +<.> The `landmark` keyspace is on the right-hand side of the join. + +.Results +[source,json] +---- +include::n1ql:example$select/ansi-join-left.jsonc[] +---- + +<.> If there is no corresponding data object on the right-hand side of the join, fields from the right-hand side are missing or null. +==== + +=== Right Outer Joins + +A right outer join returns joined objects using all the source objects from the right-hand side of the join, but only including source objects from the left-hand side of the join if they match. + +image::right-join.png['Right outer join: the result contains only matching objects from the left-hand side, and all objects from the right-hand side'] + +To create a right outer join, include the `RIGHT` or `RIGHT OUTER` keywords before the JOIN clause. + +==== +For example, the following query lists all landmarks in the United States, and for each landmark gives the first listed airport in the same city, if any. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/ansi-join-right.n1ql[] +---- + +<.> The `airport` keyspace is on the left-hand side of the join. +<.> The `landmark` keyspace is on the right-hand side of the join. + +.Results +[source,json] +---- +include::n1ql:example$select/ansi-join-right.jsonc[] +---- + +<.> If there is no corresponding data object on the left-hand side of the join, fields from the left-hand side are missing or null. +==== + +include::partial$recursive-joins.adoc[] + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/join.adoc#section_nkd_3nx_1db[Left-Hand Side] for the JOIN clause. + +== Related Links + +Reference and explanation: + +* xref:n1ql:n1ql-language-reference/join.adoc[JOIN Clause] + +Tutorials: + +* https://query-tutorial.couchbase.com/tutorial/#1[{sqlpp} Query Language Tutorial^] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] + diff --git a/modules/guides/pages/kv-operations.adoc b/modules/guides/pages/kv-operations.adoc new file mode 100644 index 000000000..bc1824c4d --- /dev/null +++ b/modules/guides/pages/kv-operations.adoc @@ -0,0 +1,39 @@ += Work with Documents +:description: How to perform CRUD key-value operations in Couchbase. +:page-pagination: next +:page-topic-type: guide +:page-aliases: sdk:development-intro +:page-toclevels: 2 + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Every item in a database goes through the basic CRUD cycle, which is typical of an application's use of data. +CRUD stands for create, read, update, and delete: + +* **C**reate: when data is first inserted into the cluster +* **R**ead: when an application retrieves the data +* **U**pdate: when data is modified to reflect a change in the state represented by the data +* **D**elete: when the data is no longer needed + +The xref:clusters:data-service/data-service.adoc[Key-Value (KV) or Data Service] offers Couchbase clients the fastest and simplest way to create, retrieve or mutate data where the key is known. + +include::partial$before-you-begin.adoc[] + +include::partial$clients.adoc[] + + +== Next Steps + +Key-Value Operations guides: + +* xref:clusters:data-service/manage-documents.adoc[] +* xref:creating-data.adoc[] +* xref:reading-data.adoc[] +* xref:updating-data.adoc[] +* xref:deleting-data.adoc[] +* xref:bulk-operations.adoc[] diff --git a/modules/guides/pages/load.adoc b/modules/guides/pages/load.adoc new file mode 100644 index 000000000..14be2797a --- /dev/null +++ b/modules/guides/pages/load.adoc @@ -0,0 +1,49 @@ += Import and Export Data +:page-role: tiles -toc +:page-pagination: next +:description: How to import data from files, and how to export data. +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Import Data with the Couchbase Capella UI + +Use the Couchbase Capella UI to import data interactively, and to preview your imports. + +* xref:clusters:data-service/import-data-documents.adoc[] + +== Import Data with an SDK + +Use an SDK to script the process of importing data. + +* xref:import.adoc[] + +== Import and Export Data with Command Line Tools + +Use Couchbase command line tools to import and export data. + +* xref:connect:cli-import-export.adoc[] + +== Related Links + +Refer to the following for information on command line tools. + +* xref:reference:command-line-tools.adoc[] \ No newline at end of file diff --git a/modules/guides/pages/manipulate.adoc b/modules/guides/pages/manipulate.adoc new file mode 100644 index 000000000..af9ca34f2 --- /dev/null +++ b/modules/guides/pages/manipulate.adoc @@ -0,0 +1,43 @@ += Manipulate Data with Queries +:page-role: tiles -toc +:page-pagination: next +:description: These guides explain how to create, update, and delete data with a {sqlpp} query. +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Inserting Data + +include::insert.adoc[tags=intro] + +* xref:insert.adoc[] + +== Updating Data + +include::update.adoc[tags=intro] + +* xref:update.adoc[] + +== Deleting Data + +include::delete.adoc[tags=intro] + +* xref:delete.adoc[] \ No newline at end of file diff --git a/modules/guides/pages/nest-unnest.adoc b/modules/guides/pages/nest-unnest.adoc new file mode 100644 index 000000000..e6b6a6df7 --- /dev/null +++ b/modules/guides/pages/nest-unnest.adoc @@ -0,0 +1,192 @@ += Nest and Unnest Documents +:page-topic-type: guide +:page-partial: +:page-pagination: +:imagesdir: ../assets/images +:clauses: Nests and Unnests +:tabs: +:description: How to nest and unnest arrays of embedded objects. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Couchbase Capella is a document database. +Data is stored as JSON documents in keyspaces, rather than as rows in tables. +This means that documents can contain arrays of embedded subdocuments. +// tag::intro[] +{sqlpp} provides syntax which enables you to _nest_ (create) or _unnest_ (flatten) arrays of embedded documents in a query. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Nesting Data + +Nesting is like creating a join from a document to documents from another data source. +However, in the resultset, the nested documents are embedded in an array within the parent document. + +{sqlpp} offers several types of nest syntax. +This guide focuses on ANSI nest, which is the recommended nest syntax. +It enables you to nest objects from one data source within objects from another, using arbitrary fields. + +To create a nest: + +1. Use the FROM clause to specify the data source on the left-hand side of the nest. +This may be a keyspace identifier, a subquery, or a subquery. + +2. Use the NEST clause to specify the data source on the right-hand side of the nest. +This must be a keyspace reference. + +3. Use the ON keyword to specify the nest predicate. +This is a condition that must be met in order to nest an object on the right-hand side within an object on the left-hand side. + +TIP: To use a xref:server:learn:data/data.adoc#keys[document key] in the nest predicate, use the xref:n1ql:n1ql-language-reference/metafun.adoc#meta[META()] function to return the `id` field from the document metadata. + +==== +For example, the following query selects a route and the associated airline. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::example$query/ansi-nest-example.n1ql[] +---- + +<.> The `route` keyspace is the left-hand side of the nest. +<.> The `airline` keyspace is the right-hand side of the nest. +<.> The `airlineid` field on the left-hand side must be equal to the document key on the right-hand side. +==== + +NOTE: Before running a query containing a nest, make sure all the required indexes exist. +To check which indexes may be required, use the xref:n1ql:n1ql-language-reference/advise.adoc[Index Advisor]. + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/nest.adoc#section_tc1_nnx_1db[ANSI NEST Clause]. + +== Nest Types + +ANSI nests support two types of nest: _inner nests_ and _left outer nests_. +(There is no provision for right outer nests, because objects from the right-hand side cannot be nested within an object that doesn't exist.) + +=== Inner Nests + +The default nest type is an inner nest. +An inner nest returns nested objects _only_ where a source object from the left-hand side of the nest matches a source object from the right-hand side of the nest. + +image::inner-nest.png['Inner nest: the result contains only matching objects from the left-hand side and right-hand side'] + +To create an inner nest, omit the nest type, or optionally include the `INNER` keyword before the NEST clause. + +==== +For example, the following query lists only airports in Toulouse which have routes starting from them, and nests details of the routes. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/ansi-nest-inner.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/ansi-nest-inner.jsonc[tags=extract;ellipsis] +---- +==== + +=== Left Outer Nests + +A left outer nest returns nested objects using _all_ the source objects from the left-hand side of the nest, but only including source objects from the right-hand side of the nest if they match. + +image::left-nest.png['Left outer nest: the result contains all objects from the left-hand side, and only matching objects from the right-hand side'] + +To create a left outer nest, include the `LEFT` or `LEFT OUTER` keywords before the NEST clause. + +==== +For example, the following query lists all airports in Toulouse, and nests details of any routes that start from each airport. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/ansi-nest-left.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/ansi-nest-left.jsonc[tags=extract;ellipsis] +---- + +<.> If there is no corresponding data object on the right-hand side of the nest, fields from the right-hand side are missing or null. +==== + +== Unnesting Data + +Unnesting data is the opposite of nesting. +Unnesting is like creating a join from a parent document to subdocuments in an array within that document. +In the resultset, the subdocuments are flattened and joined to the parent document. + +image::unnest.png['Unnest: the result contains subdocuments flattened and joined to their parent documents'] + +To unnest subdocuments from an array: + +1. Use the FROM clause to specify the parent data source on the left-hand side of the unnest. +2. Use the UNNEST clause to specify the nested data on the right-hand side of the unnest. + +==== +For example, the following query unnests the schedule data from within the route document to get details of flights on Monday (day `1`). + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/unnest.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$select/unnest.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/unnest.adoc[UNNEST Clause]. + +include::partial$recursive-joins.adoc[] + +For more information, refer to xref:n1ql:n1ql-language-reference/nest.adoc#from-term[Left-Hand Side] for NEST clauses, or xref:n1ql:n1ql-language-reference/unnest.adoc#from-term[Left-Hand Side] for UNNEST clauses. + +== Related Links + +Reference and explanation: + +* xref:n1ql:n1ql-language-reference/nest.adoc[NEST Clause] +* xref:n1ql:n1ql-language-reference/unnest.adoc[UNNEST Clause] + +Tutorials: + +* https://query-tutorial.couchbase.com/tutorial/#1[{sqlpp} Query Language Tutorial^] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/place-index.adoc b/modules/guides/pages/place-index.adoc new file mode 100644 index 000000000..cf5e415cb --- /dev/null +++ b/modules/guides/pages/place-index.adoc @@ -0,0 +1,182 @@ += Place Indexes +:page-topic-type: guide +:imagesdir: ../assets/images +:tabs: +:page-partial: +:page-pagination: +:description: How to place indexes on specified nodes, create index replicas, and partition indexes. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +To improve query responsiveness, you can choose where to save primary and secondary indexes. +You can also partition a large secondary index across multiple nodes. +You can create replicas of primary indexes, secondary indexes, and secondary index partitions, to enhance index availability. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +NOTE: This how-to guide focuses on index placement, partitioning, and replication using {sqlpp} queries. +The SDKs do not currently support all of these features fully. + +== Placing a Single Index + +When you create a primary or secondary index, you can specify the placement of the index. + +To specify the placement of a single index: + +1. Use the `WITH` clause to specify the index options. + +2. In the index options, use the `nodes` attribute to specify an array containing a single node. +The node name must include the cluster administration port, by default 8091. + +==== +The following query creates a secondary index that contains airports with an `alt` value greater than 1000 on the node `127.0.0.1`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-node.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/createprimaryindex.adoc[CREATE PRIMARY INDEX] and xref:n1ql:n1ql-language-reference/createindex.adoc[CREATE INDEX]. + +== Partitioning an Index + +When you create a secondary index, you can split the index into multiple partitions. +You can specify the placement of the partitions of an index, just as you can for a single index. + +To partition a secondary index: + +1. Use the `PARTITION BY HASH` clause to specify the field expression or expressions by which you want to partition the index. + +2. If required, use the `WITH` clause to specify the index options, and use the `num_partition` attribute to specify the number of partitions. +If you don't specify the number of partitions, the index has 8 partitions. + +==== +The following query creates an index partitioned by the document ID. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/partition-idx.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/index-partitioning.adoc[Index Partitioning]. + +== Replicating an Index + +When you create a secondary index, you can replicas of the index across multiple nodes. + +You can specify replicas for a partitioned index, just as you can for a single index. + +To replicate a secondary index by specifying the number of replicas: + +1. Use the `WITH` clause to specify the index options. + +2. In the index options, use the `num_replica` attribute to specify the number of replicas to create. + The value of this attribute must be less than or equal to the number of index nodes. + +If you specify `num_replica` but not `nodes`, the replicas are distributed amongst index nodes automatically. + +==== +The following query creates an index with two replicas, with no destination-nodes specified. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::server:learn:example$services-and-indexes/indexes/replication-num.n1ql[] +---- +==== + +To replicate a secondary index by specifying the replica nodes: + +1. Use the `WITH` clause to specify the index options. + +2. In the index options, use the `nodes` attribute to specify an array containing the nodes on which you want to create replicas. + Each node name must include the cluster administration port, by default 8091. + +If you specify `nodes` but not `num_replica`, the number of replicas (plus the original index) is equal to the number of nodes. + +==== +The following query creates an index on `node1`, with replicas on `node2` and `node3`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::server:learn:example$services-and-indexes/indexes/replication-nodes.n1ql[] +---- +==== + +NOTE: If you specify both `num_replica` _and_ `nodes`, the number of nodes must be _one greater_ than the number of replicas. + +For further details and examples, refer to xref:server:learn:services-and-indexes/indexes/index-replication.adoc#index-replication[Index Replication]. + +== Altering Index Placement + +You can alter the placement of an existing index or replica, increase or decrease the number of replicas, or to drop a replica temporarily. +You can also perform the same alterations to a partitioned index and any replica partitions. + +To alter index placement: + +1. Use the `ALTER INDEX` statement to specify the the index to alter. +2. Use the `ON` clause to specify the keyspace on which the index was built. +3. Use the `WITH` clause to specify the action to take and the parameters of that action. + +==== +The following query moves the index `def_inventory_airport_faa` to node `192.168.10.11`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/alter-idx-move.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/alterindex.adoc[ALTER INDEX]. + +== Related Links + +Reference and explanation: + +* xref:server:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes] + +Administrator guides: + +* xref:cloud:clusters:index-service/manage-indexes.adoc[Manage Indexes] +* xref:cloud:clusters:index-service/manage-indexes.adoc#accessing-indexes-in-the-capella-ui[Monitor Indexes] + +Indexes with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#indexes[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#indexes[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#indexes[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#indexes[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#indexes[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#indexes[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#indexes[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#indexes[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#indexes[Scala] diff --git a/modules/guides/pages/prep-statements.adoc b/modules/guides/pages/prep-statements.adoc new file mode 100644 index 000000000..dddfa2394 --- /dev/null +++ b/modules/guides/pages/prep-statements.adoc @@ -0,0 +1,578 @@ += Prepare Statements for Reuse +:page-topic-type: guide +:page-partial: +:page-pagination: prev +:imagesdir: ../assets/images +:description: How to create and execute prepared statements, including placeholder parameters. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +If you need to execute certain {sqlpp} statements repeatedly, you can use placeholder parameters and prepared statements to optimize query reuse. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +[[placeholders]] +== Adding Placeholder Parameters + +You can add placeholder parameters to a statement, so that you can safely supply variable values when you run the statement. +You can add placeholder parameters in the WHERE clause, the LIMIT clause, or the OFFSET clause. + +A placeholder parameter may be a _named parameter_ or a _positional parameter_. + +* To add a named parameter to a query, enter a dollar sign `$` or an at sign `@` followed by the parameter name. + +* To add a positional parameter to a query, enter a dollar sign `$` or an at sign `@` followed by the number of the parameter, or enter a question mark `?`. + +The following example includes two named parameters. + +==== +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$settings/param-names.n1ql[tag=statement] +---- + +To execute this query, the parameters must be supplied by name. +==== + +The following example includes two numbered positional parameters. + +==== +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$settings/param-numbers.n1ql[tag=statement] +---- + +To execute this query, the parameters must be supplied as a list, in order of the placeholder numbers. +==== + +The following example includes two unnumbered positional parameters. + +==== +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$settings/param-positions.n1ql[tag=statement] +---- + +To execute this query, the parameters must be supplied as a list, in the order in which the placeholders appear in the statement. +==== + +[[values]] +== Supplying Parameter Values + +To run a query containing placeholder parameters, you must supply values for the parameters. + +[tabs] +==== +{sqlpp}:: ++ +-- +To supply values for placeholder parameters using the cbq shell: + +* Use the `\SET` command to set the parameters before running the statement. +* Use the `-args` parameter to specify positional parameters. +* Use `-$` or `-@` followed by a parameter name to specify named parameters. + +ifdef::flag-devex-rest-api[] +To supply values for placeholder parameters using the {sqlpp} REST API: + +* Specify the parameters in the request body or the query URI, alongside the statement. +* Use the `args` parameter to specify positional parameters. +* Use `$` or `@` followed by a parameter name to specify named parameters. +endif::flag-devex-rest-api[] + +To supply values for placeholder parameters using the Query tab: + +* Click *Query Options* to display the Query Options window before running the statement. +* Use the *Positional Parameters* options to specify positional parameters. +* Use the *Named Parameters* options to specify named parameters. + +TIP: When you are executing a prepared statement, the `EXECUTE` statement provides another, easier way to supply parameter values. +Refer to <> below. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query supplies positional parameter values using the cbq shell. + +[source,sqlpp] +---- +include::n1ql:example$settings/param-numbers.n1ql[tags=**] +---- + +The following query supplies positional parameter values using the Query tab. + +. Click *Query Options* to display the Query Options window. +. Next to *Positional Parameters*, click btn:[+]. +. In the *$1* box, enter `"France"`. +. Next to *Positional Parameters*, click btn:[+] again. +. In the *$2* box, enter `500`. +. Choose btn:[Save]. +. Run the following query. + +[source,sqlpp] +---- +include::n1ql:example$settings/param-numbers.n1ql[tag=statement] +---- + +The following query supplies named parameter values using the cbq shell. + +[source,sqlpp] +---- +include::n1ql:example$settings/param-names.n1ql[tags=**] +---- + +The following query supplies named parameter values using the Query tab. + +. Click *Query Options* to display the Query Options window. +. Next to *Named Parameters*, click btn:[+]. +. In the *name 0* box, enter `country`, and in the *value 0* box, enter `"France"`. +. Next to *Named Parameters*, click btn:[+] again. +. In the *name 1* box, enter `altitude`, and in the *value 1* box, enter `500`. +. Choose btn:[Save]. +. Run the following query. + +[source,sqlpp] +---- +include::n1ql:example$settings/param-names.n1ql[tag=statement] +---- + +For more information and examples, refer to xref:n1ql:n1ql-manage/query-settings.adoc[]. +-- + +.NET:: ++ +-- +To supply values for placeholder parameters, use the `Parameter` method on the `QueryOptions` object. + +TIP: There are different versions of the `Parameter` method for supplying a single named parameter, a collection of named parameters, a single positional parameter, or a list of positional parameters. + +''' + +The following example supplies a single positional parameter. + +[source,csharp] +---- +include::3.5@dotnet-sdk:howtos:example$N1qlQueries.csx[tag=positional,indent=0] +---- + +The following example supplies a single named parameter. + +[source,csharp] +---- +include::3.5@dotnet-sdk:howtos:example$N1qlQueries.csx[tag=namedparameter,indent=0] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Query.QueryOptions.html[QueryOptions^]. +-- + +Java:: ++ +-- +To supply values for placeholder parameters, use the `parameter` method on the `QueryOptions` object. + +TIP: There are different versions of the `parameter` method for supplying named parameters or positional parameters. + +''' + +The following example supplies a single positional parameter. + +[source,java] +---- +include::java-sdk:howtos:example$Queries.java[tag=positional,indent=0] +---- + +The following example supplies a single named parameter. + +[source,java] +---- +include::java-sdk:howtos:example$Queries.java[tag=named,indent=0] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java/query/QueryOptions.html[QueryOptions^]. +-- + +Node.js:: ++ +-- +To supply values for placeholder parameters, use the `parameters` property on the `QueryOptions` interface. + +TIP: The `parameters` property may be an object for supplying named parameters, or an array for supplying positional parameters. + +''' + +The following example supplies a single positional parameter. + +[source,javascript] +---- +include::nodejs-sdk:devguide:example$nodejs/n1ql-queries-scoped.js[tag=queryplaceholders,indent=0] +---- + +The following example supplies a single named parameter. + +[source,javascript] +---- +include::nodejs-sdk:devguide:example$nodejs/n1ql-queries-scoped.js[tag=querynamed,indent=0] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/QueryOptions.html[QueryOptions^]. +-- + +Python:: ++ +-- +To supply positional parameter values for a query or prepared statement, use the `positional_parameters` parameter in the `QueryOptions`. + +To supply named parameter values for a query or prepared statement, use the `named_parameters` parameter in the `QueryOptions`. + +TIP: Alternatively, you can supply positional parameters or named parameters as keyword arguments for the `query()` function. + +''' + +The following examples supply a single positional parameter. + +[source,python] +---- +include::python-sdk:howtos:example$n1ql_ops.py[tag=positional_options] +---- + +[source,python] +---- +include::python-sdk:howtos:example$n1ql_ops.py[tag=positional] +---- + +The following examples supply a single named parameter. + +[source,python] +---- +include::python-sdk:howtos:example$n1ql_ops.py[tag=named_options] +---- + +[source,python] +---- +include::python-sdk:howtos:example$n1ql_ops.py[tag=named_kwargs] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/couchbase_api/options.html#queryoptions[QueryOptions^]. +-- +==== + +[[prepare]] +== Creating a Prepared Statement + +If you need to run a statement more than once, you can prepare the execution plan for the statement and cache it for reuse. + +NOTE: You can include placeholder parameters in the prepared statement, if necessary. + +[tabs] +==== +{sqlpp}:: ++ +-- +To create a prepared statement, use the `PREPARE` statement. + +1. If necessary, set the xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to the bucket and scope where you want to create the prepared statement. + +2. Use the FROM / AS clause to specify a name for the prepared statement, if required. +If you don't, a name is generated automatically. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Query +The following query prepares the execution plan for the given statement, including the specified positional parameters. + +[source,sqlpp] +---- +include::n1ql:example$utility/prepare-numbers.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$utility/prepare-numbers.jsonc[tag=extract,indent=0] +---- + +<.> The query returns the name of the prepared statement. + +.Query +The following query prepares the execution plan for the given statement, including the specified named parameters. + +[source,sqlpp] +---- +include::n1ql:example$utility/prepare-names.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$utility/prepare-names.jsonc[tag=extract,indent=0] +---- + +<.> The query returns the name of the prepared statement. + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/prepare.adoc[PREPARE]. +-- + +.NET:: ++ +-- +To create a prepared statement, use the `Cluster.QueryAsync` method with the `adhoc` query option set to false. + +''' + +The following example executes a query with the specified parameters. +If this query has not been executed before, the query plan is cached for reuse. + +[source,csharp] +---- +include::example$prepared/adhoc.cs[] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/QueryOptions.html[QueryOptions^]. +-- + +Java:: ++ +-- +To create a prepared statement, use the `query()` method with the `AdHoc` query option set to false. + +''' + +The following example executes a query with the specified parameters. +If this query has not been executed before, the query plan is cached for reuse. + +[source,java] +---- +include::java-sdk:concept-docs:example$N1qlQueryExample.java[tag=n1ql_query_1,indent=0] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Query.QueryOptions.html[QueryOptions^]. +-- + +Node.js:: ++ +-- +To create a prepared statement, use the `query()` function with the `adhoc` query option set to false. + +''' + +The following example executes a query with the specified parameters. +If this query has not been executed before, the query plan is cached for reuse. + +[source,javascript] +---- +include::example$prepared/adhoc.js[] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/QueryOptions.html[QueryOptions^]. +-- + +Python:: ++ +-- +To create a prepared statement, use the `query()` function with the `adhoc` query option set to false. + +''' + +The following example executes a query with the specified parameters. +If this query has not been executed before, the query plan is cached for reuse. + +[source,python] +---- +include::example$prepared/adhoc.py[] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/couchbase_api/options.html#queryoptions[QueryOptions^]. +-- +==== + +[[execute]] +== Executing a Prepared Statement + +When you execute a prepared statement, the cached execution plan is reused, so the query executes faster. + +NOTE: You can supply parameter values for a prepared statement, just as you can for a query. +These can be different to the parameter values that you supplied when you created the prepared statement. + +[tabs] +==== +{sqlpp}:: ++ +-- +To execute a prepared statement, use the `EXECUTE` statement. + +1. If necessary, set the xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to the bucket and scope where you created the prepared statement. + +2. Supply the name of the prepared statement, as provided when you created the prepared statement. + +3. If necessary, use the USING clause to supply the values for parameters in the prepared statement. + + ** Specify positional parameters using an array of values. + + ** Specify named parameters using an object containing name / value properties. + +''' + +.Context +include::partial$query-context.adoc[tag=example] + +.Queries +The following query executes a prepared statement, including the specified positional parameters. + +[source,sqlpp] +---- +include::n1ql:example$utility/execute-numbers.n1ql[tags=**] +---- + +The following query executes a prepared statement, including the specified named parameters. + +[source,sqlpp] +---- +include::n1ql:example$utility/execute-names.n1ql[tags=**] +---- + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/execute.adoc[EXECUTE]. +-- + +.NET:: ++ +-- +To execute a prepared statement, use the `Cluster.QueryAsync` method to run the prepared statement query string again, with the `adhoc` query option set to false. + +Specify parameter values for the query, if necessary. + +''' + +The following example executes a query with the specified parameters. +If a prepared statement has been created from this query previously, the cached query plan is reused. + +[source,csharp] +---- +include::example$prepared/adhoc.cs[] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/QueryOptions.html[QueryOptions^]. +-- + +Java:: ++ +-- +To execute a prepared statement, use the `query()` method to run the prepared statement query string again, with the `AdHoc` query option set to false. + +Specify parameter values for the query, if necessary. + +''' + +The following example executes a query with the specified parameters. +If a prepared statement has been created from this query previously, the cached query plan is reused. + +[source,java] +---- +include::java-sdk:concept-docs:example$N1qlQueryExample.java[tag=n1ql_query_1,indent=0] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-net-client/api/Couchbase.Query.QueryOptions.html[QueryOptions^]. +-- + +Node.js:: ++ +-- +To execute a prepared statement, use the `query()` function to run the prepared statement query string again, with the `adhoc` query option set to false. + +Specify parameter values for the query, if necessary. + +''' + +The following example executes a query with the specified parameters. +If a prepared statement has been created from this query previously, the cached query plan is reused. + +[source,javascript] +---- +include::example$prepared/adhoc.js[] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-node-client/interfaces/QueryOptions.html[QueryOptions^]. +-- + +Python:: ++ +-- +To execute a prepared statement, use the `query()` function to run the prepared statement query string again, with the `adhoc` query option set to false. + +Specify parameter values for the query, if necessary. + +''' + +The following example executes a query with the specified parameters. +If a prepared statement has been created from this query previously, the cached query plan is reused. + +[source,python] +---- +include::example$prepared/adhoc.py[] +---- + +For details, refer to https://docs.couchbase.com/sdk-api/couchbase-python-client/couchbase_api/options.html#queryoptions[QueryOptions^]. +-- +==== + +== Related Links + +Overview: + +* xref:n1ql:n1ql-intro/queriesandresults.adoc[{sqlpp} Queries and Results] + +Reference: + +* xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc#sys-prepared[Manage and Monitor Prepared Statements] +ifdef::flag-devex-rest-api[] +* xref:n1ql-rest-admin:index.adoc#tag-PreparedStatements[{sqlpp} Admin REST API for Prepared Statements] +endif::flag-devex-rest-api[] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] + +Prepared statements with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Scala] diff --git a/modules/guides/pages/query.adoc b/modules/guides/pages/query.adoc new file mode 100644 index 000000000..2866716c0 --- /dev/null +++ b/modules/guides/pages/query.adoc @@ -0,0 +1,57 @@ += Select Data with Queries +:page-role: tiles -toc +:page-pagination: next +:description: These guides explain how to read data with a {sqlpp} query. +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +{description} +The {sqlpp} query language enables you to retrieve a document by inspecting its contents to see if it matches a certain criterion. +Key-value operations are quicker, but querying documents allows for richer search capabilities -- for example, "Give me all likes and followed users located in the US", versus "Give me a user with the ID e3d882a4". + +include::ROOT:partial$component-signpost.adoc[] + +== Read Data and Return Results + +include::select.adoc[tags=intro] + +* xref:select.adoc[] + +== Query Across Relationships + +include::join.adoc[tags=intro] + +* xref:join.adoc[] + +== Nest and Unnest Documents + +include::nest-unnest.adoc[tags=intro] + +* xref:nest-unnest.adoc[] + +== Grouping and Aggregation + +include::group-agg.adoc[tags=intro] + +* xref:group-agg.adoc[] + +== Prepared Statements + +include::prep-statements.adoc[tags=intro] + +* xref:prep-statements.adoc[] diff --git a/modules/guides/pages/reading-data.adoc b/modules/guides/pages/reading-data.adoc new file mode 100644 index 000000000..eca334f08 --- /dev/null +++ b/modules/guides/pages/reading-data.adoc @@ -0,0 +1,487 @@ += Read Documents +:description: How to read documents with a command line tool or an SDK. +:page-pagination: full +:page-topic-type: guide +:page-toclevels: 2 +:github: Click the icon:github[] View button to see this code in context. + +include::partial$example-attributes.adoc[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Retrieving documents by ID is the fastest and simplest way to read xref:server:learn:data/data.adoc[data] in Couchbase Capella. +The xref:clusters:data-service/data-service.adoc[Key-Value (KV) or Data Service] allows you to retrieve a full document when you need to fetch all of the data stored. +However, in instances where this can be costly and unnecessary, Couchbase also provides access to specific [.term]#paths# within a document. + +include::partial$clients.adoc[tag=refs] + +include::partial$data-warning.adoc[] + +== Reading a Document + +To read a single document, perform a get operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Use the `doc get` command to retrieve a document by ID and output its data. + +An object is returned, which includes the `id`, `content`, and other metadata. +The document itself is wrapped in the `content` field. + +''' + +{kv-get-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-get] +---- + +.Result +[source,console] +---- +╭───┬───────────┬────────────────────┬─────────────────────┬───────┬─────────╮ +│ # │ id │ content │ cas │ error │ cluster │ +├───┼───────────┼────────────────────┼─────────────────────┼───────┼─────────┤ +│ 0 │ hotel-123 │ {record 11 fields} │ 1717190781443309568 │ │ capella │ +╰───┴───────────┴────────────────────┴─────────────────────┴───────┴─────────╯ +---- + +NOTE: If the document cannot be found, Couchbase Shell returns a `Key not found` error. + +For further details, refer to {cbsh-api-url}/#_reading[Reading^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +Use the `GetAsync()` method to retrieve a document by ID. + +A `GetResult` object is returned, which includes the `content`, `cas` value, and other valuable metadata. + +''' + +{kv-get-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-get,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK returns a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +Use the `get()` method to retrieve a document by ID. + +A `GetResult` object is returned, which includes the `content`, `cas` value, and other valuable metadata. + +''' + +{kv-get-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-get,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK returns a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +Use the `get()` function to retrieve a document by ID. + +A `GetResult` promise is returned, which includes the `content`, `cas` value, and other valuable metadata. + +''' + +{kv-get-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-get,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK returns a `DocumentNotFoundError` error. + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +Use the `get()` function to retrieve a document by ID. + +A `GetResult` object is returned, which includes the `content`, `cas` value, and other valuable metadata. + +''' + +{kv-get-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-get,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK returns a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +=== Reading with Options + +To specify further parameters, add options to the get operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Use the `doc get` command to retrieve a document by ID, and pass options as required. + +''' + +The example below pipes the `hotel-123` document and its metadata through the `to json` filter to transform the output to JSON. + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-get-with-opts] +---- + +.Result +[source,json] +---- +[ + { + "id": "hotel-123", + "content": + { + "address": "Capstone Road, ME7 3JE", + "city": "Medway", + "country": "United Kingdom", + "description": "40 bed summer hostel about 3 miles from Gillingham.", + "geo": + { + "accuracy": "RANGE_INTERPOLATED", + "lat": 51.35785, + "lon": 0.55818 + }, + "id": 123, + "name": "Medway Youth Hostel", + "reviews": + [ + { + "author": "Ozella Sipes", + "content": "This was our 2nd trip here and we enjoyed it more than last year.", + "date": "2021-11-17T17:35:05.351Z" + } + ], + "state": null, + "url": "http://www.yha.org.uk", + "vacancy": true + }, + "cas": 1717190781443309568, + "error": "", + "cluster": "capella" + } +] +---- + +For further details, refer to {cbsh-api-url}/#_reading[Reading^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +Pass any required options to the `GetAsync()` method when retrieving a document. + +A `GetResult` object is returned, which may include extra metadata, depending on the options passed. + +''' + +{kv-get-example-with-options} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-get-with-opts,indent=0] +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +Pass any required options to the `get()` method when retrieving a document. + +A `GetResult` object is returned, which may include extra metadata, depending on the options passed. + +''' + +{kv-get-example-with-options} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-get-with-opts,indent=0] +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +Pass any required options to the `get()` method when retrieving a document. + +A `GetResult` object is returned, which may include extra metadata, depending on the options passed. + +''' + +{kv-get-example-with-options} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-get-with-opts,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +Pass any required options to the `get()` method when retrieving a document. + +A `GetResult` object is returned, which may include extra metadata, depending on the options passed. + +''' + +{kv-get-example-with-options} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-get-with-opts,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + + +== Reading a Sub-Document + +JSON documents can contain a lot of nested data -- which might not necessarily need to be accessed all at once. +For example, the document `airport_1254` contains a sub-document called `geo`. + +.airport_1254 +[source,json] +---- +{ + "id": 1254, +// ... + "geo": { + "lat": 50.962097, + "lon": 1.954764, + "alt": 12 + } +} +---- + +Reading full documents to access a field or two is not ideal and could cause performance issues in your application. +Instead, a better practice would be to access specific paths, or [.term]#sub-documents#, to perform more efficient read operations. +To fetch a specific field inside a document, you can perform a sub-document get operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Use the `doc get` command to retrieve a document by ID. + +. Pipe the document through the `get` filter and specify the path to the field containing the sub-document. + +''' + +{kv-subdoc-get-example} + +[source,sh] +---- +include::example$kv/kv-subdoc.nu[tag=cbsh-subdoc-get] +---- + +.Result +[source,console] +---- +╭───┬────────────────────┬─────────┬────────╮ +│ # │ accuracy │ lat │ lon │ +├───┼────────────────────┼─────────┼────────┤ +│ 0 │ RANGE_INTERPOLATED │ 51.3578 │ 0.5582 │ +╰───┴────────────────────┴─────────┴────────╯ +---- + +NOTE: If the field containing the sub-document cannot be found, the `get` command returns a `Cannot find column` error. + +For further details, refer to {nushell-api-url}/get.html[get for filters^] in the Nushell documentation. +-- + +pass:[.NET]:: ++ +-- +. Call the `LookupInAsync()` method, which takes a document ID and an IEnumerable containing `LookUpInSpec` objects. + +. Use the `LookUpInSpec` object to specify the sub-operation to be performed within the lookup. + +A `LookupInResult` object is returned, containing the result and metadata relevant to the sub-document get operation. + +''' + +{kv-subdoc-get-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-get-subdoc,indent=0] +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Call the `lookupIn()` method, which takes a document ID and an array of `LookUpInSpec` objects. + +. Use the `LookUpInSpec` object to specify the sub-operation to be performed within the lookup. + +A `LookupInResult` object is returned, containing the result and metadata relevant to the sub-document get operation. + +''' + +{kv-subdoc-get-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-get-subdoc,indent=0] +---- + +NOTE: If the document path can't be found, the SDK returns a `PathNotFoundException` error. + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +. Call the `lookupIn()` function, which takes a document ID and an array of `LookUpInSpec` objects. + +. Use the `LookUpInSpec` object to specify the sub-operation to be performed within the lookup. + +A `LookupInResult` promise is returned containing the result and metadata relevant to the sub-document get operation. + +''' + +{kv-subdoc-get-example} + +[source,nodejs,indent=0] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-get-subdoc] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Call the `lookup_in()` function, which takes a document ID and a list of `LookUpInSpec` objects. + +. Use the `LookUpInSpec` object to represent the sub-operation to be performed within the lookup. + +A `LookupInResult` object is returned containing the result and metadata relevant to the sub-document get operation. + +''' + +{kv-subdoc-get-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-get-subdoc,indent=0] +---- + +NOTE: If the document path can't be found, the SDK returns a `PathNotFoundException` error. + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Related Links + +Key-Value Operations with SDKs: + +* xref:c-sdk:howtos:kv-operations.adoc[C] +| xref:dotnet-sdk:howtos:kv-operations.adoc[.NET] +| xref:go-sdk:howtos:kv-operations.adoc[Go] +| xref:java-sdk:howtos:kv-operations.adoc[Java] +| xref:nodejs-sdk:howtos:kv-operations.adoc[Node.js] +| xref:php-sdk:howtos:kv-operations.adoc[PHP] +| xref:python-sdk:howtos:kv-operations.adoc[Python] +| xref:ruby-sdk:howtos:kv-operations.adoc[Ruby] +| xref:scala-sdk:howtos:kv-operations.adoc[Scala] + +Sub-Document operations with SDKs: + +* xref:c-sdk:howtos:subdocument-operations.adoc[C] +| xref:dotnet-sdk:howtos:subdocument-operations.adoc[.NET] +| xref:go-sdk:howtos:subdocument-operations.adoc[Go] +| xref:java-sdk:howtos:subdocument-operations.adoc[Java] +| xref:nodejs-sdk:howtos:subdocument-operations.adoc[Node.js] +| xref:php-sdk:howtos:subdocument-operations.adoc[PHP] +| xref:python-sdk:howtos:subdocument-operations.adoc[Python] +| xref:ruby-sdk:howtos:subdocument-operations.adoc[Ruby] +| xref:scala-sdk:howtos:subdocument-operations.adoc[Scala] diff --git a/modules/guides/pages/select-index.adoc b/modules/guides/pages/select-index.adoc new file mode 100644 index 000000000..f384af7f4 --- /dev/null +++ b/modules/guides/pages/select-index.adoc @@ -0,0 +1,107 @@ += Select Indexes +:page-topic-type: guide +:imagesdir: ../assets/images +:tabs: +:page-partial: +:page-pagination: +:description: How to select an index for a query. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +Couchbase Capella attempts to select an appropriate secondary index for a query, based on the filters in the WHERE clause. +// end::intro[] +If it cannot select a secondary query, the query service falls back on the the primary index for the keyspace, if one exists. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +== Specifying Predicates to Select an Index + +To specify an index using query predicates, specify the leading query predicates in the WHERE clause in the same order as the index keys in the index. + +TIP: Use `IS NOT MISSING` as the predicate for any fields which are required by the index, but which are not actually used for filtering data in the query. + +==== +.Context +include::partial$query-context.adoc[tag=step] + +.Queries +The following query creates a secondary index on the `image_direct_url` field in the `landmark` keyspace. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-predicate.n1ql[] +---- + +The following query uses a minimal filter on the `image_direct_url` field to select the `idx_image_direct_url` index. + +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/select-idx-filter.n1ql[] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/selectintro.adoc#index-selection[Index Selection]. + +== Specifying an Index Hint + +// tag::intro[] +You can use an index hint to specify that a query should use a particular index. +// end::intro[] +The index must be applicable to the query. + +To specify an index by name: + +. Use an index hint within a hint comment, immediately after the SELECT keyword. + +. In the index hint, specify the keyspace to which the hint applies, and the index to use. + +==== +This example uses an index hint to select the index `def_inventory_route_route_src_dst_day`, which is installed with the travel sample data. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source.no-callouts,sqlpp] +---- +include::n1ql:example$select/index-hint.n1ql[tag=query] +---- +==== + +For further details and examples, refer to xref:n1ql:n1ql-language-reference/keyspace-hints.adoc#index[INDEX]. + +== Related Links + +Reference and explanation: + +* xref:server:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes] +* xref:n1ql:n1ql-language-reference/selectintro.adoc[SELECT] +* xref:n1ql:n1ql-language-reference/optimizer-hints.adoc[Hints] + +Administrator guides: + +* xref:cloud:clusters:index-service/manage-indexes.adoc[Manage Indexes] +* xref:cloud:clusters:index-service/manage-indexes.adoc#accessing-indexes-in-the-capella-ui[Monitor Indexes] + +Tutorials: + +* https://query-tutorial.couchbase.com/tutorial/#1[{sqlpp} Query Language Tutorial^] + +Indexes with SDKs: + +* xref:c-sdk:concept-docs:n1ql-query.adoc#indexes[C] +| xref:dotnet-sdk:concept-docs:n1ql-query.adoc#indexes[.NET] +| xref:go-sdk:concept-docs:n1ql-query.adoc#indexes[Go] +| xref:java-sdk:concept-docs:n1ql-query.adoc#indexes[Java] +| xref:nodejs-sdk:concept-docs:n1ql-query.adoc#indexes[Node.js] +| xref:php-sdk:concept-docs:n1ql-query.adoc#indexes[PHP] +| xref:python-sdk:concept-docs:n1ql-query.adoc#indexes[Python] +| xref:ruby-sdk:concept-docs:n1ql-query.adoc#indexes[Ruby] +| xref:scala-sdk:concept-docs:n1ql-query.adoc#indexes[Scala] diff --git a/modules/guides/pages/select.adoc b/modules/guides/pages/select.adoc new file mode 100644 index 000000000..889188f2e --- /dev/null +++ b/modules/guides/pages/select.adoc @@ -0,0 +1,309 @@ += Read Data and Return Results +:page-topic-type: guide +:page-partial: +:page-pagination: +:imagesdir: ../assets/images +:description: How to use a {sqlpp} selection query to read data from a data source and return results. +:github: Click the icon:github[] View button to see this code in context. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +The xref:n1ql:query.adoc[Query Service] enables you to create, read, update, and delete data by means of xref:n1ql:n1ql-language-reference/index.adoc[{sqlpp}], the Couchbase Capella query language. +// tag::intro[] +To read data from a data source using {sqlpp}, you must use a selection query; that is, a query using the `SELECT` statement. +// end::intro[] + +include::partial$before-you-begin.adoc[] + +include::partial$query-tools.adoc[] + +== Selecting + +A selection query enables you to read information from a data source, perform operations on the data, and return the results. + +To specify what the query should return, use the SELECT clause. + +[tabs] +==== +{sqlpp}:: ++ +-- +The following example uses the SELECT clause by itself to evaluate an expression. + +.Query +[source,sqlpp] +---- +include::example$query/select-clause.n1ql[] +---- + +.Result +[source,json] +---- +include::example$query/select-clause.jsonc[] +---- +-- + +.NET:: ++ +-- +The following example uses the `Cluster.QueryAsync` method to execute the query. +The result includes each row found. + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$StartUsing.cs[tag=n1ql-query,indent=0] +---- + +{github} +-- + +Java:: ++ +-- +The following example uses the `query()` method to execute the query. +The result object includes each row found. + +[source,java] +---- +include::java-sdk:devguide:example$java/StartUsing.java[tag=n1ql-query,indent=0] +---- + +{github} +-- + +Node.js:: ++ +-- +The following example uses the `query()` function to execute a query. +The result object includes an array of rows found. + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$n1ql-hello-world.js[tag=n1ql-query,indent=0] +---- + +{github} +-- + +Python:: ++ +-- +The following example uses the `query()` function to execute a query. +The result object includes an array of rows found. + +[source,python] +---- +include::python-sdk:devguide:example$python/query_hello_world.py[tag=n1ql-query,indent=0] +---- + +{github} +-- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/selectclause.adoc[SELECT Clause]. + +== Specifying a Data Source + +To specify the data source for a query, use the FROM clause. +For example, to get data from a collection, specify the path to that collection in a FROM clause. + +When you specify a FROM clause, you can use the SELECT clause to specify the fields that you want to return from that data source. +The set of fields returned by the query is known as the _projection_. + +==== +The following query gets the name and city of every airport. + +.Query +[source,sqlpp] +---- +include::example$query/from-clause.n1ql[] +---- + +There are backticks around the travel-sample dataset because its name contains a hyphen. + +.Result +[source,json] +---- +include::example$query/from-clause.jsonc[tags=extract;ellipsis] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/from.adoc[FROM Clause]. + +[#query-context] +== Setting the Query Context + +The query context enables you to specify a bucket and scope to resolve partial keyspace references within your queries. +When the query context is set, you can specify the data source in your queries using the collection name only. +This enhances the portability of your queries. + +NOTE: The query context is only used to resolve partial keyspace references. +When a query specifies a data source using the full path to a keyspace, the query context is not used to resolve that keyspace. + +[tabs] +==== +Query Tab:: ++ +-- +To set the query context: + +. Using the *Query Context* controls in the Query tab, open the Bucket drop-down menu and select the required bucket. + +. Open the Scope drop-down menu and select the required scope. + +image::query-workbench-context.png["The query context controls with `travel-sample.inventory` selected"] +-- + +CBQ Shell:: ++ +-- +To set the query context, use the `\SET` command with the `query_context` parameter. + +''' + +For example, the following command sets the query context to `travel-sample.inventory`. + +[source,sqlpp] +---- +include::example$query/context-set.n1ql[] +---- +-- +==== + +Some legacy queries contain keyspace references consisting of the bucket name only, referring to the default collection in the default scope. +To specify the data source using the bucket name only, you must unset the query context. + +[tabs] +==== +Query Tab:: ++ +-- +To unset the query context, using the *Query Context* controls in the Query tab, open the Bucket drop-down menu and choose `Select a bucket`. + +image::query-workbench-context-unset.png["The query context controls with the query context unset"] +-- + +CBQ Shell:: ++ +-- +To unset the query context, use `\UNSET` command with the `query_context` parameter. + +''' + +For example, the following command unsets the query context. + +[source,sqlpp] +---- +include::example$query/context-unset.n1ql[] +---- +-- +==== + +For more information and examples, refer to xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +== Filtering + +To filter the results of the query, use the WHERE clause to specify a comparison expression. +Only records that satisfy the comparison expression are returned. + +==== +For example, the following query finds the name and city of every airport in the Anchorage timezone whose altitude is greater than or equal to 2100. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/query-keyspace-idx.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$select/query-keyspace-idx.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/where.adoc[WHERE Clause]. + +== Limiting Results + +To limit the number of documents returned by a query, use the `LIMIT` clause. + +==== +For example, the following query finds only 2 hotels with an empty room. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/limit-number.n1ql[] +---- + +.Result +[source,json] +---- +include::n1ql:example$select/limit-result.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/limit.adoc[LIMIT Clause]. + +== Ordering Results + +To sort the documents in the resultset by one or more fields, use the `ORDER BY` clause. + +==== +For example, the following query lists cities in descending order and then landmarks in ascending order. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$select/order-by.n1ql[] +---- + +.Results: +[source,json] +---- +include::n1ql:example$select/order-by.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/orderby.adoc[ORDER BY Clause]. + +== Related Links + +In-depth explanation: + +* xref:n1ql:n1ql-language-reference/selectintro.adoc[SELECT] + +Reference: + +* xref:n1ql:n1ql-language-reference/select-syntax.adoc[SELECT Syntax] + +Tutorials: + +* https://query-tutorial.couchbase.com/tutorial/#1[{sqlpp} Query Language Tutorial^] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/transactions.adoc b/modules/guides/pages/transactions.adoc new file mode 100644 index 000000000..e945a3eb2 --- /dev/null +++ b/modules/guides/pages/transactions.adoc @@ -0,0 +1,314 @@ += Create Couchbase Transactions with {sqlpp} +:page-topic-type: guide +:page-toclevels: 2 +:imagesdir: ../assets/images +:tabs: +:description: How to create Couchbase transactions using {sqlpp}. +:github: Click the icon:github[] View button to see this code in context. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Couchbase transactions enable you to carry out ACID (atomic, consistent, isolated, and durable) actions on the database. +This how-to guide covers {sqlpp} support for Couchbase transactions. +Some SDKs also support Couchbase transactions. +Refer to <> for further details. + +Only DML (data modification language) statements are permitted within a transaction: +xref:n1ql:n1ql-language-reference/insert.adoc[INSERT], +xref:n1ql:n1ql-language-reference/upsert.adoc[UPSERT], +xref:n1ql:n1ql-language-reference/delete.adoc[DELETE], +xref:n1ql:n1ql-language-reference/update.adoc[UPDATE], +xref:n1ql:n1ql-language-reference/merge.adoc[MERGE], +xref:n1ql:n1ql-language-reference/select.adoc[SELECT], +xref:n1ql:n1ql-language-reference/execfunction.adoc[EXECUTE FUNCTION], +xref:n1ql:n1ql-language-reference/prepare.adoc[PREPARE], or +xref:n1ql:n1ql-language-reference/execute.adoc[EXECUTE]. + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +include::partial$data-warning.adoc[] + +[[settings]] +== Transaction Parameters +:lead: The following example shows transaction parameters for the examples on this page. + +You can specify various settings and parameters to control how transactions work. +You can access transaction settings and parameters through any of the usual Query tools, such as the Query tab or the cbq shell. + +[tabs] +==== +Query Tab:: ++ +-- +To specify parameters for a Couchbase transaction, use the Query Options dialog. + +. To display the Query Options dialog, click btn:[Query Options]. + +. To specify the transaction scan consistency, in the *Scan Consistency* list, select an option. + +. To specify the transaction timeout, in the *Transaction Timeout* box, enter a value in seconds. + +. To specify any other transaction parameters, click the btn:[+] button in the *Named Parameters* section. +When the new named parameter appears, enter the name in the *name* box and a value in the *value* box. + +. To save your preferences and return to the Query tab, click btn:[Save]. + +''' + +{lead} + +image::transactions-preferences.png['The Query Options dialog, with Scan Consistency set to "not_bounded", Transaction Timeout set to "120", and named parameter "durability_level" set to "none"'] + +* The transaction scan consistency is set to `not_bounded`. +* The durability level of all the mutations within the transaction is set to `"none"`. +* The transaction timeout is set to `120`. +-- + +CBQ Shell:: ++ +-- +To specify parameters for a Couchbase transaction, use the `\SET` command. + +''' + +{lead} + +[source,sqlpp] +---- +include::n1ql:example$transactions/multiple.n1ql[tag=settings] +---- + +<.> The transaction timeout. +<.> The transaction scan consistency. +<.> Durability level of all the mutations within the transaction. + +{github} +-- +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/transactions.adoc#settings-and-parameters[Transaction Settings and Parameters]. + +[[single-statement]] +== Single Statement Transactions + +You can create a Couchbase transaction containing a single DML statement. + +[tabs] +==== +//// +Query Tab:: ++ +-- +To execute a single statement as a transaction, simply enter the statement in the Query Editor and click btn:[Run as TX]. + +''' + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$transactions/single.n1ql[tag=query] +---- +-- +//// + +CBQ Shell:: ++ +-- +To execute a single statement as a transaction, set the `tximplicit` parameter to `true`. + +''' + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$transactions/single.n1ql[tags=**] +---- +-- +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/transactions.adoc#query-tools[Query Tools]. + +[[multiple-statement]] +== Multiple Statement Transactions +:lead: For a worked example showing a complete transaction using {sqlpp}, see xref:n1ql:n1ql-language-reference/transactions.adoc#worked-example[Transaction Worked Example]. \ +Individual {sqlpp} transaction statements are described in the sections below. + +A Couchbase transaction may contain multiple DML statements. +In this case, you must use {sqlpp} transaction statements to support the transaction: + +* <> to start the transaction. +* <> to specify transaction settings. +* <> to set a transaction savepoint. +* <> to roll back a transaction. +* <> to commit a transaction. + +[tabs] +==== +Query Tab:: ++ +-- +To execute a transaction containing multiple statements: + +. Compose the sequence of statements in the Query Editor. +Each statement must be terminated with a semicolon. + +. After each statement, press kbd:[Shift+Enter] to start a new line _without_ executing the query. + +. When you have entered the entire transaction, click btn:[Run] to execute the transaction. + +''' + +{lead} +-- + +CBQ Shell:: ++ +-- +To execute a transaction containing multiple statements, create the transaction one statement at a time. + +Once you have started a transaction, all statements within the cbq shell session are assumed to be part of the same transaction until you rollback or commit the transaction. + +NOTE: You must be using cbq shell version 2.0 or above to use the automatic transaction ID functionality. + +''' + +{lead} +-- +==== + +[[begin]] +=== Begin a Transaction + +To start a transaction, use the `BEGIN TRANSACTION` statement. + +==== +The following statement begins a transaction. + +[source,sqlpp] +---- +include::n1ql:example$transactions/multiple.n1ql[tag=begin] +---- + +{github} + +.Result +[source,json,indent=0] +---- +include::n1ql:example$transactions/results.jsonc[tag=begin] +---- + +<.> Beginning a transaction returns the transaction ID. +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/begin-transaction.adoc[BEGIN TRANSACTION]. + +[[set]] +=== Specify Transaction Settings + +To specify transaction settings, use the `SET TRANSACTION` statement. + +NOTE: Currently, the only available transaction setting is "isolation level read committed". +This setting is enabled by default. +The `SET TRANSACTION` statement is therefore optional and may be omitted. + +==== +The following statement specifies transaction settings. + +[source,sqlpp] +---- +include::n1ql:example$transactions/multiple.n1ql[tag=set] +---- + +{github} +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/set-transaction.adoc[SET TRANSACTION]. + +[[savepoint]] +=== Set a Savepoint + +To set a savepoint within a transaction, use the `SAVEPOINT` statement and specify a name for the savepoint. + +==== +The following statement sets a savepoint. + +[source,sqlpp] +---- +include::n1ql:example$transactions/multiple.n1ql[tag=savepoint-1] +---- + +{github} +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/savepoint.adoc[SAVEPOINT]. + +[[rollback]] +=== Roll Back a Transaction + +To roll back a transaction, use the `ROLLBACK TRANSACTION` statement. + +By default, this statement rolls back the entire transaction. +If you want to roll back to a savepoint, use the `TO SAVEPOINT` keywords and specify the savepoint name. + +==== +The following statement rolls back a transaction to a specified savepoint. + +[source,sqlpp] +---- +include::n1ql:example$transactions/multiple.n1ql[tag=rollback] +---- + +{github} +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/rollback-transaction.adoc[ROLLBACK TRANSACTION]. + +[[commit]] +=== Commit a Transaction + +To commit a transaction, use the `COMMIT TRANSACTION` statement. + +==== +The following statement commits a transaction. + +[source,sqlpp] +---- +include::n1ql:example$transactions/multiple.n1ql[tag=commit] +---- + +{github} +==== + +For further details, refer to xref:n1ql:n1ql-language-reference/commit-transaction.adoc[COMMIT TRANSACTION]. + +[[related-links]] +== Related Links + +Reference and explanation: + +* xref:server:learn:data/transactions.adoc[Transactions] +* xref:n1ql:n1ql-language-reference/transactions.adoc[{sqlpp} Support for Couchbase Transactions] + +Online transaction simulator: + +* https://transactions.couchbase.com[Query Transaction Simulator^] + +Transactions with SDKs: + +* xref:java-sdk:howtos:distributed-acid-transactions-from-the-sdk.adoc[] +* xref:cxx-txns::distributed-acid-transactions-from-the-sdk.adoc[] +* xref:dotnet-sdk:howtos:distributed-acid-transactions-from-the-sdk.adoc[] +* xref:go-sdk:howtos:distributed-acid-transactions-from-the-sdk.adoc[] +* xref:nodejs-sdk:howtos:distributed-acid-transactions-from-the-sdk.adoc[] diff --git a/modules/guides/pages/update.adoc b/modules/guides/pages/update.adoc new file mode 100644 index 000000000..5074127b1 --- /dev/null +++ b/modules/guides/pages/update.adoc @@ -0,0 +1,270 @@ += Modify Data with a Query +:page-topic-type: guide +:imagesdir: ../assets/images +:tabs: +:page-partial: +:page-pagination: +:description: How to modify documents using {sqlpp}. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +// tag::intro[] +To modify documents in a keyspace, you can use the UPDATE statement or the the MERGE statement. +// end::intro[] + +include::partial$before-you-begin.adoc[tag=body] +include::partial$query-tools.adoc[tags=body;!thumbs] + +include::partial$data-warning.adoc[] + +== Modifying Documents by Key + +To modify one or more documents by key, use the UPDATE statement with the USE KEYS hint: + +. Use the FROM keyword to specify the keyspace which contains the documents to be modified. +. Use the USE KEYS hint to specify a document keys or array of document keys. +. Use the SET and UNSET clauses to set and unset attributes as required. +. If required, use the RETURNING clause to specify what should be returned when the documents are deleted. + +You can combine this approach with the WHERE clause if necessary. + +==== +The following query adds an attribute to a document with the key `"landmark_10090"` and returns the added attribute. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-set.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-set.jsonc[] +---- +==== + +==== +The following query removes an attribute from a document with the key `"landmark_10090"` and returns the `name` attribute. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-unset.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-unset.jsonc[] +---- +==== + +== Modifying Documents by Filter + +To modify documents by filter, use the UPDATE statement with the WHERE clause: + +. Use the FROM keyword to specify the keyspace which contains the documents to be modified. +. Use the SET and UNSET clauses to set and unset attributes as required. +. Use the WHERE clause to specify the condition that needs to be met for documents to be modified. +. If required, use the LIMIT clause to specify the greatest number of documents that may be modified. +. If required, use the RETURNING clause to specify what should be returned when the documents are modified. + +You can combine this approach with the USE KEYS hint if necessary. + +==== +The following query standardizes the capitalization of the `city` field for all airports in San Francisco. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-rbac-return.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-rbac-return.jsonc[] +---- +==== + +== Modifying Documents by Subquery + +To modify documents based on the results returned by a SELECT query, use a subquery in the filter. + +==== +The following query adds an attribute to the airport whose FAA code is `NCE`, containing a list of every hotel in Nice. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-set-sub.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-set-sub.jsonc[] +---- +==== + +== Modifying Nested Arrays and Objects + +To modify nested objects in an array, use the FOR clause within the SET or UNSET clause. + +. Use the FOR keyword to specify a dummy variable that refers to each object in the array. +. Use the IN keyword to specify the path to the array. +. If required, use the WHEN clause to filter the objects in the array. + +==== +The following query adds an attribute to each object in the `schedule` array in document `"landmark_10090"`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-set-array.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-set-array.jsonc[tags=extract;ellipsis] +---- +==== + +=== Using Object Functions and Array Functions + +To modify an object attribute, use an object function. +Similarly, to modify an array attribute, use an array function. + +==== +The following query adds an attribute to the `ratings` object within each review in document `"landmark_10025"`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-set-nested.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-set-nested.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/objectfun.adoc[Object Functions] and xref:n1ql:n1ql-language-reference/arrayfun.adoc[Array Functions]. + +=== Using the ARRAY Operator + +Alternatively, to access deeply-nested attributes, use the ARRAY operator. + +==== +The following query removes an attribute from the `ratings` object within each review in document `"landmark_10025"`. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/update-unset-nested.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/update-unset-nested.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/collectionops.adoc#array[ARRAY]. + +== Merging and Updating Documents + +You can also update documents by merging: that is, by joining one data source to another, and updating any documents that match. + +To update documents using a merge, use the MERGE statement with the UPDATE action: + +. Use the INTO keyword to specify the target. +This is the data source in which documents will be updated. + +. Use the USING keyword to specify the source. +This is the data source to check against the target. + +. Use the ON keyword to specify the merge predicate. +This is a condition that must be met to match an object in the source with an object in the target. + +. Use WHEN MATCHED THEN UPDATE to specify that when a document in the source matches a document in the target, the document in the target should be updated. + + .. Use the SET and UNSET clauses to set and unset attributes as required. + + .. If necessary, use the WHERE clause to specify any further conditions that must be met for documents to be updated. + +. If required, use the LIMIT clause to specify the greatest number of documents that may be updated. + +. If required, use the RETURNING clause to specify what should be returned when the documents are updated. + +==== +The following query compares a source set of hotel data with the target `hotel` keyspace. +If the hotel already exists in the `hotel` keyspace, the record is updated, and the query returns the target document key and the attributes which were changed. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +include::n1ql:example$dml/ansi-merge-expr.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$dml/ansi-merge-expr.jsonc[] +---- +==== + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/merge.adoc[MERGE]. + +== Related Links + +Reference and explanation: + +* xref:n1ql:n1ql-language-reference/update.adoc[UPDATE] +* xref:n1ql:n1ql-language-reference/merge.adoc[MERGE] + +Querying with SDKs: + +* xref:c-sdk:howtos:n1ql-queries-with-sdk.adoc[C] +| xref:dotnet-sdk:howtos:n1ql-queries-with-sdk.adoc[.NET] +| xref:go-sdk:howtos:n1ql-queries-with-sdk.adoc[Go] +| xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc[Java] +| xref:nodejs-sdk:howtos:n1ql-queries-with-sdk.adoc[Node.js] +| xref:php-sdk:howtos:n1ql-queries-with-sdk.adoc[PHP] +| xref:python-sdk:howtos:n1ql-queries-with-sdk.adoc[Python] +| xref:ruby-sdk:howtos:n1ql-queries-with-sdk.adoc[Ruby] +| xref:scala-sdk:howtos:n1ql-queries-with-sdk.adoc[Scala] diff --git a/modules/guides/pages/updating-data.adoc b/modules/guides/pages/updating-data.adoc new file mode 100644 index 000000000..9e5992bde --- /dev/null +++ b/modules/guides/pages/updating-data.adoc @@ -0,0 +1,446 @@ += Update Documents +:description: How to update documents with a command line tool or an SDK. +:page-pagination: full +:page-topic-type: guide +:github: Click the icon:github[] View button to see this code in context. + +include::partial$example-attributes.adoc[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Introduction + +Couchbase Capella allows you to update data within a document by ID using either an upsert or a replace operation. +An upsert operation will update or create a full document with the given data. +A replace operation, on the other hand, will only replace a document if it exists within the database. + +include::partial$clients.adoc[tag=refs] + +include::partial$data-warning.adoc[] + +== Upserting a Document + +To update a document, or create the document if it doesn't exist, perform an upsert operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Create a structured JSON object containing the updated data. + +. Use `doc upsert` to update the document. + +If the document doesn't exist, Couchbase Capella creates a new document. + +''' + +{kv-update-upsert-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-upsert] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {cbsh-api-url}/#_mutating[Mutating^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +Use the `UpsertAsync()` method to update a document in the database. +If it doesn't exist, Couchbase Capella creates a new document. + +''' + +{kv-update-upsert-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-update-upsert,indent=0] +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +Use the `upsert()` method to update a document in the database. +If it doesn't exist, Couchbase Capella creates a new document. + +''' + +{kv-update-upsert-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-update-upsert,indent=0] +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +Use the `upsert()` function to update a document in the database. +If it doesn't exist, Couchbase Capella creates a new document. + +''' + +{kv-update-upsert-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-update-upsert,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +Use the `upsert()` function to update a document in the database. +If it doesn't exist, Couchbase Capella creates a new document. + +''' + +{kv-update-upsert-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-update-upsert,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Replacing a Document + +To update a document that already exists, perform a replace operation. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Create a structured JSON object containing the new data. + +. Use `doc replace` to update the document. + +''' + +{kv-update-replace-example} + +[source,sh] +---- +include::example$kv/kv-cbsh.nu[tag=cbsh-kv-replace] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +NOTE: If the document cannot be found, Couchbase Shell returns a `Key not found` error. + +For further details, refer to {cbsh-api-url}/#_mutating[Mutating^] in the Couchbase Shell documentation. +-- + +pass:[.NET]:: ++ +-- +. Fetch an existing document and change some of its data. + +. Use the `ReplaceAsync()` function to update a document in Couchbase. + To ensure data has not been modified before executing the replace operation, pass the document's `CAS` value to the method. + +A new `CAS` value is provided in the returned `MutationResult` object. + +''' + +{kv-update-replace-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-update-replace,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Fetch an existing document and change some of its data. + +. Use the `replace()` method to update a document in Couchbase. + To ensure data has not been modified before executing the replace operation, pass the document's `CAS` value to the method. + +A new `CAS` value is provided in the returned `MutationResult` object. + +''' + +{kv-update-replace-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-update-replace,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +. Fetch an existing document and change some of its data. + +. Use the `replace()` function to update a document in Couchbase. + To ensure data has not been modified before executing the replace operation, pass the document's `CAS` value to the method. + +A new `CAS` value is provided in the returned `MutationResult` object. + +''' + +{kv-update-replace-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-update-replace,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundError` error. + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Fetch an existing document and change some of its data. + +. Use the `replace()` function to update a document in Couchbase. + To ensure data has not been modified before executing the replace operation, pass the document's `CAS` value to the method. + +A new `CAS` value is provided in the returned `MutationResult` object. + +''' + +{kv-update-replace-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-update-replace,indent=0] +---- + +NOTE: If the document doesn't exist, the SDK will return a `DocumentNotFoundException` error. + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + + +== Updating a Sub-Document + +To change a specific field inside a document, you can perform a sub-document operation. +You can use either a sub-document upsert or replace operation depending on what is required for your application. + +[tabs] +==== +cbsh:: ++ +-- +. If you haven't already done so, use `cb-env` to set the bucket, scope, and collection where the document is stored. + +. Use the `doc get` command to retrieve a document by ID. + +. Pipe the document through the `upsert` filter to update or add the field containing the sub-document, or use the `update` filter if you require the field to exist. + +. Pipe the output, including the `id` and `content` fields, through the `doc replace` command to update the document. + +''' + +{kv-subdoc-update-example} + +[source,sh] +---- +include::example$kv/kv-subdoc.nu[tag=cbsh-subdoc-upsert] +---- + +.Result +[source,console] +---- +╭───┬───────────┬─────────┬────────┬──────────┬─────────╮ +│ # │ processed │ success │ failed │ failures │ cluster │ +├───┼───────────┼─────────┼────────┼──────────┼─────────┤ +│ 0 │ 1 │ 1 │ 0 │ │ capella │ +╰───┴───────────┴─────────┴────────┴──────────┴─────────╯ +---- + +For further details, refer to {nushell-api-url}/upsert.html[upsert for filters^] or {nushell-api-url}/update.html[update for filters^] in the Nushell documentation. +-- + +pass:[.NET]:: ++ +-- +. Call the `MutateInAsync()` method, which takes a document ID and an IEnumerable containing `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document update operation. + +''' + +{kv-subdoc-update-example} + +[source,csharp] +---- +include::dotnet-sdk:hello-world:example$KvHelloWorldScoped.csx[tag=kv-update-subdoc,indent=0] +---- + +{github} + +For further details, refer to {dotnet-api-url}/Couchbase.KeyValue.CollectionExtensions.html[CollectionExtensions^]. +-- + +Java:: ++ +-- +. Call the `mutateIn()` method, which takes a document ID and an array of `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document update operation. + +''' + +{kv-subdoc-update-example} + +[source,java] +---- +include::java-sdk:devguide:example$java/KvHelloWorldScoped.java[tag=kv-update-subdoc,indent=0] +---- + +{github} + +For further details, refer to {java-api-url}/Collection.html[Collection^]. +-- + +Node.js:: ++ +-- +. Call the `mutateIn()` method, which takes a document ID and an array of `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document update operation. + +''' + +{kv-subdoc-update-example} + +[source,nodejs] +---- +include::nodejs-sdk:hello-world:example$kv-hello-world-scoped.js[tag=kv-update-subdoc,indent=0] +---- + +{github} + +For further details, refer to {nodejs-api-url}/Collection.html[Collection^]. +-- + +Python:: ++ +-- +. Call the `mutate_in()` function, which takes a document ID and a list of `MutateInSpec` objects. + +. Use a `MutateInSpec` object to specify the sub-operation to be performed within the lookup. + +A `MutateInResult` object is returned, containing the result and metadata relevant to the sub-document get operation. + +''' + +{kv-subdoc-update-example} + +[source,python] +---- +include::python-sdk:devguide:example$python/kv_hello_world_scoped.py[tag=kv-update-subdoc,indent=0] +---- + +{github} + +For further details, refer to {python-api-url}#collection-object[Collection^]. +-- +==== + +== Related Links + +Key-Value Operations with SDKs: + +* xref:c-sdk:howtos:kv-operations.adoc[C] +| xref:dotnet-sdk:howtos:kv-operations.adoc[.NET] +| xref:go-sdk:howtos:kv-operations.adoc[Go] +| xref:java-sdk:howtos:kv-operations.adoc[Java] +| xref:nodejs-sdk:howtos:kv-operations.adoc[Node.js] +| xref:php-sdk:howtos:kv-operations.adoc[PHP] +| xref:python-sdk:howtos:kv-operations.adoc[Python] +| xref:ruby-sdk:howtos:kv-operations.adoc[Ruby] +| xref:scala-sdk:howtos:kv-operations.adoc[Scala] + +Sub-Document operations with SDKs: + +* xref:c-sdk:howtos:subdocument-operations.adoc[C] +| xref:dotnet-sdk:howtos:subdocument-operations.adoc[.NET] +| xref:go-sdk:howtos:subdocument-operations.adoc[Go] +| xref:java-sdk:howtos:subdocument-operations.adoc[Java] +| xref:nodejs-sdk:howtos:subdocument-operations.adoc[Node.js] +| xref:php-sdk:howtos:subdocument-operations.adoc[PHP] +| xref:python-sdk:howtos:subdocument-operations.adoc[Python] +| xref:ruby-sdk:howtos:subdocument-operations.adoc[Ruby] +| xref:scala-sdk:howtos:subdocument-operations.adoc[Scala] diff --git a/modules/guides/partials/before-you-begin.adoc b/modules/guides/partials/before-you-begin.adoc new file mode 100644 index 000000000..6dd426d48 --- /dev/null +++ b/modules/guides/partials/before-you-begin.adoc @@ -0,0 +1,5 @@ +== Before You Begin + +// tag::body[] +If you want to try out the examples in this section, follow the instructions given in xref:get-started:create-account.adoc[] to create a free account, deploy a cluster, and load a sample dataset. +// end::body[] \ No newline at end of file diff --git a/modules/guides/partials/clients.adoc b/modules/guides/partials/clients.adoc new file mode 100644 index 000000000..ac2104379 --- /dev/null +++ b/modules/guides/partials/clients.adoc @@ -0,0 +1,23 @@ +:imagesdir: ../assets/images + +=== Couchbase Clients + +// tag::body[] +Clients access data by connecting to a Couchbase cluster over the network. +The most common type of client is a Couchbase SDK, which is a full programmatic API that enables applications to take the best advantage of Couchbase. +This developer guide focuses on the most commonly-used SDKs, but full explanations and reference documentation for all SDKs is available. + +The Couchbase Shell (cbsh) also provides a quick and streamlined interface for simple access, and is suitable if you just want to access an item without writing any code. +Note that the Couchbase Shell is currently in developer preview, and is not covered by support. + +// tag::refs[] +Read the following for further information about the clients available: + +* https://couchbase.sh/docs/[Couchbase Shell (cbsh)] -- developer preview +* xref:home::sdk.adoc[SDK Clients] +// end::refs[] + +// tag::refs-ui[] +It is also possible to access document data via the Couchbase Capella UI. +// end::refs-ui[] +// end::body[] diff --git a/modules/guides/partials/data-warning.adoc b/modules/guides/partials/data-warning.adoc new file mode 100644 index 000000000..2580b3db1 --- /dev/null +++ b/modules/guides/partials/data-warning.adoc @@ -0,0 +1,3 @@ +WARNING: Please note that the examples in this guide will alter the data in your sample database. +To restore your sample data, remove and reinstall the travel sample data. +Refer to xref:clusters:data-service/import-data-documents.adoc[] for details. \ No newline at end of file diff --git a/modules/guides/partials/example-attributes.adoc b/modules/guides/partials/example-attributes.adoc new file mode 100644 index 000000000..8aaefbd44 --- /dev/null +++ b/modules/guides/partials/example-attributes.adoc @@ -0,0 +1,36 @@ +// creating-data.adoc +:kv-insert-example: pass:q[The example below inserts a new JSON document in the `hotel` keyspace in the `inventory` scope. The document's ID is `hotel-123`.] +:kv-insert-with-options-example: pass:q[The example below inserts a new JSON document and sets it to expire after 60 seconds. The document will be automatically deleted once expired.] + +// reading-data.adoc +:kv-get-example: pass:q[The example below retrieves document `hotel-123` from the `hotel` keyspace in the `inventory` scope.] +:kv-get-example-with-options: pass:q[The example below retrieves a document `hotel-123` with additional expiry metadata.] +:kv-subdoc-get-example: pass:q[The example below fetches the `geo` data from the `hotel-123` document.] + +// updating-data.adoc +:kv-update-upsert-example: pass:q[The example below updates the existing document `hotel-123`.] +:kv-update-replace-example: pass:q[The example below adds a new entry to the `reviews` array in document `hotel-123`.] +:kv-subdoc-update-example: pass:q[The example below upserts a `pets_ok` field in document `hotel-123` and sets the value to true.] + +// deleting-data.adoc +:kv-delete-example: pass:q[The example below deletes document `hotel-123` from the database.] +:kv-subdoc-delete-example: pass:q[The example below deletes the `url` field from document `hotel-123`.] + +// bulk-operations.adoc +:kv-bulk-insert-example: pass:q[The example below inserts multiple JSON documents in the `users` keyspace in the `tenant_agent_00` scope.] +:kv-bulk-update-example: pass:q[The example below upserts multiple JSON documents in the `users` keyspace in the `tenant_agent_00` scope.] +:kv-bulk-get-example: pass:q[The example below fetches multiple JSON documents from the `users` keyspace in the `tenant_agent_00` scope.] +:kv-bulk-delete-example: pass:q[The example below deletes multiple JSON documents from the `users` keyspace in the `tenant_agent_00` scope.] + +// connect.adoc +:connect-example: pass:q[The example below connects to a single-node cluster environment with basic auth credentials.] +:connect-tls-example: pass:q[The example below connects to a single-node cluster over a secure connection with a client certificate.] +:connect-cloud-example: pass:q[The example below connects to a Couchbase Capella instance over a secure connection with a client certificate.] + +// API Links +:cbsh-api-url: https://couchbase.sh/docs +:nushell-api-url: https://www.nushell.sh/commands/docs +:dotnet-api-url: https://docs.couchbase.com/sdk-api/couchbase-net-client/api +:java-api-url: https://docs.couchbase.com/sdk-api/couchbase-java-client/com/couchbase/client/java +:nodejs-api-url: https://docs.couchbase.com/sdk-api/couchbase-node-client/classes +:python-api-url: https://docs.couchbase.com/sdk-api/couchbase-python-client/api/couchbase.html diff --git a/modules/guides/partials/index-context.adoc b/modules/guides/partials/index-context.adoc new file mode 100644 index 000000000..4ecb2c296 --- /dev/null +++ b/modules/guides/partials/index-context.adoc @@ -0,0 +1,2 @@ +NOTE: The SDK calls only enable you to {work-with} indexes in the default collection and default scope within a bucket. +A {sqlpp} statement enables you to {work-with} indexes in _any_ collection and scope within a bucket. \ No newline at end of file diff --git a/modules/guides/partials/javascript-udfs/create-function-breakdown.adoc b/modules/guides/partials/javascript-udfs/create-function-breakdown.adoc new file mode 100644 index 000000000..41075941f --- /dev/null +++ b/modules/guides/partials/javascript-udfs/create-function-breakdown.adoc @@ -0,0 +1,16 @@ +//// +This is a block explaining the elements that +make up the CREATE function example. +//// + +The `CREATE FUNCTION` in this example can be broken down as follows: + +{nbsp} +[horizontal] +`GetBusinessDays(startDate,{nbsp}endDate)`:: This is the name of the N1QL User-Defined Function that will be called in your N1QL statements. + +`getBusinessDays`:: This is the name of the JavaScript function. + +`my-library`:: The name of the library where the JavaScript function resides. + +For more information on the `CREATE FUNCTION` statement, see xref:n1ql:n1ql-language-reference/createfunction.adoc[]. + diff --git a/modules/guides/partials/javascript-udfs/diagrams.adoc b/modules/guides/partials/javascript-udfs/diagrams.adoc new file mode 100644 index 000000000..c4ab20a85 --- /dev/null +++ b/modules/guides/partials/javascript-udfs/diagrams.adoc @@ -0,0 +1,63 @@ +// tag::multiple-references-to-udf[] +.References to a UDF +[plantuml#multiple-references-to-udf, subs=attributes] +.... +@startuml + +package "my-library" { + [getBusinessDays(startDate,endDate)] as jsGBDFunction + [add(x,y)] + +} + +[{sqlpp} function: GetBusinessDays('02 January 2022',\n '31 January 2023')] --> jsGBDFunction : references +[{sqlpp} function: GetWeekDays('02/14/2022', '4/16/2022')] --> jsGBDFunction : references + +@enduml +.... +// end::multiple-references-to-udf[] + +//tag::javascript-udf-library-creation-sequence[] +.Sequence for Creating a JavaScript Library +[plantuml#create-library-udf-sequence, subs=attributes] +.... +@startuml +skinparam ComponentStyle rectangle +skinparam ActorStyle awesome + +left to right direction + +actor "developer" as user + +frame "Create library and add first function" as cAndA { + [(1) Create library] as createLibrary + [(2) Add the JavaScript function to the library] as addFunction + createLibrary --> addFunction +} + +note top of cAndA #Ivory + The library and the first function + are usually added in the same step. +end note + +note right of cAndA #Ivory + The library can be created in a global library + which is accessible across the cluster, + or it can be set to be accessible + by users with access to a scope within a bucket. +end note + +user --> createLibrary +[(3) Create {sqlpp} User-Defined Function] as createN1QL + +addFunction --> createN1QL +createN1QL -->() end + +note top of addFunction #Ivory + The developer can add one or more + functions to the library +end note +@enduml +.... +//end::javascript-udf-library-creation-sequence[] + diff --git a/modules/guides/partials/javascript-udfs/execute-n1ql-result-explanation.adoc b/modules/guides/partials/javascript-udfs/execute-n1ql-result-explanation.adoc new file mode 100644 index 000000000..8f4e32dfb --- /dev/null +++ b/modules/guides/partials/javascript-udfs/execute-n1ql-result-explanation.adoc @@ -0,0 +1,10 @@ +//// +This is shared paragraph explaining the results returned from +a query using REST or the CBQ +//// +.Result +[source, json] +---- +include::example$javascript-udfs/execute-javascript-function-rest-response.jsonc[] +---- +<.> The `results` block contains the answer to the query. diff --git a/modules/guides/partials/javascript-udfs/further-reading.adoc b/modules/guides/partials/javascript-udfs/further-reading.adoc new file mode 100644 index 000000000..8c2ed44ad --- /dev/null +++ b/modules/guides/partials/javascript-udfs/further-reading.adoc @@ -0,0 +1,63 @@ +//// +This file is the further reading section at the bottom +of each page +//// + + +// tag::query-workbench[] +* xref:clusters:query-service/query-workbench.adoc[The Query Workbench] +// end::query-workbench[] + +// tag::n1ql-reference[] +* xref:n1ql:n1ql-language-reference/index.adoc[The N1QL Query Language Reference] +// end::n1ql-reference[] + +// tag::insert[] +* xref:n1ql:n1ql-language-reference/insert.adoc[] +// end::insert[] + +// tag::select[] +* xref:n1ql:n1ql-language-reference/selectclause.adoc[] +// end::select[] + +// tag::execute-function[] +* xref:n1ql:n1ql-language-reference/execfunction.adoc[] + +// end::execute-function[] + +// tag::transactions[] +* xref:server:learn:data/transactions.adoc[] +// end::transactions[] + +// tag::rbac[] +* xref:rest-api:rbac.adoc[Role-Based Access Control (RBAC)] +// end::rbac[] + +// tag::create-function[] +* xref:n1ql:n1ql-language-reference/createfunction.adoc[] +// end::create-function[] + +// tag::rest-create-library-call[] +* xref:n1ql-rest-functions:index.adoc#_post_library[REST API: Create or Update Library] +// end::rest-create-library-call[] + +// tag::rest-delete-library-call[] +* xref:n1ql-rest-functions:index.adoc#_delete_library[REST API: Delete Library] +// end::rest-delete-library-call[] + +// tag::user-defined-functions[] +* xref:n1ql:n1ql-language-reference/userfun.adoc[] +// end::user-defined-functions[] + +// tag::user-defined-functions-ui[] +* xref:tools:udfs-ui.adoc[] +// end::user-defined-functions-ui[] + + + + + + + + + + diff --git a/modules/guides/partials/nav.adoc b/modules/guides/partials/nav.adoc new file mode 100644 index 000000000..e539af3cb --- /dev/null +++ b/modules/guides/partials/nav.adoc @@ -0,0 +1,13 @@ +// Combined nav for Data +* xref:guides:data.adoc[] + ** xref:guides:kv-operations.adoc[] + *** xref:clusters:data-service/manage-documents.adoc[] + *** xref:guides:creating-data.adoc[] + *** xref:guides:reading-data.adoc[] + *** xref:guides:updating-data.adoc[] + *** xref:guides:deleting-data.adoc[] + *** xref:guides:bulk-operations.adoc[] + ** xref:guides:load.adoc[] + *** xref:clusters:data-service/import-data-documents.adoc[] + *** xref:guides:import.adoc[] + *** xref:connect:cli-import-export.adoc[] diff --git a/modules/guides/partials/query-context.adoc b/modules/guides/partials/query-context.adoc new file mode 100644 index 000000000..eff421269 --- /dev/null +++ b/modules/guides/partials/query-context.adoc @@ -0,0 +1,24 @@ +// tag::statement[] +To use the examples on this page, you must set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:select.adoc#query-context[Setting the Query Context]. +// end::statement[] + +// tag::step[] +Set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:select.adoc#query-context[Setting the Query Context]. +// end::step[] + +// tag::section[] +To try the examples in this section, set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:select.adoc#query-context[Setting the Query Context]. +// end::section[] + +// tag::example[] +For this example, set the query context to the `inventory` scope in the travel sample dataset. +For more information, see xref:select.adoc#query-context[Setting the Query Context]. +// end::example[] + +// tag::unset[] +For this example, unset the query context. +For more information, see xref:select.adoc#query-context[Setting the Query Context]. +// end::unset[] \ No newline at end of file diff --git a/modules/guides/partials/query-tools.adoc b/modules/guides/partials/query-tools.adoc new file mode 100644 index 000000000..4cff8d814 --- /dev/null +++ b/modules/guides/partials/query-tools.adoc @@ -0,0 +1,8 @@ +== Query Tools + +// tag::body[] +Read the following for further information about the tools available for editing and executing queries: + +* xref:n1ql:n1ql-intro/cbq.adoc[] +* xref:cloud:clusters:query-service/query-workbench.adoc[] +// end::body[] \ No newline at end of file diff --git a/modules/guides/partials/recursive-joins.adoc b/modules/guides/partials/recursive-joins.adoc new file mode 100644 index 000000000..2b51884cd --- /dev/null +++ b/modules/guides/partials/recursive-joins.adoc @@ -0,0 +1,26 @@ +== Chaining {clauses} + +To chain joins, nests, and unnests, use the right-hand side of one JOIN, NEST, or UNNEST clause as the left-hand side of the next. + +==== +For example, the following query joins routes to airports by destination airport, and then nests landmarks in the same city as each airport. + +.Context +include::partial$query-context.adoc[tag=step] + +.Query +[source,sqlpp] +---- +SELECT * +FROM route AS rte -- <.> +JOIN airport AS apt -- <.> + ON rte.destinationairport = apt.faa +NEST landmark AS lmk -- <.> + ON apt.city = lmk.city +LIMIT 5; +---- + +<.> The `route` keyspace is on the left-hand side of the join. +<.> The `airport` keyspace is on the right-hand side of the join and the left-hand side of the nest. +<.> The `landmark` keyspace is on the right-hand side of the nest. +==== \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-check-parse.js b/modules/javascript-udfs/examples/add-airline-check-parse.js new file mode 100644 index 000000000..1b6645e6d --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-check-parse.js @@ -0,0 +1,26 @@ +function addAirlineWithCheck(id, name, callsign, country) { + + const full_id = "airline_" + id + const d = new Date().toJSON(); + + try { + + var q = insert into `travel-sample`.`inventory`.`airline` values( + $full_id, + {"id": $id, + "type": "airline", + "name": $name, + "ca1": "Q5", + "icao": "MLA", + "callsign": $callsign, + "country": $country, + "opdate": $d}); + + return "success" + } + catch (error) { + const message = JSON.parse(error.message) // <.> + return message + } + +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-inline-call.js b/modules/javascript-udfs/examples/add-airline-inline-call.js new file mode 100644 index 000000000..47553532e --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-inline-call.js @@ -0,0 +1,9 @@ +function addAirline() { + var q = insert into airport values("1200", + {"id": 1200, + "type": "airline", + "name": "Couch Air", + "ca1": "Q5", "icao": "MLA", + "callsign": "COUCH-AIR", + "country": "United States"}); +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-n1ql-call.js b/modules/javascript-udfs/examples/add-airline-n1ql-call.js new file mode 100644 index 000000000..4eee5d985 --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-n1ql-call.js @@ -0,0 +1,10 @@ +function addAirline() { + var q = N1QL("insert into airport values(1200, " + + "{\"id\": 1200," + + " \"type\": \"airline\"," + + " \"name\": \"Couch Air\"," + + " \"ca1\": \"Q5\"," + + " \"icao\": \"MLA\"," + + " \"callsign\": \"COUCH-AIR\"," + + " \"country\": \"United States\"})") +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-named-parameters.js b/modules/javascript-udfs/examples/add-airline-named-parameters.js new file mode 100644 index 000000000..f113c4b4e --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-named-parameters.js @@ -0,0 +1,10 @@ +function addAirlineWithNamedParameters(name, callsign, country) { + var q = insert into `travel-sample`.`inventory`.`airport` values("1700", + {"id": 1700, + "type": "airline", + "name": $name, + "ca1": "Q5", + "icao": "MLA", + "callsign": $callsign, + "country": $country}); +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-parse-check-2.js b/modules/javascript-udfs/examples/add-airline-parse-check-2.js new file mode 100644 index 000000000..fd77d7e49 --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-parse-check-2.js @@ -0,0 +1,39 @@ +function addAirlineWithCheck(id, name, callsign, country) { + + const full_id = "airline_" + id + const d = new Date().toJSON(); + + try { + + var q = insert + into`travel-sample`.`inventory`.`airline` + values( + $full_id, + { + "id": $id, + "type": "airline", + "name": $name, + "ca1": "Q5", + "icao": "MLA", + "callsign": $callsign, + "country": $country, + "opdate": $d + }); + + return "success" + } catch (error) { + + const message = JSON.parse(error.message) + + if (message.cause.key == 'dml.statement.duplicatekey') { // <.> + + var myErrorObject = {} + myErrorObject.error_type = 'duplicate key' + myErrorObject.key_used = message.cause.message.replace('Duplicate Key: ', '') // <.> + return myErrorObject + } + else { + return message + } + } +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-positional-pararamers.js b/modules/javascript-udfs/examples/add-airline-positional-pararamers.js new file mode 100644 index 000000000..45bab55b2 --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-positional-pararamers.js @@ -0,0 +1,11 @@ +function addAirlineWithPositionalParameters(name, callsign, country) { + var q = N1QL("insert into `travel-sample`.`inventory`.`airport` values(\"1600\", " + + "{\"id\": $1, " + + "\"type\": $2, " + + "\"name\": $3, " + + "\"ca1\": $4, " + + "\"icao\": $5, " + + "\"callsign\": $6, " + + "\"country\": $7})", + [1600, "airline", name, "Q5", "MLA", callsign, country]) +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-check-failure-return-response.jsonc b/modules/javascript-udfs/examples/add-airline-with-check-failure-return-response.jsonc new file mode 100644 index 000000000..73e776b61 --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-check-failure-return-response.jsonc @@ -0,0 +1,3 @@ +[ + "failure" +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-check-failure-throw-object-response.jsonc b/modules/javascript-udfs/examples/add-airline-with-check-failure-throw-object-response.jsonc new file mode 100644 index 000000000..d597fb93b --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-check-failure-throw-object-response.jsonc @@ -0,0 +1,28 @@ +[ + { + "code": 10109, + "msg": "Error executing function 'AddAirlineWithCheckThrowObject' (travel-sample/inventory/my-library:addAirlineWithCheckThrowObject)", + "reason": { + "details": { + "Code": " throw error", + "Exception": { + "caller": "couchbase:2112", + "cause": { + "caller": "couchbase:1985", + "code": 17012, + "key": "dml.statement.duplicatekey", + "message": "Duplicate Key: airline_10" + }, + "code": 12009, + "icause": "Duplicate Key: airline_10", + "key": "datastore.couchbase.DML_error", + "message": "DML Error, possible causes include concurrent modification. Failed to perform INSERT on key airline_10", + "retry": false + }, + "Location": "functions/travel-sample/inventory/my-library.js:75", + "Stack": " at addAirlineWithCheckThrowObject (functions/travel-sample/inventory/my-library.js:61:17)" + }, + "type": "Exceptions from JS code" + } + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-check-failure-throw-response.jsonc b/modules/javascript-udfs/examples/add-airline-with-check-failure-throw-response.jsonc new file mode 100644 index 000000000..edf3a8f34 --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-check-failure-throw-response.jsonc @@ -0,0 +1,14 @@ +[ + { + "code": 10109, + "msg": "Error executing function 'AddAirlineWithCheckThrow' (travel-sample/inventory/my-library:addAirlineWithCheckThrow)", + "reason": { + "details": { + "Code": " throw \"failure\"", + "Exception": "failure", + "Location": "functions/travel-sample/inventory/my-library.js:49" + }, + "type": "Exceptions from JS code" + } + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-check-return.js b/modules/javascript-udfs/examples/add-airline-with-check-return.js new file mode 100644 index 000000000..6eda4ca0d --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-check-return.js @@ -0,0 +1,25 @@ +function addAirlineWithCheckReturn(id, name, callsign, country) { + + const full_id = "airline_" + id + const d = new Date().toJSON(); + + try { + + var q = insert into `travel-sample`.`inventory`.`airline` values( + $full_id, + {"id": $id, + "type": "airline", + "name": $name, + "ca1": "Q5", + "icao": "MLA", + "callsign": $callsign, + "country": $country, + "opdate": $d}); + + return "success" + } + catch (error) { + return "failure" + } + +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-check-throw-object.js b/modules/javascript-udfs/examples/add-airline-with-check-throw-object.js new file mode 100644 index 000000000..d2ecbbfdd --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-check-throw-object.js @@ -0,0 +1,25 @@ +function addAirlineWithCheckThrowObject(id, name, callsign, country) { + + const full_id = "airline_" + id + const d = new Date().toJSON(); + + try { + + var q = insert into `travel-sample`.`inventory`.`airline` values( + $full_id, + {"id": $id, + "type": "airline", + "name": $name, + "ca1": "Q5", + "icao": "MLA", + "callsign": $callsign, + "country": $country, + "opdate": $d}); + + return "success" + } + catch (error) { + throw error + } + +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-check-throw.js b/modules/javascript-udfs/examples/add-airline-with-check-throw.js new file mode 100644 index 000000000..6f57101ba --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-check-throw.js @@ -0,0 +1,25 @@ +function addAirlineWithCheckThrow(id, name, callsign, country) { + + const full_id = "airline_" + id + const d = new Date().toJSON(); + + try { + + var q = insert into `travel-sample`.`inventory`.`airline` values( + $full_id, + {"id": $id, + "type": "airline", + "name": $name, + "ca1": "Q5", + "icao": "MLA", + "callsign": $callsign, + "country": $country, + "opdate": $d}); + + return "success" + } + catch (error) { + throw "failure" + } + +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/add-airline-with-side-effect.n1ql b/modules/javascript-udfs/examples/add-airline-with-side-effect.n1ql new file mode 100644 index 000000000..3d3bb30ac --- /dev/null +++ b/modules/javascript-udfs/examples/add-airline-with-side-effect.n1ql @@ -0,0 +1 @@ +SELECT "true" AS response WHERE AddAirline() = "missing"; \ No newline at end of file diff --git a/modules/javascript-udfs/examples/array.js b/modules/javascript-udfs/examples/array.js new file mode 100644 index 000000000..804ad1321 --- /dev/null +++ b/modules/javascript-udfs/examples/array.js @@ -0,0 +1,12 @@ + +var a = [] // <.> + +a.push("London") // <.> +a.push(100) // <.> +a.push("Los Angeles") +a.push("Tokyo") +a.push(200) + +console.log(JSON.stringify(a)) // <.> + +console.log(JSON.stringify(a[2])) // <.> \ No newline at end of file diff --git a/modules/javascript-udfs/examples/array.jsonc b/modules/javascript-udfs/examples/array.jsonc new file mode 100644 index 000000000..e8cfb78aa --- /dev/null +++ b/modules/javascript-udfs/examples/array.jsonc @@ -0,0 +1 @@ +["London", 100, "Los Angeles", "Tokyo", 200] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-bank-interest-function-uk.n1ql b/modules/javascript-udfs/examples/create-bank-interest-function-uk.n1ql new file mode 100644 index 000000000..09428b67f --- /dev/null +++ b/modules/javascript-udfs/examples/create-bank-interest-function-uk.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION default:`bank-database`.`UKBank`.GetInterest(...) +LANGUAGE JAVASCRIPT as "getInterestInSterling" +AT "bank-database/UKBank/bank-library" \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-bank-interest-function-us.n1ql b/modules/javascript-udfs/examples/create-bank-interest-function-us.n1ql new file mode 100644 index 000000000..ac7b96f53 --- /dev/null +++ b/modules/javascript-udfs/examples/create-bank-interest-function-us.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION default:`bank-database`.`USBank`.GetInterest(...) +LANGUAGE JAVASCRIPT as "getInterestInDollars" +AT "bank-database/USBank/bank-library" \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql new file mode 100644 index 000000000..c64379d58 --- /dev/null +++ b/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION GetBusinessDays(startDate, endDate) +LANGUAGE JAVASCRIPT as "getBusinessDays" +AT "my-library"; -- <.> \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql new file mode 100644 index 000000000..eee12a215 --- /dev/null +++ b/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION GetBusinessDays(startDate, endDate) +LANGUAGE JAVASCRIPT as "getBusinessDays" +AT "./my-library"; -- <.> \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql new file mode 100644 index 000000000..63d1e001f --- /dev/null +++ b/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays(startDate, endDate) -- <.> +LANGUAGE JAVASCRIPT as "getBusinessDays" -- <.> +AT "travel-sample/inventory/my-library"; -- <.> \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-sum-function.n1ql b/modules/javascript-udfs/examples/create-sum-function.n1ql new file mode 100644 index 000000000..8d9dc6932 --- /dev/null +++ b/modules/javascript-udfs/examples/create-sum-function.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION SumListOfNumbers(...) +LANGUAGE JAVASCRIPT as "sumListOfNumbers" +AT "my-library"; \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-variadic-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-variadic-n1ql-udf.n1ql new file mode 100644 index 000000000..abd4cee77 --- /dev/null +++ b/modules/javascript-udfs/examples/create-variadic-n1ql-udf.n1ql @@ -0,0 +1,3 @@ +CREATE FUNCTION GetBusinessDays(...) +LANGUAGE JAVASCRIPT as "getBusinessDays" +AT "my-library"; \ No newline at end of file diff --git a/modules/javascript-udfs/examples/do-recursion-response.jsonc b/modules/javascript-udfs/examples/do-recursion-response.jsonc new file mode 100644 index 000000000..54fc55718 --- /dev/null +++ b/modules/javascript-udfs/examples/do-recursion-response.jsonc @@ -0,0 +1,20 @@ +[ + { + "code": 10109, + "msg": "Error executing function 'doRecursion' (my-library:doRecursion)", + "reason": { + "details": { + "Code": " var q = N1QL(\"EXECUTE FUNCTION doRecursion()\")", + "Exception": { + "caller": "javascript:133", + "code": 10112, + "key": "function.nested.error", + "message": "Error executing function 'doRecursion': {number-of-calls} nested javascript calls" // <.> + }, + "Location": "functions/my-library.js:30", + "Stack": " at doRecursion (functions/my-library.js:30:13)" + }, + "type": "Exceptions from JS code" + } + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/do-recursion.js b/modules/javascript-udfs/examples/do-recursion.js new file mode 100644 index 000000000..841115a51 --- /dev/null +++ b/modules/javascript-udfs/examples/do-recursion.js @@ -0,0 +1,5 @@ +function doRecursion() { + + var q = N1QL("EXECUTE FUNCTION doRecursion()") + +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/duplicate-key-error.json5 b/modules/javascript-udfs/examples/duplicate-key-error.json5 new file mode 100644 index 000000000..bc18a9225 --- /dev/null +++ b/modules/javascript-udfs/examples/duplicate-key-error.json5 @@ -0,0 +1,28 @@ +[ + { + "code": 10109, + "msg": "Error executing function 'AddAirlineWithDate' (MyLibrary:addAirlineWithDate)", + "reason": { + "details": { + "Code": " var q = N1QL('insert into `travel-sample`.`inventory`.`airline` values(\\n' +", + "Exception": { + "caller": "couchbase:2098", + "cause": { + "caller": "couchbase:1971", + "code": 17012, + "key": "dml.statement.duplicatekey", + "message": "Duplicate Key: airline_1220" + }, + "code": 12009, + "icause": "Duplicate Key: airline_1220", + "key": "datastore.couchbase.DML_error", + "message": "DML Error, possible causes include concurrent modification. Failed to perform INSERT on key airline_1220", + "retry": false + }, + "Location": "functions/MyLibrary.js:11", + "Stack": " at addAirlineWithDate (functions/MyLibrary.js:11:13)" + }, + "type": "Exceptions from JS code" + } + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/execute-airline-function-response.jsonc b/modules/javascript-udfs/examples/execute-airline-function-response.jsonc new file mode 100644 index 000000000..a762c8120 --- /dev/null +++ b/modules/javascript-udfs/examples/execute-airline-function-response.jsonc @@ -0,0 +1,28 @@ +[ + [ + { + "callsign": null, + "name": "Jc royal.britannica" + }, + { + "callsign": "FLYSTAR", + "name": "Astraeus" + }, + { + "callsign": "SPEEDBIRD", + "name": "British Airways" + }, + { + "callsign": "BRINTEL", + "name": "British International Helicopters" + }, + { + "callsign": "MIDLAND", + "name": "bmi" + }, + { + "callsign": "BABY", + "name": "bmibaby" + } + ] +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/execute-airline-function-with-date.n1ql b/modules/javascript-udfs/examples/execute-airline-function-with-date.n1ql new file mode 100644 index 000000000..e4943952f --- /dev/null +++ b/modules/javascript-udfs/examples/execute-airline-function-with-date.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION AddAirlineWithDate(1220, 'Raz Air', 'RAZ-AIR', 'United Kingdom'); diff --git a/modules/javascript-udfs/examples/execute-airline-function.n1ql b/modules/javascript-udfs/examples/execute-airline-function.n1ql new file mode 100644 index 000000000..a67a0db40 --- /dev/null +++ b/modules/javascript-udfs/examples/execute-airline-function.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION selectAirlines('United Kingdom'); \ No newline at end of file diff --git a/modules/javascript-udfs/examples/execute-do-recursion.n1ql b/modules/javascript-udfs/examples/execute-do-recursion.n1ql new file mode 100644 index 000000000..b90054ef2 --- /dev/null +++ b/modules/javascript-udfs/examples/execute-do-recursion.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION doRecursion(); diff --git a/modules/javascript-udfs/examples/execute-function-get-interest.n1ql b/modules/javascript-udfs/examples/execute-function-get-interest.n1ql new file mode 100644 index 000000000..25ecc57a4 --- /dev/null +++ b/modules/javascript-udfs/examples/execute-function-get-interest.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION GetInterest(10, 0.25); \ No newline at end of file diff --git a/modules/javascript-udfs/examples/execute-javascript-function.n1ql b/modules/javascript-udfs/examples/execute-javascript-function.n1ql new file mode 100644 index 000000000..aea6b4586 --- /dev/null +++ b/modules/javascript-udfs/examples/execute-javascript-function.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION GetBusinessDays("02/14/2022", "04/16/2022"); \ No newline at end of file diff --git a/modules/javascript-udfs/examples/execute-sum-function-result.jsonc b/modules/javascript-udfs/examples/execute-sum-function-result.jsonc new file mode 100644 index 000000000..c431deb2d --- /dev/null +++ b/modules/javascript-udfs/examples/execute-sum-function-result.jsonc @@ -0,0 +1,3 @@ +[ + 127 +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/execute-sum-function.n1ql b/modules/javascript-udfs/examples/execute-sum-function.n1ql new file mode 100644 index 000000000..5246b47e3 --- /dev/null +++ b/modules/javascript-udfs/examples/execute-sum-function.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION SumListOfNumbers(1, 2, 4, 8, 16, 32, 64); \ No newline at end of file diff --git a/modules/javascript-udfs/examples/get-business-days-no-ops.js b/modules/javascript-udfs/examples/get-business-days-no-ops.js new file mode 100644 index 000000000..cf5fa8e10 --- /dev/null +++ b/modules/javascript-udfs/examples/get-business-days-no-ops.js @@ -0,0 +1,5 @@ +function getBusinessDays(startDate, endDate) { + + // Do calculations + +} diff --git a/modules/javascript-udfs/examples/get-business-days.js b/modules/javascript-udfs/examples/get-business-days.js new file mode 100644 index 000000000..9e51836db --- /dev/null +++ b/modules/javascript-udfs/examples/get-business-days.js @@ -0,0 +1,11 @@ +function getBusinessDays(startDate, endDate) { + let count = 0; + const curDate = new Date(new Date(startDate).getTime()); + while (curDate <= new Date(endDate)) { + const dayOfWeek = curDate.getDay(); + if(dayOfWeek !== 0 && dayOfWeek !== 6) + count++; + curDate.setDate(curDate.getDate() + 1); + } + return count; // <.> +} diff --git a/modules/javascript-udfs/examples/illegal-global-variable.js b/modules/javascript-udfs/examples/illegal-global-variable.js new file mode 100644 index 000000000..d1459873c --- /dev/null +++ b/modules/javascript-udfs/examples/illegal-global-variable.js @@ -0,0 +1,4 @@ +var count = 0; // Not allowed - global variable. +function increment() { + count++; +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/key-value-dates.js b/modules/javascript-udfs/examples/key-value-dates.js new file mode 100644 index 000000000..b3641d596 --- /dev/null +++ b/modules/javascript-udfs/examples/key-value-dates.js @@ -0,0 +1,20 @@ +var a = [] + +a.push("London") +a.push(100) +a.push("Los Angeles") +a.push("Tokyo") +a.push(200) + +var kv = {} + +kv.airline = "COUCH AIR" +kv.coverage = a +kv.home_airport = "Heathrow" + +kv.date_established = new Date().toJSON() // <.> + +console.log(JSON.stringify(kv)) + +console.log(JSON.stringify(kv.coverage)) +console.log(JSON.stringify(kv["home_airport"])) \ No newline at end of file diff --git a/modules/javascript-udfs/examples/key-value.js b/modules/javascript-udfs/examples/key-value.js new file mode 100644 index 000000000..7cdc148a5 --- /dev/null +++ b/modules/javascript-udfs/examples/key-value.js @@ -0,0 +1,18 @@ +var a = [] + +a.push("London") +a.push(100) +a.push("Los Angeles") +a.push("Tokyo") +a.push(200) + +var kv = {} // <.> + +kv.airline = "COUCH AIR" // <.> +kv.coverage = a // <.> +kv.home_airport = "Heathrow" + +console.log(JSON.stringify(kv)) //<.> + +console.log(JSON.stringify(kv.coverage)) //<.> +console.log(JSON.stringify(kv["home_airport"])) // <.> \ No newline at end of file diff --git a/modules/javascript-udfs/examples/key-value.jsonc b/modules/javascript-udfs/examples/key-value.jsonc new file mode 100644 index 000000000..2e31349cd --- /dev/null +++ b/modules/javascript-udfs/examples/key-value.jsonc @@ -0,0 +1,4 @@ +{ "airline": "COUCH-AIR", + "coverage": ["London", 100, "Los Angeles", "Tokyo", 200], // <.> + "home_airport": "Heathrow" +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/key-values-dates.jsonc b/modules/javascript-udfs/examples/key-values-dates.jsonc new file mode 100644 index 000000000..b4c7ad599 --- /dev/null +++ b/modules/javascript-udfs/examples/key-values-dates.jsonc @@ -0,0 +1,12 @@ +{ + "airline": "COUCH AIR", + "coverage": [ + "London", + 100, + "Los Angeles", + "Tokyo", + 200 + ], + "home_airport": "Heathrow", + "date_established": "2022-03-18T12:44:27.923Z" // <.> +} diff --git a/modules/javascript-udfs/examples/parsed-error-in-full.json5 b/modules/javascript-udfs/examples/parsed-error-in-full.json5 new file mode 100644 index 000000000..617cb9659 --- /dev/null +++ b/modules/javascript-udfs/examples/parsed-error-in-full.json5 @@ -0,0 +1,16 @@ +[ + { + "caller": "couchbase:2098", + "cause": { + "caller": "couchbase:1971", + "code": 17012, + "key": "dml.statement.duplicatekey", + "message": "Duplicate Key: airline_1220" + }, + "code": 12009, + "icause": "Duplicate Key: airline_1220", + "key": "datastore.couchbase.DML_error", + "message": "DML Error, possible causes include concurrent modification. Failed to perform INSERT on key airline_1220", + "retry": false + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/select-airline-inline.js b/modules/javascript-udfs/examples/select-airline-inline.js new file mode 100644 index 000000000..499e1bc4a --- /dev/null +++ b/modules/javascript-udfs/examples/select-airline-inline.js @@ -0,0 +1,20 @@ +function selectAirline(country) { + + var q = SELECT name as airline_name, callsign as airline_callsign + FROM `travel-sample`.`inventory`.`airline` + WHERE country = $country; //<1> + + var res = []; + + for (const doc of q) { + + var airline = {} + airline.name = doc.airline_name // <2> + airline.callsign = doc.airline_callsign // <2> + res.push(airline); + + } + + return res; + +} diff --git a/modules/javascript-udfs/examples/select-airline-n1ql.js b/modules/javascript-udfs/examples/select-airline-n1ql.js new file mode 100644 index 000000000..9605c237a --- /dev/null +++ b/modules/javascript-udfs/examples/select-airline-n1ql.js @@ -0,0 +1,20 @@ +function selectAirline(country) { + + var q = N1QL('SELECT name as airline_name, ' + + 'callsign as airline_callsign FROM `travel-sample`.`inventory`.`airline` ' + + 'WHERE country = $country_param', {country_param: country}); // <1> + + var res = []; + + for (const doc of q) { + + var airline = {} + airline.name = doc.airline_name; // <2> + airline.callsign = doc.airline_callsign // <2> + res.push(airline); + + } + + return res; + +} diff --git a/modules/javascript-udfs/examples/select-get-business-days-response.jsonc b/modules/javascript-udfs/examples/select-get-business-days-response.jsonc new file mode 100644 index 000000000..07820afa5 --- /dev/null +++ b/modules/javascript-udfs/examples/select-get-business-days-response.jsonc @@ -0,0 +1,5 @@ +[ + { + "$1": 45 + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/select-get-business-days.n1ql b/modules/javascript-udfs/examples/select-get-business-days.n1ql new file mode 100644 index 000000000..ea28a23b3 --- /dev/null +++ b/modules/javascript-udfs/examples/select-get-business-days.n1ql @@ -0,0 +1 @@ +SELECT GetBusinessDays('02/14/2022', '4/16/2022'); \ No newline at end of file diff --git a/modules/javascript-udfs/examples/select-hotels-inline.js b/modules/javascript-udfs/examples/select-hotels-inline.js new file mode 100644 index 000000000..0f41eb020 --- /dev/null +++ b/modules/javascript-udfs/examples/select-hotels-inline.js @@ -0,0 +1,14 @@ +function selectHotels() { + + var q = SELECT * FROM `travel-sample`.`inventory`.`hotel`; // <.> + var res = []; + + for (const doc of q) { // <.> + + res.push(doc); // <.> + + } + + return res; // <.> + +} \ No newline at end of file diff --git a/modules/javascript-udfs/examples/select-true-alias-get-business-days.n1ql b/modules/javascript-udfs/examples/select-true-alias-get-business-days.n1ql new file mode 100644 index 000000000..45d3b26ad --- /dev/null +++ b/modules/javascript-udfs/examples/select-true-alias-get-business-days.n1ql @@ -0,0 +1,5 @@ +SELECT CASE + WHEN GetBusinessDays('02/14/2022', '4/16/2022') > 44 THEN "true" + ELSE "false" + END + AS response; -- <.> \ No newline at end of file diff --git a/modules/javascript-udfs/examples/select-true-get-business-days.n1ql b/modules/javascript-udfs/examples/select-true-get-business-days.n1ql new file mode 100644 index 000000000..91b881eeb --- /dev/null +++ b/modules/javascript-udfs/examples/select-true-get-business-days.n1ql @@ -0,0 +1 @@ +SELECT "true" where GetBusinessDays('02/14/2022', '4/16/2022') > 44; \ No newline at end of file diff --git a/modules/javascript-udfs/examples/true-alias-response.jsonc b/modules/javascript-udfs/examples/true-alias-response.jsonc new file mode 100644 index 000000000..fd8f7b094 --- /dev/null +++ b/modules/javascript-udfs/examples/true-alias-response.jsonc @@ -0,0 +1,5 @@ +[ + { + "response": "true" + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/true-response.jsonc b/modules/javascript-udfs/examples/true-response.jsonc new file mode 100644 index 000000000..2e0d547a2 --- /dev/null +++ b/modules/javascript-udfs/examples/true-response.jsonc @@ -0,0 +1,5 @@ +[ + { + "$1": "true" + } +] \ No newline at end of file diff --git a/modules/javascript-udfs/examples/variadic-sum.js b/modules/javascript-udfs/examples/variadic-sum.js new file mode 100644 index 000000000..fb83d1b9e --- /dev/null +++ b/modules/javascript-udfs/examples/variadic-sum.js @@ -0,0 +1,10 @@ +function sumListOfNumbers(... args) { // <.> + + var sum = 0; + + args.forEach(value => sum = sum + value); // <.> + + return sum; + +} + diff --git a/modules/javascript-udfs/images/reserved-words-7_0.png b/modules/javascript-udfs/images/reserved-words-7_0.png new file mode 100644 index 000000000..5cec2ed18 Binary files /dev/null and b/modules/javascript-udfs/images/reserved-words-7_0.png differ diff --git a/modules/javascript-udfs/pages/.calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/.calling-javascript-from-n1ql.adoc new file mode 100644 index 000000000..6ae86761b --- /dev/null +++ b/modules/javascript-udfs/pages/.calling-javascript-from-n1ql.adoc @@ -0,0 +1,141 @@ += Calling JavaScript from {sqlpp} +:description: Using a {sqlpp} User-Defined Function to call JavaScript functions. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-toclevels: 2 +:keywords: scopes, variadic + +[abstract] +{description} + +== Introduction + +Before you can call a JavaScript function, you must first create a {sqlpp} User-Defined Function to call it. +The process to do this is explained in the xref:guides:create-user-defined-function.adoc#creating-the-n1ql-udf-function[Creating the {sqlpp} User-Defined Function] section of the xref:guides:javascript-udfs.adoc[] guide. + +If you are unfamiliar with creating User-Defined Functions to call JavaScript, then the xref:guides:javascript-udfs.adoc[guide] is the best place to start. + +In this section, you're going to take a closer look at concepts around {sqlpp} User-Defined Functions, such as variadic parameter lists. + +== Scopes and {sqlpp} User-Defined Functions + +A JavaScript function can be xref:guides:create-javascript-library.adoc#creating-the-library-and-adding-your-first-function[created through the WorkBench or through the REST API]. + +[source, javascript, role="no-callouts"] +---- +include::example$get-business-days.js[] +---- + +And the corresponding {sqlpp} User-Defined Function can be created through the xref:guides:create-user-defined-function.adoc#creating-the-n1ql-udf-function[Query Workbench] or by executing a {sqlpp} statement: + +[source, sqlpp] +---- +include::example$create-scoped-n1ql-udf.n1ql[] +---- +<.> The new {sqlpp} User-Defined Function is called `GetBusinessDays` and takes the `inventory` scope inside the `travel-sample` bucket. +As well as providing a logical separation between JavaScript libraries, using scopes provides a means of securing access to the library: a user must have a context that matches the scope of the library in order to access it. +<.> This function will reference the `getBusinessDays` JavaScript function … +<.> … in a library called `my-library` which is set to the `inventory` scope within the `travel-sample` bucket. + +=== Global Library Path + +Of course, you can define the library at the cluster level, where it will be accessible to anyone who has access rights to the cluster. +Functions in the global library are accessible across the cluster. + +.Creating a {sqlpp} User-Defined Function to access the JavaScript function in the global library +[source, sqlpp] +---- +include::example$create-globally-scoped-n1ql-udf.n1ql[] +---- +<.> There is no prefix path before `my-library` which means the library is a globally accessible library defined at the cluster level. + +=== Relative Library Path + +You can also use relative paths for the library location: + +[source, sqlpp] +---- +include::example$create-relatively-scoped-n1ql-udf.n1ql[] +---- +<.> In this case, the User-Defined Function will be created for the JavaScript function under the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +== Calling the Function + +Once the {sqlpp} User-Defined Function is defined, it can be called as if it were a built-in {sqlpp} function: + +.Query +[source, sqlpp] +---- +include::example$select-get-business-days.n1ql[] +---- + +which will return the following result: + +.Result +[source, json] +---- +include::example$select-get-business-days-response.jsonc[] +---- + +You can also use the `EXECUTE FUNCTION` statement to execute the function: + +[source, sqlpp] +---- +include::example$execute-javascript-function.n1ql[] +---- + +or as part of a complex statement: + +[source, n1ql, role=no-callouts] +---- +include::example$select-true-alias-get-business-days.n1ql[] +---- + +[#variadic-parameters] +== Variadic Parameters + +You can define a {sqlpp} User-Defined Function with a variadic parameter, which means that the parameter will accept a list of values which it will pass to the JavaScript function it references. +You can create the `GetBusinessDays` function using a variadic parameter rather than the `startDate` and `endDate` parameters: + +[source, sqlpp] +---- +include::example$create-variadic-n1ql-udf.n1ql[] +---- +Note that the statement used three dots (...) rather than a list of parameter list. This indicates a variable length parameter list. +The underlying JavaScript function will reference the parameter list as named variables: + +[source, javascript, role=no-callouts] +---- +include::example$get-business-days-no-ops.js[] +---- + +You can also use a variable length parameter list in the JavaScript function itself: + +[source, javascript] +---- +include::example$variadic-sum.js[] +---- +<.> JavaScript uses three dots (...) followed by a parameter name to denote a parameter that is an array of values. +<.> Scans through the variadic parameter list, summing all the numbers it contains. + +A {sqlpp} User-Defined Function can now be created that takes a variable length list of numbers as an argument: + +[source, sqlpp] +---- +include::example$create-sum-function.n1ql[] +---- + +which can then be called with a variable length list of numbers as a parameter + +.Query +[source, sqlpp] +---- +include::example$execute-sum-function.n1ql[] +---- + +.Result +[source, json] +---- +include::example$execute-sum-function-result.jsonc[] +---- diff --git a/modules/javascript-udfs/pages/.calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/.calling-n1ql-from-javascript.adoc new file mode 100644 index 000000000..63712b2ec --- /dev/null +++ b/modules/javascript-udfs/pages/.calling-n1ql-from-javascript.adoc @@ -0,0 +1,186 @@ += Calling {sqlpp} from JavaScript +:description: Executing {sqlpp} statements from JavaScript functions. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-toclevels: 2 +:stem: + +[abstract] +{description} + +== Introduction + +As well as being able to call JavaScript functions from {sqlpp}, you can also call {sqlpp} statements from inside your JavaScript functions. + +[#calling-statements-inline] +== Calling {sqlpp} Statements Inline + +You can embed a {sqlpp} statement directly in your JavaScript code: + +[source,javascript] +---- +include::example$add-airline-inline-call.js[] +---- + +== Executing {sqlpp} Statements Using the N1QL() Call + +In addition, you can also execute a {sqlpp} statement by calling it from the `N1QL(…)` function. +[source, javascript] +---- +include::example$add-airline-n1ql-call.js[] +---- + +NOTE: Behind the scenes, the inline call method will generate the equivalent `{sqlpp}` call, so whichever you choose to use will come down to personal preference. + + +== Side Effects + +Functions executed as part of expressions cannot have side effects that will change data stored by the Couchbase engine. +For example, this statement: + +[source, sqlpp] +---- +include::example$add-airline-with-side-effect.n1ql[] +---- + +will generate an error because the `AddAirline()` function will attempt to alter data, which the caller may be unaware of. + +IMPORTANT: Functions that change data must be called using the `EXECUTE FUNCTION` statement. + + +== Returning Values from {sqlpp} Statements + +As shown in the <>, embedded {sqlpp} statements return values which can be used later on in your code. + +The values returned from the statement calls are JavaScript https://www.w3schools.com/js/js_object_iterables.asp[iterators^]: lists of values or documents returned from the database. +In the next example, you're going to retrieve a list of the hotels stored in the `travel-sample` database: + +[source, javascript] +---- +include::example$select-hotels-inline.js[] +---- + +<.> The {sqlpp} statement returns an iterator containing the items retrieved by the query. +<.> Using the standard JavaScript iterator pattern to loop through the items returned in `q`. +<.> Add the current document from the iterator to the result array `res`. +<.> Once all the items have been retrieved, return the result array. + +[IMPORTANT] +==== +If an inline statement/{sqlpp} call does not return a value, then the associated {sqlpp} statement is executed as part of a synchronous operation. i.e. the runtime will wait until the statement completes before moving on to the next line of JavaScript. + +If the inline statement/{sqlpp} call returns a value then it is executed _asynchronously_: execution continues before the iterator is returned. +Each document is fetched from the bucket as it requested by the iterator. + +[plantuml,inline-call-sequence,svg,subs=attributes] +.... +include::partial$diagrams/inline-call-sequence.puml[] +.... +==== + +== Passing Parameters to {sqlpp} Statements + +You can pass parameters from your JavaScript to your {sqlpp} statements. +Parameters can either be _positional_ or _named_. + +Positional:: The parameters are applied to the statement in the order they appear in the list. ++ +[source, javascript] +---- +include::example$add-airline-positional-pararamers.js[] +---- + +Named:: The parameters are given a mnemonic name attached to the value, so they can be included directly in the {sqlpp} statement. ++ +[source, javascript] +---- +include::example$add-airline-named-parameters.js[] +---- ++ +NOTE: The names of the parameters passed into the JavaScript function are used in the {sqlpp} statement without any need to assign the parameters in a separate step. + +[sidebar] +**** +{sqlpp} calls support both _named_ and _positional_ parameters. +Inline calls only support named parameters. + +[cols="^,^,^"] + +|=== +|Call |Named Parameters |Positional Parameters + +|{sqlpp} calls +| ✔️ +| ✔ + +|Inline Calls +| ✔️ +| ❌ +|=== + +**** + +== Transactions + +Transactions are supported from {sqlpp} statements called from JavaScript functions. + +* The function can run statements in a transaction that was started before the function was executed. +* The function can run a statement that starts the transaction. +* The function can run a statement that rolls back a transaction. + +[NOTE] +==== +A {sqlpp} statement and its corresponding iterator must live entirely within the scope of a transaction. +If a transaction is started during the iteration process, then the transaction cannot be rolled back entirely. + +[plantuml,transactions-and-iterators,svg,subs=attributes] +.... +include::partial$diagrams/transactions-and-iterators.puml[] +.... +==== + +== Role-Based Access Control + +In order to execute {sqlpp} statements as part of a JavaScript function, the user executing the function must have the appropriate privileges to perform the action on any objects referenced in the {sqlpp} statement. + +== Executing {sqlpp} Statements that Call Functions + +It is often the case that JavaScript function will call a {sqlpp} statement that may itself call another JavaScript function. +However, it is important to be aware that each JavaScript function call executed from a parent call will use a new JavaScript worker process to run. +The deeper the calls are nested, the fewer JavaScript workers are available to run, so the calling chain will eventually fail and throw an error. +This can be demonstrated using a recursive call sequence as shown below: + +[source, javascript] +---- +include::example$do-recursion.js[] +---- + +Then executing the function: + +[source, sqlpp] +---- +include::example$execute-do-recursion.n1ql[] +---- + +returns the following result: + +:number-of-calls: 10 +[source, json, subs="+attributes"] +---- +include::example$do-recursion-response.jsonc[] +---- +<.> The call failed after {number-of-calls} nested call, which exhausted the number of JavaScript workers available during the call sequence. + +[NOTE] +==== +The JavaScript workers are created when the Couchbase server is started up. + +asciimath:["Number of JavaScript Workers" = 4 xx "Number of CPUs"] + +The service will automatically prevent recursive calls if there are fewer than 50% JavaScript workers available. +==== + +== Further Reading + +include::guides:partial$javascript-udfs/further-reading.adoc[tags="select;execute-function;transactions;rbac"] diff --git a/modules/javascript-udfs/pages/.handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/.handling-errors-javascript-udf.adoc new file mode 100644 index 000000000..8e5ce12d7 --- /dev/null +++ b/modules/javascript-udfs/pages/.handling-errors-javascript-udf.adoc @@ -0,0 +1,113 @@ += Handling Errors in JavaScript Functions +:description: Error handling in JavaScript user-defined functions use the same standard exception mechanism as part of the language standard. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-topic-type: reference +:page-toclevels: 2 + +[abstract] +{description} + +== Handle Errors with the Runtime + +Errors that occur during the execution of a {sqlpp} statement are usually handled by the runtime, which will return a JSON object giving details of the error. +For example, if you execute a record insertion function with a key that already exists: + +[source, sqlpp] +---- +include::example$execute-airline-function-with-date.n1ql[] +---- + +then an error object is returned: + +[source, json] +---- +include::example$duplicate-key-error.json5[] +---- + +== Handle Errors with the Function + +In most cases, it's a lot better if the JavaScript function itself can handle errors that are likely to occur. +This gives the developer the option of responding with a more user-friendly message, or taking an alternative course of action. + +The following function will add an airline record, but will return an `failure` message if the attempt isn't successful. + +[source, javascript] +---- +include::example$add-airline-with-check-return.js[] +---- + +If the record key already exists, then calling this method with `EXECUTE FUNCTION` will produce the following result: + +[source, json] +---- +include::example$add-airline-with-check-failure-return-response.jsonc[] +---- + +Alternatively, you can simply throw the error, rather than returning it as a string: + +[source, javascript] +---- +include::example$add-airline-with-check-throw.js[] +---- + +which will produce the following result: + +[source,javascript] +---- +include::example$add-airline-with-check-failure-throw-response.jsonc[] +---- + +As well as wrapping the expection in a detailed JSON object, there is another fundamental difference between throwing an error or returning it. + +=== Throw vs Return + +Aside from the data returned, throwing an error or returning a value/error will affect how subsequent {sqlpp} operations are processed. + +*Returning an error*:: If the JavaScript function _returns_ any value, then the {sqlpp} runtime will assume that the function completed successfully, and the caller will continue to run subsequent statements. + +*Throwing an error*:: If an error is _thrown_ then this is treated as an error condition, so further statements in the request will not be run. + +You can, of course, throw the error object itself, rather than just a string. + +[source, javascript] +---- +include::example$add-airline-with-check-throw-object.js[] +---- + +which deliver a lot more useful information than just posting back a string: + +[source, json] +---- +include::example$add-airline-with-check-failure-throw-object-response.jsonc[] +---- + +=== Parse the Error + +Another approach is to parse the error using the `JSON.parse()` function and return the resulting object: + +[source, javascript] +---- +include::example$add-airline-check-parse.js[] +---- +<.> The `error` object contains a JSON string (`message`) detailing the nature of the error. +It is much easier to interrogate the message if it's converted back into a JSON object on its own. +This code will send back the entire message structure. + +[source, json] +---- +include::example$parsed-error-in-full.json5[] +---- + +=== Carry Out Alternative Actions + +Once you know the structure of the error message, there's no reason why you can't carry out alternative actions depending on the type of error encountered: + +[source, javascript] +---- +include::example$add-airline-parse-check-2.js[] +---- +<.> Check to see if this is a message that can be handled by the function itself. +<.> Strips out the `"Duplicate Key: "` part of the message, leaving just the duplicate key. + diff --git a/modules/javascript-udfs/pages/.javascript-functions-with-couchbase.adoc b/modules/javascript-udfs/pages/.javascript-functions-with-couchbase.adoc new file mode 100644 index 000000000..82b44b81b --- /dev/null +++ b/modules/javascript-udfs/pages/.javascript-functions-with-couchbase.adoc @@ -0,0 +1,178 @@ += JavaScript Functions for Query Reference +:description: This reference guide describes how to write extension functions for {sqlpp} for Query using the JavaScript language. +ifndef::flag-devex-javascript-udfs[] +:page-embargo: EMBARGOED +endif::flag-devex-javascript-udfs[] +:page-topic-type: reference +:page-toclevels: 2 +:keywords: library namespacing + +[abstract] +{description} + +== Introduction + +include::partial$javascript-udf-introduction.adoc[] + +This reference includes details of external functions using JavaScript. + +include::partial$libraries-and-scopes.adoc[] + +include::partial$sqlpp-managed-udfs.adoc[] + +== Added Constructs + +JavaScript functions in {sqlpp} for Query support most of the language constructs available in https://en.wikipedia.org/wiki/ECMAScript[ECMAScript], though there are a number of restrictions related to the Couchbase environment. +There are also additions that have been made to the language for working specifically with Couchbase. + +=== {sqlpp} Embedded Statements + +Top level {sqlpp} keywords, such as SELECT, UPDATE, INSERT and DELETE, are available as inline keywords in functions. +Operations that return values such as SELECT are accessible through a returned iterable handle. +{sqlpp} Query results, via a SELECT, are streamed in batches to the iterable handle as the iteration progresses through the result set. + +.JavaScript code with embedded {sqlpp} statements +==== +[source, javascript] +---- +include::example$select-airline-inline.js[] +---- + +<1> The {sqlpp} is written directly into the JavaScript code without having to be used as part of a function call. +You can even provide parameters that can be used in the {sqlpp} statement. +<2> A standard JavaScript iterator is used to access the values returned from the {sqlpp} statement. +==== + +For more details, see xref:calling-n1ql-from-javascript.adoc[]. + +== Unsupported Features + +The following features are not supported in JavaScript functions for Query. + +=== Browser Extensions + +Because JavaScript functions in {sqlpp} for Query do not execute in the context of a browser, the extensions that browsers add to the core language, such as window methods, DOM events, and so on, are not available. + +=== Global State + +All variables must be local to the function; global state is not permitted. + +.JavaScript code with global variable +==== +[source, javascript] +---- +include::example$illegal-global-variable.js[] +---- +==== + +Along with global state, global https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions[arrow functions] are not supported. +Arrow functions local to individual JavaScript functions are supported. + +=== Logging + +Logging using the `console.log(..)` function is not supported. + +== Restricted Features + +[.status]#Couchbase Server 7.6.2# + +The following features are restricted in JavaScript functions for Query in Couchbase Server 7.6.2 and later. + +=== Code Injection + +JavaScript constructs that may allow for code injection have been removed: + +* The `eval` symbol has been removed. +* The `Function` construct has been removed. + +.JavaScript code with the `eval` symbol +==== +The following example does not compile as it uses the `eval` symbol. + +[source,javascript] +---- +function evaluate() { + var q = select jscode from where meta().id = ; + let iter = q[Symbol.iterator](); + let code = iter.next(); + let result = eval(code); +} +---- +==== + +.JavaScript code with the `Function` construct +==== +The following example does not compile as it uses the `Function` construct. + +[source,javascript] +---- +function dynamicfunction() { +var q = select jscode from where meta().id = ; + let iter = q[Symbol.iterator](); + let code = iter.next(); + return new Function("inject", code); +} + +function evaluate() { + dynamicfunction(); +} +---- +==== + +=== Date Granularity + +The granularity of the `Date` object has been reduced to 1 second. +This is to prevent a potential attacker from easily measuring the difference between a CPU cache miss and cache hit, hence taking advantage of side-channel attacks or speculative execution attacks. + +.JavaScript code with timestamp +==== +The following example executes a {sqlpp} query to insert a document with a field containing the current timestamp. +The timestamp is returned to the last second, rather than the most recent millisecond. + +[source,javascript] +---- +function addOrder() { + let curr = Date.now(); + N1QL('INSERT INTO orders VALUES (uuid(),{"time":'+ curr +'})') +} +---- +==== + +.JavaScript code with date comparison +==== +The following example simulates sleep by blocking execution by the number of milliseconds passed as a function parameter. +Since the `Date.Now()` function does not return the current time with millisecond granularity, the function may not work as expected. + +[source,javascript] +---- +function sleep(milliseconds) { + let init = Date.now(); + let curr = null; + do { + curr = Date.now(); + } while (curr - init < milliseconds); +} +---- +==== + +== See Also + +.User-Defined Function Guides +* xref:guides:javascript-udfs.adoc[] +* xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions] + +.{sqlpp} User-Defined Function Commands +* xref:n1ql:n1ql-language-reference/createfunction.adoc[] +* xref:n1ql:n1ql-language-reference/explainfunction.adoc[] +* xref:n1ql:n1ql-language-reference/execfunction.adoc[] +* xref:n1ql:n1ql-language-reference/dropfunction.adoc[] +* xref:n1ql:n1ql-language-reference/userfun.adoc[] + +.External Libraries +* xref:tools:udfs-ui.adoc[] +* xref:n1ql-rest-functions:index.adoc[] + +.JavaScript Functions +* xref:calling-javascript-from-n1ql.adoc[] +* xref:calling-n1ql-from-javascript.adoc[] +* xref:handling-errors-javascript-udf.adoc[] diff --git a/modules/javascript-udfs/partials/diagrams.adoc b/modules/javascript-udfs/partials/diagrams.adoc new file mode 100644 index 000000000..eb32f01a9 --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams.adoc @@ -0,0 +1,39 @@ +//// +Previews the diagrams used in the JavaScript UDF section +//// + +.Inline call sequence +[plantuml, subs=attributes] +.... +include::diagrams/inline-call-sequence.puml[] +.... + +.Transactions and iterators +[plantuml, subs=attributes] +.... +include::diagrams/transactions-and-iterators.puml[] +.... + +.Data transformation +[plantuml, subs=attributes] +.... +include::diagrams/data-transformation.puml[] +.... + +.UDF scopes +[plantuml, subs=attributes] +.... +include::diagrams/udf-scopes-diagram.puml[] +.... + +.Banking scope scenario +[plantuml, subs=attributes] +.... +include::diagrams/banking-scope-scenario.puml[] +.... + +.JavaScript scopes +[plantuml] +.... +include::diagrams/javascript-scopes.puml[] +.... diff --git a/modules/javascript-udfs/partials/diagrams/banking-scope-scenario.puml b/modules/javascript-udfs/partials/diagrams/banking-scope-scenario.puml new file mode 100644 index 000000000..8498e30b8 --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams/banking-scope-scenario.puml @@ -0,0 +1,61 @@ +@startuml + +allow_mixing +skinparam actorStyle Awesome + + +actor "US\nUser" as USUser +actor "UK\nUser" as UKUser + + +database "Banking\nDatabase" as bankingDatabase { + + node "UK Bank Scope" as UKBankScope { + + frame "bank-library" as UKLibrary { + file "getInterestInSterling(termInYears, rate)" as interestInSterling + } + } + + node "US Bank Scope" as USBankScope { + + frame "bank-library" as USLibrary { + file "getInterestInDollars(termInYears, rate)" as interestInDollars + } + } + +} + + +component "GetInterest(...)" <<{sqlpp} User-Defined Function>> as UKReferenceFunction +component "GetInterest(...)" <<{sqlpp} User-Defined Function>> as USReferenceFunction + + +UKReferenceFunction --> interestInSterling : references +UKUser --> UKReferenceFunction + +USReferenceFunction --> interestInDollars : references +USUser --> USReferenceFunction + +note left of UKUser #Ivory + **UK** User is logged on with + the BankingDatabase.**UKBank** + context scope +end note + +note right of USUser #Ivory + **US** User is logged on with + the BankingDatabase.**USBank** + context scope +end note + +note as referenceFunctionNote #Ivory + Two N1QL User-Defined Functions with the same name, + but pointing at different JavaScript functions + in different libraries in different scopes. +end note + +referenceFunctionNote .. UKReferenceFunction +referenceFunctionNote .. USReferenceFunction + +@enduml diff --git a/modules/javascript-udfs/partials/diagrams/data-transformation.puml b/modules/javascript-udfs/partials/diagrams/data-transformation.puml new file mode 100644 index 000000000..344f2dfb9 --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams/data-transformation.puml @@ -0,0 +1,10 @@ +@startuml + +skinparam componentStyle rectangle + +left to right direction + +[Run {sqlpp} statement] --> [Transform JSON data] : {item1, item2, item3} +[Transform JSON data] --> return : {item1, item3} + +@enduml diff --git a/modules/javascript-udfs/partials/diagrams/inline-call-sequence.puml b/modules/javascript-udfs/partials/diagrams/inline-call-sequence.puml new file mode 100644 index 000000000..010db5b4d --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams/inline-call-sequence.puml @@ -0,0 +1,26 @@ +@startuml + + skinparam actorStyle Awesome + + actor Dev + participant JSEngine + participant QueryEngine + database Bucket + + Dev ->> JSEngine: JS: var q = select … + activate JSEngine + JSEngine ->> QueryEngine : {sqlpp}(…) call + activate QueryEngine + QueryEngine ->> JSEngine : return query + deactivate QueryEngine + JSEngine ->> Dev : return q + deactivate JSEngine + + loop Every document in q + Dev ->> JSEngine : operate on document + JSEngine ->> QueryEngine ++ : get document + QueryEngine ->> Bucket ++ : get document + Bucket ->> QueryEngine -- : retrieved document + QueryEngine ->> JSEngine -- : retrieved document + end +@enduml \ No newline at end of file diff --git a/modules/javascript-udfs/partials/diagrams/javascript-scopes.puml b/modules/javascript-udfs/partials/diagrams/javascript-scopes.puml new file mode 100644 index 000000000..9adf07289 --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams/javascript-scopes.puml @@ -0,0 +1,42 @@ +@startuml + +frame Namespace { + + frame "global library" as globalLibrary #white { + + component function3 #Ivory [ + +function globalUKHoliday(... args) { + ... +} + + ] + + component function4 #Ivory [ + +function globalUSHoliday(... args) { + ... +} + + ] + } + + database "Bucket" { + + node "Scope" #White { + + frame "my-library" #White { + + component function1 #Ivory [ + +function add(x, y) { + ... +} + + ] + + } + } +} + +@enduml diff --git a/modules/javascript-udfs/partials/diagrams/transactions-and-iterators.puml b/modules/javascript-udfs/partials/diagrams/transactions-and-iterators.puml new file mode 100644 index 000000000..2734ae3d0 --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams/transactions-and-iterators.puml @@ -0,0 +1,20 @@ +@startuml + + +start + +:start transaction; +note right: Transaction started before the initial\n{sqlpp} statement is called +: var q = execute N1QL statement; + + while (next q?) is (yes) + + : process q; + + endwhile (no) + +:commit or rollback; + +stop + +@enduml diff --git a/modules/javascript-udfs/partials/diagrams/udf-scopes-diagram.puml b/modules/javascript-udfs/partials/diagrams/udf-scopes-diagram.puml new file mode 100644 index 000000000..63a4fa8ea --- /dev/null +++ b/modules/javascript-udfs/partials/diagrams/udf-scopes-diagram.puml @@ -0,0 +1,41 @@ +@startuml +allow_mixing + +left to right direction +skinparam actorStyle Awesome +skinparam linetype polyline +skinparam linetype ortho + +component "getBusinessDays(...)" <<{sqlpp} User-Defined Function>> as n1qlUDFunction + + frame "my-library" as MyLibrary { + + file "getBusinessDays(startDate, \nendDate)" as getBusinessDays + + } + + + +n1qlUDFunction ---> getBusinessDays +actor "user" as user + + + +database "bucket" as bucket { + node "**scope**" as scope +} + + +scope <...r.... MyLibrary + + + +user --> n1qlUDFunction + +note top of user #Ivory + Users can access the getBusinessDays + function as long as they are working + inside the "**bucket.scope**" context +end note + +@enduml diff --git a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc new file mode 100644 index 000000000..d7f473006 --- /dev/null +++ b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc @@ -0,0 +1,8 @@ +There are two types of user-defined function in {sqlpp} for Query: + +* [.term]#Inline functions# are defined using {sqlpp} expressions. +They enable you to name and reuse complex or repetitive expressions, including subqueries, in order to simplify your queries. + +* [.term]#External functions# are defined using an external language. +They enable you to create functions that may be difficult or impossible to define using built-in {sqlpp} expressions. +The only supported language is JavaScript. \ No newline at end of file diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc new file mode 100644 index 000000000..b6bba3717 --- /dev/null +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -0,0 +1,55 @@ +//// +The libraries and scope section can be reused in the SQL++ reference +//// + +[#libraries-and-scopes] +// tag::extract[] +=== External Libraries + +(((library namespacing))) +You can store JavaScript functions in [.term]#external libraries#. +This enables you to share external function code for use in more than one {sqlpp} user-defined function. +A library can contain one or more JavaScript functions. + +You must create the external library and the external function code using the xref:tools:udfs-ui.adoc[Query Workbench] or the {sqlpp} xref:n1ql-rest-functions:index.adoc[Functions REST API]. +// This line left blank intentionally + +// end::extract[] + +You do not call the external function code directly from {sqlpp}. +Instead, when you have created an external library and added a JavaScript function to it, you must define a {sqlpp} user-defined function to call the JavaScript function. + +// tag::extract[] +External libraries, like {sqlpp} user-defined functions, may be scoped or global. +This enables you to keep the code for external functions separate where required. +// This line left blank intentionally + +// end::extract[] + +.Global and scoped external libraries +[plantuml#javascript-scopes,javascript-scopes,svg] +.... +include::partial$diagrams/javascript-scopes.puml[] +.... + +* A [.term]#global library# is created within a xref:n1ql:n1ql-intro/queriesandresults.adoc#logical-hierarchy[namespace], at the same level as the buckets within the namespace. + +* A [.term]#scoped library# is created within a xref:n1ql:n1ql-intro/queriesandresults.adoc#logical-hierarchy[scope], at the same level as the collections within a scope. + +You can apply access restrictions to scopes, so that only certain groups of users will be able to access collections and libraries within that scope. + +// tag::extract[] +Code which is stored in a scoped library is private to users of that scope, and is not visible or available to users of another scope. +Code which is stored in a global library is available to users of all scopes. + +A global library may have the same name as a scoped library, and scoped libraries may have the same name as each other. +For example, you may have a global `math` library, and a `math` library in each scope. +// end::extract[] + +.Calling a function in a scoped external library +[plantuml#scopes-for-udf,udf-scopes-diagram,svg,subs=attributes] +.... +include::partial$diagrams/udf-scopes-diagram.puml[] +.... + +In order to use a {sqlpp} user-defined function which calls external JavaScript code in a scoped library, you must set the xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to the same bucket and scope as the scoped library. diff --git a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc new file mode 100644 index 000000000..a42f091b6 --- /dev/null +++ b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc @@ -0,0 +1,9 @@ +=== {sqlpp} Managed User-Defined Functions + +[.status]#Couchbase Server 7.6# + +In clusters using Couchbase Server 7.6 and later, you can create the code for an external function and the corresponding {sqlpp} user-defined function in a single operation. +This means that you don't have to specify an external library and create the code for the external function, before creating the {sqlpp} user-defined function. + +With a {sqlpp} managed user-defined function, the external function code is stored inline, along with the {sqlpp} user-defined function. +You cannot share this external function code with other user-defined functions, or access it from any external libraries. diff --git a/modules/learn/assets/images/services-and-indexes/indexes/IndexKeyOrder.png b/modules/learn/assets/images/services-and-indexes/indexes/IndexKeyOrder.png new file mode 100644 index 000000000..4d198a215 Binary files /dev/null and b/modules/learn/assets/images/services-and-indexes/indexes/IndexKeyOrder.png differ diff --git a/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-build.png b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-build.png new file mode 100644 index 000000000..d90c97a3b Binary files /dev/null and b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-build.png differ diff --git a/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-scan.png b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-scan.png new file mode 100644 index 000000000..7699a861b Binary files /dev/null and b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-scan.png differ diff --git a/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-update-1.png b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-update-1.png new file mode 100644 index 000000000..848eede22 Binary files /dev/null and b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-update-1.png differ diff --git a/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-update-2.png b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-update-2.png new file mode 100644 index 000000000..2d986a14a Binary files /dev/null and b/modules/learn/assets/images/services-and-indexes/indexes/index-lifecycle-update-2.png differ diff --git a/modules/learn/assets/images/services-and-indexes/indexes/query_execution.png b/modules/learn/assets/images/services-and-indexes/indexes/query_execution.png new file mode 100644 index 000000000..e76da2b70 Binary files /dev/null and b/modules/learn/assets/images/services-and-indexes/indexes/query_execution.png differ diff --git a/modules/learn/assets/images/services-and-indexes/indexes/query_service.svg b/modules/learn/assets/images/services-and-indexes/indexes/query_service.svg new file mode 100644 index 000000000..ff2611d6f --- /dev/null +++ b/modules/learn/assets/images/services-and-indexes/indexes/query_service.svg @@ -0,0 +1,250 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Parse + + + Plan + + + Scan + + + Fetch + + + Join + + + Sort + + + Offset + + + Limit + + + Project + + + Filter + + + Pre-Aggregate + + + Aggregate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client + + + Query Service + + + + Index Service + + + + Data Service + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/create-idx-array.n1ql b/modules/learn/examples/services-and-indexes/indexes/create-idx-array.n1ql new file mode 100644 index 000000000..b91da3ca6 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/create-idx-array.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX travel_sched ON route +(DISTINCT ARRAY v.day FOR v IN schedule END); \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/create-idx-composite.n1ql b/modules/learn/examples/services-and-indexes/indexes/create-idx-composite.n1ql new file mode 100644 index 000000000..fd87909d5 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/create-idx-composite.n1ql @@ -0,0 +1 @@ +CREATE INDEX travel_info ON airline(name, id, icao, iata); \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/create-idx-expr.n1ql b/modules/learn/examples/services-and-indexes/indexes/create-idx-expr.n1ql new file mode 100644 index 000000000..7fea3311c --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/create-idx-expr.n1ql @@ -0,0 +1 @@ +CREATE INDEX travel_cxname ON airport(LOWER(name)); \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/create-idx-partial.n1ql b/modules/learn/examples/services-and-indexes/indexes/create-idx-partial.n1ql new file mode 100644 index 000000000..cc2b8182e --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/create-idx-partial.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX travel_eat ON landmark(name, id, address) +WHERE activity='eat'; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-1.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-filter-1.jsonc new file mode 100644 index 000000000..364b1c52c --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-1.jsonc @@ -0,0 +1,80 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ // <.> + "cover ((`landmark`.`city`))", + "cover ((`landmark`.`name`))", + "cover ((meta(`landmark`).`id`))" + ], + "filter_covers": { + "cover ((`landmark`.`activity`))": "eat" + }, + "index": "idx_eat_city_name", +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "e5dbf76060ed1d19", + "index_projection": { + "entry_keys": [ + 0, + 1 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", +// tag::extract[] + "spans": [ + { + "exact": true, + "range": [ // <.> + { + "high": "\"Paris\"", + "inclusion": 3, + "index_key": "`city`", + "low": "\"Paris\"" + } + ] +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((cover ((`landmark`.`city`)) = \"Paris\") and (cover ((`landmark`.`activity`)) = \"eat\"))" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`landmark`.`city`))" + }, + { + "expr": "cover ((`landmark`.`name`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city, name FROM `travel-sample`.inventory.landmark\nWHERE city = \"Paris\" AND activity = \"eat\";" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-1.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-filter-1.n1ql new file mode 100644 index 000000000..5922f157b --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-1.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT city, name FROM landmark +WHERE city = "Paris" AND activity = "eat"; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-2.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-filter-2.jsonc new file mode 100644 index 000000000..20d9e0d18 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-2.jsonc @@ -0,0 +1,74 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_eat_city_name", + "index_id": "e5dbf76060ed1d19", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ // <.> + { + "high": "\"Paris\"", + "inclusion": 3, + "index_key": "`city`", + "low": "\"Paris\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", // <.> + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(((`landmark`.`city`) = \"Paris\") and ((`landmark`.`activity`) = \"eat\"))" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + }, + { + "expr": "(`landmark`.`name`)" + }, + { + "expr": "(`landmark`.`address`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city, name, address FROM `travel-sample`.inventory.landmark\nWHERE city = \"Paris\" AND activity = \"eat\";" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-2.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-filter-2.n1ql new file mode 100644 index 000000000..ddc9e5330 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-2.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT city, name, address FROM landmark +WHERE city = "Paris" AND activity = "eat"; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-3.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-filter-3.jsonc new file mode 100644 index 000000000..6e8f255bd --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-3.jsonc @@ -0,0 +1,83 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "filter": "(lower(_index_key ((`landmark`.`city`))) = \"paris\")", // <.> + "index": "idx_eat_city_name", + "index_conditions": { // <.> + "_index_condition ((`landmark`.`activity`))": "eat" + }, + "index_id": "e5dbf76060ed1d19", + "index_keys": [ // <.> + "_index_key ((`landmark`.`city`))", + "_index_key ((meta(`landmark`).`id`))" + ], + "index_projection": { + "entry_keys": [ // <.> + 0 + ], + "primary_key": true + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "range": [ + { + "inclusion": 0, + "index_key": "`city`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((lower((`landmark`.`city`)) = \"paris\") and ((`landmark`.`activity`) = \"eat\"))" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + }, + { + "expr": "(`landmark`.`name`)" + }, + { + "expr": "(`landmark`.`address`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city, name, address FROM `travel-sample`.inventory.landmark\nWHERE LOWER(city) = \"paris\" AND activity = \"eat\";" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-3.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-filter-3.n1ql new file mode 100644 index 000000000..662080961 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-3.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT city, name, address FROM landmark +WHERE LOWER(city) = "paris" AND activity = "eat"; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-4.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-filter-4.jsonc new file mode 100644 index 000000000..6d80b7313 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-4.jsonc @@ -0,0 +1,95 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "filter": "(_index_key ((`landmark`.`name`)) like \"%Paris%\")", // <.> + "index": "idx_eat_city_name", + "index_conditions": { + "_index_condition ((`landmark`.`activity`))": "eat" + }, + "index_id": "e5dbf76060ed1d19", + "index_keys": [ + "_index_key ((`landmark`.`name`))", + "_index_key ((meta(`landmark`).`id`))" + ], +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_projection": { + "entry_keys": [ + 1 + ], + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", +// tag::extract[] + "spans": [ // <.> + { + "range": [ + { + "high": "\"Paris\"", + "inclusion": 3, + "index_key": "`city`", + "low": "\"Paris\"" + }, + { + "high": "[]", + "inclusion": 1, + "index_key": "`name`", + "low": "\"\"" + } + ] +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((((`landmark`.`city`) = \"Paris\") and ((`landmark`.`name`) like \"%Paris%\")) and ((`landmark`.`activity`) = \"eat\"))" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + }, + { + "expr": "(`landmark`.`name`)" + }, + { + "expr": "(`landmark`.`address`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city, name, address FROM `travel-sample`.inventory.landmark\nWHERE city = \"Paris\" AND name LIKE \"%Paris%\" AND activity = \"eat\";" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-4.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-filter-4.n1ql new file mode 100644 index 000000000..c2e328815 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-4.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT city, name, address FROM landmark +WHERE city = "Paris" AND name LIKE "%Paris%" AND activity = "eat"; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-filter-idx.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-filter-idx.n1ql new file mode 100644 index 000000000..1e4b1f2c9 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-filter-idx.n1ql @@ -0,0 +1,3 @@ +CREATE INDEX idx_eat_city_name +ON landmark(city DESC, name) +WHERE activity = "eat"; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-1.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-paginate-1.jsonc new file mode 100644 index 000000000..5f5af7d47 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-1.jsonc @@ -0,0 +1,92 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((`landmark`.`name`))", + "cover ((meta(`landmark`).`id`))" + ], + "index": "idx_landmark_city_name", + "index_id": "c2a48a468ef63f23", + "index_order": [ // <.> + { + "desc": true, + "keypos": 0 + }, + { + "keypos": 1 + } + ], + "index_projection": { + "entry_keys": [ + 0, + 1 + ] + }, + "keyspace": "landmark", + "limit": "5", // <.> + "namespace": "default", + "offset": "100", // <.> + "scope": "inventory", +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "index_key": "`city`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(cover ((`landmark`.`city`)) is not missing)" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`landmark`.`city`))" + }, + { + "expr": "cover ((`landmark`.`name`))" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "5" + } + ] + }, + "text": "SELECT city, name FROM `travel-sample`.inventory.landmark\nWHERE city IS NOT MISSING\nORDER BY city DESC, name OFFSET 100 LIMIT 5;" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-1.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-paginate-1.n1ql new file mode 100644 index 000000000..036337baa --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-1.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city, name FROM landmark +WHERE city IS NOT MISSING +ORDER BY city DESC, name OFFSET 100 LIMIT 5; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-2.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-paginate-2.jsonc new file mode 100644 index 000000000..070811a7d --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-2.jsonc @@ -0,0 +1,94 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_landmark_city_name", + "index_id": "c2a48a468ef63f23", + "index_order": [ // <.> + { + "desc": true, + "keypos": 0 + }, + { + "keypos": 1 + } + ], + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "limit": "5", // <.> + "namespace": "default", + "offset": "100", // <.> + "scope": "inventory", +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "index_key": "`city`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`landmark`.`city`) is not missing)" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + }, + { + "expr": "(`landmark`.`name`)" + }, + { + "expr": "(`landmark`.`address`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "5" + } + ] + }, + "text": "SELECT city, name, address FROM `travel-sample`.inventory.landmark\nWHERE city IS NOT MISSING\nORDER BY city DESC, name OFFSET 100 LIMIT 5;" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-2.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-paginate-2.n1ql new file mode 100644 index 000000000..9146aad66 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-2.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city, name, address FROM landmark +WHERE city IS NOT MISSING +ORDER BY city DESC, name OFFSET 100 LIMIT 5; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-3.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-paginate-3.jsonc new file mode 100644 index 000000000..3f2274c4b --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-3.jsonc @@ -0,0 +1,104 @@ +// tag::extract[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_landmark_city_name", + "index_id": "c2a48a468ef63f23", + "index_keys": [ + "_index_key ((`landmark`.`city`))", + "_index_key ((`landmark`.`name`))", + "_index_key ((meta(`landmark`).`id`))" + ], + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "index_key": "`city`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Order", // <.> + "flags": 1, + "limit": "5", // <.> + "offset": "100", // <.> + "sort_terms": [ + { + "expr": "_index_key ((`landmark`.`name`))" + }, + { + "desc": "\"desc\"", + "expr": "_index_key ((`landmark`.`city`))" + } + ] + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "#operator": "Offset", + "expr": "100" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`landmark`.`city`) is not missing)" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + }, + { + "expr": "(`landmark`.`name`)" + }, + { + "expr": "(`landmark`.`address`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "5" + } + ] + }, + "text": "SELECT city, name, address FROM `travel-sample`.inventory.landmark\nWHERE city IS NOT MISSING\nORDER BY name, city DESC OFFSET 100 LIMIT 5;" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-3.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-paginate-3.n1ql new file mode 100644 index 000000000..6da43dbcf --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-3.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city, name, address FROM landmark +WHERE city IS NOT MISSING +ORDER BY name, city DESC OFFSET 100 LIMIT 5; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-4.jsonc b/modules/learn/examples/services-and-indexes/indexes/early-paginate-4.jsonc new file mode 100644 index 000000000..794d18024 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-4.jsonc @@ -0,0 +1,107 @@ +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_landmark_city_name", + "index_id": "c2a48a468ef63f23", + "index_keys": [ + "_index_key ((`landmark`.`city`))", + "_index_key ((`landmark`.`name`))", + "_index_key ((meta(`landmark`).`id`))" + ], + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "index_key": "`city`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, +// tag::ellipsis[] +// ... +// end::ellipsis[] +// tag::extract[] + { + "#operator": "Order", + "flags": 1, + "limit": "5", + "offset": "100", + "sort_terms": [ // <.> + { + "desc": "\"asc\"", + "expr": "_index_key ((`landmark`.`city`))" + }, + { + "expr": "_index_key ((`landmark`.`name`))" + } + ] + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "#operator": "Offset", + "expr": "100" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`landmark`.`city`) is not missing)" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + }, + { + "expr": "(`landmark`.`name`)" + }, + { + "expr": "(`landmark`.`address`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "5" + } + ] + }, + "text": "SELECT city, name, address FROM `travel-sample`.inventory.landmark\nWHERE city IS NOT MISSING\nORDER BY city ASC, name OFFSET 100 LIMIT 5;" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-4.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-paginate-4.n1ql new file mode 100644 index 000000000..113d62044 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-4.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city, name, address FROM landmark +WHERE city IS NOT MISSING +ORDER BY city ASC, name OFFSET 100 LIMIT 5; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/early-paginate-idx.n1ql b/modules/learn/examples/services-and-indexes/indexes/early-paginate-idx.n1ql new file mode 100644 index 000000000..929fe64a3 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/early-paginate-idx.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX idx_landmark_city_name +ON landmark(city DESC, name); \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-comp-explain.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-comp-explain.jsonc new file mode 100644 index 000000000..b50c6775e --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-comp-explain.jsonc @@ -0,0 +1,67 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`route`.`distance`))", + "cover ((`route`.`sourceairport`))", + "cover ((`route`.`destinationairport`))", + "cover ((meta(`route`).`id`))" + ], + "filter": "((cover ((`route`.`distance`)) < 2000) and (cover ((`route`.`sourceairport`)) = \"LAX\"))", + "index": "idx_route_src_dst_dist", + "index_id": "6a502445eefe20b5", + "index_projection": { + "entry_keys": [ + 0, + 1, + 2 + ] + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "spans": [ // <.> + { + "exact": true, + "range": [ // <.> + { + "high": "2000", // <.> + "inclusion": 0, + "low": "null" + }, + { + "high": "\"LAX\"", // <.> + "inclusion": 3, + "low": "\"LAX\"" + } + ] + } + ], +// end::excerpt[] + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`route`.`destinationairport`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT destinationairport\nFROM `travel-sample`.inventory.route\nUSE INDEX (idx_route_src_dst_dist)\nWHERE distance < 2000 AND sourceairport = \"LAX\";" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-comp-plan.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-comp-plan.jsonc new file mode 100644 index 000000000..f6bf4bf58 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-comp-plan.jsonc @@ -0,0 +1,110 @@ +{ + "#operator": "Authorize", + "#stats": { + "#phaseSwitches": 4, + "execTime": "1.693µs", + "servTime": "18.503µs" + }, + "privileges": { + "List": [ + { + "Target": "default:travel-sample.inventory.route", + "Priv": 7, + "Props": 0 + } + ] + }, + "~child": { + "#operator": "Sequence", + "#stats": { + "#phaseSwitches": 2, + "execTime": "54.027µs" + }, +// tag::index[] + "~children": [ + { + "#operator": "IndexScan3", + "#stats": { + "#heartbeatYields": 54, + "#itemsOut": 165, + "#phaseSwitches": 663, + "execTime": "462.968µs", + "kernTime": "638.333µs", + "servTime": "38.110289ms" + }, +// end::index[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "bucket": "travel-sample", + "covers": [ + "cover ((`route`.`distance`))", + "cover ((`route`.`sourceairport`))", + "cover ((`route`.`destinationairport`))", + "cover ((meta(`route`).`id`))" + ], + "filter": "((cover ((`route`.`distance`)) \u003c 2000) and (cover ((`route`.`sourceairport`)) = \"LAX\"))", + "index": "idx_route_src_dst_dist", + "index_id": "6a502445eefe20b5", + "index_projection": { + "entry_keys": [ + 0, + 1, + 2 + ] + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "2000", + "inclusion": 0, + "low": "null" + }, + { + "high": "\"LAX\"", + "inclusion": 3, + "low": "\"LAX\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "InitialProject", + "#stats": { + "#itemsIn": 165, + "#itemsOut": 165, + "#phaseSwitches": 501, + "execTime": "209.778µs", + "kernTime": "38.688318ms" + }, + "result_terms": [ + { + "expr": "cover ((`route`.`destinationairport`))" + } + ] + }, +// tag::final[] + { + "#operator": "Stream", + "#stats": { + "#itemsIn": 165, + "#itemsOut": 165, + "#phaseSwitches": 166, + "execTime": "354.652µs" + } + } +// end::final[] + ] + }, + "~versions": [ + "7.0.0-N1QL", + "7.0.0-5071-enterprise" + ] +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-count.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-count.jsonc new file mode 100644 index 000000000..2dfef9a50 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-count.jsonc @@ -0,0 +1,74 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", // <1> + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))", + "cover (count(cover ((`landmark`.`city`))))" + ], + "index": "def_inventory_landmark_city", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`city`))", + "id": 2, + "keypos": 0 + } +// end::excerpt[] + ], + "depends": [ + 0 + ] + }, + "index_id": "39eb8e83720948f", + "index_projection": { + "entry_keys": [ + 2 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "as": "NumberOfCities", + "expr": "cover (count(cover ((`landmark`.`city`))))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT COUNT(city) AS NumberOfCities\nFROM `travel-sample`.inventory.landmark\nUSE INDEX (def_inventory_landmark_city)\nWHERE city IS NOT NULL;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-def-city.n1ql b/modules/learn/examples/services-and-indexes/indexes/pushdown-def-city.n1ql new file mode 100644 index 000000000..4ca79f78a --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-def-city.n1ql @@ -0,0 +1 @@ +CREATE INDEX def_inventory_landmark_city ON landmark(city); \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-distinct.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-distinct.jsonc new file mode 100644 index 000000000..25e138ec3 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-distinct.jsonc @@ -0,0 +1,75 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", // <1> + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))", + "cover (count(DISTINCT cover ((`landmark`.`city`))))" + ], + "index": "def_inventory_landmark_city", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 0 + ], + "distinct": true, + "expr": "cover ((`landmark`.`city`))", + "id": 2, + "keypos": 0 + } +// end::excerpt[] + ], + "depends": [ + 0 + ] + }, + "index_id": "39eb8e83720948f", + "index_projection": { + "entry_keys": [ + 2 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "as": "NumberOfDistinctCities", + "expr": "cover (count(DISTINCT cover ((`landmark`.`city`))))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT COUNT (DISTINCT city) AS NumberOfDistinctCities\nFROM `travel-sample`.inventory.landmark\nUSE index (def_inventory_landmark_city)\nWHERE city IS NOT NULL;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-1.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-1.jsonc new file mode 100644 index 000000000..c21389ca5 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-1.jsonc @@ -0,0 +1,74 @@ +// tag::index[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))" + ], + "filter": "(cover ((`landmark`.`city`)) like \"San%\")", + "index": "def_inventory_landmark_city", +// end::index[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "39eb8e83720948f", + "index_order": [ + { + "keypos": 0 + } + ], + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"Sao\"", + "inclusion": 1, + "low": "\"San\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ +// tag::query[] + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`landmark`.`city`))" + } + ] + } // <1> +// end::query[] + ] + } + } + ] + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.landmark\nWHERE city LIKE \"San%\"\nORDER BY city;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-2.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-2.jsonc new file mode 100644 index 000000000..baa8852b2 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-2.jsonc @@ -0,0 +1,71 @@ +// tag::index[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))" + ], + "filter": "(cover ((`landmark`.`city`)) like \"San%\")", + "index": "def_inventory_landmark_city", +// end::index[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "39eb8e83720948f", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"Sao\"", + "inclusion": 1, + "low": "\"San\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ +// tag::query[] + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`landmark`.`city`))" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Order", // <1> + "sort_terms": [ + { + "expr": "cover ((meta(`landmark`).`id`))" + } + ] + } +// end::query[] + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.landmark\nWHERE city LIKE \"San%\"\nORDER BY meta().id;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-3.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-3.jsonc new file mode 100644 index 000000000..4b1963fbb --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-idx-3.jsonc @@ -0,0 +1,75 @@ +// tag::index[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))" + ], + "filter": "(cover ((`landmark`.`city`)) like \"San%\")", + "index": "idx_landmark_city_desc", + "index_id": "efc36547ec1c0f00", + "index_order": [ + { + "desc": true, + "keypos": 0 + } +// end::index[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + ], + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"Sao\"", + "inclusion": 1, + "low": "\"San\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ +// tag::query[] + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`landmark`.`city`))" + } + ] + } +// end::query[] + ] + } + } + ] + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.landmark\nWHERE city LIKE \"San%\"\nORDER BY city DESC;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-max.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-max.jsonc new file mode 100644 index 000000000..9568e0c18 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-max.jsonc @@ -0,0 +1,73 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))", + "cover (max(cover ((`landmark`.`city`))))" + ], + "index": "def_inventory_landmark_city", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "MAX", + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`city`))", + "id": 2, + "keypos": 0 + } +// end::excerpt[] + ], + "depends": [ + 0 + ] + }, + "index_id": "39eb8e83720948f", + "index_projection": { + "entry_keys": [ + 2 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover (max(cover ((`landmark`.`city`))))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT MAX(city)\nFROM `travel-sample`.inventory.landmark\nUSE INDEX (def_inventory_landmark_city)\nWHERE city IS NOT NULL;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-min.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-min.jsonc new file mode 100644 index 000000000..78aebef95 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-min.jsonc @@ -0,0 +1,73 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((meta(`landmark`).`id`))", + "cover (min(cover ((`landmark`.`city`))))" + ], + "index": "def_inventory_landmark_city", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "MIN", + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`city`))", + "id": 2, + "keypos": 0 + } +// end::excerpt[] + ], + "depends": [ + 0 + ] + }, + "index_id": "39eb8e83720948f", + "index_projection": { + "entry_keys": [ + 2 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover (min(cover ((`landmark`.`city`))))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT MIN(city)\nFROM `travel-sample`.inventory.landmark\nUSE INDEX (def_inventory_landmark_city)\nWHERE city IS NOT NULL;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-page-1.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-page-1.jsonc new file mode 100644 index 000000000..9e7742617 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-page-1.jsonc @@ -0,0 +1,74 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "def_inventory_landmark_city", + "index_id": "39eb8e83720948f", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "limit": "10000", // <1> + "namespace": "default", + "offset": "4000", // <2> + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"San Francisco\"", + "inclusion": 3, + "low": "\"San Francisco\"" + } + ] + } + ], +// end::excerpt[] + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`landmark`.`city`) = \"San Francisco\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "10000" + } + ] + }, + "text": "SELECT * FROM `travel-sample`.inventory.landmark\nWHERE city = \"San Francisco\"\nOFFSET 4000 LIMIT 10000;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-page-2.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-page-2.jsonc new file mode 100644 index 000000000..566ad497e --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-page-2.jsonc @@ -0,0 +1,57 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_landmark_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "limit": "10000", // <1> + "namespace": "default", + "offset": "4000", // <2> + "scope": "inventory", + "using": "gsi" + }, +// end::excerpt[] + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "10000" + } + ] + }, + "text": "SELECT * FROM `travel-sample`.inventory.landmark\nOFFSET 4000 LIMIT 10000;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-page-3.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-page-3.jsonc new file mode 100644 index 000000000..a0b6f631c --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-page-3.jsonc @@ -0,0 +1,91 @@ +// tag::index[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", // <1> + "bucket": "travel-sample", + "index": "def_inventory_landmark_city", + "index_id": "39eb8e83720948f", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", +// end::index[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"San Francisco\"", + "inclusion": 3, + "low": "\"San Francisco\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`landmark`.`city`) = \"San Francisco\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, +// tag::order[] + { + "#operator": "Order", + "limit": "10000", + "offset": "4000", + "sort_terms": [ + { + "expr": "(`landmark`.`name`)" + } + ] + }, + { + "#operator": "Offset", // <2> + "expr": "4000" + }, + { + "#operator": "Limit", // <3> + "expr": "10000" + } +// end::order[] + ] + }, + "text": "SELECT * FROM `travel-sample`.inventory.landmark\nUSE INDEX(def_inventory_landmark_city)\nWHERE city = \"San Francisco\"\nORDER BY name\nOFFSET 4000 LIMIT 10000;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-simple.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-simple.jsonc new file mode 100644 index 000000000..72af360ba --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-simple.jsonc @@ -0,0 +1,76 @@ +// tag::projection[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "limit": "1", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`route`.`sourceairport`))", + "cover ((`route`.`destinationairport`))", + "cover ((distinct (array (`v`.`day`) for `v` in (`route`.`schedule`) end)))", + "cover ((meta(`route`).`id`))" + ], + "filter": "(cover ((`route`.`sourceairport`)) = \"SFO\")", + "index": "def_inventory_route_route_src_dst_day", + "index_id": "e7eb4b4555f90179", + "index_projection": { + "entry_keys": [ // <1> + 0 + ], + "primary_key": true // <2> + }, +// end::projection[] + "keyspace": "route", + "namespace": "default", + "scope": "inventory", +// tag::predicate[] + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "low": "\"SFO\"" + } + ] + } + ], +// end::predicate[] + "using": "gsi" + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`route`.`sourceairport`))" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "1" + } + ] + }, + "text": "SELECT sourceairport FROM `travel-sample`.inventory.route\nUSE INDEX (def_inventory_route_route_src_dst_day)\nWHERE sourceairport = \"SFO\"\nLIMIT 1;" +} \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/pushdown-skip.jsonc b/modules/learn/examples/services-and-indexes/indexes/pushdown-skip.jsonc new file mode 100644 index 000000000..a734f534a --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/pushdown-skip.jsonc @@ -0,0 +1,72 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`route`.`distance`))", + "cover ((`route`.`sourceairport`))", + "cover ((`route`.`destinationairport`))", + "cover ((meta(`route`).`id`))" + ], + "filter": "((cover ((`route`.`distance`)) < 2000) and (cover ((`route`.`destinationairport`)) = \"LAX\"))", + "index": "idx_route_src_dst_dist", + "index_id": "6a502445eefe20b5", + "index_projection": { + "entry_keys": [ + 0, + 1, + 2 + ] + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "spans": [ // <.> + { + "exact": true, + "range": [ + { + "high": "2000", // <.> + "inclusion": 0, + "low": "null" + }, + { + "inclusion": 0 // <.> + }, + { + "high": "\"LAX\"", // <.> + "inclusion": 3, + "low": "\"LAX\"" + } + ] + } + ], +// end::excerpt[] + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`route`.`sourceairport`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT sourceairport\nFROM `travel-sample`.inventory.route\nUSE INDEX (idx_route_src_dst_dist)\nWHERE distance < 2000 AND destinationairport = \"LAX\";" + } +] \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/replication-nodes.n1ql b/modules/learn/examples/services-and-indexes/indexes/replication-nodes.n1ql new file mode 100644 index 000000000..e039abcb5 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/replication-nodes.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX country_idx ON airport(country, city) +WITH {"nodes": ["node1:8091", "node2:8091", "node3:8091"]}; \ No newline at end of file diff --git a/modules/learn/examples/services-and-indexes/indexes/replication-num.n1ql b/modules/learn/examples/services-and-indexes/indexes/replication-num.n1ql new file mode 100644 index 000000000..c9d3df6b7 --- /dev/null +++ b/modules/learn/examples/services-and-indexes/indexes/replication-num.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX country_idx ON airport(country, city) +WITH {"num_replica": 2}; \ No newline at end of file diff --git a/modules/learn/pages/services-and-indexes/indexes/.indexes.adoc b/modules/learn/pages/services-and-indexes/indexes/.indexes.adoc new file mode 100644 index 000000000..da44b73c7 --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/.indexes.adoc @@ -0,0 +1,40 @@ += Indexes +:description: Couchbase Capella indexes enhance the performance of query and search operations. +:page-aliases: understanding-couchbase:services-and-indexes/indexes/indexes,concepts:indexing + +[abstract] +{description} + +_Indexes_ are used by certain services, such as _Query_, _Analytics_, and _Search_, as targets for search-routines. +Each index makes a predefined subset of data available for the search. + +The _Query_ service relies on indexes provided by the _Index_ service. +The _Search_ and _Analytics_ services both provide their own indexes, internally. + +Indexes, when well-designed, provide significant enhancements to the performance of search-operations. + +== Indexes + +The following forms of index are available: + +Primary:: Provided by the xref:services-and-indexes/services/index-service.adoc[Index Service], this is based on the unique key of every item in a specified collection. +Every primary index is maintained asynchronously. +A primary index is intended to be used for simple queries, which have no filters or predicates. +For information on primary indexes, see xref:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes]. + +Secondary:: Provided by the xref:services-and-indexes/services/index-service.adoc[Index Service], this is based on an attribute _within_ a document. +The value associated with the attribute can be of any type: scalar, object, or array. ++ +A Secondary Index is frequently referred to as a _Global Secondary Index_, or _GSI_. +This is the kind of index used most frequently in Couchbase Server, for queries performed with {sqlpp}. +For information on Global Secondary Indexes, see xref:services-and-indexes/indexes/global-secondary-indexes.adoc[Using Indexes]. + +Full Text:: Provided by the xref:services-and-indexes/services/search-service.adoc[Search Service], this is a specially purposed index, which contains targets derived from the textual contents of documents within one or more specified keyspaces. +Text-matches of different degrees of exactitude can be searched for. +Both input and target text-values can be purged of irrelevant characters (such as punctuation marks or html tags). +For information on how to create Full Text Indexes, see xref:fts:fts-creating-indexes.adoc[Creating Indexes]. + +Analytics:: Provided by the xref:services-and-indexes/services/analytics-service.adoc[Analytics Service], this is a materialized access path for the shadow data in an Analytics collection. +Analytics indexes can be used to speed up Analytics selection queries and join queries. +If changes in operational data result in corresponding modifications to shadow data, Analytics indexes are updated automatically. +See the section on xref:analytics:7_using_index.adoc[Using Indexes] in Couchbase Analytics. diff --git a/modules/learn/pages/services-and-indexes/indexes/early-filters-and-pagination.adoc b/modules/learn/pages/services-and-indexes/indexes/early-filters-and-pagination.adoc new file mode 100644 index 000000000..4942d0312 --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/early-filters-and-pagination.adoc @@ -0,0 +1,496 @@ += Early Filters, Order, and Pagination +:page-topic-type: concept +:description: When covering indexes and index pushdowns are not available, the Query Service may use early filtering, early ordering, and early pagination to improve the query response time. + +[abstract] +{description} + +.Examples on this Page +**** +The examples in this topic use the travel-sample dataset which is supplied with Couchbase Capella. +For instructions on how to install the sample data, see xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data]. + +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Overview + +If a query has a xref:n1ql:n1ql-language-reference/covering-indexes.adoc[covering index], and the query is on a single keyspace, then the index contains all the data needed to perform the query. +The Query service does not need to fetch data from the Data service. +Any filters, order, or pagination (offset and limit) are performed by the Index service. + +.Covering index +[plantuml#cover,covered-query,svg] +.... +@startuml + +skinparam defaultTextAlignment center +skinparam linetype ortho + +() " " as start +() " " as end + +rectangle "Index\nService"{ + rectangle "Index Scan" as IndexScan + rectangle Filter + rectangle Order + rectangle Offset + rectangle Limit +} + +note bottom of Filter + Filters, order, and pagination + performed by the Index Service +end note + +start ..r..> IndexScan +IndexScan -> Filter +Filter -> Order +Order -> Offset +Offset -> Limit +Limit ..r..> end + +@enduml +.... + +If a query is _not_ covered by an index, then the query needs to fetch data from the Data service after performing the index scan, in order to return the requested results. +By default, any filters, order, or pagination are performed by the Query service after the fetch. + +.Default filters, order, and pagination +[plantuml#fig-uncovered,uncovered-query,svg] +.... +@startuml + +skinparam defaultTextAlignment center + +() " " as start +() " " as end + +rectangle "Index\nService"{ + rectangle "Index Scan" as IndexScan +} + +rectangle "Query\nService"{ + rectangle Fetch + rectangle Filter + rectangle Order + rectangle Offset + rectangle Limit +} + +note bottom of Filter + Filters, order, and pagination + performed after fetch +end note + +database "Data\nService" as Data + +start ..r..> IndexScan +IndexScan -> Fetch +Fetch -> Filter +Filter -> Order +Order -> Offset +Offset -> Limit +Fetch --> Data +Fetch <-- Data +Limit ..r..> end + +@enduml +.... + +Fetching data from the Data service can be expensive. +Any feature that can reduce the amount of data to be fetched will improve the query response time. +It would obviously be inefficient to fetch an entire dataset, and then discard a large portion of it by applying filters and pagination. +Couchbase Capella therefore attempts to apply filters, order, and pagination _before_ fetching data, wherever possible. + +Index xref:learn:services-and-indexes/indexes/index_pushdowns.adoc[pushdowns] provide one way to reduce the amount of data to be fetched. +Some filters, ordering, and pagination may be pushed down to the Index service, along with grouping and aggregates. +The Index service applies these operations to the result of the index scan. +The Query service then only needs to fetch the remaining data. + +.Filter, order, and pagination pushdown +[plantuml#fig-pushdown,index-pushdown,svg] +.... +@startuml + +skinparam defaultTextAlignment center +skinparam linetype ortho + +() " " as start +() " " as end + +rectangle "Index\nService"{ + rectangle "Index Scan" as IndexScan + rectangle Filter + rectangle Order + rectangle Offset + rectangle Limit +} + +note bottom of Filter + Filters, order, and pagination + pushed down to the Index Service +end note + +rectangle "Query\nService"{ + rectangle Fetch +} + +database "Data\nService" as Data + +start ..r..> IndexScan +IndexScan -> Filter +Filter -> Order +Order -> Offset +Offset -> Limit +Limit -r-> Fetch +Fetch --> Data +Fetch <-- Data +Fetch ..r..> end + +@enduml +.... + +However, there are some operations that cannot be pushed down to the Index service: for example, a filter that uses a function or a LIKE operator on top of an index term. +These operations must be performed by the Query service. +If the Query Service has to perform a fetch from the Data service, and then apply any operations that could not be pushed down to the Index service, +this may still lead to some inefficient queries. + +In Couchbase Capella, [def]_early filtering_, [def]_early ordering_, and [def]_early pagination_ provide another line of defense, in cases where covering indexes and index pushdowns are not available. +With this feature, the Query service may apply filtering, ordering, and pagination directly to the results returned by the Index service, before performing the fetch. + +.Early filters, order, and pagination +[plantuml#fig-early,early-filter-pagination,svg] +.... +@startuml + +skinparam defaultTextAlignment center + +() " " as start +() " " as end + +rectangle "Index\nService"{ + rectangle "Index Scan" as IndexScan +} + +rectangle "Query\nService"{ + rectangle Fetch + rectangle Filter + rectangle Order + rectangle Offset + rectangle Limit +} + +note bottom of Filter + Early filters, order, and pagination + performed by Query service +end note + +database "Data\nService" as Data + +start ..r..> IndexScan +IndexScan -> Filter +Filter -> Order +Order -> Offset +Offset -> Limit +Limit -> Fetch +Fetch --> Data +Fetch <-- Data +Fetch ..r..> end + +@enduml +.... + +Note that in practice, an uncovered query may use a mixture of the methods illustrated by <>, <>, and <>. +In addition, early filtering may be performed independently of early ordering and pagination, and vice versa. + +== Early Filtering + +Early filtering may be applied independently of early ordering and pagination. +For an illustration of early filtering, consider the following index. + +==== +[[early-filter-idx]] +.Index I +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-filter-idx.n1ql[] +---- +==== + +This index contains all the data needed to perform <>; it therefore acts as a covering index to this query. + +[[early-filter-1]] +.Covered query +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-filter-1.n1ql[] +---- + +The query plan shows that the query is covered. +In addition, the predicate `city = "Paris"` is applied as a span by the Index service. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-filter-1.jsonc[tags=extract;ellipsis] +---- + +<.> The `covers` section shows that the query is covered. +<.> The `range` section shows that this predicate is applied as a span by the Index service. +==== + +<> adds an extra field to the projection. +Now the query is no longer covered, and the Query service needs to fetch documents based on keys returned from the index. + +[[early-filter-2]] +.Predicate pushdown +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-filter-2.n1ql[] +---- + +This query does not run too slowly, since the predicate `city = "Paris"` is pushed down to the Index service. +The index only returns document keys for documents matching the predicate. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-filter-2.jsonc[tags=extract;ellipsis] +---- + +<.> The `range` section shows that this predicate is pushed down to the Index service. +<.> After the pushdown, the Query service fetches documents from the Data service. +==== + +Now let's consider the case when the filter is not on the index key exactly, but applies a function on top of the index key. + +[[early-filter-3]] +.Early filtering +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-filter-3.n1ql[] +---- + +In this case, the filter cannot be pushed down to the Index service. +This is where early filtering comes into play. +The Query service can apply the specified filter to the results of the index scan, before fetching the matching documents from the Data service. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-filter-3.jsonc[tags=extract;ellipsis] +---- + +<.> The early index filters, including all the filters that can be evaluated on the index keys. +Inside the filter, `pass:c[_index_key ((`landmark`.`city`))]` is analogous to `pass:c[cover ((`landmark`.`city`))]` for a covering index scan. +<.> The `index_conditions` section is analogous to the `filter_covers` section in the plan for a covered query. +<.> The `index_keys` section is analogous to the `covers` section in the plan for a covered query. +<.> The `index_projection` section contains the `_index_key` needed for evaluating the early index filters -- in this case position `0` for `"city"`. +==== + +If necessary, the Query service may use a mixture of index pushdowns and early filtering, as shown in the following example. + +[[early-filter-4]] +.Predicate pushdown and early filter +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-filter-4.n1ql[] +---- + +The Index service evaluates the filters used to generate the index spans first, before returning to the Query service. +As a result, the early filters only contain the predicates that were not pushed down to the Index service. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-filter-4.jsonc[tags=extract;ellipsis] +---- + +<.> The filter `name LIKE "%Paris%"` does not generate an exact index span, and needs to be evaluated as an early index filter. +<.> The filter `city = "Paris"` generates an exact span, and thus can be pushed down to the Index service. +==== + +== Early Order and Pagination + +Early order and pagination may be applied independently of early filtering. +As an illustration, consider the following index. + +==== +[[early-paginate-idx]] +.Index II +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-paginate-idx.n1ql[] +---- +==== + +This index acts as a covering index to <>. + +[[early-paginate-1]] +.Covered query +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-paginate-1.n1ql[] +---- + +The `covers` section of the query plan shows that the query is covered. +In addition, the ordering, offset, and limit are performed by the Index service. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-paginate-1.jsonc[tags=extract;ellipsis] +---- + +<.> Index order performed by index operator +<.> Limit performed by index operator +<.> Offset performed by index operator +==== + +<> adds an extra field to the projection. +Now the query is no longer covered. + +[[early-paginate-2]] +.Order and pagination pushdown +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-paginate-2.n1ql[] +---- + +However the query runs pretty quickly, since the ordering, offset, and limit can still be pushed down to the Index service. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-paginate-2.jsonc[tags=extract;ellipsis] +---- + +<.> Index order pushdown +<.> Limit pushdown +<.> Offset pushdown +==== + +However, if we change the order of the ordering terms so that they no longer match the index key order, ordering cannot be pushed down to the Index service. + +[[early-paginate-3]] +.Early order and pagination +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-paginate-3.n1ql[] +---- + +So in this case, early ordering, limit, and offset are done by the Query service before fetch. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-paginate-3.jsonc[tags=extract;ellipsis] +---- + +<.> Early ordering +<.> Early limit +<.> Early offset +==== + +Similarly, if we change the direction of the sort from descending to ascending, the ordering cannot be pushed down to the Index service, since it does not support reverse index scan. + +[[early-paginate-4]] +.Early reverse order and pagination +==== +.Query +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/early-paginate-4.n1ql[] +---- + +In this case also, early ordering, limit, and offset are done by the Query service before fetch. + +[source,json] +---- +include::example$services-and-indexes/indexes/early-paginate-4.jsonc[tags=extract;ellipsis] +---- + +<.> The `sort_terms` section uses `_index_key` expressions to sort the results using the index keys. +==== + +=== Limitations + +The optimizer only selects early ordering and pagination when the following conditions are met. +Many of these conditions are similar to the conditions for index order pushdowns. + +* The query must be simple, referencing a single keyspace with no joins. + +* There can be no `GROUP BY` or aggregates in the query. + +* Index pushdown for `ORDER`, `LIMIT` and `OFFSET` must not be possible. + +* The `ORDER BY` clause and `LIMIT` clause must be present. +The `OFFSET` clause is optional. + +* All expression references in the `ORDER BY` clause must be present in the index -- similar to the covering requirement for index pushdown. +However there is no requirement for exact index spans. + +* Projection alias can be used in the `ORDER BY` clause, if all the references in the aliased expression are available from the index. + +* Only simple `IndexScan` is supported for early ordering. +More complex index scans such as `IntersectScan`, `OrderedIntersectScan`, `UnionScan` and `DistinctScan` are not supported. + +* When early ordering is in effect, parallelism is turned off. + +== Summary + +The following table summarizes the different methods of performing filtering, order, or pagination, from most efficient to least. + +[%header,cols="32%,17%,17%,17%,17%"] +|==== +| +| Covering index +| Index pushdown + +^<>^ +| Early filters, order, or pagination + +^<>^ +| Default filters, order, or pagination + +^<>^ + +| Fetch required? +| icon:times-circle[red] No +| icon:check-circle[green] Yes +| icon:check-circle[green] Yes +| icon:check-circle[green] Yes + +| Filters, order, and pagination + +performed: +| After scan +| After scan, + +before fetch +| After scan, + +before fetch +| After fetch + +| ... by: +| Index service +| Index service +| Query service +| Query service +|==== + +[[note]] +NOTE: An uncovered query may use a mixture of these methods. + +== Related Links + +* xref:learn:services-and-indexes/indexes/index-scans.adoc#query-execution-details[Query Execution: Details] +* xref:n1ql:n1ql-language-reference/covering-indexes.adoc[Covering Indexes] +* xref:learn:services-and-indexes/indexes/index_pushdowns.adoc[Index Pushdown Optimizations] +* xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[Grouping and Aggregate Pushdown] +* xref:n1ql:n1ql-language-reference/where.adoc[WHERE Clause] -- to apply a filter +* xref:n1ql:n1ql-language-reference/orderby.adoc[ORDER BY Clause] -- to apply a sort +* xref:n1ql:n1ql-language-reference/offset.adoc[OFFSET Clause] and xref:n1ql:n1ql-language-reference/limit.adoc[LIMIT Clause] -- to apply pagination diff --git a/modules/learn/pages/services-and-indexes/indexes/global-secondary-indexes.adoc b/modules/learn/pages/services-and-indexes/indexes/global-secondary-indexes.adoc new file mode 100644 index 000000000..7e8680ab6 --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/global-secondary-indexes.adoc @@ -0,0 +1,55 @@ += Primary and Secondary Index Reference +:page-aliases: indexes:indexing-overview,understanding-couchbase:services-and-indexes/indexes/global-secondary-indexes,indexes:gsi-for-n1ql,architecture:global-secondary-indexes,architecture:gsi-versus-views,clusters:index-service/index-service.adoc +:page-role: tiles -toc +:!sectids: +:description: Primary Indexes and Global Secondary Indexes (GSI) support queries made by the Query Service. + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} + +== Tuning and Query Performance + +* xref:learn:services-and-indexes/indexes/query-without-index.adoc[] +* xref:learn:services-and-indexes/indexes/index-lifecycle.adoc[] +* xref:learn:services-and-indexes/indexes/indexing-and-query-perf.adoc[] +* xref:n1ql:n1ql-language-reference/covering-indexes.adoc[] +* xref:learn:services-and-indexes/indexes/index-scans.adoc[] +* xref:learn:services-and-indexes/indexes/index_pushdowns.adoc[] +* xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[] +* xref:learn:services-and-indexes/indexes/early-filters-and-pagination.adoc[] + +== Index Commands + +* xref:n1ql:n1ql-language-reference/advise.adoc[ADVISE] +* xref:n1ql:n1ql-language-reference/createindex.adoc[CREATE INDEX] +* xref:n1ql:n1ql-language-reference/createprimaryindex.adoc[CREATE PRIMARY INDEX] +* xref:n1ql:n1ql-language-reference/build-index.adoc[BUILD INDEX] +* xref:n1ql:n1ql-language-reference/alterindex.adoc[ALTER INDEX] +* xref:n1ql:n1ql-language-reference/dropindex.adoc[DROP INDEX] +* xref:n1ql:n1ql-language-reference/dropprimaryindex.adoc[DROP PRIMARY INDEX] + +== Storage and Availability + +* xref:learn:services-and-indexes/indexes/index-replication.adoc[] +* xref:learn:services-and-indexes/indexes/storage-modes.adoc[] + +== Related Links + +//// +* xref:learn:services-and-indexes/indexes/indexes.adoc[All Couchbase Capella Indexes] +//// +* xref:clusters:index-service/index-service.adoc[Index Service] +* xref:clusters:index-service/manage-indexes.adoc[Manage and Monitor Indexes] diff --git a/modules/learn/pages/services-and-indexes/indexes/index-lifecycle.adoc b/modules/learn/pages/services-and-indexes/indexes/index-lifecycle.adoc new file mode 100644 index 000000000..86569a912 --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/index-lifecycle.adoc @@ -0,0 +1,63 @@ += Index Lifecycle +:page-topic-type: concept +:imagesdir: ../../../assets/images +:description: An overview of the lifecycle of a Global Secondary Index, from creation and building to updates and scans. + +[abstract] +{description} + +A Global Secondary Index is created on a single collection -- not on an entire bucket. +(A collection may, of course, have multiple indexes.) +By carefully planning the structure of your data, and storing documents of different types in separate collections, you can improve performance at every stage in the lifecycle of an index. + +== Index Creation + +Index creation happens in two phases: the [def]_creation phase_ and the [def]_build phase_. +During the creation phase, the Index Service validates the user input, decides the host node for the index, and creates the index metadata on the host node. +The build phase cannot start until the creation phase is complete. + +== Index Building + +During the build phase, the Index Service reads the documents from the Data Service and builds the index. + +image::services-and-indexes/indexes/index-lifecycle-build.png[align=center] + +. The projector requests a DCP stream on the specified collection. +. DCP streams only the documents in the collection. +. The projector evaluates each document and extracts the indexed field(s). +. The indexed fields are forwarded to the indexer. + +Creating and building indexes can take a long time on keyspaces with lots of existing documents. +When you create an index, you can choose to _defer_ the build phase, and then build the deferred index later. +This allows multiple indexes to be built at once rather than having to re-scan the entire keyspace for each index. + +For more information and examples, refer to xref:n1ql:n1ql-language-reference/createprimaryindex.adoc[CREATE PRIMARY INDEX], xref:n1ql:n1ql-language-reference/createindex.adoc[CREATE INDEX], and xref:n1ql:n1ql-language-reference/build-index.adoc[BUILD INDEX]. + +== Index Updates + +When a Global Secondary Index has been created on a collection, the index is updated when documents within the collection are updated. + +image::services-and-indexes/indexes/index-lifecycle-update-1.png[align=center] + +image::services-and-indexes/indexes/index-lifecycle-update-2.png[align=center] + +. The projector keeps a _bucket-level_ DCP stream open for updates -- this limits the number of DCP connections. +. When a document within the collection is updated, the projector utilizes the collection ID available with each mutation, and only evaluates the indexes defined for that collection. +. The projector only sends updated indexed fields for the qualified indexes within the collection. + +There is no additional processing or disk overhead for indexes on unrelated collections. + +Refer to xref:server:learn:clusters-and-availability/intra-cluster-replication.adoc#database-change-protocol[Database Change Protocol (DCP)] for further details. + +== Index Scans + +When a query needs to make use of a Global Secondary Index, the index is scanned. + +image::services-and-indexes/indexes/index-lifecycle-scan.png[align=center] + +* If the index consistency is `not_bounded`, the scan proceeds without waiting for the index to be updated. +* If the scan consistency is `at_plus` or `request_plus`, the scan coordinator waits for the index to be updated for that collection only, and then performs the scan. + +The scan coordinator does not need to wait for indexes on other collections to be updated, even if documents in other collections are being mutated. + +Refer to xref:learn:services-and-indexes/indexes/index-scans.adoc[Index Scans] and xref:learn:services-and-indexes/indexes/index-replication.adoc#index-consistency[Index Consistency] for further details. \ No newline at end of file diff --git a/modules/learn/pages/services-and-indexes/indexes/index-replication.adoc b/modules/learn/pages/services-and-indexes/indexes/index-replication.adoc new file mode 100644 index 000000000..a46ab9c8c --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/index-replication.adoc @@ -0,0 +1,183 @@ += Index Availability and Performance +:navtitle: Availability and Performance +:description: The Index Service ensures availability and performance through replication and partitioning. +:page-topic-type: concept +:page-partial: +:page-aliases: indexes:index-replication,indexes:performance-consistency,understanding-couchbase:services-and-indexes/indexes/index-replication +:keywords: consistency, consistent + +// Cross-references +:index-service: xref:clusters:index-service/index-service.adoc +:index-partitioning: xref:n1ql:n1ql-language-reference/index-partitioning.adoc +:failover: xref:server:learn:clusters-and-availability/failover.adoc +:database-change-protocol: xref:server:learn:clusters-and-availability/intra-cluster-replication.adoc#database-change-protocol +:index-storage-mode: xref:server:manage:manage-settings/general-settings.adoc#index-storage-mode +:index-storage-settings-via-cli: xref:server:manage:manage-settings/general-settings.adoc#index-storage-settings-via-cli +:index-settings-via-rest: xref:server:manage:manage-settings/general-settings.adoc#index-settings-via-rest +:install-sample-buckets: xref:clusters:data-service/import-data-documents.adoc#import-sample-data +:query: xref:n1ql:query.adoc +:query-preferences: xref:clusters:query-service/query-workbench.adoc#query-settings +:scan_consistency: xref:server:n1ql:n1ql-manage/query-settings.adoc#scan_consistency + +[abstract] +The _Index Service_ ensures availability and performance through _replication_ and _partitioning_. +The _consistency_ of query-results can be controlled per query. + +.Examples on this Page +**** +The examples in this topic use the travel-sample dataset which is supplied with Couchbase Capella. +For instructions on how to install the sample data, see {install-sample-buckets}[Import Sample Data]. + +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +[#index-replication] +== Index Replication + +Secondary indexes can be replicated across cluster-nodes. +This ensures: + +* _Availability_: If one Index-Service node is lost, the other continues to provide access to replicated indexes. +* _High Performance_: If original and replica copies are available, incoming queries are load-balanced across them. + +Index-replicas can be created with the {sqlpp} `CREATE INDEX` statement. +Note that whenever a given number of index-replicas is specified for creation, the number must be less than the number of cluster-nodes currently running the {index-service}[Index Service]. +If it is not, the index creation fails. +Note also that if, following creation of the maximum number of copies, the number of nodes running the Index Service decreases, Couchbase Capella progressively assigns replacement index-replicas to any and all Index-Service nodes subsequently be added to the cluster, until the required number of index-replicas again exists for each replicated index. + +Index-replicas can be created as follows: + +* Specifying, by means of the `WITH` clause, the destination nodes. +In the following example, an index with two replicas is created. +The active index is on `node1`, and the replicas are on `node2` and `node3`: ++ +[#nodes-example2] +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/replication-nodes.n1ql[] +---- + +* Specifying _no_ destination nodes; but specifying instead, by means of the `WITH` clause and the `num_replica` attribute, only the _number_ of replicas required. +The replicas are automatically distributed across those nodes of the cluster that are running the Index Service: the distribution-pattern is based on a projection of optimal index-availability, given the number and disposition of Index-Service nodes across defined server-groups. ++ +In the following example, an index is created with two replicas, with no destination-nodes specified: ++ +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/replication-num.n1ql[] +---- ++ +Note that if `nodes` and `num_replica` are both specified in the `WITH` clause, the specified number of nodes must be _one greater_ than `num_replica`. + +ifdef::flag-devex-rest-api[] +* Specifying a number of index-replicas to be created by the Index Service whenever `CREATE INDEX` is invoked. +The default is `0`. +If the default is changed to, say, `2`, creation of a single index is henceforth accompanied by the creation of two replicas, which are automatically distributed across the nodes of the cluster running the Index Service. +No explicit specification within the `CREATE INDEX` statement is required. ++ +With credentials that provide appropriate authorization, this default can be changed by means of the `curl` command, as follows: ++ +[source,sh] +---- +curl -X POST -u 'Administrator:password' \ +'http://localhost:8091/settings/indexes' \ +-d 'numReplica=2' +---- ++ +Here, `numReplica` is an integer that establishes the default number of replicas that must be created whenever `CREATE INDEX` is invoked. +Note that this call only succeeds if the cluster contains enough Index Service nodes to host each new index and its replicas: for example, if `2` is specified as the default number of replicas, the Index Service must have been established on at least 3 nodes. ++ +Note also that whenever explicit specification of replica-numbers is made within the `CREATE INDEX` statement, this explicit specification takes precedence over any established default. + +You can change index replication settings via the {index-storage-mode}[UI] or the {index-settings-via-rest}[REST API]. +For further information on using {sqlpp}, refer to {query}[Query Fundamentals]. +endif::flag-devex-rest-api[] + +[[index-partitioning]] +== Index Partitioning + +_Index Partitioning_ increases query performance, by dividing and spreading a large index of documents across multiple nodes. + +The benefits include: + +* The ability to scale out horizontally, as index size increases. + +* Transparency to queries, requiring no change to existing queries. + +* Reduction of query latency for large, aggregated queries; since partitions can be scanned in parallel. + +* Provision of a low-latency range query, while allowing indexes to be scaled out as needed. + +For detailed information, refer to {index-partitioning}[Index Partitioning]. + +[[index-consistency]] +== Index Consistency + +(((consistency))) +(((consistent))) +Whereas Couchbase Capella handles data-mutations with _full consistency_ — all mutations to a given key are applied to the same vBucket, and become immediately available — it maintains indexes with degrees of _eventual consistency_. +This means that indexes may at times not contain the most up-to-date information, especially when deployed in a write-heavy environment: changes may take some time to propagate over to the index nodes. + +The asynchronous updating nature of global secondary indexes means that they can be very quick to query and do not require the additional overhead of index recalculations at the time documents are modified. +{sqlpp} queries are forwarded to the relevant indexes and the queries are done based on indexed information, rather than the documents as they exist in the data service. + +With default query options, the query service will rely on the current index state: the most up-to-date document versions are not retrieved, and only the indexed versions are queried. +This provides the best performance. +Only updates occurring with a small time frame may not yet have been indexed. + +The query service can use the latest versions of documents by modifying the [.api]`scan_consistency` parameter, specified per query: + +// tag::scan_consistency[] +* `not_bounded`: Executes the query immediately, without requiring any consistency for the query. +If index-maintenance is running behind, out-of-date results may be returned. +* `at_plus`: Executes the query, requiring indexes first to be updated to the timestamp of the last update. +If index-maintenance is running behind, the query waits for it to catch up. +* `request_plus`: Executes the query, requiring the indexes first to be updated to the timestamp of the current query-request. +If index-maintenance is running behind, the query waits for it to catch up. + +For {sqlpp}, the default consistency is `not_bounded`. +// end::scan_consistency[] +When using the `request_plus` consistency mode, the query service will ensure that the indexes are synchronized with the data service before querying. + +You can specify the scan consistency via the {query-preferences}[run-time preferences] in the Query tab, or by setting the {scan_consistency}[scan_consistency] request-level parameter. + +[[index-snapshots]] +== Index Snapshots + +One or more _index snapshots_ are maintained on disk, to permit rapid recovery if node-failures are experienced. +In cases where recovery requires an Index-Service node to be restarted, the node’s indexes are rebuilt from the snapshots retained on disk. + +By default, two index snapshots are stored on disk. +ifdef::flag-devex-rest-api[] +You can change index snapshot settings via the {index-storage-settings-via-cli}[CLI] or the {index-settings-via-rest}[REST API]. +endif::flag-devex-rest-api[] + +[[index-rollback]] +== Index Rollback + +The index service also maintains a {database-change-protocol}[DCP failover log]. +If necessary, the data service can request the index service to return to a specified rollback point and update its history. + +ifdef::flag-devex-rest-api[] +You can change index rollback settings via the {index-storage-settings-via-cli}[CLI] or the {index-settings-via-rest}[REST API]. +endif::flag-devex-rest-api[] + +[[index-rollback-after-failover]] +=== Index Rollback After Failover + +When a data node {failover}[fails over], a replica data node is promoted to active. +If the index service has more recent data than the new active data node, the data node issues a rollback request to the index service. + +When the index service receives the rollback request, it first attempts to revert to a stored index snapshot. +If successful, the index service does not need to rebuild its indexes from scratch when the data node fails over. +The index service can continue servicing query clients without interruption. + +If the index service cannot revert to a current index snapshot, it rebuilds all indexes from scratch. + +[NOTE] +==== +If <> is set to `not_bounded`, the index service may return stale data for a short time after reverting to a snapshot, until the index service is fully up-to-date with the new active data node. + +If <> is set to `request_plus`, the index service will not perform any scans until a consistent snapshot is created. +In this case, stale results are not returned. +==== diff --git a/modules/learn/pages/services-and-indexes/indexes/index-scans.adoc b/modules/learn/pages/services-and-indexes/indexes/index-scans.adoc new file mode 100644 index 000000000..32687446b --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/index-scans.adoc @@ -0,0 +1,1912 @@ += Index Scans +:description: This section discusses how index spans are generated from query predicates and provides a number of examples. +:page-topic-type: concept +:page-aliases: performance:index-scans +:imagesdir: ../../../assets/images + +[abstract] +During query execution, when the index path is chosen, the query engine requests the scan by providing a range of values to return. +This range is represented as a _span_ in the query plan. +Index scans play a major role in optimizing the query plan generation and execution. +{description} + +Couchbase {sqlpp} is a modern query processing engine designed to +provide SQL for JSON on distributed data with a flexible data model. +Modern databases are deployed across multiple nodes. +Using JSON provides a flexible data mode, and +{sqlpp} supports enhanced SQL for JSON, to make query processing easier. + +== Query Execution: Details + +Applications and database drivers submit the {sqlpp} query to one of the available Query nodes on a cluster. +The Query node analyzes the query, uses metadata on underlying objects to figure out the optimal execution plan, which it then executes. +During execution, depending on the query, using applicable indexes, the Query node works with the Index and Data nodes to retrieve and perform the planned operations. +Because Couchbase is a modular clustered database, you scale out data, index, and query services to fit your performance and availability goals. + +[plantuml,query-execution,svg] +.... +include::partial$diagrams/query-execution.puml[] +.... + +[#inside_a_query_node] +=== Inside a Query Node + +The following figure shows all the possible phases a SELECT query goes through to return the results. +Not all queries need to go through every phase, some go through many of these phases multiple times. +For example, the Sort phase can be skipped when there is no ORDER BY clause in the query; and the Scan-Fetch-Join phases will execute multiple times for correlated subqueries. + +[plantuml,query-service,svg] +.... +include::partial$diagrams/query-service.puml[] +.... + +http://blog.couchbase.com/sql-for-documents-n1ql-brief-introduction-to-query-planning[This brief introduction to query planning^] has details of query planner. +When the Index path is chosen, query engine requests the scan by providing the range of values to return. +This range is represented as a SPAN in the query plan. +The index spans will play major roles in optimal plan generation and execution. +Here, we discuss how the Index spans are generated from the query predicates (filters). + +== Spans Overview + +FILTER, JOIN, and PROJECT are fundamental operations of database query processing. +The filtering process takes the initial keyspace and produces an optimal subset of the documents the query is interested in. +To produce the smallest possible subset, indexes are used to apply as many predicates as possible. + +Query predicates indicate the subsets of data that we are interested in. +During the query planning phase, we select the indexes to be used. +Then, for each index, we decide the predicates to be applied by each index. +The query predicates are translated into spans in the query plan and passed to the Indexer. +Spans simply express the predicates in terms of data ranges. + + +== Examples + +The examples in this section use the travel-sample dataset which is supplied with Couchbase Capella. +For instructions on how to install the sample data, see xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data]. + +include::ROOT:partial$query-context.adoc[tag=statement] + +The examples on this page illustrate the spans for different predicates and require the following indexes. + +[source,sqlpp] +---- +CREATE INDEX idx_airline_id ON airline(`id`); + +CREATE INDEX idx_airline_name ON airline(`name`); + +CREATE INDEX idx_route_src_dst_stops +ON route(sourceairport, destinationairport, stops); + +CREATE INDEX idx_route_sched +ON route(DISTINCT ARRAY v.day FOR v IN schedule END); +---- + +=== Example Translations + +The following table shows some example translations: + +|=== +| Predicate | Span Low | Span High | Span Inclusion + +| id = 10 +| 10 +| 10 +| 3 (BOTH) + +| id > 10 +| 10 +| No upper bound +| 0 (NEITHER) + +| id \<= 10 +| NULL +| 10 +| 2 (HIGH) +|=== + +Consider the plan for the following query: + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id = 10; +---- + +You can see the spans in the `IndexScan3` section of the Explain for the query: + +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`airline`.`id`))", + "cover ((meta(`airline`).`id`))" + ], + "filter": "(cover ((`airline`.`id`)) = 10)", + "index": "idx_airline_id", + "index_id": "39cf9192429a6581", + "keyspace": "airline", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 3, + "low": "10" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((meta(`airline`).`id`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT meta().id FROM airline WHERE id = 10;" + } +] +---- + +Note that the above codeblock shows the entire EXPLAIN plan, but the examples +below show only the "spans" section. + +In {sqlpp}, Index Scan requests are based on a range where each range has a start value, an end value, and specifies whether to include the start or the end value. + +* A "High" field in the range indicates the end value. +If "High" is missing, then there is no upper bound. +* A "Low" field in the range indicates the start value. +If "Low" is missing, the scan starts with `MISSING`. +* Inclusion indicates if the values of the High and Low fields are included. ++ +[cols="2,2,5"] +|=== +| Inclusion Number | Meaning | Description + +| 0 +| NEITHER +| Neither High nor Low fields are included. + +| 1 +| LOW +| Only Low fields are included. + +| 2 +| HIGH +| Only High fields are included. + +| 3 +| BOTH +| Both High and Low fields are included. +|=== + +[#ex1-equality] +=== Example 1: EQUALITY Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id = 10; +---- + +In this example, the predicate `id = 10` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id = 10` +| `10` +| `10` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id = 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 3, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex2-one-sided-range] +=== Example 2: Inclusive One-Sided Range Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id >= 10; +---- + +In this example, the predicate `id >= 10` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id >= 10` +| `10` +| `Unbounded` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id >= 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex3-exclusive-one-sided-range] +=== Example 3: Exclusive One-Sided Range Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id > 10; +---- + +In this example, the predicate `id > 10` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id > 10` +| `10` +| `Unbounded` +| `0 (NEITHER)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id > 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex4-inclusive-one-sided-range] +=== Example 4: Inclusive One-Sided Range Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id <= 10; +---- + +In this example, the predicate `+id <= 10+` is pushed to index scan. +This query predicate doesn’t contain an explicit start value, so the start value will implicitly be the non-inclusive null value. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `+id <= 10+` +| `NULL` +| `10` +| `2 (HIGH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id <= 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 2, + "low": "null" + } + ] + } + ], +// ... +---- + +[#ex5-exclusive-one-sided-range] +=== Example 5: Exclusive One-Sided Range Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id < 10; +---- + +In this example, the predicate `id < 10` is pushed to index scan. +The query predicate doesn’t contain an explicit start value, so the start value will implicitly be the non-inclusive null value. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id < 10` +| `NULL` +| `10` +| `0 (NEITHER)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id < 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 0, + "low": "null" + } + ] + } + ], +// ... +---- + +[#ex6-and] +=== Example 6: AND Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id >= 10 AND id < 25; +---- + +In this example, the predicate `id >= 10 AND id < 25` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id >= 10 AND id < 25` +| `10` +| `25` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id >=10 AND id < 25; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "25", + "inclusion": 1, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex7-multiple-and] +=== Example 7: Multiple AND Predicates + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE id >= 10 AND id < 25 AND id <= 20; +---- + +In this example, the predicate `+id >= 10 AND id < 25 AND id <= 20+` is pushed to the index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| id >= 10 AND id < 25 AND id \<= 20 +| 10 +| 20 +| 3 (BOTH) +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE id >=10 AND id < 25 AND id <= 20; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "20", + "inclusion": 3, + "low": "10" + } + ] + } + ], +// ... +---- + +Observe that the optimizer created the span without the `id < 25` predicate because the AND predicate `+id <=20+` makes the former predicate redundant. +Internally, the optimizer breaks down each predicate and then combines it in a logically consistent manner. +If this is too detailed for now, you can skip over to <>. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id >= 10` +| `10` +| `Unbounded` +| `1 (LOW)` + +| `id < 25` +| `NULL` +| `25` +| `0 (NEITHER)` + +| `id >= 10 AND id < 25` +| `10` +| `25` +| `1 (LOW)` + +| `+id <= 20+` +| `NULL` +| `20` +| `2 (HIGH)` + +| `+id >= 10 AND id < 25 AND id <= 20+` +| `10` +| `20` +| `3 (BOTH)` +|=== + +Internally, the following steps occur: + +[#ul_xkc_vky_mx] +. Combined Low becomes highest of both Low values (NULL is the lowest.) +. Combined High becomes lowest of both High values (Unbounded is the highest.) +. Combined Inclusion becomes OR of corresponding inclusions of Step 1 and Step 2. +. Repeat Steps 1 to 3 for each AND clause. + +[#ex8-and-makes-empty] +=== Example 8: AND Predicate Makes Empty + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id > 10 AND id < 5; +---- + +In this example, the predicate `id > 10 AND id < 5` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id > 10 AND id < 5` +| `NULL` +| `NULL` +| `0 (NEITHER)` +|=== + +This is a special case where the span is Low: 10, High: 5, and Inclusion: 0. +In this case, the start value is higher than the end value and will not produce results; so, the span is converted to EMPTY SPAN, which will not do any IndexScan. + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id > 10 AND id < 5; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "null", + "inclusion": 0, + "low": "null" + } + ] + } + ], +// ... +---- + +[#ex9-between] +=== Example 9: BETWEEN Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id BETWEEN 10 AND 25; +---- + +In this example, the predicate `id BETWEEN 10 AND 25` (that is, id >= 10 AND id \<= 25) is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id BETWEEN 10 AND 25` +| `10` +| `25` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id BETWEEN 10 AND 25; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "25", + "inclusion": 3, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex10-simple-or] +=== Example 10: Simple OR Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id = 10 OR id = 20; +---- + +In this example, the predicate `id = 10 OR id = 20` produces two independent ranges and both of them are pushed to index scan. +Duplicate ranges are eliminated, but overlaps are not eliminated. + +[cols="2,1,1,1"] +|=== +| Span for | Low | High | Inclusion + +| `id = 10` +| `10` +| `10` +| `3 (BOTH)` + +| `id = 20` +| `20` +| `20` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id = 10 OR id = 20; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 3, + "low": "10" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "20", + "inclusion": 3, + "low": "20" + } + ] + } + ], +// ... +---- + +[#ex11-simple-in] +=== Example 11: Simple IN Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id IN [10, 20]; +---- + +In this example, the predicate is `id IN [10,20]` (that is, id = 10 OR id = 20). +After eliminating the duplicates, each element is pushed as a separate range to index scan. + +NOTE: In version 4.5, up to 8192 IN elements are pushed as separate ranges to the index service. +If the number of elements exceed 8192, then the index service performs a full scan on that key. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id = 10` +| `10` +| `10` +| `3 (BOTH)` + +| `id = 20` +| `20` +| `20` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id IN [10, 20]; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 3, + "low": "10" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "20", + "inclusion": 3, + "low": "20" + } + ] + } + ], +// ... +---- + +[#ex12-or-between-and] +=== Example 12: OR, BETWEEN, AND Predicates + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE (id BETWEEN 10 AND 25) + OR (id > 50 AND id <= 60); +---- + +In this example, the predicate `+(id BETWEEN 10 AND 25) OR (id > 50 AND id <= 60)+` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id BETWEEN 10 AND 25` +| `10` +| `25` +| `3 (BOTH)` + +| `+id > 50 AND id <= 60+` +| `50` +| `60` +| `2 (HIGH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE (id BETWEEN 10 AND 25) + OR (id > 50 AND id <= 60); +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "25", + "inclusion": 3, + "low": "10" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "60", + "inclusion": 2, + "low": "50" + } + ] + } + ], +// ... +---- + +[#ex13-not] +=== Example 13: NOT Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id <> 10; +---- + +In this example, the predicate `id <> 10` is transformed to `id < 10 OR id > 10` and then pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id < 10` +| `NULL` +| `10` +| `0 (NEITHER)` + +| `id > 10` +| `10` +| `Unbounded` +| `0 (NEITHER)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id <> 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 0, + "low": "null" + } + ] + }, + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex14-not-and] +=== Example 14: NOT, AND Predicates + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE NOT (id >= 10 AND id < 25); +---- + +In this example, the predicate `id >= 10 AND id < 25` is transformed to `id <10 OR id >=25` and pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id < 10` +| `NULL` +| `10` +| `0 (NEITHER)` + +| `id >= 25` +| `25` +| `Unbounded` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE NOT (id >= 10 AND id < 25); +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 0, + "low": "null" + } + ] + }, + { + "exact": true, + "range": [ + { + "inclusion": 1, + "low": "25" + } + ] + } + ], +// ... +---- + +[#ex15-equality-string] +=== Example 15: EQUALITY Predicate on String Type + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE name = "American Airlines"; +---- + +In this example, the predicate `name >= "American Airlines"` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `name = "American Airlines"` +| `"American Airlines"` +| `"American Airlines"` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE name = "American Airlines"; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"American Airlines\"", + "inclusion": 3, + "low": "\"American Airlines\"" + } + ] + } + ], +// ... +---- + +[#ex16-range-string] +=== Example 16: Range Predicate on String Type + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE name >= "American Airlines" + AND name <= "United Airlines"; +---- + +In this example, the predicate `+name >= "American Airlines" AND name <= "United Airlines"+` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `+name >= "American Airlines" AND name <= "United Airlines"+` +| `"American Airlines"` +| `"United Airlines"` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline + WHERE name >= "American Airlines" + AND name <= "United Airlines"; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"United Airlines\"", + "inclusion": 3, + "low": "\"American Airlines\"" + } + ] + } + ], +// ... +---- + +[#ex17-like-1] +=== Example 17: LIKE Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE name LIKE "American%"; +---- + +In this example, the predicate `name LIKE "American%"` is transformed to `name >= "American"` AND `name < "Americao"` (where "Americao" is the next string in {sqlpp} collation order after "American") and then pushed to index scan. +In the LIKE predicate, the % means match with any number of any characters. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `name LIKE "American%"` +| `"American"` +| `"Americao"` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE name LIKE "American%"; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"Americao\"", + "inclusion": 1, + "low": "\"American\"" + } + ] + } + ], +// ... +---- + +[#ex18-like-2] +=== Example 18: LIKE Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE name LIKE "%American%"; +---- + +In this example, the predicate `name LIKE "%American%"` is transformed and pushed to index scan. +In this LIKE predicate '%' is the leading portion of the string, so we can't push any portion of the string to the index service. +`""` is the lowest string. +`[]` is an empty array and is greater than every string value in the {sqlpp} collation order. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `name LIKE "%American%"` +| `""` +| `"[]"` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE name LIKE "%American%"; +---- + +[source,json] +---- +// ... + "spans": [ + { + "range": [ + { + "high": "[]", + "inclusion": 1, + "low": "\"\"" + } + ] + } + ], +// ... +---- + +[#ex19-and-composite-index-1] +=== Example 19: AND Predicate with Composite Index + +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE sourceairport = "SFO" + AND destinationairport = "JFK" + AND stops BETWEEN 0 AND 2; +---- + +In this example, the predicate `sourceairport = "SFO" AND destinationairport = "JFK" AND stops BETWEEN 0 AND 2` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `sourceairport = "SFO"` +| `"SFO"` +| `"SFO"` +| `3 (BOTH)` + +| `destinationairport = "JFK"` +| `"JFK"` +| `"JFK"` +| `3 (BOTH)` + +| `stops BETWEEN 0 AND 2` +| `0` +| `2` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +WHERE sourceairport = "SFO" + AND destinationairport = "JFK" + AND stops BETWEEN 0 AND 2; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "low": "\"SFO\"" + }, + { + "high": "\"JFK\"", + "inclusion": 3, + "low": "\"JFK\"" + }, + { + "high": "2", + "inclusion": 3, + "low": "0" + } + ] + } + ], +// ... +---- + +[#ex20-and-composite-index-2] +=== Example 20: AND Predicate with Composite Index + +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE sourceairport IN ["SFO", "SJC"] + AND destinationairport = "JFK" + AND stops = 0; +---- + +In this example, the predicate `sourceairport IN ["SFO", "SJC"] AND destinationairport = "JFK" AND stops = 0` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `sourceairport IN ["SFO", "SJC"]` +| `"SFO"` + +`"SJC"` +| `"SFO"` + +`"SJC"` +| `3 (BOTH)` + +`3 (BOTH)` + +| `destinationairport = "JFK"` +| `"JFK"` +| `"JFK"` +| `3 (BOTH)` + +| `stops` +| `0` +| `0` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +WHERE sourceairport IN ["SFO", "SJC"] + AND destinationairport = "JFK" + AND stops = 0; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "low": "\"SFO\"" + }, + { + "high": "\"JFK\"", + "inclusion": 3, + "low": "\"JFK\"" + }, + { + "high": "0", + "inclusion": 3, + "low": "0" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "\"SJC\"", + "inclusion": 3, + "low": "\"SJC\"" + }, + { + "high": "\"JFK\"", + "inclusion": 3, + "low": "\"JFK\"" + }, + { + "high": "0", + "inclusion": 3, + "low": "0" + } + ] + } + ], +// ... +---- + +[#ex21-composite-and-trailing-keys-missing] +=== Example 21: Composite AND Predicate with Trailing Keys Missing in Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE sourceairport = "SFO" + AND destinationairport = "JFK"; +---- + +In this example, the predicate `sourceairport = "SFO" AND destinationairport = "JFK"` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `sourceairport = "SFO"` +| `"SFO"` +| `"SFO"` +| `3 (BOTH)` + +| `destinationairport = "JFK"` +| `"JFK"` +| `"JFK"` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +WHERE sourceairport = "SFO" + AND destinationairport = "JFK"; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "low": "\"SFO\"" + }, + { + "high": "\"JFK\"", + "inclusion": 3, + "low": "\"JFK\"" + } + ] + } + ], +// ... +---- + +[#ex22-composite-and-unbounded-high-trailing] +=== Example 22: Composite AND Predicate with Unbounded High of Trailing Key + +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE sourceairport = "SFO" + AND destinationairport = "JFK" + AND stops >= 0; +---- + +In this example, the predicate `sourceairport = "SFO" AND destinationairport = "JFK" AND stops >= 0` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `sourceairport = "SFO"` +| `"SFO"` +| `"SFO"` +| `3 (BOTH)` + +| `destinationairport = "JFK"` +| `"JFK"` +| `"JFK"` +| `3 (BOTH)` + +| `stops >= 0` +| `0` +| `Unbounded` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +WHERE sourceairport = "SFO" + AND destinationairport = "JFK" + AND stops >= 0; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "low": "\"SFO\"" + }, + { + "high": "\"JFK\"", + "inclusion": 3, + "low": "\"JFK\"" + }, + { + "inclusion": 1, + "low": "0" + } + ] + } + ], +// ... +---- + +[#ex23-equality-query-params] +=== Example 23: EQUALITY Predicate with Query Parameters + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id = $1; +---- + +This example pushes the predicate `id = $1` to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id = $1` +| `$1` +| `$1` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id = $1; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "$1", + "inclusion": 3, + "low": "$1" + } + ] + } + ], +// ... +---- + +[#ex24-and-query-params] +=== Example 24: AND Predicate with Query Parameters + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id >= $1 AND id < $2; +---- + +In this example, the predicate `id >= $1 AND id < $2` is pushed to the index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id >= $1 AND id < $2` +| `$1` +| `$2` +| `1 (LOW)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id >= $1 AND id < $2; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "$2", + "inclusion": 1, + "low": "$1" + } + ] + } + ], +// ... +---- + +[#ex25-or-query-params] +=== Example 25: OR Predicate with Query Parameters + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id = $1 OR id < $2; +---- + +This example pushes the predicate `id = $1 OR id < $2` to the index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id = $1` +| `$1` +| `$1` +| `3 (BOTH)` + +| `id < $2` +| `NULL` +| `$2` +| `0 (NEITHER)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id = $1 OR id < $2; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "$1", + "inclusion": 3, + "low": "$1" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "$2", + "inclusion": 0, + "low": "null" + } + ] + } + ], +// ... +---- + +[#ex26-in-query-params] +=== Example 26: IN Predicate with Query Parameters + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE id IN [ $1, 10, $2] ; +---- + +In this example, the predicate `id IN [$1, 10, $2]` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id IN [$1, 10, $2]` +| `$1` + +`10` + +`$2` +| `$1` + +`10` + +`$2` +| `3 (BOTH)` + +`3 (BOTH)` + +`3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE id IN [$1, 10, $2]; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "$1", + "inclusion": 3, + "low": "$1" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 3, + "low": "10" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "$2", + "inclusion": 3, + "low": "$2" + } + ] + } + ], +// ... +---- + +[#ex27-any-1] +=== Example 27: ANY Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE ANY v IN schedule SATISFIES v.day = 0 +END; +---- + +In this example, the predicate `v.day = 0` is pushed to ARRAY index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `v.day = 0` +| `0` +| `0` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +WHERE ANY v IN schedule SATISFIES v.day = 0 +END; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "0", + "inclusion": 3, + "low": "0" + } + ] + } + ], +// ... +---- + +[#ex28-any-2] +=== Example 28: ANY Predicate + +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE ANY v IN schedule SATISFIES v.day IN [1,2,3] +END; +---- + +In this example, the predicate `v.day IN [1,2,3]` is pushed to ARRAY index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `v.day IN [1,2,3]` +| `1` + +`2` + +`3` +| `1` + +`2` + +`3` +| `3 (BOTH)` + +`3 (BOTH)` + +`3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +WHERE ANY v IN schedule SATISFIES v.day IN [1,2,3] +END; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "1", + "inclusion": 3, + "low": "1" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "2", + "inclusion": 3, + "low": "2" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "3", + "inclusion": 3, + "low": "3" + } + ] + } + ], +// ... +---- + +[#ex29-equality-on-expr] +=== Example 29: EQUALITY Predicate on Expression + +NOTE: The following examples don't have the right indexes, or the queries need to be modified to produce an optimal plan. + +[source,sqlpp] +---- +SELECT meta().id FROM airline WHERE abs(id) = 10; +---- + +In this example, no predicate is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `id` +| `NULL` +| `Unbounded` +| `0 (NEITHER)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline WHERE abs(id) = 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], +// ... +---- + +The span indicates that the index service is performing a complete index scan. +If the index does not cover the query, the query service fetches the document from the data node and then applies the predicate. +For better performance, create a new index as follows: + +[source,sqlpp] +---- +CREATE INDEX `idx_airline_absid` ON airline(abs(`id`)); +---- + +When index `idx_airline_absid` is used, the predicate `abs(id) = 10` is pushed to index scan. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `abs(id) = 10` +| `10` +| `10` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +USE INDEX (idx_airline_absid) +WHERE abs(id) = 10; +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "10", + "inclusion": 3, + "low": "10" + } + ] + } + ], +// ... +---- + +[#ex30-overlap] +=== Example 30: Overlapping Predicates + +[source,sqlpp] +---- +SELECT meta().id FROM airline +WHERE id <= 100 + OR (id BETWEEN 50 AND 150); +---- + +In this example, the predicates `+id <= 100 OR (id BETWEEN 50 AND 150)+` are pushed to index scan as two ranges. + +[cols="2,1,1,1"] +|=== +| Span Range for | Low | High | Inclusion + +| `+id <= 100+` +| `NULL` +| `100` +| `2 (HIGH)` + +| `id BETWEEN 50 AND 150` +| `50` +| `150` +| `3 (BOTH)` +|=== + +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM airline +WHERE id <= 100 + OR (id BETWEEN 50 AND 150); +---- + +[source,json] +---- +// ... + "spans": [ + { + "exact": true, + "range": [ + { + "high": "100", + "inclusion": 2, + "low": "null" + } + ] + }, + { + "exact": true, + "range": [ + { + "high": "150", + "inclusion": 3, + "low": "50" + } + ] + } + ], +// ... +---- + +== Summary + +When you analyze the explain plan, correlate the predicates in the explain to the spans. +Ensure the most optimal index is selected and the spans have the expected range for all the index keys. +More keys in each span will make the query more efficient. diff --git a/modules/learn/pages/services-and-indexes/indexes/index_pushdowns.adoc b/modules/learn/pages/services-and-indexes/indexes/index_pushdowns.adoc new file mode 100644 index 000000000..218bf6177 --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/index_pushdowns.adoc @@ -0,0 +1,635 @@ += Index Pushdowns +:description: Index Pushdowns are performance optimizations where the Query engine pushes more of the work down to the Indexer. +:imagesdir: ../../../assets/images +:page-topic-type: concept +:page-aliases: performance:index_pushdowns + +[abstract] +{description} + +The GSI Indexes are a vital part of query performance and are tightly coupled with the Query engine. +The Query engine implements many query processing optimizations to achieve the best possible performance for {sqlpp} queries. + +Query Indexer not only indexes data, it also supports various operations such as point scans, range scans, array indexing, sort order, and pagination. +The Query engine tries to leverage the indexer functionality as much as possible by pushing down operations to the indexer as part of the index scan. +This helps performance, predominantly, in two ways: + +. Minimize the amount of data transferred from Indexer nodes to Query nodes. +. Minimize the amount of processing done at Query nodes. + +.Examples on this Page +**** +The examples in this topic use the travel-sample dataset which is supplied with Couchbase Capella. +For instructions on how to install the sample data, see xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data]. + +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Index Projection + +When processing a SELECT or DML with a WHERE clause, the Query engine picks one or more qualified indexes to be used for the query. +Note that each index will have document field names explicitly specified as index-keys, and some metadata fields, such as `meta().id`, implicitly stored in the index. +The Query engine requests the exact list of fields needed for the query. +For a covered query, it is the fields referred in projection, predicate, GROUP BY clauses, ORDER BY clauses, HAVING clauses, ON key, and subqueries of the query. +For non-covered queries, it is just `META().id`. + +For example, consider the following index and query: + +[[example-simple]] +.Index Projection +==== +This example uses the `def_inventory_route_route_src_dst_day` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +CREATE INDEX def_inventory_route_route_src_dst_day +ON route(sourceairport, destinationairport, + (DISTINCT (ARRAY (v.day) FOR v IN schedule END))); +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT sourceairport FROM route +USE INDEX (def_inventory_route_route_src_dst_day) +WHERE sourceairport = "SFO" +LIMIT 1; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-simple.jsonc[tag=projection] +---- + +The query refers to fields `sourceairport` and `type`. +The index is wider in scope, that is, it has `sourceairport`, `destinationairport`, `schedule.day`, and `type` fields. + +So, for each matching document, the query requires only a subset of the data stored in the index. +With index-projection support, the Query engine indicates the exact data requested as part of the index-scan. +In this example, + +<1> The `entry_keys` in the EXPLAIN output indicate the exact index-key fields that should be returned in the index-scan result. +This has only one entry (`0`) indicating the first index-key `sourceairport`. +<2> Also, the `primary_key` indicates whether the index should return the primary key `meta().id` of the matching document. + +Note that in some cases (such as when `distinctScan` or `intersectScan` are used, as in this example), the primary key `meta().id` may be retrieved even though the query doesn’t explicitly specify it in the query. +Without this optimization, index-scan would return all the index-keys defined in the index. +If the `index_projection` field is missing in the EXPLAIN output, then Indexer would return all index-keys. +==== + +== Predicate Pushdown + +The Query engine and GSI indexes support many optimizations for efficiently processing predicate push-downs. +In general, this performance optimization is leveraged when the Query engine decides to use an Index-scan for processing a query, and whole or partial predicates can be pushed to the indexer to filter documents of interest to the query. + +For example, in the above query <> with a simple WHERE clause, the predicate (`sourceairport = "SFO"`) is pushed to the index `def_inventory_route_route_src_dst_day` with the following single `span` and `range`. +These attributes exactly define different characteristics of the index scan: + +.Predicate Pushdown +==== +The `span` and `range` from the EXPLAIN output of <>. + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-simple.jsonc[tag=predicate] +---- + +* Each Span defines details about one index-key summarizing corresponding predicate conditions into a range-scan lookup for the index. +In this example, the predicate condition (`sourceairport = "SFO"`) translates to one span with one range that specifies both `low` and `high` values of "SFO" (to imply equals condition). +* Refer to section xref:learn:services-and-indexes/indexes/index-scans.adoc[Scans] for more information. +==== + +== Composite Predicate Pushdown + +Compound or composite predicates are those with multiple conditions on different fields of the document. +When the predicate is conjunctive with multiple AND conditions, then a single `span` with multiple `ranges` are specified in the index-scan request. +When the predicate is disjunctive, then multiple `spans` are specified. +See xref:learn:services-and-indexes/indexes/index-scans.adoc[Scans] +for more details and examples on how predicate pushdown works for various types of index-scans as well as the conjunctive predicate AND and the disjunctive predicate OR. + +=== Index Key Order and Structure + +Composite indexes have more than one index key, and the order of the index keys is important for any lookup or scan of the index, because the indexes structure all the indexed entries in linearized default collation sorted order of all the index-keys. +For example, consider the following hypothetical index: + +[source,sqlpp] +---- +CREATE INDEX `idx_age_name` ON users(age, name); +---- + +image::services-and-indexes/indexes/IndexKeyOrder.png[,570] + +Various age and name values are stored in the index in a tree-like structure, represented in simplified form in the diagram above, with all the index key values linearly sorted as ordered pairs. +For instance, + +* The diagram above shows index-entries with all names in sorted order with an age of 20 followed by the entries for age 21 and related names. +* The arrowed paths logically depict how an index lookup or scan would find entries in the index. +* A point lookup query for `age=20 AND name="joe"` may follow arrows labelled *p1*. +* Similarly, a range scan for `(age BETWEEN 20 and 21) AND (name="joe")` may find entries of interest between the paths labelled *p1* and *p2* (highlighted in green). + +[NOTE] +==== +This range may include some unwanted entries (such as "mark", "abby", "anne") which will be filtered subsequently. + +Queries with predicates such as `(age = 20) AND (name BETWEEN "joe" and "mark")` will need all the entries found using range scans. +==== + +In general, when the predicate has a range condition on prefixing index-keys (such as `age`) may produce unwanted results from the range-scan index-lookups. +In Couchbase Capella, the Query service and Indexer are enhanced with complete and accurate predicate pushdown to filter such unnecessary results in the Indexer itself. +This improves query performance as it saves the additional overhead in transferring the unwanted data/results to query nodes and subsequently filtering the results. +This is explained with an example in the following section: <>. + +[[range-scan-prefix]] +=== Composite Predicate with Range Scan on Prefix Index-Keys + +The Query engine supports efficient predicate pushdown to indexes in the cases when the WHERE clause has a range predicate on any of the prefixing index-keys. + +Consider the following query, which finds all destination airports within 2000 miles of LAX. + +[[example-comp-explain]] +.Composite Predicate with Range Scan +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx_route_src_dst_dist +ON route(distance, sourceairport, destinationairport); +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT destinationairport +FROM route +USE INDEX (idx_route_src_dst_dist) +WHERE distance < 2000 AND sourceairport = "LAX"; -- <1> +---- + +<1> In this query, the predicate has the range condition on the first index-key `distance` and an equality predicate on the 2nd index-key `sourceairport`. + +.Results +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-comp-explain.jsonc[tag=excerpt] +---- + +<.> The `spans` attribute of the EXPLAIN query plan output shows that the predicate is accurately represented and pushed-down to the indexer. +<.> The `range[]` attribute is an array of the predicate bounds for individual index-keys involved in the compound predicate. +<.> The first element of `range[]` corresponds to the index-key `distance` with (`low`, `high`) values (`null`, `2000`) respectively. +<.> The second element of `range[]` corresponds to the index-key `sourceairport` with (`low`, `high`) values (`"LAX"`, `"LAX"`) representing equals condition. + +The Indexer processes the lookup request and exactly returns only the documents matching the predicate conditions. +For example, when you xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc[enable monitoring] with the configuration parameter `profile = "timings"` for this query, you can see that the indexer returns 165 documents, which is the same as the final result set of the query. + +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-comp-plan.jsonc[tags=index;ellipsis;final] +---- +==== + +=== Composite Predicate with Skip-Key Range Scan + +In <> above, the query has a composite predicate on continuous leading index-keys, namely the index-keys `distance` and `sourceairport`, which occur together at the start of the index definition. +In Couchbase Capella, it is possible to push down a composite predicate on non-continuous leading index-keys. +There must be a predicate on the first key in the index definition, and then on any of the subsequent index-keys. + +Consider the following query, which is a variant of the query in <> above, and uses the same index. + +[[example-skip]] +.Composite Predicate with Skip-Key Range Scan +==== +.Query +[source,sqlpp] +---- +EXPLAIN SELECT sourceairport +FROM route +USE INDEX (idx_route_src_dst_dist) +WHERE distance < 2000 AND destinationairport = "LAX"; -- <1> +---- + +<1> This query has a range predicate on the first index-key `distance` and an equality predicate on the 3rd index-key `destinationairport`. +There is no predicate on the 2nd index-key `sourceairport`. + +.Results +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-skip.jsonc[tag=excerpt] +---- + +<.> The EXPLAIN query plan output shows that the predicate is pushed-down to the indexer. +<.> The first element of `range[]` corresponds to the index-key `distance` with (`low`, `high`) values (`null`, `2000`) respectively. +<.> The second element of `range[]` corresponds to the index-key `sourceairport` with no low or high bounds, i.e. a whole range scan. +<.> The third element of `range[]` corresponds to the index-key `destinationairport` with (`low`, `high`) values (`"LAX"`, `"LAX"`) representing equals condition. + +By skipping the index-key that does not have a predicate, and including all the non-continuous index-keys that do have predicates, the query uses the index more effectively and reduces the number of documents that need to be fetched. +This increases query preparation time a little, but vastly speeds up the execution of the query. +==== + +== Pagination Pushdown + +Pagination in {sqlpp} queries is achieved by using the LIMIT and OFFSET clauses, and both of the operators can be pushed to indexer whenever possible. +These operators may not always be pushed to Indexer, depending on the following factors: + +* Whether or not the whole predicate in the WHERE clause can be completely and accurately pushed to a single index. +* When using IntersectScan, the Query engine uses multiple indexes to process the query. +As such, LIMIT/OFFSET will need to be processed in the Query engine at a later stage of query processing, and hence cannot be pushed to the Indexer. +* Whether or not the SELECT query has other clauses that may impact pagination, such as ORDER BY or JOIN. +For example, + ** When ORDER BY key in the query is different from that of the index order, then the query layer will need to process the sort; and hence, in those cases, the pagination cannot be pushed to the indexer as shown in <> below. + ** For JOIN queries, index scans can be used only for the left side keyspace. +Subsequent JOIN phrases may filter some documents, after which only LIMIT/OFFSET can be applied. +Hence, the pagination operators cannot be pushed when a query has JOIN clauses. + +[[example-page-1]] +.Pagination with Secondary Index +==== +When using a secondary index, both LIMIT and OFFSET operators are pushed to the index. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT * FROM landmark +WHERE city = "San Francisco" +OFFSET 4000 LIMIT 10000; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-page-1.jsonc[tag=excerpt] +---- + +<1> The `IndexScan3` operator handles `limit`. +<2> The `IndexScan3` operator handles `offset`. +==== + +[[example-page-2]] +.Pagination with Primary Index +==== +When using a primary index, both LIMIT and OFFSET operators are pushed to the Indexer. +This example uses the `def_inventory_landmark_primary` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +CREATE PRIMARY INDEX `def_inventory_landmark_primary` + ON landmark; +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT * FROM landmark +OFFSET 4000 LIMIT 10000; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-page-2.jsonc[tag=excerpt] +---- + +<1> The `PrimaryScan3` operator handles `limit`. +<2> The `PrimaryScan3` operator handles `offset`. +==== + +[[example-page-3]] +.Pagination with Different Index Order +==== +LIMIT and OFFSET operators are not pushed to the Indexer when the index order is different from that specified in the ORDER BY. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- +.Query +[source,sqlpp] +---- +EXPLAIN SELECT * FROM landmark +USE INDEX(def_inventory_landmark_city) +WHERE city = "San Francisco" +ORDER BY name +OFFSET 4000 LIMIT 10000; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-page-3.jsonc[tags=index;ellipsis;order] +---- + +<1> The `IndexScan3` operator does not handle `offset` or `limit`. +<2> The Offset operator is handled by the Query engine. +<3> The Limit operator is handled by the Query engine. +==== + +== Using Index Order + +The Query engine may avoid ORDER BY processing in cases where the ordering of entries in the index can be leveraged for the query. +The Query engine carefully evaluates each query to decide whether ORDER BY keys are aligned with the index key order. +For example, ORDER BY may not be pushed down when the ORDER BY fields are not aligned with the index-key order defining the index. + +[[example-idx-1]] +.Ascending Sort by String Field +==== +Find all cities that start with "San", and sort the results by the city name in ascending order. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT city FROM landmark +WHERE city LIKE "San%" +ORDER BY city; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-idx-1.jsonc[tags=index;ellipsis;query] +// ... +---- + +<1> In this example, you can see that the query plan does not have an ORDER operator before the final projection. +That means order pushdown is being leveraged, and the query is relying on the index order. +==== + +[[example-idx-2]] +.Ascending Sort by Primary Key +==== +Find all cities that start with "San", and sort the results by the document primary key in ascending order. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT city FROM landmark +WHERE city LIKE "San%" +ORDER BY meta().id; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-idx-2.jsonc[tags=index;ellipsis;query] +---- + +<1> In this example, you can see an additional ORDER operator before the final projection, because the ORDER BY field `meta().id` is different from the index order key `city`. +==== + +[discrete] +=== Limitation + +Currently the Query engine supports order pushdown only when the ORDER BY keys are aligned with the Index order. +But reverse-scan of the index is not supported. + +For example, in <> above, you can see that the query plan does not have an ORDER operator before the final projection, because the index order is the same as the ascending order specified in the query. +Similarly, in the following example <>, the ORDER BY clause has DESC, and that matches with the index order defined by the index `idx_landmark_city_desc`. + +However, the ASC order in <> will not be able to leverage the index order in the index `idx_landmark_city_desc`, nor will the DESC order in <> be able to leverage the index order in the index `def_inventory_landmark_city`. + +[[example-idx-3]] +.Descending Sort by String Field +==== +Descending variation of <>. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx_landmark_city_desc ON landmark(city DESC); +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT city FROM landmark +WHERE city LIKE "San%" +ORDER BY city DESC; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-idx-3.jsonc[tags=index;ellipsis;query] +---- +==== + +== Operator Pushdowns + +The Query engine tries to avoid unnecessary processing operators such as MIN(), MAX(), and COUNT(), which can be processed by the Indexer much more efficiently. +In such cases, the Query engine pushes down necessary hints or options to the Indexer to process the following operators. + +=== MAX() Pushdown + +This function returns the highest value of the input field based on the default collation rules. (For details, see xref:n1ql:n1ql-language-reference/datatypes.adoc[Data types] and xref:n1ql:n1ql-language-reference/comparisonops.adoc[Comparison Operators].) + +MAX() can be pushed to the Indexer even if the index was not created with matching index keys or sort order. + +.MAX of a String Field +==== +Find the alphabetically highest city name in the `landmark` collection. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT MAX(city) +FROM landmark +USE INDEX (def_inventory_landmark_city) +WHERE city IS NOT NULL; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-max.jsonc[tag=excerpt] +---- +==== + +=== MIN() Pushdown + +This function returns the lowest value of the input field based on the default collation rules. (For details, see xref:n1ql:n1ql-language-reference/datatypes.adoc[Data types] and xref:n1ql:n1ql-language-reference/comparisonops.adoc[Comparison Operators].) + +MIN() can be pushed to the Indexer even if the index was not created with matching index keys or sort order. + +.MIN of a String Field +==== +Find the alphabetically lowest city name in the `landmark` collection. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT MIN(city) +FROM landmark +USE INDEX (def_inventory_landmark_city) +WHERE city IS NOT NULL; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-min.jsonc[tag=excerpt] +---- +==== + +=== COUNT() Pushdown + +This function returns the total number of non-Null values of an input field from the matching documents of an index scan. + +[[example-count-out]] +.Count of a String Field +==== +Find the number of cities entered in the `landmark` collection. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +SELECT COUNT(city) AS NumberOfCities +FROM landmark +USE INDEX (def_inventory_landmark_city) +WHERE city IS NOT NULL; +---- + +.Result +[source,json] +---- +[ + { + "NumberOfCities": 4479 + } +] +---- +==== + +[[example-count-plan]] +.Count Details +==== +The details behind <>. + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT COUNT(city) AS NumberOfCities +FROM landmark +USE INDEX (def_inventory_landmark_city) +WHERE city IS NOT NULL; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-count.jsonc[tag=excerpt] +---- + +<1> The index operator `IndexCountScan3` counts values so the Query Service does not need to do additional processing. +==== + +=== COUNT(DISTINCT) Pushdown + +This function returns the total number of unique non-Null values of an input field from the matching documents of an index scan. + +.Count Distinct of a String Field +[[example-distinct-out]] +==== +Find the number of unique city names in the `landmark` collection. +This example uses the `def_inventory_landmark_city` index that comes pre-installed and can be made by the statement: + +.Index +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/pushdown-def-city.n1ql[] +---- + +.Query +[source,sqlpp] +---- +SELECT COUNT (DISTINCT city) AS NumberOfDistinctCities +FROM landmark +USE index (def_inventory_landmark_city) +WHERE city IS NOT NULL; +---- + +.Result +[source,json] +---- +[ + { + "NumberOfDistinctCities": 625 + } +] +---- +==== + +[[example-distinct-plan]] +.Count Distinct Details +==== +The details behind <>. + +.Query +[source,sqlpp] +---- +EXPLAIN SELECT COUNT (DISTINCT city) AS NumberOfDistinctCities +FROM landmark +USE index (def_inventory_landmark_city) +WHERE city IS NOT NULL; +---- + +.Result +[source,json] +---- +include::example$services-and-indexes/indexes/pushdown-distinct.jsonc[tag=excerpt] +---- + +<1> The index operator `IndexCountScan3` counts distinct values so the Query Service does not need to do additional processing. +==== + +== Related Links + +* xref:learn:services-and-indexes/indexes/index-scans.adoc#query-execution-details[Query Execution: Details] +* xref:n1ql:n1ql-language-reference/covering-indexes.adoc[Covering Indexes] +* xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[Grouping and Aggregate Pushdown] +* xref:learn:services-and-indexes/indexes/early-filters-and-pagination.adoc[Early Filters, Ordering and Pagination] diff --git a/modules/learn/pages/services-and-indexes/indexes/indexing-and-query-perf.adoc b/modules/learn/pages/services-and-indexes/indexes/indexing-and-query-perf.adoc new file mode 100644 index 000000000..1d039648e --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/indexing-and-query-perf.adoc @@ -0,0 +1,584 @@ += Types of Primary and Secondary Index +:navtitle: Types of Index +:description: This topic provides an overview of the types of index that you can create using the Index Service, and explains how they help to query for data efficiently and improve query performance. +:page-topic-type: concept +:page-aliases: performance:indexing-and-query-perf + +// Cross-references +:install-sample-buckets: xref:clusters:data-service/import-data-documents.adoc#import-sample-data +:aggregatefun: xref:n1ql:n1ql-language-reference/aggregatefun.adoc +:indexing-arrays: xref:n1ql:n1ql-language-reference/indexing-arrays.adoc +:covering-indexes: xref:n1ql:n1ql-language-reference/covering-indexes.adoc +:bucket-analyzer: xref:clusters:query-service/query-workbench.adoc#insights-sidebar +:storage-modes: xref:learn:services-and-indexes/indexes/storage-modes.adoc +:additional-storage-use: xref:server:learn:data/transactions.adoc#additional-storage-use + +Creating the right index -- with the right keys, in the right order, and using the right expressions -- is critical to query performance in any database system. +This is true for Couchbase as well. +{description} + +.Examples on this Page +**** +The examples in this topic use the travel-sample dataset which is supplied with Couchbase Capella. +For instructions on how to install the sample data, see {install-sample-buckets}[Import Sample Data]. + +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Introduction: Document Keys + +Couchbase Capella is a distributed database that supports flexible data model using JSON. +Each document in a keyspace has a user-generated unique document key and this uniqueness is enforced when inserting data into the keyspace. +Consider the following sample document: + +==== +[source,sqlpp] +---- +SELECT meta().id, travel +FROM airline travel +LIMIT 1; +---- + +[source,json] +---- +[ + { + "id": "airline_10", // <.> + "travel": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + } // <.> + } +] +---- + +<.> The document key +<.> The document content +==== + +[#primary-index] +== Primary Index + +The primary index is simply an index on the document key on the entire keyspace. + +==== +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-pri-nameless.n1ql[tag=query] +---- +==== + +The Couchbase data layer enforces the uniqueness constraint on the document key. +The primary index, like every other index, is maintained asynchronously. +Use the primary index for full keyspace scans (primary scans) when the query does not have any filters (predicates) or when no other index or access path can be used. + +NOTE: A primary index does not index any {additional-storage-use}[transaction records] that may be stored in a keyspace. +This means that if you are counting the number of documents in a keyspace, you may see slightly different results, depending on whether you are using a primary index or not. +Refer to {aggregatefun}[Aggregate Functions] and {bucket-analyzer}[Viewing the Data Insights]. + +.Metadata for Primary Index +==== +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-pri-nameless.n1ql[tag=check] +---- + +.Results +[source,json] +---- +include::n1ql:example$n1ql-language-reference/create-pri-nameless.jsonc[] +---- +==== + +The metadata provides additional information about the index, such as where the index resides ([.out]`datastore_id`), its state ([.out]`state`), and the indexing method used ([.out]`using`). + +[#named-primary-index] +== Named Primary Index + +You can name the primary index, as seen in the following example. + +==== +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-pri-name.n1ql[] +---- +==== + +The rest of the features of the primary index are the same, except that this index is named. +The advantage of naming a primary index is that you can have multiple primary indexes in the system. +Duplicate indexes help with high availability and query load distribution between the indexes. +This is true for both primary indexes and secondary indexes. + +[#secondary-index] +== Secondary Index + +The secondary index is an index on any key-value or document-key. +This index can use any key within the document and the key can be of any type: scalar, object, or array. +The query has to use the same type of object for the query engine to use the index. + +.Key is a Simple Scalar Value +==== +[source,sqlpp] +---- +include::n1ql:example$n1ql-language-reference/create-idx-name.n1ql[] +---- + +In this keyspace, `name` is a simple scalar value such as `{ "name": "Air France" }`. +==== + +.Key is an Object Embedded Within the Document +==== +[source,sqlpp] +---- +CREATE INDEX travel_geo on landmark(geo); +---- + +In this keyspace, `geo` is an object embedded within the document, such as: + +[source,json] +---- +"geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 +} +---- +==== + +.Keys from Nested Objects +==== +[source,sqlpp] +---- +CREATE INDEX travel_geo_alt on landmark(geo.alt); + +CREATE INDEX travel_geo_lat on landmark(geo.lat); +---- +==== + +.Keys from an Array of Objects +==== +In the `route` keyspace, `schedule` is an array of objects with flight details. + +[source,json] +---- +"schedule": [ + { + "day": 0, + "flight": "AF198", + "utc": "10:13:00" + }, + { + "day": 0, + "flight": "AF547", + "utc": "19:14:00" + }, + { + "day": 0, + "flight": "AF943", + "utc": "01:31:00" + }, + { + "day": 1, + "flight": "AF356", + "utc": "12:40:00" + }, + { + "day": 1, + "flight": "AF480", + "utc": "08:58:00" + }, + { + "day": 1, + "flight": "AF250", + "utc": "12:59:00" + } +] +---- + +This command indexes the complete array and is useful only if you're looking for the entire array. + +[source,sqlpp] +---- +CREATE INDEX travel_schedule ON route(schedule); +---- +==== + +[#composite-secondary-index] +== Composite Secondary Index + +It's common to have queries with multiple filters (predicates). +In such cases, you want to use indexes with multiple keys so the indexes can return only the qualified document keys. +Additionally, if a query is referencing only the keys in the index, the query engine can simply answer the query from the index scan result without having to fetch from the data nodes. +This is commonly used for performance optimization. + +==== +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/create-idx-composite.n1ql[] +---- +==== + +Each of the keys can be a simple scalar field, object, or an array. +For the index filtering to be exploited, the filters have to use respective object type in the query filter. + +The keys to the secondary indexes can include document keys (`meta().id`) explicitly if you need to filter on the document keys in the index. + +[#functional-index] +== Functional Index + +It's common to have names in the database with a mix of upper and lower cases. +When you need to search, say for the city "Villeneuve-sur-lot", you want to search for all uppercase and lowercase possibilities of it. +In order to do so, first create an index using an expression or a function as the key. +For example: + +==== +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/create-idx-expr.n1ql[] +---- +==== + +If you provide the search string in lowercase, the index helps the query engine more efficiently search for already lowercase values in the index. + +==== +[source,sqlpp] +---- +EXPLAIN SELECT * FROM airport +WHERE LOWER(name) = "villeneuve-sur-lot"; +---- + +.Results +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "travel_cxname", + "index_id": "97307509cbce54ca", + "index_projection": { + "primary_key": true + }, + "keyspace": "airport", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"villeneuve-sur-lot\"", + "inclusion": 3, + "low": "\"villeneuve-sur-lot\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "airport", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(lower((`airport`.`name`)) = \"villeneuve-sur-lot\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "text": "SELECT * FROM airport WHERE LOWER(name) = \"villeneuve-sur-lot\";" + } +] +---- +==== + +You can also use complex expressions in the functional index. +For example: + +==== +[source,sqlpp] +---- +CREATE INDEX travel_cx1 ON airport +(LOWER(name), ROUND(geo.alt * 0.3048)); +---- +==== + +[#array-index] +== Array Index + +JSON is hierarchical. +At the top level, it can have scalar fields, objects, or arrays. +Each object can nest other objects and arrays; each array can have other objects and arrays, and the nesting can continue. +Consider the following example array. + +==== +[source,json] +---- +"schedule": [ + { + "day" : 0, + "special_flights" : [ + { + "flight" : "AI111", + "utc" : "1:11:11" + }, + { + "flight" : "AI222", + "utc" : "2:22:22" + } + ] + }, + { + "day" : 1, + "flight" : "AF552", + "utc" : "14:41:00" + } +] +---- +==== + +With a rich structure as seen in the array schedule, here's how you index a particular array or a field within the sub-object. + +==== +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/create-idx-array.n1ql[] +---- +==== + +This index key is an expression on the array to clearly reference only the elements that need to be indexed. + +* `schedule` -- the array we’re dereferencing into. +* `v` -- the variable implicitly declared to reference each element/object within the array `schedule`. +* `v.day` -- the element within each object of the array `schedule`. + +The following query uses the array index created above. + +==== +[source,sqlpp] +---- +EXPLAIN SELECT * FROM route +WHERE ANY v IN schedule SATISFIES v.day = 2 END; +---- + +.Results +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "travel_sched", + "index_id": "7cb7b03a5a2a7522", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "2", + "inclusion": 3, + "low": "2" + } + ] + } + ], + "using": "gsi" + } + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "any `v` in (`route`.`schedule`) satisfies ((`v`.`day`) = 2) end" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "text": "SELECT * FROM route\nWHERE ANY v IN schedule SATISFIES v.day = 2 END;" + } +] +---- + +The `scan` section shows that this query uses the index created above. +==== + +Because the key is a generalized expression, it provides the flexibility to apply additional logic and processing on the data before indexing. +For example, you can create functional indexing on elements of each array. +As you're referencing individual fields of the object or element within the array, the index creation, size, and search are efficient. + +The index `travel_sched` stores only the distinct values within an array. +To store all elements of an array in an index, do not use the DISTINCT modifier to the expression. + +==== +[source,sqlpp] +---- +CREATE INDEX travel_sched ON route +(ALL ARRAY v.day FOR v IN schedule END); +---- +==== + +For further details and examples, refer to {indexing-arrays}[Array Indexing]. + +[#partial-index] +== Partial Index + +Unlike relational systems where each type of row is in a distinct table, Couchbase keyspaces can have documents of various types. +You can include a distinguishing field in your document to differentiate distinct types. + +For example, the `landmark` keyspace distinguishes types of landmark using the `activity` field: + +==== +[source,sqlpp] +---- +SELECT DISTINCT activity FROM landmark; +---- + +.Result +[source,json] +---- +[ + { + "activity": "see" + }, + { + "activity": "eat" + }, + { + "activity": "do" + }, + { + "activity": "drink" + }, + { + "activity": "buy" + }, + { + "activity": "listing" + } +] +---- +==== + +Since the Couchbase data model is JSON and the JSON schema is flexible, an index may not contain entries to documents with absent index keys. + +When you want to create an index of restaurants, you can simply add the distinguishing field for the WHERE clause of the index. + +==== +[source,sqlpp] +---- +include::example$services-and-indexes/indexes/create-idx-partial.n1ql[] +---- +==== + +This creates an index only on documents that have `activity='eat'`. +The queries must include the filter `activity='eat'` in addition to other filters for this index to qualify. + +You can use complex predicates in the WHERE clause of the index. +Here are some examples where you can use partial indexes: + +* Partitioning a large index into multiple indexes using the mod function. +* Partitioning a large index into multiple indexes and placing each index into distinct indexer nodes. +* Partitioning the index based on a list of values. +For example, you can have an index for each state. +* Simulating index range partitioning via a range filter in the WHERE clause. +Note that {sqlpp} queries use one partitioned index per query block. +Use UNION ALL to have a query exploit multiple partitioned indexes in a single query. + +[#duplicate-index] +== Duplicate Index + +Duplicate index isn't really a special type of index, but a feature of Couchbase indexing. +You can create duplicate indexes with distinct names. + +==== +[source,sqlpp] +---- +CREATE INDEX i1 ON airport(LOWER(name), id, icao) +WHERE country = 'France'; + +CREATE INDEX i2 ON airport(LOWER(name), id, icao) +WHERE country = 'France'; + +CREATE INDEX i3 ON airport(LOWER(name), id, icao) +WHERE country = 'France'; +---- +==== + +All three indexes have identical keys and an identical WHERE clause; the only difference is the name of these indexes. +You can choose their physical location using the WITH clause of the CREATE INDEX statement. + +During query optimization, the query engine chooses one of the index names as seen in the explain plan. +During query execution, these indexes are used in a round-robin fashion to distribute the load. +Thus providing scale-out, multi-dimensional scaling, performance, and high availability. + +[#covering-index] +== Covering Index + +Index selection for a query solely depends on the filters in the WHERE clause of your query. +After the index selection is made, the query engine analyzes the query to see if it can be answered using only the data in the index. +If it does, the query engine skips retrieving the whole document from the data nodes. +This is a performance optimization to keep in mind when designing your indexes. + +For further details and examples, refer to {covering-indexes}[Covering Indexes]. diff --git a/modules/learn/pages/services-and-indexes/indexes/query-without-index.adoc b/modules/learn/pages/services-and-indexes/indexes/query-without-index.adoc new file mode 100644 index 000000000..ad442bd64 --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/query-without-index.adoc @@ -0,0 +1,295 @@ += Query without Indexes +:page-topic-type: concept +:description: Sequential scans enable you to query a keyspace, even if the keyspace has no indexes. + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:install-sample-buckets: xref:clusters:data-service/import-data-documents.adoc#import-sample-data + +[abstract] +{description} + +NOTE: Query without Indexes is not available by default for paid service plans. +For details, see <>. + +.Examples on this Page +**** +The examples in this topic use the travel-sample dataset which is supplied with Couchbase Capella. +For instructions on how to install the sample bucket, see {install-sample-buckets}[Import Sample Data]. +**** + +== Sequential Scans + +If a keyspace does not have any suitable primary or secondary indexes for a query, the Query service can fall back on a sequential scan of the data to retrieve the document keys. +A sequential scan uses an underlying mechanism known as a K/V range scan. + +Sequential scans are intended for simple, ready access to data, and are not intended as a high performance solution. + +Sequential scans are best suited to small collections where key order is unimportant, or where the overhead of maintaining an index can't be justified. +For larger collections and greater performance, define the appropriate indexes to speed up your queries. +For ordered document key operations, a primary index provides the same functionality, and will outperform a sequential scan. + +NOTE: Sequential scans are unavailable on Memory Only buckets. + +== Use Sequential Scans + +To query an index using sequential scan, run the query as usual. + +If there is a primary index or any suitable secondary index available for the keyspace, the Query service uses that in preference to sequential scan. + +=== Prerequisites + +[discrete] +===== RBAC Privileges + +Users must have the *Query Use Sequential Scans* role on the keyspace to be able to execute a request with a sequential scan. +For more details about user roles, see +{authorization-overview}[]. + +=== Examples + +To try the examples in this section, set the query context to the `tenant_agent_01` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +.Check that a collection has no indexes +==== +.Query +[source,sqlpp] +---- +SELECT * FROM system:indexes +WHERE scope_id = "tenant_agent_01" + AND keyspace_id = "users"; +---- + +.Result +[source,json] +---- +{ + "results": [] +} +---- + +You should see that collection has no primary or secondary indexes. +==== + +.Run a query without indexes +==== +.Query +[source,sqlpp] +---- +SELECT name FROM users; +---- + +.Result +[source,json] +---- +[ + { + "name": "Haley Rohan" + }, + { + "name": "Johnnie Lind" + }, + { + "name": "Verdie Jaskolski" + }, + { + "name": "Marc Mills" + }, + { + "name": "Valentine Funk" + }, + { + "name": "Jocelyn Wuckert" + }, + { + "name": "Gretchen Auer" + }, + { + "name": "Meghan Homenick" + }, + { + "name": "Kraig Hilll" + }, + { + "name": "Destini Turcotte" + }, + { + "name": "Sienna Cummerata" + } +] +---- + +The query returns 11 documents. +Notice that the query takes one or more seconds. +==== + +.Check explain plan for query without index +==== +.Query +[source,sqlpp] +---- +EXPLAIN SELECT name FROM users; +---- + +.Result +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "#sequentialscan", + "index_projection": { + "primary_key": true + }, + "keyspace": "users", + "namespace": "default", + "scope": "tenant_agent_01", + "using": "sequentialscan" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "early_projection": [ + "name" + ], + "keyspace": "users", + "namespace": "default", + "scope": "tenant_agent_01" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "discard_original": true, + "preserve_order": true, + "result_terms": [ + { + "expr": "(`users`.`name`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT name FROM users;" + } +] +---- + +The explain plan includes a primary scan operator, using `sequentialscan` rather than `gsi`. + +The explain plan reports that the primary scan operator uses an index called `#sequentialscan`. +This name is a placeholder -- in reality there is no index. +==== + +== Monitor Sequential Scans + +You can monitor sequential scans using the `system:completed_requests` catalog. + +* Completed requests which used sequential scan include a `primaryScan.Seq` property within the request's `phaseCounts`, `phaseOperators`, and `phaseTimes`, in addition to the `primaryScan` property. + +* In contrast, queries which used a primary index include a `primaryScan.GSI` property within the request's `phaseCounts`, `phaseOperators`, and `phaseTimes`, in addition to the `primaryScan` property. + +The `system:completed_requests` catalog also includes a `~qualifier` field, which indicates the reason why any request was captured. +A completed requests qualifier automatically captures any requests where more than 10000 keys have been returned by sequential scans. +In most cases, this indicates that you should create an index to support the request. + +Statistics on sequential scan usage are also available in request profiling information. + +For more details, see xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc[]. + +=== Examples + +.Get completed requests which used sequential scan +==== +.Query +[source,sqlpp] +---- +SELECT * FROM system:completed_requests +WHERE phaseCounts.`primaryScan.Seq` IS NOT MISSING; +---- + +You must wrap the property name `primaryScan.Seq` in backquotes, because the property name contains a period. +The period after `phaseCounts` is a separator between nested property names, whereas the period within `primaryScan.Seq` is actually part of the property name. + +.Result +[source,json] +---- +[ + { + "completed_requests": { + "clientContextID": "4eb44ea6-170a-4700-ae79-e22f57100e43", + "cpuTime": "820.464µs", + "elapsedTime": "4.728840089s", + "errorCount": 0, + "errors": [], + "n1qlFeatCtrl": 76, + "node": "127.0.0.1:8091", + "phaseCounts": { + "fetch": 11, + "primaryScan": 11, + "primaryScan.Seq": 11 + }, + "phaseOperators": { + "authorize": 1, + "fetch": 1, + "primaryScan": 1, + "primaryScan.Seq": 1, + "project": 1, + "stream": 1 + }, + "phaseTimes": { + "authorize": "8.471µs", + "fetch": "107.915507ms", + "instantiate": "19.769µs", + "parse": "870.813µs", + "plan": "293.479µs", + "plan.index.metadata": "17.998µs", + "plan.keyspace.metadata": "7.601µs", + "primaryScan": "4.72730895s", + "primaryScan.Seq": "4.72730895s", + "project": "161.687µs", + "run": "4.727550611s", + "stream": "234.174µs" + }, + "queryContext": "default:travel-sample.tenant_agent_01", + "remoteAddr": "127.0.0.1:43164", + "requestId": "d80b0d08-1794-4932-8188-af7e7e57b7b3", + "requestTime": "2024-02-09T15:05:09.343Z", + "resultCount": 11, + "resultSize": 435, + "scanConsistency": "unbounded", + "serviceTime": "4.728754078s", + "state": "completed", + "statement": "SELECT name FROM users;", + "statementType": "SELECT", + "useCBO": true, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0", + "users": "builtin:Administrator", + "~qualifier": "threshold" + } + }, + // ... +] +---- + +The query returns details of completed requests using a sequential scan, if any are logged. +==== + +[#manage-sequential-scans] +== Manage Sequential Scans + +For a xref:billing:billing.adoc#free-tier-plan[free operational cluster], sequential scan is available in the Query tab, and via cluster access credentials in the SDKs or Couchbase Shell. + +For xref:billing:billing.adoc#paid-plan[paid service plans], sequential scan is not available by default. +To enable sequential scan, please xref:support:manage-support.adoc[contact support]. \ No newline at end of file diff --git a/modules/learn/pages/services-and-indexes/indexes/storage-modes.adoc b/modules/learn/pages/services-and-indexes/indexes/storage-modes.adoc new file mode 100644 index 000000000..78310edbd --- /dev/null +++ b/modules/learn/pages/services-and-indexes/indexes/storage-modes.adoc @@ -0,0 +1,70 @@ += Index Storage Settings +:navtitle: Storage Settings +:description: All indexes in Couchbase Capella use the Couchbase Plasma storage engine. +:page-topic-type: concept +:page-aliases: indexes:storage-modes,understanding-couchbase:services-and-indexes/indexes/storage-modes,architecture:index-storage + +[abstract] +{description} + +Couchbase Capella indexes implement multi-version concurrency control (MVCC) to provide consistent index scan results and high throughput. + +[#standard-index-storage] +== Index Storage + +In Couchbase Capella, indexes are saved on disk, in a disk-optimized format that uses both memory and disk for index-update and scanning. +The performance of standard index storage depends on overall I/O performance. + +Couchbase Capella index storage supports indexes for both Couchbase buckets and Memory-only buckets. +See xref:clusters:data-service/manage-buckets.adoc[Manage Buckets]. + +The standard global secondary index uses a B-Tree index and keeps the optimal working set of data in the buffer. +This means the total size of the index can be much bigger than the amount of memory available in each index node. + +Standard index-storage is supported by the _Plasma_ storage engine. +Plasma is highly scalable and performant storage engine that is optimized specifically for indexes. +Compaction is handled automatically. + + +== Plasma Memory Enhancements + +Couchbase Capella provides the following enhancements for Plasma: + +* Per page _Bloom Filters_. + +* In-memory compression. + +These are described below. + +[#per-page-bloom-filters] +=== Per Page Bloom Filters + +A https://en.wikipedia.org/wiki/Bloom_filter[Bloom filter^] gives guidance as to whether a searched-for item resides on disk. +By indicating that the item is _not_ on disk, the filter prevents unnecessary on-disk searches. + +If Bloom filters are enabled (which is the default), when a lookup occurs, and the correct Plasma page is located, the Bloom filter indicates either that the item is _not_ on the page, or that it _may be_ on the page. +If the filter indicates that: + +* The item is _not_ on the page, then the item is not on disk, and no disk read need occur. + +* The item _may be_ on the page, then the item can continue to be searched for, and a disk read must therefore occur. + +The consequent reduction in disk reads promotes the efficiency of mutation processing, when the mutations are insert heavy. + +//// +Bloom filters can be enabled or disabled by means of the Couchbase Web Console UI, or the REST API. +See the information provided on establishing xref:manage:manage-settings/general-settings.adoc[General] settings for the cluster. +//// + +=== In-Memory Compression + +In Couchbase Capella, Plasma memory-management routinely performs the _compression_ of a subset of items, in order to free memory; and thereby, due to the additional memory made available, keep a greater number of items in memory overall. +By keeping more items in memory, the need for disk reads is reduced, as are corresponding latencies. + +The selection of items to be compressed occurs periodically. +Only items that have already been flushed to disk are compressed: after compression, such items are principal candidates for subsequent ejection. + +Disk-flushing occurs every ten minutes: items not yet flushed to disk are not compressed; nor is any recently used item. +In consequence, items most likely to be accessed remain _uncompressed_ in memory, and are therefore accessible with the least latency; while items less likely to be accessed are retained in memory in _compressed_ form, until their ejection; beyond which, they must be accessed through disk reads. + +This new model of memory usage leads to higher _residence ratios_, and greater _access-efficiency_; at the cost of some additional CPU utilization, due to the more frequent performance of compression and decompression routines. diff --git a/modules/learn/partials/diagrams/query-execution.puml b/modules/learn/partials/diagrams/query-execution.puml new file mode 100644 index 000000000..b82f744ec --- /dev/null +++ b/modules/learn/partials/diagrams/query-execution.puml @@ -0,0 +1,63 @@ +@startuml query_execution + +skinparam maxMessageSize 125 +skinparam roundcorner 5 +skinparam responseMessageBelowArrow true +skinparam sequenceMessageAlign direction +skinparam ParticipantPadding 10 +skinparam BoxPadding 60 +skinparam box { +BackgroundColor PaleGreen +ArrowColor SeaGreen +BorderColor SpringGreen +} + +participant Clients + +box Couchbase Capella Cluster #White +collections "Query Service" as Query +collections "Index Service" as Index +collections "Data Service" as Data +end box + +Clients -> Query: Submit the\nquery +activate Query #teal +' tag::example[] +note left + SELECT airportname, city + FROM airport + WHERE tz = "America/Anchorage" + AND geo.alt >= 2100; +end note +' end::example[] + +Query -[#transparent]-> Query: Parse, analyze, create plan + +Query -> Index: Scan request; index filters +activate Index #deepskyblue +||| +Index -> Query: Get qualified doc keys and index keys +deactivate Index + +' tag::fetch[] +Query -> Data: Fetch request, doc keys +activate Data #midnightblue +||| +Data -> Query: Fetch the\ndocuments +deactivate Data +' end::fetch[] + +Query -[#transparent]> Query: Evaluate; documents to results + +Query -> Clients: Query\nresult +deactivate Query +' tag::example[] +note left + { + "airportname": "Analtuvuk", + "city": "Anaktuvuk Pass" + } +end note +' end::example[] + +@enduml \ No newline at end of file diff --git a/modules/learn/partials/diagrams/query-service.puml b/modules/learn/partials/diagrams/query-service.puml new file mode 100644 index 000000000..0f55cde4a --- /dev/null +++ b/modules/learn/partials/diagrams/query-service.puml @@ -0,0 +1,143 @@ +@startuml query_service + +skinparam defaultTextAlignment center + +rectangle Client + +rectangle "Query Service"{ + rectangle Parse [ + Parse + + + ▢ + + + + ] + rectangle Plan [ + Plan + + + ▢ + + + + ] + rectangle Scan [ + Scan + + + ▢ + + ▢ + + ] + rectangle Fetch [ + Fetch + + + ▢ + ▢ + ▢ + ▢ + ] + rectangle Join [ + Join + + + ▢ + ▢ + ▢ + ▢ + ] + rectangle Filter [ + Filter + + + ▢ + ▢ + ▢ + ▢ + ] + rectangle PreAggregate [ + Pre- + Aggregate + + ▢ + ▢ + ▢ + ▢ + ] + rectangle Aggregate [ + Aggregate + + + ▢ + + + + ] + rectangle Sort [ + Sort + + + ▢ + ▢ + ▢ + ▢ + ] + rectangle Offset [ + Offset + + + ▢ + + + + ] + rectangle Limit [ + Limit + + + ▢ + + + + ] + rectangle Project [ + Project + + + ▢ + ▢ + ▢ + ▢ + ] +} + +database "Data\nService" as Data +database "Index\nService" as Index +database "Search\nService" as Search + +() " " as End + +Client .d.> Parse +Parse -> Plan +Plan -> Scan +Scan -> Fetch +Fetch -> Join +Join -> Filter +Filter -> PreAggregate +PreAggregate -> Aggregate +Aggregate -> Sort +Sort -> Offset +Offset -> Limit +Limit -> Project +Project .u.> End + +Scan .. Index +Scan .. Search +Fetch .. Data +Join .. Data + +@enduml \ No newline at end of file diff --git a/modules/mobile-guides/pages/intro.adoc b/modules/mobile-guides/pages/intro.adoc new file mode 100644 index 000000000..62894c495 --- /dev/null +++ b/modules/mobile-guides/pages/intro.adoc @@ -0,0 +1,46 @@ += Build Mobile Apps +:page-role: tiles -toc +:description: Use App Services in Capella, in combination with Couchbase Lite embedded NoSQL database, to develop mobile apps. +:no-escape-hatch: +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +Couchbase Mobile consists of Couchbase Lite -- an embedded, offline-first database for edge devices -- synced peer-to-peer, or synchronized to your Couchbase Cluster via App Services +(or Sync Gateway, if you're using self-managed Couchbase Server instead of Capella). + +For the easiest way to start building mobile apps with Couchbase, +follow the steps to xref:cloud:get-started:configuring-app-services.adoc[set up an App Services trial], creating your endpoint, and getting your connection string. +Then head to the getting started section of your chosen platform in the xref:couchbase-lite::introduction.adoc[Couchbase Lite Docs]. + + +== App Services + +App Services synchronizes data between the Couchbase Capella cluster and your mobile apps. + +* xref:cloud:app-services:index.adoc[] + +== Couchbase Lite + +The Couchbase Lite documentation contains resources to help you develop mobile apps on all major operating systems and platforms. + +* xref:couchbase-lite::introduction.adoc[Go to Couchbase Lite Docs] diff --git a/modules/mobile-guides/partials/nav.adoc b/modules/mobile-guides/partials/nav.adoc new file mode 100644 index 000000000..d091d8859 --- /dev/null +++ b/modules/mobile-guides/partials/nav.adoc @@ -0,0 +1 @@ +* xref:mobile-guides:intro.adoc[] \ No newline at end of file diff --git a/modules/n1ql/assets/attachments/irregular-time-series.csv b/modules/n1ql/assets/attachments/irregular-time-series.csv new file mode 100644 index 000000000..6b500040d --- /dev/null +++ b/modules/n1ql/assets/attachments/irregular-time-series.csv @@ -0,0 +1,21 @@ +Date,Price,District +7/1/97,69950,South +10/1/97,67000,South +6/1/98,71500,South +7/1/98,73000,South +8/1/98,72000,South +8/1/01,115000,South +9/1/02,139950,South +6/1/04,195000,South +7/1/05,225000,South +8/1/06,210000,South +4/1/09,125000,South +11/1/09,163500,South +9/1/11,200000,South +12/1/12,212000,South +6/1/13,171000,South +8/1/15,252500,South +10/1/16,330000,South +6/1/17,290000,South +1/1/18,325000,South +6/1/19,370000,South \ No newline at end of file diff --git a/modules/n1ql/assets/attachments/regular-time-series.csv b/modules/n1ql/assets/attachments/regular-time-series.csv new file mode 100644 index 000000000..cb92b4f5a --- /dev/null +++ b/modules/n1ql/assets/attachments/regular-time-series.csv @@ -0,0 +1,366 @@ +Date,Low,High,Mean,Region +2013-1-2,-2,5,1.5,UK +2013-1-1,-2,5,1.5,UK +2013-1-3,-2,5,1.5,UK +2013-1-4,-2,5,1.5,UK +2013-1-5,-2,5,1.5,UK +2013-1-6,-2,5,1.5,UK +2013-1-7,-2,5,1.5,UK +2013-1-8,-2,5,1.5,UK +2013-1-9,-2,5,1.5,UK +2013-1-10,-2,5,1.5,UK +2013-1-11,-2,5,1.5,UK +2013-1-12,-2,5,1.5,UK +2013-1-13,-2,5,1.5,UK +2013-1-14,-2,5,1.5,UK +2013-1-15,-2,5,1.5,UK +2013-1-16,-2,5,1.5,UK +2013-1-17,-2,5,1.5,UK +2013-1-18,-2,5,1.5,UK +2013-1-19,-2,5,1.5,UK +2013-1-20,-2,5,1.5,UK +2013-1-21,-2,5,1.5,UK +2013-1-22,-2,5,1.5,UK +2013-1-23,-2,5,1.5,UK +2013-1-24,-2,5,1.5,UK +2013-1-25,-2,9,3.5,UK +2013-1-26,-2,9,3.5,UK +2013-1-27,-2,9,3.5,UK +2013-1-28,-2,9,3.5,UK +2013-1-29,-2,9,3.5,UK +2013-1-30,-2,9,3.5,UK +2013-1-31,-2,9,3.5,UK +2013-2-1,-1,9,4,UK +2013-2-2,-1,9,4,UK +2013-2-3,-1,9,4,UK +2013-2-4,-1,9,4,UK +2013-2-5,-1,9,4,UK +2013-2-6,-1,9,4,UK +2013-2-7,-1,9,4,UK +2013-2-8,-1,9,4,UK +2013-2-9,-1,9,4,UK +2013-2-10,-1,9,4,UK +2013-2-11,-1,9,4,UK +2013-2-12,-1,9,4,UK +2013-2-13,-1,9,4,UK +2013-2-14,-1,9,4,UK +2013-2-15,-1,9,4,UK +2013-2-16,-1,9,4,UK +2013-2-17,-1,9,4,UK +2013-2-18,-1,9,4,UK +2013-2-19,-1,9,4,UK +2013-2-20,-1,9,4,UK +2013-2-21,-1,9,4,UK +2013-2-22,-1,9,4,UK +2013-2-23,-1,9,4,UK +2013-2-24,-1,11,5,UK +2013-2-25,-1,11,5,UK +2013-2-26,-1,11,5,UK +2013-2-27,-1,11,5,UK +2013-2-28,-1,11,5,UK +2013-3-1,0,11,5.5,UK +2013-3-2,0,11,5.5,UK +2013-3-3,0,11,5.5,UK +2013-3-4,0,11,5.5,UK +2013-3-5,0,11,5.5,UK +2013-3-6,0,11,5.5,UK +2013-3-7,0,11,5.5,UK +2013-3-8,0,11,5.5,UK +2013-3-9,0,11,5.5,UK +2013-3-10,0,11,5.5,UK +2013-3-11,0,11,5.5,UK +2013-3-12,0,11,5.5,UK +2013-3-13,0,11,5.5,UK +2013-3-14,0,11,5.5,UK +2013-3-15,0,11,5.5,UK +2013-3-16,0,11,5.5,UK +2013-3-17,0,11,5.5,UK +2013-3-18,0,11,5.5,UK +2013-3-19,0,11,5.5,UK +2013-3-20,0,13,6.5,UK +2013-3-21,0,13,6.5,UK +2013-3-22,0,13,6.5,UK +2013-3-23,0,13,6.5,UK +2013-3-24,0,13,6.5,UK +2013-3-25,0,13,6.5,UK +2013-3-26,0,13,6.5,UK +2013-3-27,0,13,6.5,UK +2013-3-28,0,13,6.5,UK +2013-3-29,0,13,6.5,UK +2013-3-30,0,13,6.5,UK +2013-3-31,0,13,6.5,UK +2013-4-1,1,13,7,UK +2013-4-2,1,13,7,UK +2013-4-3,1,13,7,UK +2013-4-4,1,13,7,UK +2013-4-5,1,13,7,UK +2013-4-6,1,13,7,UK +2013-4-7,1,13,7,UK +2013-4-8,1,13,7,UK +2013-4-9,1,13,7,UK +2013-4-10,1,13,7,UK +2013-4-11,1,13,7,UK +2013-4-12,1,13,7,UK +2013-4-13,1,13,7,UK +2013-4-14,1,17,9,UK +2013-4-15,1,17,9,UK +2013-4-16,1,17,9,UK +2013-4-17,1,17,9,UK +2013-4-18,1,17,9,UK +2013-4-19,1,17,9,UK +2013-4-20,1,17,9,UK +2013-4-21,1,17,9,UK +2013-4-22,1,17,9,UK +2013-4-23,1,17,9,UK +2013-4-24,1,17,9,UK +2013-4-25,1,17,9,UK +2013-4-26,1,17,9,UK +2013-4-27,1,17,9,UK +2013-4-28,1,17,9,UK +2013-4-29,1,17,9,UK +2013-4-30,1,17,9,UK +2013-5-1,5,17,11,UK +2013-5-2,5,17,11,UK +2013-5-3,5,17,11,UK +2013-5-4,5,17,11,UK +2013-5-5,5,17,11,UK +2013-5-6,5,17,11,UK +2013-5-7,5,17,11,UK +2013-5-8,5,17,11,UK +2013-5-9,5,17,11,UK +2013-5-10,7,17,12,UK +2013-5-11,7,20,13.5,UK +2013-5-12,7,20,13.5,UK +2013-5-13,7,20,13.5,UK +2013-5-14,7,20,13.5,UK +2013-5-15,7,20,13.5,UK +2013-5-16,7,20,13.5,UK +2013-5-17,7,20,13.5,UK +2013-5-18,7,20,13.5,UK +2013-5-19,7,20,13.5,UK +2013-5-20,7,20,13.5,UK +2013-5-21,7,20,13.5,UK +2013-5-22,7,20,13.5,UK +2013-5-23,7,20,13.5,UK +2013-5-24,7,20,13.5,UK +2013-5-25,7,20,13.5,UK +2013-5-26,7,20,13.5,UK +2013-5-27,7,20,13.5,UK +2013-5-28,7,20,13.5,UK +2013-5-29,7,20,13.5,UK +2013-5-30,7,20,13.5,UK +2013-5-31,7,20,13.5,UK +2013-6-1,9,20,14.5,UK +2013-6-2,9,20,14.5,UK +2013-6-3,9,20,14.5,UK +2013-6-4,9,20,14.5,UK +2013-6-5,9,20,14.5,UK +2013-6-6,9,20,14.5,UK +2013-6-7,9,20,14.5,UK +2013-6-8,9,20,14.5,UK +2013-6-9,9,20,14.5,UK +2013-6-10,9,25,17,UK +2013-6-11,9,25,17,UK +2013-6-12,9,25,17,UK +2013-6-13,9,25,17,UK +2013-6-14,9,25,17,UK +2013-6-15,9,25,17,UK +2013-6-16,9,25,17,UK +2013-6-17,9,25,17,UK +2013-6-18,9,25,17,UK +2013-6-19,9,25,17,UK +2013-6-20,9,25,17,UK +2013-6-21,9,25,17,UK +2013-6-22,9,25,17,UK +2013-6-23,9,25,17,UK +2013-6-24,9,25,17,UK +2013-6-25,9,25,17,UK +2013-6-26,9,27,18,UK +2013-6-27,9,27,18,UK +2013-6-28,9,27,18,UK +2013-6-29,9,27,18,UK +2013-6-30,9,27,18,UK +2013-7-1,10,27,18.5,UK +2013-7-2,10,27,18.5,UK +2013-7-3,10,27,18.5,UK +2013-7-4,10,27,18.5,UK +2013-7-5,10,30,20,UK +2013-7-6,10,30,20,UK +2013-7-7,10,30,20,UK +2013-7-8,10,30,20,UK +2013-7-9,10,30,20,UK +2013-7-10,10,30,20,UK +2013-7-11,10,30,20,UK +2013-7-12,10,30,20,UK +2013-7-13,10,30,20,UK +2013-7-14,10,30,20,UK +2013-7-15,10,30,20,UK +2013-7-16,10,30,20,UK +2013-7-17,10,30,20,UK +2013-7-18,10,30,20,UK +2013-7-19,10,30,20,UK +2013-7-20,10,30,20,UK +2013-7-21,10,30,20,UK +2013-7-22,10,23,16.5,UK +2013-7-23,10,23,16.5,UK +2013-7-24,10,23,16.5,UK +2013-7-25,10,23,16.5,UK +2013-7-26,10,23,16.5,UK +2013-7-27,10,23,16.5,UK +2013-7-28,10,23,16.5,UK +2013-7-29,10,23,16.5,UK +2013-7-30,10,23,16.5,UK +2013-7-31,10,23,16.5,UK +2013-8-1,12,27,19.5,UK +2013-8-2,12,27,19.5,UK +2013-8-3,12,27,19.5,UK +2013-8-4,12,27,19.5,UK +2013-8-5,12,27,19.5,UK +2013-8-6,12,27,19.5,UK +2013-8-7,12,27,19.5,UK +2013-8-8,12,27,19.5,UK +2013-8-9,12,27,19.5,UK +2013-8-10,12,27,19.5,UK +2013-8-11,12,22,17,UK +2013-8-12,9,22,15.5,UK +2013-8-13,9,22,15.5,UK +2013-8-14,9,22,15.5,UK +2013-8-15,9,22,15.5,UK +2013-8-16,9,22,15.5,UK +2013-8-17,9,22,15.5,UK +2013-8-18,9,22,15.5,UK +2013-8-19,9,22,15.5,UK +2013-8-20,9,22,15.5,UK +2013-8-21,9,22,15.5,UK +2013-8-22,9,22,15.5,UK +2013-8-23,9,22,15.5,UK +2013-8-24,9,22,15.5,UK +2013-8-25,9,22,15.5,UK +2013-8-26,9,22,15.5,UK +2013-8-27,9,22,15.5,UK +2013-8-28,9,19,14,UK +2013-8-29,9,19,14,UK +2013-8-30,9,19,14,UK +2013-8-31,9,19,14,UK +2013-9-1,7,19,13,UK +2013-9-2,7,19,13,UK +2013-9-3,7,19,13,UK +2013-9-4,7,19,13,UK +2013-9-5,7,19,13,UK +2013-9-6,7,19,13,UK +2013-9-7,7,19,13,UK +2013-9-8,7,19,13,UK +2013-9-9,7,19,13,UK +2013-9-10,7,17,12,UK +2013-9-11,7,17,12,UK +2013-9-12,7,17,12,UK +2013-9-13,7,17,12,UK +2013-9-14,7,17,12,UK +2013-9-15,7,17,12,UK +2013-9-16,7,17,12,UK +2013-9-17,7,17,12,UK +2013-9-18,5,17,11,UK +2013-9-19,5,17,11,UK +2013-9-20,5,17,11,UK +2013-9-21,5,17,11,UK +2013-9-22,5,17,11,UK +2013-9-23,5,17,11,UK +2013-9-24,5,22,13.5,UK +2013-9-25,5,22,13.5,UK +2013-9-26,5,22,13.5,UK +2013-9-27,5,22,13.5,UK +2013-9-28,5,22,13.5,UK +2013-9-29,5,22,13.5,UK +2013-9-30,5,22,13.5,UK +2013-10-1,5,22,13.5,UK +2013-10-2,5,22,13.5,UK +2013-10-3,5,12,8.5,UK +2013-10-4,5,12,8.5,UK +2013-10-5,5,12,8.5,UK +2013-10-6,5,12,8.5,UK +2013-10-7,5,12,8.5,UK +2013-10-8,5,12,8.5,UK +2013-10-9,5,12,8.5,UK +2013-10-10,5,12,8.5,UK +2013-10-11,5,12,8.5,UK +2013-10-12,5,12,8.5,UK +2013-10-13,5,12,8.5,UK +2013-10-14,5,12,8.5,UK +2013-10-15,5,12,8.5,UK +2013-10-16,5,9,7,UK +2013-10-17,5,9,7,UK +2013-10-18,5,9,7,UK +2013-10-19,5,9,7,UK +2013-10-20,5,9,7,UK +2013-10-21,5,9,7,UK +2013-10-22,5,9,7,UK +2013-10-23,5,9,7,UK +2013-10-24,5,9,7,UK +2013-10-25,5,7,6,UK +2013-10-26,5,7,6,UK +2013-10-27,5,7,6,UK +2013-10-28,5,7,6,UK +2013-10-29,5,7,6,UK +2013-10-30,5,7,6,UK +2013-10-31,5,7,6,UK +2013-11-1,3,7,5,UK +2013-11-2,3,7,5,UK +2013-11-3,3,11,7,UK +2013-11-4,3,11,7,UK +2013-11-5,3,11,7,UK +2013-11-6,3,11,7,UK +2013-11-7,3,11,7,UK +2013-11-8,3,11,7,UK +2013-11-9,3,11,7,UK +2013-11-10,3,11,7,UK +2013-11-11,3,11,7,UK +2013-11-12,1,7,4,UK +2013-11-13,1,7,4,UK +2013-11-14,1,7,4,UK +2013-11-15,1,7,4,UK +2013-11-16,1,7,4,UK +2013-11-17,1,7,4,UK +2013-11-18,1,7,4,UK +2013-11-19,1,6,3.5,UK +2013-11-20,1,6,3.5,UK +2013-11-21,1,6,3.5,UK +2013-11-22,1,6,3.5,UK +2013-11-23,1,6,3.5,UK +2013-11-24,1,6,3.5,UK +2013-11-25,1,6,3.5,UK +2013-11-26,1,6,3.5,UK +2013-11-27,1,6,3.5,UK +2013-11-28,1,6,3.5,UK +2013-11-29,1,6,3.5,UK +2013-11-30,1,6,3.5,UK +2013-12-1,1,6,3.5,UK +2013-12-2,1,6,3.5,UK +2013-12-3,1,6,3.5,UK +2013-12-4,1,5,3,UK +2013-12-5,1,5,3,UK +2013-12-6,1,5,3,UK +2013-12-7,1,5,3,UK +2013-12-8,1,5,3,UK +2013-12-9,1,5,3,UK +2013-12-10,1,5,3,UK +2013-12-11,0,5,2.5,UK +2013-12-12,0,5,2.5,UK +2013-12-13,0,5,2.5,UK +2013-12-14,0,5,2.5,UK +2013-12-15,0,5,2.5,UK +2013-12-16,0,5,2.5,UK +2013-12-17,0,5,2.5,UK +2013-12-18,0,5,2.5,UK +2013-12-19,0,5,2.5,UK +2013-12-20,0,3,1.5,UK +2013-12-21,0,3,1.5,UK +2013-12-22,0,3,1.5,UK +2013-12-23,0,3,1.5,UK +2013-12-24,0,3,1.5,UK +2013-12-25,0,3,1.5,UK +2013-12-26,0,3,1.5,UK +2013-12-27,0,3,1.5,UK +2013-12-28,0,3,1.5,UK +2013-12-29,-1,3,1,UK +2013-12-30,-1,3,1,UK +2013-12-31,-1,3,1,UK \ No newline at end of file diff --git a/modules/n1ql/assets/images/CURL_Access.png b/modules/n1ql/assets/images/CURL_Access.png new file mode 100644 index 000000000..9308a1bc0 Binary files /dev/null and b/modules/n1ql/assets/images/CURL_Access.png differ diff --git a/modules/n1ql/assets/images/FROM_AnsiJoin-Ex4-BeerVisual1.png b/modules/n1ql/assets/images/FROM_AnsiJoin-Ex4-BeerVisual1.png new file mode 100644 index 000000000..a007ca445 Binary files /dev/null and b/modules/n1ql/assets/images/FROM_AnsiJoin-Ex4-BeerVisual1.png differ diff --git a/modules/n1ql/assets/images/FROM_AnsiJoin-Ex4-BeerVisual2.png b/modules/n1ql/assets/images/FROM_AnsiJoin-Ex4-BeerVisual2.png new file mode 100644 index 000000000..580c7963f Binary files /dev/null and b/modules/n1ql/assets/images/FROM_AnsiJoin-Ex4-BeerVisual2.png differ diff --git a/modules/n1ql/assets/images/GBAP_Ex0_QP_after55.png b/modules/n1ql/assets/images/GBAP_Ex0_QP_after55.png new file mode 100644 index 000000000..e3b5b7d83 Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_Ex0_QP_after55.png differ diff --git a/modules/n1ql/assets/images/GBAP_Ex0_QP_before55.png b/modules/n1ql/assets/images/GBAP_Ex0_QP_before55.png new file mode 100644 index 000000000..84983abee Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_Ex0_QP_before55.png differ diff --git a/modules/n1ql/assets/images/GBAP_Ex10_VP.png b/modules/n1ql/assets/images/GBAP_Ex10_VP.png new file mode 100644 index 000000000..6f5a1bcdb Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_Ex10_VP.png differ diff --git a/modules/n1ql/assets/images/GBAP_Ex2A_EP.png b/modules/n1ql/assets/images/GBAP_Ex2A_EP.png new file mode 100644 index 000000000..58d1e4eb4 Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_Ex2A_EP.png differ diff --git a/modules/n1ql/assets/images/GBAP_Ex4A_VP.png b/modules/n1ql/assets/images/GBAP_Ex4A_VP.png new file mode 100644 index 000000000..1407e5cf2 Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_Ex4A_VP.png differ diff --git a/modules/n1ql/assets/images/GBAP_ExB_Plan.png b/modules/n1ql/assets/images/GBAP_ExB_Plan.png new file mode 100644 index 000000000..f041ad69e Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_ExB_Plan.png differ diff --git a/modules/n1ql/assets/images/GBAP_ExC_Plan.png b/modules/n1ql/assets/images/GBAP_ExC_Plan.png new file mode 100644 index 000000000..c86f553db Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_ExC_Plan.png differ diff --git a/modules/n1ql/assets/images/GBAP_ExD2_Plan.png b/modules/n1ql/assets/images/GBAP_ExD2_Plan.png new file mode 100644 index 000000000..2857ee081 Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_ExD2_Plan.png differ diff --git a/modules/n1ql/assets/images/GBAP_ExD_Plan.png b/modules/n1ql/assets/images/GBAP_ExD_Plan.png new file mode 100644 index 000000000..babe09874 Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_ExD_Plan.png differ diff --git a/modules/n1ql/assets/images/GBAP_ExE_Plan.png b/modules/n1ql/assets/images/GBAP_ExE_Plan.png new file mode 100644 index 000000000..23cb0293a Binary files /dev/null and b/modules/n1ql/assets/images/GBAP_ExE_Plan.png differ diff --git a/modules/n1ql/assets/images/alter-index_servers_step1.png b/modules/n1ql/assets/images/alter-index_servers_step1.png new file mode 100644 index 000000000..edd32e5bf Binary files /dev/null and b/modules/n1ql/assets/images/alter-index_servers_step1.png differ diff --git a/modules/n1ql/assets/images/alter-index_servers_step2.png b/modules/n1ql/assets/images/alter-index_servers_step2.png new file mode 100644 index 000000000..17ea4d30e Binary files /dev/null and b/modules/n1ql/assets/images/alter-index_servers_step2.png differ diff --git a/modules/n1ql/assets/images/create-index-replica-id.png b/modules/n1ql/assets/images/create-index-replica-id.png new file mode 100644 index 000000000..8ea43b61e Binary files /dev/null and b/modules/n1ql/assets/images/create-index-replica-id.png differ diff --git a/modules/n1ql/assets/images/flex-fts-keyword-analyzer.png b/modules/n1ql/assets/images/flex-fts-keyword-analyzer.png new file mode 100644 index 000000000..4f71ed361 Binary files /dev/null and b/modules/n1ql/assets/images/flex-fts-keyword-analyzer.png differ diff --git a/modules/n1ql/assets/images/icon-query.svg b/modules/n1ql/assets/images/icon-query.svg new file mode 100644 index 000000000..fc5383986 --- /dev/null +++ b/modules/n1ql/assets/images/icon-query.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/n1ql/assets/images/join-order-hint.png b/modules/n1ql/assets/images/join-order-hint.png new file mode 100644 index 000000000..bc63b2176 Binary files /dev/null and b/modules/n1ql/assets/images/join-order-hint.png differ diff --git a/modules/n1ql/assets/images/join-order-optimize.png b/modules/n1ql/assets/images/join-order-optimize.png new file mode 100644 index 000000000..603e37198 Binary files /dev/null and b/modules/n1ql/assets/images/join-order-optimize.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/advise.png b/modules/n1ql/assets/images/n1ql-language-reference/advise.png new file mode 100644 index 000000000..eed8b247c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/advise.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/aggregate-function-name.png b/modules/n1ql/assets/images/n1ql-language-reference/aggregate-function-name.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/aggregate-function-name.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/aggregate-function.png b/modules/n1ql/assets/images/n1ql-language-reference/aggregate-function.png new file mode 100644 index 000000000..7063f1800 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/aggregate-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/aggregate-quantifier.png b/modules/n1ql/assets/images/n1ql-language-reference/aggregate-quantifier.png new file mode 100644 index 000000000..39c16ff65 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/aggregate-quantifier.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/alias.png b/modules/n1ql/assets/images/n1ql-language-reference/alias.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/alias.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/alter-index.png b/modules/n1ql/assets/images/n1ql-language-reference/alter-index.png new file mode 100644 index 000000000..2de22bde5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/alter-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/alter-sequence-options.png b/modules/n1ql/assets/images/n1ql-language-reference/alter-sequence-options.png new file mode 100644 index 000000000..e2ab0939c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/alter-sequence-options.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/alter-sequence.png b/modules/n1ql/assets/images/n1ql-language-reference/alter-sequence.png new file mode 100644 index 000000000..5d41d5fdf Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/alter-sequence.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/anchor-select.png b/modules/n1ql/assets/images/n1ql-language-reference/anchor-select.png new file mode 100644 index 000000000..8f7ce8495 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/anchor-select.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/and.png b/modules/n1ql/assets/images/n1ql-language-reference/and.png new file mode 100644 index 000000000..74cbfc925 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/and.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-hint-terms.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-hint-terms.png new file mode 100644 index 000000000..4b3a1ea65 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-hint-terms.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-clause.png new file mode 100644 index 000000000..1c3922dca Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-hints.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-hints.png new file mode 100644 index 000000000..23e520b3e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-hints.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-predicate.png new file mode 100644 index 000000000..2bd5d4f0d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-rhs.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-rhs.png new file mode 100644 index 000000000..1dd6d42f6 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-rhs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-type.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-type.png new file mode 100644 index 000000000..de6232405 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-join-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-actions.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-actions.png new file mode 100644 index 000000000..789305a36 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-actions.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-insert.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-insert.png new file mode 100644 index 000000000..6c58af303 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-insert.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-predicate.png new file mode 100644 index 000000000..2bd5d4f0d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-source.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-source.png new file mode 100644 index 000000000..b195a70c9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge-source.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge.png new file mode 100644 index 000000000..a59ddb408 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-merge.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-clause.png new file mode 100644 index 000000000..757128168 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-predicate.png new file mode 100644 index 000000000..2bd5d4f0d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-rhs.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-rhs.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-rhs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-type.png b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-type.png new file mode 100644 index 000000000..25cd28997 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ansi-nest-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/arithmetic-term.png b/modules/n1ql/assets/images/n1ql-language-reference/arithmetic-term.png new file mode 100644 index 000000000..687c1aed7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/arithmetic-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/array-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/array-expr.png new file mode 100644 index 000000000..7fd3ef5e5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/array-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/array.png b/modules/n1ql/assets/images/n1ql-language-reference/array.png new file mode 100644 index 000000000..8fb1b9a5e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/array.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/begin-transaction.png b/modules/n1ql/assets/images/n1ql-language-reference/begin-transaction.png new file mode 100644 index 000000000..b7735c469 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/begin-transaction.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/between-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/between-expr.png new file mode 100644 index 000000000..fd36a5ef2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/between-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/block-comment.png b/modules/n1ql/assets/images/n1ql-language-reference/block-comment.png new file mode 100644 index 000000000..0a54de47a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/block-comment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/block-hint-comment.png b/modules/n1ql/assets/images/n1ql-language-reference/block-hint-comment.png new file mode 100644 index 000000000..069160423 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/block-hint-comment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/body.png b/modules/n1ql/assets/images/n1ql-language-reference/body.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/body.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/boolean.png b/modules/n1ql/assets/images/n1ql-language-reference/boolean.png new file mode 100644 index 000000000..0a25b7be1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/boolean.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/bucket.png b/modules/n1ql/assets/images/n1ql-language-reference/bucket.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/bucket.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/build-index.png b/modules/n1ql/assets/images/n1ql-language-reference/build-index.png new file mode 100644 index 000000000..a351bc8ab Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/build-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/cache.png b/modules/n1ql/assets/images/n1ql-language-reference/cache.png new file mode 100644 index 000000000..f40c5e86a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/cache.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/case-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/case-expr.png new file mode 100644 index 000000000..352517b15 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/case-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/char.png b/modules/n1ql/assets/images/n1ql-language-reference/char.png new file mode 100644 index 000000000..7e5869984 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/char.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/collection-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/collection-expr.png new file mode 100644 index 000000000..6fe815207 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/collection-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/collection.png b/modules/n1ql/assets/images/n1ql-language-reference/collection.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/collection.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/comma-separated-join.png b/modules/n1ql/assets/images/n1ql-language-reference/comma-separated-join.png new file mode 100644 index 000000000..14856dcd8 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/comma-separated-join.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/comment.png b/modules/n1ql/assets/images/n1ql-language-reference/comment.png new file mode 100644 index 000000000..3820e135c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/comment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/commit-transaction.png b/modules/n1ql/assets/images/n1ql-language-reference/commit-transaction.png new file mode 100644 index 000000000..df46b6147 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/commit-transaction.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/comparison-term.png b/modules/n1ql/assets/images/n1ql-language-reference/comparison-term.png new file mode 100644 index 000000000..6ab5b5f00 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/comparison-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/concatenation-term.png b/modules/n1ql/assets/images/n1ql-language-reference/concatenation-term.png new file mode 100644 index 000000000..5f0bb4c0f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/concatenation-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/cond.png b/modules/n1ql/assets/images/n1ql-language-reference/cond.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/cond.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/construction-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/construction-expr.png new file mode 100644 index 000000000..4eba938f2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/construction-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-collection.png b/modules/n1ql/assets/images/n1ql-language-reference/create-collection.png new file mode 100644 index 000000000..6278a2f8a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-collection.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png b/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png new file mode 100644 index 000000000..d8a611c09 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-function-inline.png b/modules/n1ql/assets/images/n1ql-language-reference/create-function-inline.png new file mode 100644 index 000000000..52a883508 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-function-inline.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-function.png b/modules/n1ql/assets/images/n1ql-language-reference/create-function.png new file mode 100644 index 000000000..b3ef9f005 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-index.png b/modules/n1ql/assets/images/n1ql-language-reference/create-index.png new file mode 100644 index 000000000..2dc3ec5a0 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-primary-index.png b/modules/n1ql/assets/images/n1ql-language-reference/create-primary-index.png new file mode 100644 index 000000000..be7e89910 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-primary-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-scope.png b/modules/n1ql/assets/images/n1ql-language-reference/create-scope.png new file mode 100644 index 000000000..dfff0f01c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-scope.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-sequence-options.png b/modules/n1ql/assets/images/n1ql-language-reference/create-sequence-options.png new file mode 100644 index 000000000..8e944a60d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-sequence-options.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-sequence.png b/modules/n1ql/assets/images/n1ql-language-reference/create-sequence.png new file mode 100644 index 000000000..4159e08d8 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-sequence.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/create-statement.png new file mode 100644 index 000000000..9abbc3084 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/create-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/cume-dist-function.png b/modules/n1ql/assets/images/n1ql-language-reference/cume-dist-function.png new file mode 100644 index 000000000..174dbfdc7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/cume-dist-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/cycle-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/cycle-clause.png new file mode 100644 index 000000000..ba4916278 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/cycle-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/cycle.png b/modules/n1ql/assets/images/n1ql-language-reference/cycle.png new file mode 100644 index 000000000..bb3512245 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/cycle.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/dcl-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/dcl-statement.png new file mode 100644 index 000000000..f94539500 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/dcl-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ddl-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/ddl-statement.png new file mode 100644 index 000000000..e551fecf5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ddl-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/default.png b/modules/n1ql/assets/images/n1ql-language-reference/default.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/default.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/delete-all.png b/modules/n1ql/assets/images/n1ql-language-reference/delete-all.png new file mode 100644 index 000000000..ccb891ee2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/delete-all.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/delete-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/delete-clause.png new file mode 100644 index 000000000..1be7e5508 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/delete-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/delete-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/delete-expr.png new file mode 100644 index 000000000..84709e9cb Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/delete-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/delete.png b/modules/n1ql/assets/images/n1ql-language-reference/delete.png new file mode 100644 index 000000000..4590d36b0 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/delete.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/dense-rank-function.png b/modules/n1ql/assets/images/n1ql-language-reference/dense-rank-function.png new file mode 100644 index 000000000..c90110ae5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/dense-rank-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/dml-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/dml-statement.png new file mode 100644 index 000000000..4d17a8b8d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/dml-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/dql-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/dql-statement.png new file mode 100644 index 000000000..a12123dce Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/dql-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-collection.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-collection.png new file mode 100644 index 000000000..a2f3f5570 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-collection.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-function.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-function.png new file mode 100644 index 000000000..9c5933ee4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-index.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-index.png new file mode 100644 index 000000000..2558a10c0 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-primary-index.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-primary-index.png new file mode 100644 index 000000000..4f0d73357 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-primary-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-scope.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-scope.png new file mode 100644 index 000000000..0b91aca11 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-scope.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-sequence.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-sequence.png new file mode 100644 index 000000000..b284d04b7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-sequence.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/drop-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/drop-statement.png new file mode 100644 index 000000000..ad8f3791c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/drop-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/element-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/element-expr.png new file mode 100644 index 000000000..97293dac1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/element-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/element.png b/modules/n1ql/assets/images/n1ql-language-reference/element.png new file mode 100644 index 000000000..956dac77d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/element.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/end-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/end-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/end-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/escaped-identifier.png b/modules/n1ql/assets/images/n1ql-language-reference/escaped-identifier.png new file mode 100644 index 000000000..b1c1e2678 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/escaped-identifier.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/execute-function.png b/modules/n1ql/assets/images/n1ql-language-reference/execute-function.png new file mode 100644 index 000000000..2afbd1dbe Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/execute-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/execute.png b/modules/n1ql/assets/images/n1ql-language-reference/execute.png new file mode 100644 index 000000000..5065ee1f4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/execute.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/exists-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/exists-expr.png new file mode 100644 index 000000000..71e5f6695 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/exists-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/explain-function.png b/modules/n1ql/assets/images/n1ql-language-reference/explain-function.png new file mode 100644 index 000000000..1b16d6d76 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/explain-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/explain.png b/modules/n1ql/assets/images/n1ql-language-reference/explain.png new file mode 100644 index 000000000..4cd35f825 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/explain.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/exponent.png b/modules/n1ql/assets/images/n1ql-language-reference/exponent.png new file mode 100644 index 000000000..df9f92dee Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/exponent.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/expr.png b/modules/n1ql/assets/images/n1ql-language-reference/expr.png new file mode 100644 index 000000000..a4c35bdfe Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/field-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/field-expr.png new file mode 100644 index 000000000..8e68fc656 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/field-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/filter-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/filter-clause.png new file mode 100644 index 000000000..1703e9708 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/filter-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/first-value-function.png b/modules/n1ql/assets/images/n1ql-language-reference/first-value-function.png new file mode 100644 index 000000000..13338987b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/first-value-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/format-specifier.png b/modules/n1ql/assets/images/n1ql-language-reference/format-specifier.png new file mode 100644 index 000000000..2dd4fe4fa Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/format-specifier.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/fraction.png b/modules/n1ql/assets/images/n1ql-language-reference/fraction.png new file mode 100644 index 000000000..06c267547 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/fraction.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/from-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/from-clause.png new file mode 100644 index 000000000..9c2bb8900 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/from-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/from-generic.png b/modules/n1ql/assets/images/n1ql-language-reference/from-generic.png new file mode 100644 index 000000000..3e0def7cb Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/from-generic.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/from-keyspace.png b/modules/n1ql/assets/images/n1ql-language-reference/from-keyspace.png new file mode 100644 index 000000000..15dbccea4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/from-keyspace.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/from-select.png b/modules/n1ql/assets/images/n1ql-language-reference/from-select.png new file mode 100644 index 000000000..2a0677b68 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/from-select.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/from-subquery.png b/modules/n1ql/assets/images/n1ql-language-reference/from-subquery.png new file mode 100644 index 000000000..1fbb406b9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/from-subquery.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/from-terms.png b/modules/n1ql/assets/images/n1ql-language-reference/from-terms.png new file mode 100644 index 000000000..f7eb0da88 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/from-terms.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/fts-hint-json.png b/modules/n1ql/assets/images/n1ql-language-reference/fts-hint-json.png new file mode 100644 index 000000000..4d01d76c9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/fts-hint-json.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/fts-hint-simple.png b/modules/n1ql/assets/images/n1ql-language-reference/fts-hint-simple.png new file mode 100644 index 000000000..2ec1f4ea1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/fts-hint-simple.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/full-array-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/full-array-expr.png new file mode 100644 index 000000000..3aa364d49 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/full-array-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/function-call.png b/modules/n1ql/assets/images/n1ql-language-reference/function-call.png new file mode 100644 index 000000000..a7c93a8e3 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/function-call.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/function-name.png b/modules/n1ql/assets/images/n1ql-language-reference/function-name.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/function-name.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/function.png b/modules/n1ql/assets/images/n1ql-language-reference/function.png new file mode 100644 index 000000000..61fccd954 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/generic-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/generic-expr.png new file mode 100644 index 000000000..4bff1888f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/generic-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/grant.png b/modules/n1ql/assets/images/n1ql-language-reference/grant.png new file mode 100644 index 000000000..5a1b680e8 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/grant.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/group-as-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/group-as-clause.png new file mode 100644 index 000000000..9740afa53 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/group-as-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/group-by-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/group-by-clause.png new file mode 100644 index 000000000..514ed0d41 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/group-by-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/group-term.png b/modules/n1ql/assets/images/n1ql-language-reference/group-term.png new file mode 100644 index 000000000..e7b543e73 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/group-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/gsi-hint-json.png b/modules/n1ql/assets/images/n1ql-language-reference/gsi-hint-json.png new file mode 100644 index 000000000..d207f6e0e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/gsi-hint-json.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/gsi-hint-simple.png b/modules/n1ql/assets/images/n1ql-language-reference/gsi-hint-simple.png new file mode 100644 index 000000000..2593a87b6 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/gsi-hint-simple.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hash-array.png b/modules/n1ql/assets/images/n1ql-language-reference/hash-array.png new file mode 100644 index 000000000..357df4195 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hash-array.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hash-hint-json.png b/modules/n1ql/assets/images/n1ql-language-reference/hash-hint-json.png new file mode 100644 index 000000000..d60ba48fd Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hash-hint-json.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hash-hint-simple.png b/modules/n1ql/assets/images/n1ql-language-reference/hash-hint-simple.png new file mode 100644 index 000000000..5256d20ed Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hash-hint-simple.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hash-object.png b/modules/n1ql/assets/images/n1ql-language-reference/hash-object.png new file mode 100644 index 000000000..bc38985b7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hash-object.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/having-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/having-clause.png new file mode 100644 index 000000000..7864bdff1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/having-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hex.png b/modules/n1ql/assets/images/n1ql-language-reference/hex.png new file mode 100644 index 000000000..395e6d74f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hex.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hint-comment.png b/modules/n1ql/assets/images/n1ql-language-reference/hint-comment.png new file mode 100644 index 000000000..8913568b1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hint-comment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/hints.png b/modules/n1ql/assets/images/n1ql-language-reference/hints.png new file mode 100644 index 000000000..078d83ecb Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/hints.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/identifier.png b/modules/n1ql/assets/images/n1ql-language-reference/identifier.png new file mode 100644 index 000000000..abae035b3 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/identifier.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/in-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/in-expr.png new file mode 100644 index 000000000..173105b77 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/in-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/include-missing.png b/modules/n1ql/assets/images/n1ql-language-reference/include-missing.png new file mode 100644 index 000000000..7842511f3 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/include-missing.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/increment-by.png b/modules/n1ql/assets/images/n1ql-language-reference/increment-by.png new file mode 100644 index 000000000..c9e25ea7a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/increment-by.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-array.png b/modules/n1ql/assets/images/n1ql-language-reference/index-array.png new file mode 100644 index 000000000..a24cad83d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-array.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/index-clause.png new file mode 100644 index 000000000..386c615ae Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/index-expr.png new file mode 100644 index 000000000..b983771fc Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-join-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/index-join-clause.png new file mode 100644 index 000000000..5eed8d28e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-join-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-join-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/index-join-predicate.png new file mode 100644 index 000000000..8000d7df3 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-join-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-join-rhs.png b/modules/n1ql/assets/images/n1ql-language-reference/index-join-rhs.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-join-rhs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-join-type.png b/modules/n1ql/assets/images/n1ql-language-reference/index-join-type.png new file mode 100644 index 000000000..25cd28997 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-join-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-key-object.png b/modules/n1ql/assets/images/n1ql-language-reference/index-key-object.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-key-object.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-key.png b/modules/n1ql/assets/images/n1ql-language-reference/index-key.png new file mode 100644 index 000000000..28f6fb377 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-key.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-name.png b/modules/n1ql/assets/images/n1ql-language-reference/index-name.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-name.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-nest-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-clause.png new file mode 100644 index 000000000..22d594f1a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-nest-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-predicate.png new file mode 100644 index 000000000..165fb5e38 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-nest-rhs.png b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-rhs.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-rhs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-nest-type.png b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-type.png new file mode 100644 index 000000000..25cd28997 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-nest-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-object.png b/modules/n1ql/assets/images/n1ql-language-reference/index-object.png new file mode 100644 index 000000000..d71baec1a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-object.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-order.png b/modules/n1ql/assets/images/n1ql-language-reference/index-order.png new file mode 100644 index 000000000..58083de80 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-order.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-partition.png b/modules/n1ql/assets/images/n1ql-language-reference/index-partition.png new file mode 100644 index 000000000..25bbd9a9a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-partition.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-path.png b/modules/n1ql/assets/images/n1ql-language-reference/index-path.png new file mode 100644 index 000000000..d017c09aa Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-path.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-ref.png b/modules/n1ql/assets/images/n1ql-language-reference/index-ref.png new file mode 100644 index 000000000..cf4e0db27 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-ref.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-term.png b/modules/n1ql/assets/images/n1ql-language-reference/index-term.png new file mode 100644 index 000000000..6fca45c57 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-type.png b/modules/n1ql/assets/images/n1ql-language-reference/index-type.png new file mode 100644 index 000000000..937adbd1c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-using.png b/modules/n1ql/assets/images/n1ql-language-reference/index-using.png new file mode 100644 index 000000000..df6db283b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-using.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/index-with.png b/modules/n1ql/assets/images/n1ql-language-reference/index-with.png new file mode 100644 index 000000000..a5130be94 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/index-with.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/indexes-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/indexes-clause.png new file mode 100644 index 000000000..227b88aea Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/indexes-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/indexes-property.png b/modules/n1ql/assets/images/n1ql-language-reference/indexes-property.png new file mode 100644 index 000000000..cb586b345 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/indexes-property.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/infer.png b/modules/n1ql/assets/images/n1ql-language-reference/infer.png new file mode 100644 index 000000000..29c5870e2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/infer.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/insert-select.png b/modules/n1ql/assets/images/n1ql-language-reference/insert-select.png new file mode 100644 index 000000000..dd89d9122 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/insert-select.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/insert-values.png b/modules/n1ql/assets/images/n1ql-language-reference/insert-values.png new file mode 100644 index 000000000..5652de573 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/insert-values.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/insert.png b/modules/n1ql/assets/images/n1ql-language-reference/insert.png new file mode 100644 index 000000000..85adaf4a1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/insert.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/integer.png b/modules/n1ql/assets/images/n1ql-language-reference/integer.png new file mode 100644 index 000000000..f9947999e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/integer.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/is-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/is-expr.png new file mode 100644 index 000000000..697cda84b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/is-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/javascript.png b/modules/n1ql/assets/images/n1ql-language-reference/javascript.png new file mode 100644 index 000000000..42231623b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/javascript.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/join-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/join-clause.png new file mode 100644 index 000000000..b1caa379c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/join-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/json-hint-object.png b/modules/n1ql/assets/images/n1ql-language-reference/json-hint-object.png new file mode 100644 index 000000000..e6e53b31f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/json-hint-object.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/json-hint.png b/modules/n1ql/assets/images/n1ql-language-reference/json-hint.png new file mode 100644 index 000000000..ecf058aa7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/json-hint.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/key-attribs.png b/modules/n1ql/assets/images/n1ql-language-reference/key-attribs.png new file mode 100644 index 000000000..91d65dbcc Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/key-attribs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/key-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/key-clause.png new file mode 100644 index 000000000..2677dc3b5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/key-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/key.png b/modules/n1ql/assets/images/n1ql-language-reference/key.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/key.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-array.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-array.png new file mode 100644 index 000000000..bac29a4ff Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-array.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-full.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-full.png new file mode 100644 index 000000000..72e9f2a41 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-full.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-object.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-object.png new file mode 100644 index 000000000..01553a1c0 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-object.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-partial.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-partial.png new file mode 100644 index 000000000..7f2c64736 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-partial.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-path.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-path.png new file mode 100644 index 000000000..9d6453695 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-path.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-prefix.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-prefix.png new file mode 100644 index 000000000..771e58794 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-prefix.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-property.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-property.png new file mode 100644 index 000000000..515080dda Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-property.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace-ref.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-ref.png new file mode 100644 index 000000000..ff3d15917 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace-ref.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/keyspace.png b/modules/n1ql/assets/images/n1ql-language-reference/keyspace.png new file mode 100644 index 000000000..dbb476a12 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/keyspace.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lag-function.png b/modules/n1ql/assets/images/n1ql-language-reference/lag-function.png new file mode 100644 index 000000000..cbabef58b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lag-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/last-value-function.png b/modules/n1ql/assets/images/n1ql-language-reference/last-value-function.png new file mode 100644 index 000000000..34eb03ac8 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/last-value-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lead-function.png b/modules/n1ql/assets/images/n1ql-language-reference/lead-function.png new file mode 100644 index 000000000..07bc88776 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lead-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lead-key-attribs.png b/modules/n1ql/assets/images/n1ql-language-reference/lead-key-attribs.png new file mode 100644 index 000000000..d88ddaab3 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lead-key-attribs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/let-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/let-clause.png new file mode 100644 index 000000000..ab16c883b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/let-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/letting-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/letting-clause.png new file mode 100644 index 000000000..990344316 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/letting-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/library.png b/modules/n1ql/assets/images/n1ql-language-reference/library.png new file mode 100644 index 000000000..42231623b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/library.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/like-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/like-expr.png new file mode 100644 index 000000000..64127f1e6 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/like-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/limit-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/limit-clause.png new file mode 100644 index 000000000..0600ef3ff Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/limit-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/line-comment.png b/modules/n1ql/assets/images/n1ql-language-reference/line-comment.png new file mode 100644 index 000000000..608dd34be Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/line-comment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/line-hint-comment.png b/modules/n1ql/assets/images/n1ql-language-reference/line-hint-comment.png new file mode 100644 index 000000000..cfdf569ac Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/line-hint-comment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/literal.png b/modules/n1ql/assets/images/n1ql-language-reference/literal.png new file mode 100644 index 000000000..6e1ecd63c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/literal.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/logical-term.png b/modules/n1ql/assets/images/n1ql-language-reference/logical-term.png new file mode 100644 index 000000000..6d5c955c9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/logical-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-clause.png new file mode 100644 index 000000000..fd336c300 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-predicate.png new file mode 100644 index 000000000..44cb4a23c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-rhs.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-rhs.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-rhs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-type.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-type.png new file mode 100644 index 000000000..25cd28997 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-join-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-actions.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-actions.png new file mode 100644 index 000000000..04c791a3d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-actions.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-insert.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-insert.png new file mode 100644 index 000000000..c827666d9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-insert.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-predicate.png new file mode 100644 index 000000000..f7268400b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-source.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-source.png new file mode 100644 index 000000000..fccc90a6d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge-source.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge.png new file mode 100644 index 000000000..711f7292a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-merge.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-clause.png new file mode 100644 index 000000000..d0b84b65c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-predicate.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-predicate.png new file mode 100644 index 000000000..941732b76 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-predicate.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-rhs.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-rhs.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-rhs.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-type.png b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-type.png new file mode 100644 index 000000000..25cd28997 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/lookup-nest-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/maxvalue.png b/modules/n1ql/assets/images/n1ql-language-reference/maxvalue.png new file mode 100644 index 000000000..dab60d082 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/maxvalue.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/merge-delete.png b/modules/n1ql/assets/images/n1ql-language-reference/merge-delete.png new file mode 100644 index 000000000..f8df6bd69 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/merge-delete.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/merge-source-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/merge-source-expr.png new file mode 100644 index 000000000..e7b543e73 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/merge-source-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/merge-source-keyspace.png b/modules/n1ql/assets/images/n1ql-language-reference/merge-source-keyspace.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/merge-source-keyspace.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/merge-source-subquery.png b/modules/n1ql/assets/images/n1ql-language-reference/merge-source-subquery.png new file mode 100644 index 000000000..1fbb406b9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/merge-source-subquery.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/merge-update.png b/modules/n1ql/assets/images/n1ql-language-reference/merge-update.png new file mode 100644 index 000000000..ad8be3ee5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/merge-update.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/merge.png b/modules/n1ql/assets/images/n1ql-language-reference/merge.png new file mode 100644 index 000000000..5d09d1b94 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/merge.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/minvalue.png b/modules/n1ql/assets/images/n1ql-language-reference/minvalue.png new file mode 100644 index 000000000..e44e0c9b4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/minvalue.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/missing.png b/modules/n1ql/assets/images/n1ql-language-reference/missing.png new file mode 100644 index 000000000..070f89d4c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/missing.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/multiple-hints.png b/modules/n1ql/assets/images/n1ql-language-reference/multiple-hints.png new file mode 100644 index 000000000..d0ae0cfcd Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/multiple-hints.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/name-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/name-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/name-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/name-var.png b/modules/n1ql/assets/images/n1ql-language-reference/name-var.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/name-var.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/name.png b/modules/n1ql/assets/images/n1ql-language-reference/name.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/name.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/namespace.png b/modules/n1ql/assets/images/n1ql-language-reference/namespace.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/namespace.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nest-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/nest-clause.png new file mode 100644 index 000000000..872a6c292 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nest-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nested-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/nested-expr.png new file mode 100644 index 000000000..aba7ec91e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nested-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/next-val-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/next-val-expr.png new file mode 100644 index 000000000..95a6fd295 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/next-val-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nl-hint-json.png b/modules/n1ql/assets/images/n1ql-language-reference/nl-hint-json.png new file mode 100644 index 000000000..d75a08674 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nl-hint-json.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nl-hint-simple.png b/modules/n1ql/assets/images/n1ql-language-reference/nl-hint-simple.png new file mode 100644 index 000000000..33acaaa40 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nl-hint-simple.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/not.png b/modules/n1ql/assets/images/n1ql-language-reference/not.png new file mode 100644 index 000000000..437454f5b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/not.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nth-value-function.png b/modules/n1ql/assets/images/n1ql-language-reference/nth-value-function.png new file mode 100644 index 000000000..0a294fce2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nth-value-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nthval-from.png b/modules/n1ql/assets/images/n1ql-language-reference/nthval-from.png new file mode 100644 index 000000000..d8e95b68b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nthval-from.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ntile-function.png b/modules/n1ql/assets/images/n1ql-language-reference/ntile-function.png new file mode 100644 index 000000000..9e87d4da4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ntile-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/null.png b/modules/n1ql/assets/images/n1ql-language-reference/null.png new file mode 100644 index 000000000..1018f4138 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/null.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/nulls-treatment.png b/modules/n1ql/assets/images/n1ql-language-reference/nulls-treatment.png new file mode 100644 index 000000000..aa13f3847 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/nulls-treatment.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/num_tiles.png b/modules/n1ql/assets/images/n1ql-language-reference/num_tiles.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/num_tiles.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/number.png b/modules/n1ql/assets/images/n1ql-language-reference/number.png new file mode 100644 index 000000000..d67d2e897 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/number.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/obj.png b/modules/n1ql/assets/images/n1ql-language-reference/obj.png new file mode 100644 index 000000000..42231623b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/obj.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/object.png b/modules/n1ql/assets/images/n1ql-language-reference/object.png new file mode 100644 index 000000000..fb31f8672 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/object.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/offset-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/offset-clause.png new file mode 100644 index 000000000..4faa43d15 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/offset-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/offset.png b/modules/n1ql/assets/images/n1ql-language-reference/offset.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/offset.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/option-property.png b/modules/n1ql/assets/images/n1ql-language-reference/option-property.png new file mode 100644 index 000000000..ed88683da Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/option-property.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/options-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/options-clause.png new file mode 100644 index 000000000..fe81f5d05 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/options-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/options.png b/modules/n1ql/assets/images/n1ql-language-reference/options.png new file mode 100644 index 000000000..64616778f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/options.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/or.png b/modules/n1ql/assets/images/n1ql-language-reference/or.png new file mode 100644 index 000000000..2dec84bd1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/or.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/order-by-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/order-by-clause.png new file mode 100644 index 000000000..e99595a2e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/order-by-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ordered-hint-json.png b/modules/n1ql/assets/images/n1ql-language-reference/ordered-hint-json.png new file mode 100644 index 000000000..f10206cc2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ordered-hint-json.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ordered-hint-simple.png b/modules/n1ql/assets/images/n1ql-language-reference/ordered-hint-simple.png new file mode 100644 index 000000000..1b74def4e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ordered-hint-simple.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ordering-term.png b/modules/n1ql/assets/images/n1ql-language-reference/ordering-term.png new file mode 100644 index 000000000..7cec99980 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ordering-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ordinary-function.png b/modules/n1ql/assets/images/n1ql-language-reference/ordinary-function.png new file mode 100644 index 000000000..8c8c2941f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ordinary-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/other-hint-terms.png b/modules/n1ql/assets/images/n1ql-language-reference/other-hint-terms.png new file mode 100644 index 000000000..d7f11e919 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/other-hint-terms.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/other-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/other-statement.png new file mode 100644 index 000000000..11e4e38d9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/other-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/over-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/over-clause.png new file mode 100644 index 000000000..64fb86c7f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/over-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/pairs-function.png b/modules/n1ql/assets/images/n1ql-language-reference/pairs-function.png new file mode 100644 index 000000000..3254fbbce Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/pairs-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/parameters.png b/modules/n1ql/assets/images/n1ql-language-reference/parameters.png new file mode 100644 index 000000000..c2ad12e9d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/parameters.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/params.png b/modules/n1ql/assets/images/n1ql-language-reference/params.png new file mode 100644 index 000000000..0111b2ff7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/params.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/partition-key-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/partition-key-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/partition-key-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/path.png b/modules/n1ql/assets/images/n1ql-language-reference/path.png new file mode 100644 index 000000000..7843c1283 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/path.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/percent-rank-function.png b/modules/n1ql/assets/images/n1ql-language-reference/percent-rank-function.png new file mode 100644 index 000000000..f2f83f387 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/percent-rank-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/position.png b/modules/n1ql/assets/images/n1ql-language-reference/position.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/position.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/prepare.png b/modules/n1ql/assets/images/n1ql-language-reference/prepare.png new file mode 100644 index 000000000..0093a5bd0 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/prepare.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/prev-val-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/prev-val-expr.png new file mode 100644 index 000000000..55ebd97dd Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/prev-val-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/projection.png b/modules/n1ql/assets/images/n1ql-language-reference/projection.png new file mode 100644 index 000000000..537aac7da Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/projection.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/range-cond.png b/modules/n1ql/assets/images/n1ql-language-reference/range-cond.png new file mode 100644 index 000000000..8ea94b80a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/range-cond.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/range-xform.png b/modules/n1ql/assets/images/n1ql-language-reference/range-xform.png new file mode 100644 index 000000000..43d7a8a93 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/range-xform.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/range.png b/modules/n1ql/assets/images/n1ql-language-reference/range.png new file mode 100644 index 000000000..8e6b0c295 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/range.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rank-function.png b/modules/n1ql/assets/images/n1ql-language-reference/rank-function.png new file mode 100644 index 000000000..2f11f8de8 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rank-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/ratio-to-report-function.png b/modules/n1ql/assets/images/n1ql-language-reference/ratio-to-report-function.png new file mode 100644 index 000000000..e0d265dba Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/ratio-to-report-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/recursive-select-term.png b/modules/n1ql/assets/images/n1ql-language-reference/recursive-select-term.png new file mode 100644 index 000000000..e6b0335cb Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/recursive-select-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/recursive-select.png b/modules/n1ql/assets/images/n1ql-language-reference/recursive-select.png new file mode 100644 index 000000000..19a655dc7 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/recursive-select.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/relational-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/relational-expr.png new file mode 100644 index 000000000..aeeec2685 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/relational-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/request.png b/modules/n1ql/assets/images/n1ql-language-reference/request.png new file mode 100644 index 000000000..c60259a0d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/request.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/restart-with.png b/modules/n1ql/assets/images/n1ql-language-reference/restart-with.png new file mode 100644 index 000000000..014c6ee95 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/restart-with.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/result-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/result-expr.png new file mode 100644 index 000000000..48ca9a2e2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/result-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/returning-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/returning-clause.png new file mode 100644 index 000000000..57cf7a25e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/returning-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/revoke.png b/modules/n1ql/assets/images/n1ql-language-reference/revoke.png new file mode 100644 index 000000000..91d35cb63 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/revoke.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rhs-generic-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/rhs-generic-expr.png new file mode 100644 index 000000000..ed439c2be Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rhs-generic-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rhs-generic.png b/modules/n1ql/assets/images/n1ql-language-reference/rhs-generic.png new file mode 100644 index 000000000..e7b543e73 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rhs-generic.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rhs-keyspace.png b/modules/n1ql/assets/images/n1ql-language-reference/rhs-keyspace.png new file mode 100644 index 000000000..447c520d0 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rhs-keyspace.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rhs-subquery.png b/modules/n1ql/assets/images/n1ql-language-reference/rhs-subquery.png new file mode 100644 index 000000000..1fbb406b9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rhs-subquery.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/role.png b/modules/n1ql/assets/images/n1ql-language-reference/role.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/role.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rollback-transaction.png b/modules/n1ql/assets/images/n1ql-language-reference/rollback-transaction.png new file mode 100644 index 000000000..011a68bdb Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rollback-transaction.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/row-number-function.png b/modules/n1ql/assets/images/n1ql-language-reference/row-number-function.png new file mode 100644 index 000000000..ffec6618b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/row-number-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/rr-2.0.png b/modules/n1ql/assets/images/n1ql-language-reference/rr-2.0.png new file mode 100644 index 000000000..ef1a5a29f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/rr-2.0.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/savepoint.png b/modules/n1ql/assets/images/n1ql-language-reference/savepoint.png new file mode 100644 index 000000000..202952ffd Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/savepoint.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/savepointname.png b/modules/n1ql/assets/images/n1ql-language-reference/savepointname.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/savepointname.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/scope.png b/modules/n1ql/assets/images/n1ql-language-reference/scope.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/scope.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/search-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/search-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/search-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/searched-case-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/searched-case-expr.png new file mode 100644 index 000000000..02cb6578d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/searched-case-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/select-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/select-clause.png new file mode 100644 index 000000000..187f34128 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/select-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/select-from.png b/modules/n1ql/assets/images/n1ql-language-reference/select-from.png new file mode 100644 index 000000000..36a1d0fe4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/select-from.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/select-term.png b/modules/n1ql/assets/images/n1ql-language-reference/select-term.png new file mode 100644 index 000000000..5f87e916c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/select-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/select.png b/modules/n1ql/assets/images/n1ql-language-reference/select.png new file mode 100644 index 000000000..55290291b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/select.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/sequence-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/sequence-expr.png new file mode 100644 index 000000000..42bc02a20 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/sequence-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/sequence-with.png b/modules/n1ql/assets/images/n1ql-language-reference/sequence-with.png new file mode 100644 index 000000000..a5130be94 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/sequence-with.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/sequence.png b/modules/n1ql/assets/images/n1ql-language-reference/sequence.png new file mode 100644 index 000000000..bbcb7600a Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/sequence.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/set-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/set-clause.png new file mode 100644 index 000000000..d37791c89 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/set-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/set-op.png b/modules/n1ql/assets/images/n1ql-language-reference/set-op.png new file mode 100644 index 000000000..4e855242c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/set-op.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/set-transaction.png b/modules/n1ql/assets/images/n1ql-language-reference/set-transaction.png new file mode 100644 index 000000000..de1b93ac9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/set-transaction.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/simple-array-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/simple-array-expr.png new file mode 100644 index 000000000..aa7a4734c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/simple-array-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/simple-case-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/simple-case-expr.png new file mode 100644 index 000000000..efc909705 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/simple-case-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/simple-hint-sequence.png b/modules/n1ql/assets/images/n1ql-language-reference/simple-hint-sequence.png new file mode 100644 index 000000000..316402b5c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/simple-hint-sequence.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/simple-hint.png b/modules/n1ql/assets/images/n1ql-language-reference/simple-hint.png new file mode 100644 index 000000000..78ed28d6b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/simple-hint.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/slice-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/slice-expr.png new file mode 100644 index 000000000..a02b7242c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/slice-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/start-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/start-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/start-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/start-with.png b/modules/n1ql/assets/images/n1ql-language-reference/start-with.png new file mode 100644 index 000000000..d64070a5f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/start-with.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/statement.png b/modules/n1ql/assets/images/n1ql-language-reference/statement.png new file mode 100644 index 000000000..07b2451e1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/string.png b/modules/n1ql/assets/images/n1ql-language-reference/string.png new file mode 100644 index 000000000..a8a1c45bf Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/string.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/subquery-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/subquery-expr.png new file mode 100644 index 000000000..25844dc93 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/subquery-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/subselect.png b/modules/n1ql/assets/images/n1ql-language-reference/subselect.png new file mode 100644 index 000000000..0fb461888 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/subselect.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/target-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/target-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/target-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/target-keyspace.png b/modules/n1ql/assets/images/n1ql-language-reference/target-keyspace.png new file mode 100644 index 000000000..4f416817c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/target-keyspace.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/tcl-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/tcl-statement.png new file mode 100644 index 000000000..85931a42d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/tcl-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/unescaped-identifier.png b/modules/n1ql/assets/images/n1ql-language-reference/unescaped-identifier.png new file mode 100644 index 000000000..8c0c81fbb Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/unescaped-identifier.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/unnest-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/unnest-clause.png new file mode 100644 index 000000000..2db8cbb79 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/unnest-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/unnest-type.png b/modules/n1ql/assets/images/n1ql-language-reference/unnest-type.png new file mode 100644 index 000000000..25cd28997 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/unnest-type.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/unset-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/unset-clause.png new file mode 100644 index 000000000..80417808f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/unset-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update-for.png b/modules/n1ql/assets/images/n1ql-language-reference/update-for.png new file mode 100644 index 000000000..61a81a38b Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update-for.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-delete.png b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-delete.png new file mode 100644 index 000000000..987962bf3 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-delete.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-expr.png new file mode 100644 index 000000000..0d2aca46e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-index.png b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-index.png new file mode 100644 index 000000000..5137b17d6 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-index.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-indexes.png b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-indexes.png new file mode 100644 index 000000000..d24257537 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics-indexes.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update-statistics.png b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics.png new file mode 100644 index 000000000..79d0a9264 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update-statistics.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/update.png b/modules/n1ql/assets/images/n1ql-language-reference/update.png new file mode 100644 index 000000000..9fa22c1c6 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/update.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/upsert.png b/modules/n1ql/assets/images/n1ql-language-reference/upsert.png new file mode 100644 index 000000000..2316e9571 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/upsert.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/use-clause.png new file mode 100644 index 000000000..0dc40bc1c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-hash-hint.png b/modules/n1ql/assets/images/n1ql-language-reference/use-hash-hint.png new file mode 100644 index 000000000..2060b3c5c Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-hash-hint.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-hash-term.png b/modules/n1ql/assets/images/n1ql-language-reference/use-hash-term.png new file mode 100644 index 000000000..a91704214 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-hash-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-index-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/use-index-clause.png new file mode 100644 index 000000000..b5e544619 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-index-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-index-term.png b/modules/n1ql/assets/images/n1ql-language-reference/use-index-term.png new file mode 100644 index 000000000..6cd50b4a6 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-index-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-keys-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/use-keys-clause.png new file mode 100644 index 000000000..7e029055e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-keys-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-keys-term.png b/modules/n1ql/assets/images/n1ql-language-reference/use-keys-term.png new file mode 100644 index 000000000..8233d3dd5 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-keys-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-nl-hint.png b/modules/n1ql/assets/images/n1ql-language-reference/use-nl-hint.png new file mode 100644 index 000000000..94ef7d176 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-nl-hint.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/use-nl-term.png b/modules/n1ql/assets/images/n1ql-language-reference/use-nl-term.png new file mode 100644 index 000000000..44f3babc4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/use-nl-term.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/user.png b/modules/n1ql/assets/images/n1ql-language-reference/user.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/user.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/utility-statement.png b/modules/n1ql/assets/images/n1ql-language-reference/utility-statement.png new file mode 100644 index 000000000..dbef92b7d Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/utility-statement.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/value.png b/modules/n1ql/assets/images/n1ql-language-reference/value.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/value.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/values-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/values-clause.png new file mode 100644 index 000000000..bc2d7d3da Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/values-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/var-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/var-expr.png new file mode 100644 index 000000000..3c8ea052f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/var-expr.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/var.png b/modules/n1ql/assets/images/n1ql-language-reference/var.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/var.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/where-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/where-clause.png new file mode 100644 index 000000000..e1e63cec9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/where-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/width.png b/modules/n1ql/assets/images/n1ql-language-reference/width.png new file mode 100644 index 000000000..931282f20 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/width.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/window-clause.png new file mode 100644 index 000000000..ab4f221ae Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-declaration.png b/modules/n1ql/assets/images/n1ql-language-reference/window-declaration.png new file mode 100644 index 000000000..9ce01646e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-declaration.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-definition.png b/modules/n1ql/assets/images/n1ql-language-reference/window-definition.png new file mode 100644 index 000000000..8f32ecad1 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-definition.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-frame-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/window-frame-clause.png new file mode 100644 index 000000000..c13b3e78f Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-frame-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-frame-exclusion.png b/modules/n1ql/assets/images/n1ql-language-reference/window-frame-exclusion.png new file mode 100644 index 000000000..12ca40643 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-frame-exclusion.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-frame-extent.png b/modules/n1ql/assets/images/n1ql-language-reference/window-frame-extent.png new file mode 100644 index 000000000..92d3755f9 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-frame-extent.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-function-arguments.png b/modules/n1ql/assets/images/n1ql-language-reference/window-function-arguments.png new file mode 100644 index 000000000..732c0c786 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-function-arguments.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-function-name.png b/modules/n1ql/assets/images/n1ql-language-reference/window-function-name.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-function-name.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-function-options.png b/modules/n1ql/assets/images/n1ql-language-reference/window-function-options.png new file mode 100644 index 000000000..9ed50611e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-function-options.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-function.png b/modules/n1ql/assets/images/n1ql-language-reference/window-function.png new file mode 100644 index 000000000..6cb3f9ec2 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-function.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-name.png b/modules/n1ql/assets/images/n1ql-language-reference/window-name.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-name.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-order-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/window-order-clause.png new file mode 100644 index 000000000..e99595a2e Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-order-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-partition-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/window-partition-clause.png new file mode 100644 index 000000000..dc52e5aa4 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-partition-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/window-ref.png b/modules/n1ql/assets/images/n1ql-language-reference/window-ref.png new file mode 100644 index 000000000..ac1499429 Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/window-ref.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/with-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/with-clause.png new file mode 100644 index 000000000..2fd5f73ef Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/with-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/with-recursive-clause.png b/modules/n1ql/assets/images/n1ql-language-reference/with-recursive-clause.png new file mode 100644 index 000000000..1244164ab Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/with-recursive-clause.png differ diff --git a/modules/n1ql/assets/images/n1ql-language-reference/within-expr.png b/modules/n1ql/assets/images/n1ql-language-reference/within-expr.png new file mode 100644 index 000000000..305a63caf Binary files /dev/null and b/modules/n1ql/assets/images/n1ql-language-reference/within-expr.png differ diff --git a/modules/n1ql/assets/images/query-workbench-context-tx.png b/modules/n1ql/assets/images/query-workbench-context-tx.png new file mode 100644 index 000000000..3c4316007 Binary files /dev/null and b/modules/n1ql/assets/images/query-workbench-context-tx.png differ diff --git a/modules/n1ql/assets/images/time-series-irregular.svg b/modules/n1ql/assets/images/time-series-irregular.svg new file mode 100644 index 000000000..58d707493 --- /dev/null +++ b/modules/n1ql/assets/images/time-series-irregular.svg @@ -0,0 +1 @@ +2005-01-01T00:00:002006-01-01T00:00:002007-01-01T00:00:002008-01-01T00:00:002009-01-01T00:00:002010-01-01T00:00:002011-01-01T00:00:002012-01-01T00:00:002013-01-01T00:00:002014-01-01T00:00:00160,000170,000180,000190,000200,000210,000220,000230,000240,000 \ No newline at end of file diff --git a/modules/n1ql/assets/images/time-series-regular.svg b/modules/n1ql/assets/images/time-series-regular.svg new file mode 100644 index 000000000..86d56dc03 --- /dev/null +++ b/modules/n1ql/assets/images/time-series-regular.svg @@ -0,0 +1 @@ +2013-07-29T00:00:002013-07-29T12:00:002013-07-30T00:00:002013-07-30T12:00:002013-07-31T00:00:002013-07-31T12:00:002013-08-01T00:00:002013-08-01T12:00:002013-08-02T00:00:002013-08-02T12:00:002013-08-03T00:00:002013-08-03T12:00:002013-08-04T00:00:0081012141618202224262830highlow \ No newline at end of file diff --git a/modules/n1ql/assets/images/time-series-window.svg b/modules/n1ql/assets/images/time-series-window.svg new file mode 100644 index 000000000..33b5cd922 --- /dev/null +++ b/modules/n1ql/assets/images/time-series-window.svg @@ -0,0 +1 @@ +2013-06-23T00:00:002013-06-30T00:00:002013-07-07T00:00:002013-07-14T00:00:002013-07-21T00:00:002013-07-28T00:00:002013-08-04T00:00:002013-08-11T00:00:002013-08-18T00:00:002013-08-25T00:00:002013-09-01T00:00:00131415161718192021four_week_mov_avgweek_avg \ No newline at end of file diff --git a/modules/n1ql/assets/images/window-example.png b/modules/n1ql/assets/images/window-example.png new file mode 100644 index 000000000..197d269b5 Binary files /dev/null and b/modules/n1ql/assets/images/window-example.png differ diff --git a/modules/n1ql/assets/source/window-example.svg b/modules/n1ql/assets/source/window-example.svg new file mode 100644 index 000000000..724a6cb5e --- /dev/null +++ b/modules/n1ql/assets/source/window-example.svg @@ -0,0 +1,1979 @@ + + + +image/svg+xml + + +NAME + + +TIME + + +DATA + + + + + +Alice + + +13:01 + + +A267ED64-5B85-4A43-BF9B-A0D3C76020DE + + +Alice + + +13:02 + + +D0EC1315-21A2-4A46-9FD3-DD9C7360C859 + + +Alice + + +13:03 + + +EF38FBAB-774D-4AD9-8872-D8C7AF8655B5 + + + + + +Bob + + +13:01 + + +30D51BE4-EA1C-45E1-8AC5-3EC153FA6712 + + +Bob + + +13:02 + + +66300479-580E-4545-9CD7-D8980B71B59F + + + + + + + + +Bob + + +13:03 + + +C9CC6F85-9CA2-4D6D-8F4F-EB2F49C71BD9 + + +Bob + + +13:04 + + +6C0ED5C7-28CD-4BB8-8D93-5F505DC114F6 + + + + + +Eve + + +13:57 + + +DB131701-D42E-4B12-9C1E-6C23BB2B798B + + +Eve + + +13:58 + + +905E27F0-AEFB-4A66-8CA7-93F76FC2A5E4 + + +Eve + + +13:59 + + +4F0CB76F-191B-4263-A8B4-B2FE8FBF49B3 + + + \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-else.jsonc b/modules/n1ql/examples/dml/ansi-merge-else.jsonc new file mode 100644 index 000000000..d09ac11c6 --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-else.jsonc @@ -0,0 +1,33 @@ +[ + { + "target": { + "airportname": "Anglesey Airport / Maes Awyr Môn", + "faa": "VLY", + "inserted": true, + "type": "airport" + } + }, + { + "source": { + "iata": "DSA", + "name": "Doncaster Sheffield Airport" + }, + "target": { + "airportname": "Doncaster Sheffield Airport", + "city": "Doncaster, Sheffield", + "country": "United Kingdom", + "faa": "DSA", + "geo": { + "alt": 55, + "lat": 53.474722, + "lon": -1.004444 + }, + "icao": "EGCN", + "id": 5562, + "old_name": "Robin Hood Doncaster Sheffield Airport", + "type": "airport", + "tz": "Europe/London", + "updated": true + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-else.n1ql b/modules/n1ql/examples/dml/ansi-merge-else.n1ql new file mode 100644 index 000000000..6df2f7dbd --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-else.n1ql @@ -0,0 +1,17 @@ +MERGE INTO airport AS target +USING [ + {"iata":"DSA", "name": "Doncaster Sheffield Airport"}, + {"iata":"VLY", "name": "Anglesey Airport / Maes Awyr Môn"} +] AS source +ON target.faa = source.iata +WHEN MATCHED THEN + UPDATE SET target.old_name = target.airportname, + target.airportname = source.name, + target.updated = true +WHEN NOT MATCHED THEN + INSERT (KEY UUID(), + VALUE {"faa": source.iata, + "airportname": source.name, + "type": "airport", + "inserted": true} ) +RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-expire.jsonc b/modules/n1ql/examples/dml/ansi-merge-expire.jsonc new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-expire.jsonc @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-expire.n1ql b/modules/n1ql/examples/dml/ansi-merge-expire.n1ql new file mode 100644 index 000000000..ccef87045 --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-expire.n1ql @@ -0,0 +1,18 @@ +MERGE INTO airport AS target +USING [ + {"iata":"DSA", "name": "Doncaster Sheffield Airport"}, + {"iata":"VLY", "name": "Anglesey Airport / Maes Awyr Môn"} +] AS source +ON target.faa = source.iata +WHEN MATCHED THEN + UPDATE SET target.old_name = target.airportname, + target.airportname = source.name, + target.updated = true, + meta(target).expiration = meta(target).expiration +WHEN NOT MATCHED THEN + INSERT (KEY UUID(), + VALUE {"faa": source.iata, + "airportname": source.name, + "type": "airport", + "inserted": true}, + OPTIONS {"expiration": 7*24*60*60} ); \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-expr.jsonc b/modules/n1ql/examples/dml/ansi-merge-expr.jsonc new file mode 100644 index 000000000..a0949de1a --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-expr.jsonc @@ -0,0 +1,12 @@ +[ + { + "id": "hotel_21728", + "old_vacancy": false, + "vacancy": true + }, + { + "id": "hotel_21730", + "old_vacancy": true, + "vacancy": true + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-expr.n1ql b/modules/n1ql/examples/dml/ansi-merge-expr.n1ql new file mode 100644 index 000000000..a4bf0ba35 --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-expr.n1ql @@ -0,0 +1,10 @@ +MERGE INTO hotel t +USING [ + {"id":"21728", "vacancy": true}, + {"id":"21730", "vacancy": true} +] source +ON meta(t).id = "hotel_" || source.id +WHEN MATCHED THEN + UPDATE SET t.old_vacancy = t.vacancy, + t.vacancy = source.vacancy +RETURNING meta(t).id, t.old_vacancy, t.vacancy; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-keyspace.jsonc b/modules/n1ql/examples/dml/ansi-merge-keyspace.jsonc new file mode 100644 index 000000000..cd2975daa --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-keyspace.jsonc @@ -0,0 +1,46 @@ +[ + { + "equipment": "763 757", + "sourceairport": "CDG" + }, + { + "equipment": "797", + "old_equipment": "734 319", + "sourceairport": "BOD" + }, + { + "equipment": "797", + "old_equipment": "319 320 321", + "sourceairport": "CDG" + }, + { + "equipment": "797", + "old_equipment": "319", + "sourceairport": "LYS" + }, + { + "equipment": "797", + "old_equipment": "319 320", + "sourceairport": "MRS" + }, + { + "equipment": "797", + "old_equipment": "319 320 734", + "sourceairport": "NCE" + }, + { + "equipment": "797", + "old_equipment": "319 320 321", + "sourceairport": "NCE" + }, + { + "equipment": "797", + "old_equipment": "319 320", + "sourceairport": "ORY" + }, + { + "equipment": "797", + "old_equipment": "320 319 321", + "sourceairport": "TLS" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/ansi-merge-keyspace.n1ql b/modules/n1ql/examples/dml/ansi-merge-keyspace.n1ql new file mode 100644 index 000000000..3d23ef3ce --- /dev/null +++ b/modules/n1ql/examples/dml/ansi-merge-keyspace.n1ql @@ -0,0 +1,15 @@ +MERGE INTO route +USING airport +ON route.sourceairport = airport.faa +WHEN MATCHED THEN UPDATE + SET route.old_equipment = route.equipment, + route.equipment = "797", + route.updated = true + WHERE airport.country = "France" + AND route.airline = "BA" + AND CONTAINS(route.equipment, "319") +WHEN MATCHED THEN DELETE + WHERE airport.country = "France" + AND route.airline = "BA" + AND CONTAINS(route.equipment, "757") +RETURNING route.old_equipment, route.equipment, airport.faa; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-all-return.n1ql b/modules/n1ql/examples/dml/delete-all-return.n1ql new file mode 100644 index 000000000..fa7b72a5a --- /dev/null +++ b/modules/n1ql/examples/dml/delete-all-return.n1ql @@ -0,0 +1 @@ +DELETE FROM hotel RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-all.n1ql b/modules/n1ql/examples/dml/delete-all.n1ql new file mode 100644 index 000000000..d19542128 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-all.n1ql @@ -0,0 +1 @@ +DELETE FROM hotel; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-filter-return.n1ql b/modules/n1ql/examples/dml/delete-filter-return.n1ql new file mode 100644 index 000000000..75d563ea8 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-filter-return.n1ql @@ -0,0 +1,3 @@ +DELETE FROM hotel +WHERE city = "San Francisco" +RETURNING meta().id; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-filter.jsonc b/modules/n1ql/examples/dml/delete-filter.jsonc new file mode 100644 index 000000000..23e9edf81 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-filter.jsonc @@ -0,0 +1,5 @@ +[ + { + "id": "4445" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-filter.n1ql b/modules/n1ql/examples/dml/delete-filter.n1ql new file mode 100644 index 000000000..7488efad1 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-filter.n1ql @@ -0,0 +1,3 @@ +DELETE FROM airline f +WHERE f.callsign = "AIR-X" +RETURNING f.id \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-key.jsonc b/modules/n1ql/examples/dml/delete-key.jsonc new file mode 100644 index 000000000..054870f16 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-key.jsonc @@ -0,0 +1,13 @@ +[ + { + "k": { + "callsign": "MY-AIR", + "country": "United States", + "iata": "Z1", + "icao": "AQZ", + "name": "80-My Air", + "id": "4444", + "type": "airline" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-key.n1ql b/modules/n1ql/examples/dml/delete-key.n1ql new file mode 100644 index 000000000..cc9dc53bb --- /dev/null +++ b/modules/n1ql/examples/dml/delete-key.n1ql @@ -0,0 +1,3 @@ +DELETE FROM airline k +USE KEYS "airline_4444" +RETURNING k \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-offset-before.jsonc b/modules/n1ql/examples/dml/delete-offset-before.jsonc new file mode 100644 index 000000000..0bc05ca1c --- /dev/null +++ b/modules/n1ql/examples/dml/delete-offset-before.jsonc @@ -0,0 +1,65 @@ +[ + { + "id": 1191 + }, + { + "id": 1203 + }, + { + "id": 137 + }, + { + "id": 139 + }, + { + "id": 13947 + }, + { + "id": 1523 + }, + { + "id": 16837 + }, + { + "id": 1908 + }, + { + "id": 1909 + }, + { + "id": 21 //<.> + }, + { + "id": 225 + }, + { + "id": 2704 + }, + { + "id": 2757 + }, + { + "id": 4299 + }, + { + "id": 477 + }, + { + "id": 4965 + }, + { + "id": 547 + }, + { + "id": 5479 + }, + { + "id": 551 + }, + { + "id": 567 //<.> + }, + { + "id": 8745 + } + ] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-offset-before.n1ql b/modules/n1ql/examples/dml/delete-offset-before.n1ql new file mode 100644 index 000000000..d427f4376 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-offset-before.n1ql @@ -0,0 +1,2 @@ +SELECT id FROM airline +WHERE country="France"; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-offset.jsonc b/modules/n1ql/examples/dml/delete-offset.jsonc new file mode 100644 index 000000000..0d30b594c --- /dev/null +++ b/modules/n1ql/examples/dml/delete-offset.jsonc @@ -0,0 +1,35 @@ +[ + { + "id": 1191 + }, + { + "id": 1203 + }, + { + "id": 137 + }, + { + "id": 139 + }, + { + "id": 13947 + }, + { + "id": 1523 + }, + { + "id": 16837 + }, + { + "id": 1908 + }, + { + "id": 1909 + }, + { + "id": 21 //<.> + }, + { + "id": 8745 //<.> + } + ] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-offset.n1ql b/modules/n1ql/examples/dml/delete-offset.n1ql new file mode 100644 index 000000000..38ff940c9 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-offset.n1ql @@ -0,0 +1,6 @@ +DELETE FROM airline +WHERE country="France" +LIMIT 10 OFFSET 10; + +SELECT id FROM airline +WHERE country="France"; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-sub-other.n1ql b/modules/n1ql/examples/dml/delete-sub-other.n1ql new file mode 100644 index 000000000..eafc236ad --- /dev/null +++ b/modules/n1ql/examples/dml/delete-sub-other.n1ql @@ -0,0 +1,3 @@ +DELETE FROM airport +WHERE city IN (SELECT raw city FROM `beer-sample` WHERE city IS NOT MISSING) +RETURNING airportname; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-sub-same.jsonc b/modules/n1ql/examples/dml/delete-sub-same.jsonc new file mode 100644 index 000000000..04f456736 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-sub-same.jsonc @@ -0,0 +1,5 @@ +[ + { + "airportname": "√éle d'Yeu Airport" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/delete-sub-same.n1ql b/modules/n1ql/examples/dml/delete-sub-same.n1ql new file mode 100644 index 000000000..8a73ba778 --- /dev/null +++ b/modules/n1ql/examples/dml/delete-sub-same.n1ql @@ -0,0 +1,3 @@ +DELETE FROM airport +WHERE city IN (SELECT RAW MAX(t.city) FROM airport AS t) +RETURNING airportname; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-batch.jsonc b/modules/n1ql/examples/dml/insert-batch.jsonc new file mode 100644 index 000000000..4e451247b --- /dev/null +++ b/modules/n1ql/examples/dml/insert-batch.jsonc @@ -0,0 +1,39 @@ +{ + "requestID": "2fabc03a-ea9b-49fd-a044-6ef667381311", + "signature": { + "*": "*" + }, + "results": [ + { + "airline": { + "callsign": "MY-AIR", + "country": "United States", + "iata": "Z1", + "icao": "AQZ", + "id": "4444", + "name": "80-My Air", + "type": "airline" + } + }, + { + "airline": { + "callsign": "AIR-X", + "country": "United States", + "iata": "X1", + "icao": "ARX", + "id": "4445", + "name": "10-AirX", + "type": "airline" + } + } + ], + "status": "success", + "metrics": { + "elapsedTime": "5.7617ms", + "executionTime": "5.4635ms", + "resultCount": 2, + "resultSize": 505, + "serviceLoad": 4, + "mutationCount": 2 + } +} \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-batch.n1ql b/modules/n1ql/examples/dml/insert-batch.n1ql new file mode 100644 index 000000000..bf3fd6394 --- /dev/null +++ b/modules/n1ql/examples/dml/insert-batch.n1ql @@ -0,0 +1,18 @@ +INSERT INTO airline (KEY,VALUE) +VALUES ( "airline_4444", + { "callsign": "MY-AIR", + "country": "United States", + "iata": "Z1", + "icao": "AQZ", + "name": "80-My Air", + "id": "4444", + "type": "airline"} ), +VALUES ( "airline_4445", + { "callsign": "AIR-X", + "country": "United States", + "iata": "X1", + "icao": "ARX", + "name": "10-AirX", + "id": "4445", + "type": "airline"} ) +RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-doc.jsonc b/modules/n1ql/examples/dml/insert-doc.jsonc new file mode 100644 index 000000000..6532e8d86 --- /dev/null +++ b/modules/n1ql/examples/dml/insert-doc.jsonc @@ -0,0 +1,28 @@ +{ + "requestID": "c3bd0276-5d7d-425f-98f9-b333b9ae4302", + "signature": { + "*": "*" + }, + "results": [ + { + "airline": { + "callsign": "MY-AIR", + "country": "United States", + "iata": "Z1", + "icao": "AQZ", + "id": "1011", + "name": "80-My Air", + "type": "airline" + } + } + ], + "status": "success", + "metrics": { + "elapsedTime": "5.9133ms", + "executionTime": "5.6264ms", + "resultCount": 1, + "resultSize": 254, + "serviceLoad": 4, + "mutationCount": 1 + } +} \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-doc.n1ql b/modules/n1ql/examples/dml/insert-doc.n1ql new file mode 100644 index 000000000..96c726c57 --- /dev/null +++ b/modules/n1ql/examples/dml/insert-doc.n1ql @@ -0,0 +1,11 @@ +INSERT INTO airline (KEY,VALUE) + VALUES ( "1025", + { "callsign": "MY-AIR", + "country": "United States", + "iata": "Z1", + "icao": "AQZ", + "id": "1011", + "name": "80-My Air", + "type": "airline" + } ) +RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-select.jsonc b/modules/n1ql/examples/dml/insert-select.jsonc new file mode 100644 index 000000000..4e7323beb --- /dev/null +++ b/modules/n1ql/examples/dml/insert-select.jsonc @@ -0,0 +1,19 @@ +[ + { + "airport": { + "airportname": "Heathrow", + "city": "London", + "country": "United Kingdom", + "faa": "LHR", + "geo": { + "alt": 83, + "lat": 51.4775, + "lon": -0.461389 + }, + "icao": "EGLL", + "id": 507, + "type": "airport", + "tz": "Europe/London" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-select.n1ql b/modules/n1ql/examples/dml/insert-select.n1ql new file mode 100644 index 000000000..df8d230f6 --- /dev/null +++ b/modules/n1ql/examples/dml/insert-select.n1ql @@ -0,0 +1,4 @@ +INSERT INTO airport (KEY UUID(), VALUE _airport) + SELECT _airport FROM airport _airport + WHERE airportname = "Heathrow" +RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-value.jsonc b/modules/n1ql/examples/dml/insert-value.jsonc new file mode 100644 index 000000000..fcefeab0c --- /dev/null +++ b/modules/n1ql/examples/dml/insert-value.jsonc @@ -0,0 +1,25 @@ +{ + "requestID": "df5846b1-1044-4b1f-ae8a-979be25282d1", + "signature": { + "*": "*", + "docid": "json" + }, + "results": [ + { + "airline": { + "id": "01", + "type": "airline" + }, + "docid": "k001" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "6.916ms", + "executionTime": "6.6224ms", + "resultCount": 1, + "resultSize": 117, + "serviceLoad": 4, + "mutationCount": 1 + } +} \ No newline at end of file diff --git a/modules/n1ql/examples/dml/insert-value.n1ql b/modules/n1ql/examples/dml/insert-value.n1ql new file mode 100644 index 000000000..8eaef74ec --- /dev/null +++ b/modules/n1ql/examples/dml/insert-value.n1ql @@ -0,0 +1,7 @@ +INSERT INTO airline ( KEY, VALUE ) + VALUES + ( + "k001", + { "id": "01", "type": "airline"} + ) +RETURNING META().id as docid, *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/lookup-merge-else.jsonc b/modules/n1ql/examples/dml/lookup-merge-else.jsonc new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/modules/n1ql/examples/dml/lookup-merge-else.jsonc @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/lookup-merge-else.n1ql b/modules/n1ql/examples/dml/lookup-merge-else.n1ql new file mode 100644 index 000000000..4114d744f --- /dev/null +++ b/modules/n1ql/examples/dml/lookup-merge-else.n1ql @@ -0,0 +1,10 @@ +MERGE INTO all_empts a USING emps_deptb b ON KEY b.empId +WHEN MATCHED THEN + UPDATE SET a.depts = a.depts + 1 + a.title = b.title || ", " || b.title +WHEN NOT MATCHED THEN + INSERT { "name": b.name, + "title": b.title, + "depts": b.depts, + "empId": b.empId, + "dob": b.dob }; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/lookup-merge-expr.jsonc b/modules/n1ql/examples/dml/lookup-merge-expr.jsonc new file mode 100644 index 000000000..5fdcbf8ea --- /dev/null +++ b/modules/n1ql/examples/dml/lookup-merge-expr.jsonc @@ -0,0 +1,12 @@ +[ + { + "id": "hotel_21728", + "old_vacancy": true, + "vacancy": true + }, + { + "id": "hotel_21730", + "old_vacancy": true, + "vacancy": true + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/lookup-merge-expr.n1ql b/modules/n1ql/examples/dml/lookup-merge-expr.n1ql new file mode 100644 index 000000000..e9d2d9bf3 --- /dev/null +++ b/modules/n1ql/examples/dml/lookup-merge-expr.n1ql @@ -0,0 +1,9 @@ +MERGE INTO hotel t +USING [ + {"id":"21728", "vacancy": true}, + {"id":"21730", "vacancy": true} +] source +ON KEY "hotel_"|| source.id +WHEN MATCHED THEN + UPDATE SET t.old_vacancy = t.vacancy, t.vacancy = source.vacancy +RETURNING meta(t).id, t.old_vacancy, t.vacancy; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/lookup-merge-keyspace.jsonc b/modules/n1ql/examples/dml/lookup-merge-keyspace.jsonc new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/modules/n1ql/examples/dml/lookup-merge-keyspace.jsonc @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/lookup-merge-keyspace.n1ql b/modules/n1ql/examples/dml/lookup-merge-keyspace.n1ql new file mode 100644 index 000000000..674d10322 --- /dev/null +++ b/modules/n1ql/examples/dml/lookup-merge-keyspace.n1ql @@ -0,0 +1,5 @@ +MERGE INTO product p USING orders o ON KEY o.productId +WHEN MATCHED THEN + UPDATE SET p.lastSaleDate = o.orderDate +WHEN MATCHED THEN + DELETE WHERE p.inventoryCount <= 0; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-preserve-expire.n1ql b/modules/n1ql/examples/dml/update-preserve-expire.n1ql new file mode 100644 index 000000000..79931b179 --- /dev/null +++ b/modules/n1ql/examples/dml/update-preserve-expire.n1ql @@ -0,0 +1,3 @@ +UPDATE route t USE KEYS "route_10003" +SET meta(t).expiration = meta(t).expiration, +s.codeshare = NULL FOR s IN schedule END; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-rbac-return.jsonc b/modules/n1ql/examples/dml/update-rbac-return.jsonc new file mode 100644 index 000000000..e5a1cd92f --- /dev/null +++ b/modules/n1ql/examples/dml/update-rbac-return.jsonc @@ -0,0 +1,19 @@ +[ + { + "airport": { + "airportname": "San Francisco Intl", + "city": "San Francisco", + "country": "United States", + "faa": "SFO", + "geo": { + "alt": 13, + "lat": 37.618972, + "lon": -122.374889 + }, + "icao": "KSFO", + "id": 3469, + "type": "airport", + "tz": "America/Los_Angeles" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-rbac-return.n1ql b/modules/n1ql/examples/dml/update-rbac-return.n1ql new file mode 100644 index 000000000..a54aa8001 --- /dev/null +++ b/modules/n1ql/examples/dml/update-rbac-return.n1ql @@ -0,0 +1,4 @@ +UPDATE airport +SET city = "San Francisco" +WHERE lower(city) = "san francisco" +RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-rbac-sub.n1ql b/modules/n1ql/examples/dml/update-rbac-sub.n1ql new file mode 100644 index 000000000..720f470fa --- /dev/null +++ b/modules/n1ql/examples/dml/update-rbac-sub.n1ql @@ -0,0 +1,3 @@ +UPDATE airport +SET foo = 9 +WHERE city IN (SELECT RAW city FROM `beer-sample` WHERE type = "brewery"); \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-rbac.n1ql b/modules/n1ql/examples/dml/update-rbac.n1ql new file mode 100644 index 000000000..d690c2f7a --- /dev/null +++ b/modules/n1ql/examples/dml/update-rbac.n1ql @@ -0,0 +1 @@ +UPDATE airport SET foo = 5; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-array.jsonc b/modules/n1ql/examples/dml/update-set-array.jsonc new file mode 100644 index 000000000..e987f48c6 --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-array.jsonc @@ -0,0 +1,186 @@ +// tag::extract[] +[ + { + "t": { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ATL", + "distance": 654.9546621929924, + "equipment": "757 739", + "id": 10003, + "schedule": [ + { + "codeshare": null, + "day": 0, + "flight": "AF986", + "utc": "22:26:00" + }, + { + "codeshare": null, + "day": 0, + "flight": "AF962", + "utc": "04:25:00" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "codeshare": null, + "day": 0, + "flight": "AF301", + "utc": "12:11:00" + }, + { + "codeshare": null, + "day": 0, + "flight": "AF923", + "utc": "04:31:00" + }, + { + "codeshare": null, + "day": 0, + "flight": "AF908", + "utc": "07:23:00" + }, + { + "codeshare": null, + "day": 1, + "flight": "AF085", + "utc": "20:08:00" + }, + { + "codeshare": null, + "day": 1, + "flight": "AF450", + "utc": "08:08:00" + }, + { + "codeshare": null, + "day": 2, + "flight": "AF538", + "utc": "02:03:00" + }, + { + "codeshare": null, + "day": 2, + "flight": "AF797", + "utc": "13:57:00" + }, + { + "codeshare": null, + "day": 2, + "flight": "AF355", + "utc": "01:56:00" + }, + { + "codeshare": null, + "day": 3, + "flight": "AF535", + "utc": "19:36:00" + }, + { + "codeshare": null, + "day": 3, + "flight": "AF110", + "utc": "19:03:00" + }, + { + "codeshare": null, + "day": 3, + "flight": "AF595", + "utc": "09:41:00" + }, + { + "codeshare": null, + "day": 3, + "flight": "AF072", + "utc": "09:43:00" + }, + { + "codeshare": null, + "day": 3, + "flight": "AF358", + "utc": "23:52:00" + }, + { + "codeshare": null, + "day": 4, + "flight": "AF759", + "utc": "09:24:00" + }, + { + "codeshare": null, + "day": 4, + "flight": "AF922", + "utc": "02:44:00" + }, + { + "codeshare": null, + "day": 5, + "flight": "AF016", + "utc": "06:53:00" + }, + { + "codeshare": null, + "day": 5, + "flight": "AF962", + "utc": "00:50:00" + }, + { + "codeshare": null, + "day": 5, + "flight": "AF222", + "utc": "16:21:00" + }, + { + "codeshare": null, + "day": 5, + "flight": "AF201", + "utc": "12:13:00" + }, + { + "codeshare": null, + "day": 5, + "flight": "AF792", + "utc": "09:33:00" + }, + { + "codeshare": null, + "day": 6, + "flight": "AF271", + "utc": "14:35:00" + }, + { + "codeshare": null, + "day": 6, + "flight": "AF484", + "utc": "23:21:00" + }, + { + "codeshare": null, + "day": 6, + "flight": "AF248", + "utc": "15:40:00" + }, + { + "codeshare": null, + "day": 6, + "flight": "AF130", + "utc": "00:02:00" + }, + { + "codeshare": null, + "day": 6, + "flight": "AF540", + "utc": "11:07:00" + } +// tag::extract[] + ], + "sourceairport": "TPA", + "stops": 0, + "type": "route" + } + } +] +// end::extract[] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-array.n1ql b/modules/n1ql/examples/dml/update-set-array.n1ql new file mode 100644 index 000000000..5c89ef32e --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-array.n1ql @@ -0,0 +1,4 @@ +UPDATE route t +USE KEYS "route_10003" +SET s.codeshare = NULL FOR s IN schedule END +RETURNING t; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-expire.n1ql b/modules/n1ql/examples/dml/update-set-expire.n1ql new file mode 100644 index 000000000..951f4eefe --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-expire.n1ql @@ -0,0 +1,3 @@ +UPDATE route t USE KEYS "route_10003" +SET meta(t).expiration = 7*24*60*60, +s.codeshare = NULL FOR s IN schedule END; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-nested.jsonc b/modules/n1ql/examples/dml/update-set-nested.jsonc new file mode 100644 index 000000000..19f964f1d --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-nested.jsonc @@ -0,0 +1,26 @@ +[ + { + "ratings": [ + { + "Cleanliness": 5, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 5, + "Value": 4, + "new": "new_value" + }, + { + "Business service (e.g., internet access)": 4, + "Check in / front desk": 4, + "Cleanliness": 4, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 3, + "Value": 5, + "new": "new_value" + } + ] + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-nested.n1ql b/modules/n1ql/examples/dml/update-set-nested.n1ql new file mode 100644 index 000000000..fea4289a7 --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-nested.n1ql @@ -0,0 +1,3 @@ +UPDATE hotel AS h USE KEYS "hotel_10025" +SET i.ratings = OBJECT_ADD(i.ratings, "new", "new_value" ) FOR i IN reviews END +RETURNING h.reviews[*].ratings; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-sub.jsonc b/modules/n1ql/examples/dml/update-set-sub.jsonc new file mode 100644 index 000000000..fc1ed92e3 --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-sub.jsonc @@ -0,0 +1,49 @@ +[ + { + "a": { + "airportname": "Cote D\\'Azur", + "city": "Nice", + "country": "France", + "faa": "NCE", + "geo": { + "alt": 12, + "lat": 43.658411, + "lon": 7.215872 + }, + "hotels": [ + { + "id": 20419, + "name": "Best Western Hotel Riviera Nice" + }, + { + "id": 20420, + "name": "Hotel Anis" + }, + { + "id": 20421, + "name": "NH Nice" + }, + { + "id": 20422, + "name": "Hotel Suisse" + }, + { + "id": 20423, + "name": "Gounod" + }, + { + "id": 20424, + "name": "Grimaldi Hotel Nice" + }, + { + "id": 20425, + "name": "Negresco" + } + ], + "icao": "LFMN", + "id": 1354, + "type": "airport", + "tz": "Europe/Paris" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set-sub.n1ql b/modules/n1ql/examples/dml/update-set-sub.n1ql new file mode 100644 index 000000000..38d43d2a5 --- /dev/null +++ b/modules/n1ql/examples/dml/update-set-sub.n1ql @@ -0,0 +1,7 @@ +UPDATE airport AS a +SET hotels = + (SELECT h.name, h.id + FROM hotel AS h + WHERE h.city = "Nice") +WHERE a.faa ="NCE" +RETURNING a; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set.jsonc b/modules/n1ql/examples/dml/update-set.jsonc new file mode 100644 index 000000000..49a63d2c6 --- /dev/null +++ b/modules/n1ql/examples/dml/update-set.jsonc @@ -0,0 +1,5 @@ +[ + { + "nickname": "Squiggly Bridge" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-set.n1ql b/modules/n1ql/examples/dml/update-set.n1ql new file mode 100644 index 000000000..1e8d06aac --- /dev/null +++ b/modules/n1ql/examples/dml/update-set.n1ql @@ -0,0 +1,4 @@ +UPDATE landmark +USE KEYS "landmark_10090" +SET nickname = "Squiggly Bridge" +RETURNING landmark.nickname; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-unset-expire-alt.n1ql b/modules/n1ql/examples/dml/update-unset-expire-alt.n1ql new file mode 100644 index 000000000..449e79d51 --- /dev/null +++ b/modules/n1ql/examples/dml/update-unset-expire-alt.n1ql @@ -0,0 +1,2 @@ +UPDATE route t USE KEYS "route_10003" +SET s.codeshare = NULL FOR s IN schedule END; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-unset-expire.n1ql b/modules/n1ql/examples/dml/update-unset-expire.n1ql new file mode 100644 index 000000000..27db1b188 --- /dev/null +++ b/modules/n1ql/examples/dml/update-unset-expire.n1ql @@ -0,0 +1,3 @@ +UPDATE route t USE KEYS "route_10003" +SET meta(t).expiration = 0, +s.codeshare = NULL FOR s IN schedule END; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-unset-nested.jsonc b/modules/n1ql/examples/dml/update-unset-nested.jsonc new file mode 100644 index 000000000..c1d94112e --- /dev/null +++ b/modules/n1ql/examples/dml/update-unset-nested.jsonc @@ -0,0 +1,24 @@ +[ + { + "ratings": [ + { + "Cleanliness": 5, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 5, + "Value": 4 + }, + { + "Business service (e.g., internet access)": 4, + "Check in / front desk": 4, + "Cleanliness": 4, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 3, + "Value": 5 + } + ] + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-unset-nested.n1ql b/modules/n1ql/examples/dml/update-unset-nested.n1ql new file mode 100644 index 000000000..90a149058 --- /dev/null +++ b/modules/n1ql/examples/dml/update-unset-nested.n1ql @@ -0,0 +1,5 @@ +UPDATE hotel AS h USE KEYS "hotel_10025" +UNSET i.new FOR i IN + (ARRAY j.ratings FOR j IN reviews END) +END +RETURNING h.reviews[*].ratings; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-unset.jsonc b/modules/n1ql/examples/dml/update-unset.jsonc new file mode 100644 index 000000000..379c4742c --- /dev/null +++ b/modules/n1ql/examples/dml/update-unset.jsonc @@ -0,0 +1,5 @@ +[ + { + "name": "Tradeston Pedestrian Bridge" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/update-unset.n1ql b/modules/n1ql/examples/dml/update-unset.n1ql new file mode 100644 index 000000000..98569e459 --- /dev/null +++ b/modules/n1ql/examples/dml/update-unset.n1ql @@ -0,0 +1,4 @@ +UPDATE landmark +USE KEYS "landmark_10090" +UNSET nickname +RETURNING landmark.name; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/upsert-batch.jsonc b/modules/n1ql/examples/dml/upsert-batch.jsonc new file mode 100644 index 000000000..10fa97021 --- /dev/null +++ b/modules/n1ql/examples/dml/upsert-batch.jsonc @@ -0,0 +1,4 @@ +[ + "The Minster Inn", + "The Black Swan" +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/upsert-batch.n1ql b/modules/n1ql/examples/dml/upsert-batch.n1ql new file mode 100644 index 000000000..a6aa6c9c1 --- /dev/null +++ b/modules/n1ql/examples/dml/upsert-batch.n1ql @@ -0,0 +1,4 @@ +UPSERT INTO landmark (KEY, VALUE) +VALUES ("upsert-1", { "name": "The Minster Inn", "type": "landmark-pub"}), +("upsert-2", {"name": "The Black Swan", "type": "landmark-pub"}) +RETURNING VALUE name; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/upsert-rbac-return.jsonc b/modules/n1ql/examples/dml/upsert-rbac-return.jsonc new file mode 100644 index 000000000..74f168293 --- /dev/null +++ b/modules/n1ql/examples/dml/upsert-rbac-return.jsonc @@ -0,0 +1,8 @@ +[ + { + "hotel": { + "name": "new hotel", + "type": "hotel" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/dml/upsert-rbac-return.n1ql b/modules/n1ql/examples/dml/upsert-rbac-return.n1ql new file mode 100644 index 000000000..7bb3030af --- /dev/null +++ b/modules/n1ql/examples/dml/upsert-rbac-return.n1ql @@ -0,0 +1,3 @@ +UPSERT INTO hotel (KEY, VALUE) +VALUES ("key1", { "type" : "hotel", "name" : "new hotel" }) +RETURNING *; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/upsert-rbac-select.n1ql b/modules/n1ql/examples/dml/upsert-rbac-select.n1ql new file mode 100644 index 000000000..2af2cb077 --- /dev/null +++ b/modules/n1ql/examples/dml/upsert-rbac-select.n1ql @@ -0,0 +1,2 @@ +UPSERT INTO landmark (KEY foo, VALUE bar) +SELECT META(doc).id AS foo, doc AS bar FROM `beer-sample` AS doc WHERE type = "brewery"; \ No newline at end of file diff --git a/modules/n1ql/examples/dml/upsert-rbac.n1ql b/modules/n1ql/examples/dml/upsert-rbac.n1ql new file mode 100644 index 000000000..02a69883d --- /dev/null +++ b/modules/n1ql/examples/dml/upsert-rbac.n1ql @@ -0,0 +1,2 @@ +UPSERT INTO hotel (KEY, VALUE) +VALUES ("key1", { "type" : "hotel", "name" : "new hotel" }); \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-abort.jsonc b/modules/n1ql/examples/functions/advisor-abort.jsonc new file mode 100644 index 000000000..745072a74 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-abort.jsonc @@ -0,0 +1,5 @@ +[ + { + "Abort": [] + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-abort.n1ql b/modules/n1ql/examples/functions/advisor-abort.n1ql new file mode 100644 index 000000000..1d9a6f39b --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-abort.n1ql @@ -0,0 +1,2 @@ +SELECT ADVISOR({"action": "abort", "session": "0cd09ae4-a083-4a7e-86cd-85e42c140d60"}) +AS Abort; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-get.jsonc b/modules/n1ql/examples/functions/advisor-get.jsonc new file mode 100644 index 000000000..f55b5debf --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-get.jsonc @@ -0,0 +1,100 @@ +// tag::current[] +[ + { + "Get": [ + [ + { + "current_used_indexes": [ + { + "index": "CREATE PRIMARY INDEX idx_airport_primary ON `default`:`travel-sample`.`inventory`.`airport`", + "statements": [ + { + "run_count": 1, + "statement": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } + ] +// end::current[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + }, + { + "index": "CREATE INDEX def_inventory_landmark_city ON `default`:`travel-sample`.`inventory`.`landmark`(`city`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT city FROM `travel-sample`.inventory.landmark WHERE city LIKE \"Par%\" OR city LIKE \"Lon%\";" + } + ] + }, + { + "index": "CREATE PRIMARY INDEX def_inventory_route_primary ON `default`:`travel-sample`.`inventory`.`route`", + "statements": [ + { + "run_count": 1, + "statement": "SELECT d.id, d.destinationairport, RATIO_TO_REPORT(d.distance) OVER (PARTITION BY d.destinationairport) AS `distance-ratio` FROM `travel-sample`.inventory.route AS d LIMIT 7;" + } + ] + }, + { + "index": "CREATE INDEX def_inventory_hotel_city ON `default`:`travel-sample`.`inventory`.`hotel`(`city`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT h.name, h.city, a.airportname FROM `travel-sample`.inventory.hotel h JOIN `travel-sample`.inventory.airport a ON h.city = a.city LIMIT 5;" + } + ] + }, + { + "index": "CREATE INDEX idx_city_faa_airport ON `default`:`travel-sample`.`inventory`.`airport`(`city`,`faa`,`airportname`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT h.name, h.city, a.airportname FROM `travel-sample`.inventory.hotel h JOIN `travel-sample`.inventory.airport a ON h.city = a.city LIMIT 5;" + } + ] +// tag::covering[] + } + ], + "recommended_covering_indexes": [ + { + "index": "CREATE INDEX adv_city_name ON `default`:`travel-sample`.`inventory`.`hotel`(`city`,`name`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT h.name, h.city, a.airportname FROM `travel-sample`.inventory.hotel h JOIN `travel-sample`.inventory.airport a ON h.city = a.city LIMIT 5;" + } + ] +// end::covering[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + }, + { + "index": "CREATE INDEX adv_geo_alt_airportname ON `default`:`travel-sample`.`inventory`.`airport`(`geo`.`alt`,`airportname`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } + ] +// tag::recommended[] + } + ], + "recommended_indexes": [ + { + "index": "CREATE INDEX adv_geo_alt ON `default`:`travel-sample`.`inventory`.`airport`(`geo`.`alt`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } + ] + } + ] + } + ] + ] + } +] +// end::recommended[] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-get.n1ql b/modules/n1ql/examples/functions/advisor-get.n1ql new file mode 100644 index 000000000..fb0c22abd --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-get.n1ql @@ -0,0 +1,2 @@ +SELECT ADVISOR({"action": "get", "session": "0cd09ae4-a083-4a7e-86cd-85e42c140d60"}) +AS Get; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-list.jsonc b/modules/n1ql/examples/functions/advisor-list.jsonc new file mode 100644 index 000000000..1da36dbf5 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-list.jsonc @@ -0,0 +1,45 @@ +// tag::completed[] +[ + { + "List": [ + { + "tasks_cache": { + "class": "advisor", + "delay": "10s", + "id": "583af6ae-841e-5090-9a74-3607784533fa", + "name": "0cd09ae4-a083-4a7e-86cd-85e42c140d60", + "node": "127.0.0.1:8091", + "results": [ +// end::completed[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + [] +// tag::cancelled[] + ], + "startTime": "2021-01-19 15:57:51.015716783 +0000 UTC m=+19106.791327072", + "state": "completed", + "stopTime": "2021-01-19 15:57:51.123751229 +0000 UTC m=+19106.899361513", + "subClass": "analyze", + "submitTime": "2021-01-19 15:57:41.01262637 +0000 UTC m=+19096.788236671" + } + }, + { + "tasks_cache": { + "class": "advisor", + "delay": "1h0m0s", + "id": "ce4ec13f-720e-56ae-8790-8136ea0648e3", + "name": "4e394fad-03d5-4fbf-b9a5-6ad902c8df75", + "node": "127.0.0.1:8091", + "results": [ + {} + ], + "state": "cancelled", + "subClass": "analyze", + "submitTime": "2021-01-19 15:56:12.398458243 +0000 UTC m=+19008.174068538" + } + } + ] + } +] +// end::cancelled[] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-list.n1ql b/modules/n1ql/examples/functions/advisor-list.n1ql new file mode 100644 index 000000000..e98fa9791 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-list.n1ql @@ -0,0 +1 @@ +SELECT ADVISOR({"action": "list"}) AS List; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-multiple.jsonc b/modules/n1ql/examples/functions/advisor-multiple.jsonc new file mode 100644 index 000000000..47e53f920 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-multiple.jsonc @@ -0,0 +1,41 @@ +[ + { + "Multiple": { + "current_used_indexes": [ + { + "index": "CREATE INDEX def_inventory_landmark_city ON `default`:`travel-sample`.`inventory`.`landmark`(`city`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT * FROM `travel-sample`.inventory.landmark\n WHERE activity = 'eat' AND city = 'Paris'" + }, + { + "run_count": 1, + "statement": "SELECT * FROM `travel-sample`.inventory.landmark\n WHERE activity = 'see' AND city = 'San Francisco'" + } + ] + } + ], + "recommended_indexes": [ + { + "index": "CREATE INDEX adv_city_activity ON `default`:`travel-sample`.`inventory`.`landmark`(`city`,`activity`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT * FROM `travel-sample`.inventory.landmark\n WHERE activity = 'eat' AND city = 'Paris'" + } + ] + }, + { + "index": "CREATE INDEX adv_activity_city ON `default`:`travel-sample`.`inventory`.`landmark`(`activity`,`city`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT * FROM `travel-sample`.inventory.landmark\n WHERE activity = 'see' AND city = 'San Francisco'" + } + ] + } + ] + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-multiple.n1ql b/modules/n1ql/examples/functions/advisor-multiple.n1ql new file mode 100644 index 000000000..145aef8e0 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-multiple.n1ql @@ -0,0 +1,6 @@ +SELECT ADVISOR([ + "SELECT * FROM landmark + WHERE activity = 'eat' AND city = 'Paris'", + "SELECT * FROM landmark + WHERE activity = 'see' AND city = 'San Francisco'" +]) AS Multiple; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-purge.jsonc b/modules/n1ql/examples/functions/advisor-purge.jsonc new file mode 100644 index 000000000..054062255 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-purge.jsonc @@ -0,0 +1,5 @@ +[ + { + "Purge": [] + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-purge.n1ql b/modules/n1ql/examples/functions/advisor-purge.n1ql new file mode 100644 index 000000000..590096471 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-purge.n1ql @@ -0,0 +1,2 @@ +SELECT ADVISOR({"action": "purge", "session": "0cd09ae4-a083-4a7e-86cd-85e42c140d60"}) +AS Purge; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-recent.jsonc b/modules/n1ql/examples/functions/advisor-recent.jsonc new file mode 100644 index 000000000..30b25cef0 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-recent.jsonc @@ -0,0 +1,84 @@ +// tag::current[] +[ + { + "Recent": { + "current_used_indexes": [ + { + "index": "CREATE PRIMARY INDEX def_inventory_route_primary ON `default`:`travel-sample`.`inventory`.`route`", + "statements": [ + { + "run_count": 3, + "statement": "SELECT * FROM `travel-sample`.inventory.route r JOIN `travel-sample`.inventory.airline a ON r.airlineid= META(a).id WHERE a.country = \"France\";" + }, + { + "run_count": 2, + "statement": "SELECT d.id, d.destinationairport, RATIO_TO_REPORT(d.distance) OVER (PARTITION BY d.destinationairport) AS `distance-ratio` FROM `travel-sample`.inventory.route AS d LIMIT 7;" + }, +// end::current[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "run_count": 1, + "statement": "SELECT sum(array_length(PAIRS(self))) FROM `travel-sample`.inventory.route\nLIMIT 1;" + } +// tag::recommended[] + ] + }, + { + "index": "CREATE PRIMARY INDEX def_inventory_airport_primary ON `default`:`travel-sample`.`inventory`.`airport`", + "statements": [ + { + "run_count": 1, + "statement": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } + ] + } + ], + "recommended_covering_indexes": [ + { + "index": "CREATE INDEX adv_geo_alt_airportname ON `default`:`travel-sample`.`inventory`.`airport`(`geo`.`alt`,`airportname`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } + ] + } + ], + "recommended_indexes": [ + { + "index": "CREATE INDEX adv_geo_alt ON `default`:`travel-sample`.`inventory`.`airport`(`geo`.`alt`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } + ] + }, + { + "index": "CREATE INDEX adv_airlineid ON `default`:`travel-sample`.`inventory`.`route`(`airlineid`)", + "statements": [ + { + "run_count": 3, + "statement": "SELECT * FROM `travel-sample`.inventory.route r JOIN `travel-sample`.inventory.airline a ON r.airlineid= META(a).id WHERE a.country = \"France\";" + } +// end::recommended[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + ] + }, + { + "index": "CREATE INDEX adv_country ON `default`:`travel-sample`.`inventory`.`airline`(`country`)", + "statements": [ + { + "run_count": 3, + "statement": "SELECT * FROM `travel-sample`.inventory.route r JOIN `travel-sample`.inventory.airline a ON r.airlineid= META(a).id WHERE a.country = \"France\";" + } + ] + } + ] + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-recent.n1ql b/modules/n1ql/examples/functions/advisor-recent.n1ql new file mode 100644 index 000000000..7b5d492e2 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-recent.n1ql @@ -0,0 +1 @@ +SELECT ADVISOR((SELECT RAW statement FROM system:completed_requests)) AS Recent; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-single.jsonc b/modules/n1ql/examples/functions/advisor-single.jsonc new file mode 100644 index 000000000..459194389 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-single.jsonc @@ -0,0 +1,28 @@ +[ + { + "Single": { + "current_used_indexes": [ + { + "index": "CREATE INDEX def_inventory_landmark_city ON `default`:`travel-sample`.`inventory`.`landmark`(`city`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT * FROM `travel-sample`.inventory.landmark\nWHERE activity = 'eat' AND city = 'Paris'" + } + ] + } + ], + "recommended_indexes": [ + { + "index": "CREATE INDEX adv_city_activity ON `default`:`travel-sample`.`inventory`.`landmark`(`city`,`activity`)", + "statements": [ + { + "run_count": 1, + "statement": "SELECT * FROM `travel-sample`.inventory.landmark\nWHERE activity = 'eat' AND city = 'Paris'" + } + ] + } + ] + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-single.n1ql b/modules/n1ql/examples/functions/advisor-single.n1ql new file mode 100644 index 000000000..696e2b249 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-single.n1ql @@ -0,0 +1,2 @@ +SELECT ADVISOR("SELECT * FROM landmark +WHERE activity = 'eat' AND city = 'Paris'") AS Single; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-start.jsonc b/modules/n1ql/examples/functions/advisor-start.jsonc new file mode 100644 index 000000000..4a41c3da9 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-start.jsonc @@ -0,0 +1,7 @@ +[ + { + "Collect": { + "session": "0cd09ae4-a083-4a7e-86cd-85e42c140d60" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-start.n1ql b/modules/n1ql/examples/functions/advisor-start.n1ql new file mode 100644 index 000000000..c0d54e865 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-start.n1ql @@ -0,0 +1 @@ +SELECT ADVISOR({"action": "start", "response": "0s", "duration": "1h"}) AS Collect; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-stop.jsonc b/modules/n1ql/examples/functions/advisor-stop.jsonc new file mode 100644 index 000000000..59b5b54a3 --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-stop.jsonc @@ -0,0 +1,5 @@ +[ + { + "Stop": [] + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/advisor-stop.n1ql b/modules/n1ql/examples/functions/advisor-stop.n1ql new file mode 100644 index 000000000..5cd78f22e --- /dev/null +++ b/modules/n1ql/examples/functions/advisor-stop.n1ql @@ -0,0 +1,2 @@ +SELECT ADVISOR({"action": "stop", "session": "0cd09ae4-a083-4a7e-86cd-85e42c140d60"}) +AS Stop; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/avg-all.jsonc b/modules/n1ql/examples/functions/avg-all.jsonc new file mode 100644 index 000000000..44163e379 --- /dev/null +++ b/modules/n1ql/examples/functions/avg-all.jsonc @@ -0,0 +1,5 @@ +[ + { + "AvgAllStops": 0.0002 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/avg-all.n1ql b/modules/n1ql/examples/functions/avg-all.n1ql new file mode 100644 index 000000000..443485699 --- /dev/null +++ b/modules/n1ql/examples/functions/avg-all.n1ql @@ -0,0 +1 @@ +SELECT AVG(ALL stops) AS AvgAllStops FROM route; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/avg-distinct.jsonc b/modules/n1ql/examples/functions/avg-distinct.jsonc new file mode 100644 index 000000000..ac42ad1dd --- /dev/null +++ b/modules/n1ql/examples/functions/avg-distinct.jsonc @@ -0,0 +1,5 @@ +[ + { + "AvgDistinctStops": 0.5 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/avg-distinct.n1ql b/modules/n1ql/examples/functions/avg-distinct.n1ql new file mode 100644 index 000000000..a4ed95a9e --- /dev/null +++ b/modules/n1ql/examples/functions/avg-distinct.n1ql @@ -0,0 +1 @@ +SELECT AVG(DISTINCT stops) AS AvgDistinctStops FROM route; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/avg.jsonc b/modules/n1ql/examples/functions/avg.jsonc new file mode 100644 index 000000000..27ac2c176 --- /dev/null +++ b/modules/n1ql/examples/functions/avg.jsonc @@ -0,0 +1,5 @@ +[ + { + "AverageAltitude": 870.1651422764228 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/avg.n1ql b/modules/n1ql/examples/functions/avg.n1ql new file mode 100644 index 000000000..71ffeb14a --- /dev/null +++ b/modules/n1ql/examples/functions/avg.n1ql @@ -0,0 +1 @@ +SELECT AVG(geo.alt) AS AverageAltitude FROM airport; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/min-filter.jsonc b/modules/n1ql/examples/functions/min-filter.jsonc new file mode 100644 index 000000000..1edbb7342 --- /dev/null +++ b/modules/n1ql/examples/functions/min-filter.jsonc @@ -0,0 +1,5 @@ +[ + { + "MinName": "AIRE NATURELLE LE GROZEAU Aire naturelle" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/min-filter.n1ql b/modules/n1ql/examples/functions/min-filter.n1ql new file mode 100644 index 000000000..3f66e4a5c --- /dev/null +++ b/modules/n1ql/examples/functions/min-filter.n1ql @@ -0,0 +1,2 @@ +SELECT MIN(name) FILTER (WHERE SUBSTR(name,0)>="A") AS MinName +FROM hotel; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/min-num.jsonc b/modules/n1ql/examples/functions/min-num.jsonc new file mode 100644 index 000000000..33d7b086c --- /dev/null +++ b/modules/n1ql/examples/functions/min-num.jsonc @@ -0,0 +1,5 @@ +[ + { + "MinLatitude": 32.68092 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/min-num.n1ql b/modules/n1ql/examples/functions/min-num.n1ql new file mode 100644 index 000000000..8839c5513 --- /dev/null +++ b/modules/n1ql/examples/functions/min-num.n1ql @@ -0,0 +1 @@ +SELECT MIN(geo.lat) AS MinLatitude FROM hotel; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/min-string.jsonc b/modules/n1ql/examples/functions/min-string.jsonc new file mode 100644 index 000000000..6441c8965 --- /dev/null +++ b/modules/n1ql/examples/functions/min-string.jsonc @@ -0,0 +1,5 @@ +[ + { + "MinName": "'La Mirande Hotel" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/min-string.n1ql b/modules/n1ql/examples/functions/min-string.n1ql new file mode 100644 index 000000000..b9f118bce --- /dev/null +++ b/modules/n1ql/examples/functions/min-string.n1ql @@ -0,0 +1 @@ +SELECT MIN(name) AS MinName FROM hotel; \ No newline at end of file diff --git a/modules/n1ql/examples/functions/unnest-pos.jsonc b/modules/n1ql/examples/functions/unnest-pos.jsonc new file mode 100644 index 000000000..3f90c5068 --- /dev/null +++ b/modules/n1ql/examples/functions/unnest-pos.jsonc @@ -0,0 +1,14 @@ +[ + { + "u": 10, + "upos": 0 + }, + { + "u": 9, + "upos": 1 + }, + { + "u": 4, + "upos": 2 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/functions/unnest-pos.n1ql b/modules/n1ql/examples/functions/unnest-pos.n1ql new file mode 100644 index 000000000..c38c56b8a --- /dev/null +++ b/modules/n1ql/examples/functions/unnest-pos.n1ql @@ -0,0 +1 @@ +SELECT UNNEST_POS(u) AS upos, u FROM [{"a1":[10,9,4]}] AS d UNNEST d.a1 AS u; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c1.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c1.n1ql new file mode 100644 index 000000000..17a265831 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c1.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `def_inventory_airport_airportname` +ON `travel-sample`.`inventory`.`airport`(`airportname`) WITH { "defer_build":true } \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c10.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c10.n1ql new file mode 100644 index 000000000..cd017a824 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c10.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `ai_city1` +ON hotel(DISTINCT PAIRS({"city" : LOWER(city)})); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c13.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c13.n1ql new file mode 100644 index 000000000..d44424035 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c13.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `ai_city2` +ON hotel(DISTINCT PAIRS({"city" : city})); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c2.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c2.n1ql new file mode 100644 index 000000000..3325682f8 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c2.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `def_inventory_airport_city` +ON `travel-sample`.`inventory`.`airport`(`city`) WITH { "defer_build":true } \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c3.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c3.n1ql new file mode 100644 index 000000000..0310b105b --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c3.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `def_inventory_airport_faa` +ON `travel-sample`.`inventory`.`airport`(`faa`) WITH { "defer_build":true } \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c4.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c4.n1ql new file mode 100644 index 000000000..47c62979f --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c4.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `ai_airport_day_faa` +ON airport(DISTINCT PAIRS({airportname, city, faa, type})); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c5.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c5.n1ql new file mode 100644 index 000000000..b7f1b00c3 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c5.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `ai_self` +ON airport(DISTINCT PAIRS(self)); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c6.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c6.n1ql new file mode 100644 index 000000000..373da9ed3 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c6.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `idx_city_faa_airport` +ON airport(city, faa, airportname); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c7.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c7.n1ql new file mode 100644 index 000000000..97d44615d --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c7.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `def_inventory_hotel_city` +ON `travel-sample`.`inventory`.`hotel`(`city`) WITH { "defer_build":true }; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c8.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c8.n1ql new file mode 100644 index 000000000..caebf55ab --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c8.n1ql @@ -0,0 +1 @@ +CREATE INDEX `ai_city` ON hotel(DISTINCT PAIRS({city})); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c9a.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c9a.n1ql new file mode 100644 index 000000000..15d43b1b3 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c9a.n1ql @@ -0,0 +1,3 @@ +CREATE INDEX ai_geo ON landmark +(DISTINCT PAIRS({geo.alt, geo.lat, geo.lon})) +WHERE activity = "see"; -- <1> \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c9b.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c9b.n1ql new file mode 100644 index 000000000..da65fb3e4 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-c9b.n1ql @@ -0,0 +1,3 @@ +CREATE INDEX ai_geo_activity ON landmark +(DISTINCT PAIRS({geo.alt, geo.lat, geo.lon, activity})) +WHERE activity = "see"; -- <1> \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-1.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-1.jsonc new file mode 100644 index 000000000..ef249fd4a --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-1.jsonc @@ -0,0 +1,58 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"San Francisco\")", + "index": "def_inventory_hotel_city", + "index_id": "581febfa2f2a8923", + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"San Francisco\"", + "inclusion": 3, + "low": "\"San Francisco\"" + } + ] + } + ], + "using": "gsi" + }, +// end::excerpt[] + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`hotel`.`city`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.hotel USE INDEX (def_inventory_hotel_city) WHERE city = \"San Francisco\";" +} \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-2.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-2.jsonc new file mode 100644 index 000000000..44529a3fc --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-2.jsonc @@ -0,0 +1,65 @@ +// tag::excerpt[] +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "ai_city", + "index_id": "64e238e4686486d2", + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[\"city\", \"San Francisco\"]", + "inclusion": 3, + "low": "[\"city\", \"San Francisco\"]" // <1> + } + ] + } + ], + "using": "gsi" + } + }, +// end::excerpt[] + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`hotel`.`city`) = \"San Francisco\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`hotel`.`city`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.hotel USE INDEX (ai_city) WHERE city = \"San Francisco\";" +} \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-3.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-3.jsonc new file mode 100644 index 000000000..963a2b383 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-3.jsonc @@ -0,0 +1,5 @@ +[ + { + "$1": 103 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-3.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-3.n1ql new file mode 100644 index 000000000..3eb707f5b --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-3.n1ql @@ -0,0 +1,2 @@ +SELECT array_length(PAIRS(self)) FROM route +LIMIT 1; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-4.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-4.jsonc new file mode 100644 index 000000000..6fb466678 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-4.jsonc @@ -0,0 +1,5 @@ +[ + { + "$1": 2285464 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-4.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-4.n1ql new file mode 100644 index 000000000..8a27f1233 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-limits-4.n1ql @@ -0,0 +1,2 @@ +SELECT sum(array_length(PAIRS(self))) FROM route +LIMIT 1; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-partial-1.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-partial-1.jsonc new file mode 100644 index 000000000..00cf99557 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-partial-1.jsonc @@ -0,0 +1,53 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "as": "t", + "bucket": "travel-sample", + "index": "def_inventory_landmark_primary", // <1> +// end::excerpt[] + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "t", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((1000 < ((`t`.`geo`).`alt`)) and ((`t`.`activity`) = \"see\"))" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(meta(`t`).`id`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT META(t).id FROM `travel-sample`.inventory.landmark t WHERE t.geo.alt > 1000 AND t.activity = \"see\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-partial-2.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-partial-2.jsonc new file mode 100644 index 000000000..f887a57c9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-partial-2.jsonc @@ -0,0 +1,103 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IntersectScan", + "scans": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "as": "t", + "bucket": "travel-sample", + "index": "ai_geo_activity", // <1> + "index_id": "29640ebd837e32fb", + "index_projection": { + "primary_key": true + }, +// end::excerpt[] + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[successor(\"alt\")]", + "inclusion": 0, + "low": "[\"alt\", 1000]" + } + ] + } + ], + "using": "gsi" + } + }, + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "as": "t", + "bucket": "travel-sample", + "index": "ai_geo_activity", + "index_id": "29640ebd837e32fb", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[\"activity\", \"see\"]", + "inclusion": 3, + "low": "[\"activity\", \"see\"]" + } + ] + } + ], + "using": "gsi" + } + } + ] + }, + { + "#operator": "Fetch", + "as": "t", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((1000 < ((`t`.`geo`).`alt`)) and ((`t`.`activity`) = \"see\"))" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(meta(`t`).`id`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT META(t).id FROM `travel-sample`.inventory.landmark t WHERE t.geo.alt > 1000 AND t.activity = \"see\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-1.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-1.jsonc new file mode 100644 index 000000000..5041b08e7 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-1.jsonc @@ -0,0 +1,105 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IntersectScan", // <1> + "scans": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_name", +// end::excerpt[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "eb63e6a4402eb274", + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" +// tag::excerpt[] + }, + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_self", +// end::excerpt[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "8e7fe011f32820e5", + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[successor(\"name\")]", + "inclusion": 1, + "low": "[\"name\", false]" + } + ] + } + ], + "using": "gsi" + } + } + ] + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`hotel`.`name`) is not null)" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "text": "SELECT * FROM `travel-sample`.inventory.hotel WHERE name IS NOT NULL;" + } +] diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-1.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-1.n1ql new file mode 100644 index 000000000..41c02b6b2 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-1.n1ql @@ -0,0 +1,3 @@ +CREATE INDEX idx_name ON hotel(name); -- <1> +CREATE INDEX idx_self ON hotel(DISTINCT PAIRS(self)); -- <2> +EXPLAIN SELECT * FROM hotel WHERE name IS NOT NULL; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-2.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-2.n1ql new file mode 100644 index 000000000..d05520f80 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-perform-2.n1ql @@ -0,0 +1,9 @@ +CREATE INDEX idx_adpt ON landmark(DISTINCT PAIRS(self)) +WHERE city="Paris"; + +CREATE INDEX idx_reg1 ON landmark(name) WHERE city="Paris"; + +CREATE INDEX idx_reg2 ON landmark(city); + +SELECT * FROM landmark +WHERE city="Paris" AND name IS NOT NULL; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q1.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q1.n1ql new file mode 100644 index 000000000..5f7a215fc --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q1.n1ql @@ -0,0 +1 @@ +SELECT * FROM airport WHERE airportname LIKE "San Francisco%"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q10.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q10.jsonc new file mode 100644 index 000000000..a25390f32 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q10.jsonc @@ -0,0 +1,58 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(lower(cover ((`hotel`.`city`))) = \"san francisco\")", + "index": "def_inventory_hotel_city", // <1> + "index_id": "581febfa2f2a8923", +// end::excerpt[] + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`hotel`.`city`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.hotel\nUSE INDEX (ai_city1)\nWHERE LOWER(city) = \"san francisco\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q10.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q10.n1ql new file mode 100644 index 000000000..90c620008 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q10.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city FROM hotel +USE INDEX (ai_city1) +WHERE LOWER(city) = "san francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q11.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q11.jsonc new file mode 100644 index 000000000..f44a8500d --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q11.jsonc @@ -0,0 +1,58 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(not (cover ((`hotel`.`city`)) like \"%Francisco\"))", + "index": "def_inventory_hotel_city", // <1> + "index_id": "581febfa2f2a8923", +// end::excerpt[] + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`hotel`.`city`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.hotel\nUSE INDEX (ai_city)\nWHERE city NOT LIKE \"%Francisco\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q11.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q11.n1ql new file mode 100644 index 000000000..148705cf7 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q11.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city FROM hotel +USE INDEX (ai_city) +WHERE city NOT LIKE "%Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q12.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q12.jsonc new file mode 100644 index 000000000..b18783bac --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q12.jsonc @@ -0,0 +1,67 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "ai_city", // <1> + "index_id": "64e238e4686486d2", +// end::excerpt[] + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[\"city\", like_stop(\"%Francisco\")]", + "inclusion": 1, + "low": "[\"city\", like_prefix(\"%Francisco\")]" + } + ] + } + ], + "using": "gsi" + } + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`hotel`.`city`) like \"%Francisco\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`hotel`.`city`)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.hotel\nUSE INDEX (ai_city)\nWHERE city LIKE \"%Francisco\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q12.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q12.n1ql new file mode 100644 index 000000000..ce3cdd553 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q12.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city FROM hotel +USE INDEX (ai_city) +WHERE city LIKE "%Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q13.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q13.jsonc new file mode 100644 index 000000000..2a4f3935a --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q13.jsonc @@ -0,0 +1,60 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"San Francisco\")", + "index": "def_inventory_hotel_city", // <1> + "index_id": "581febfa2f2a8923", +// end::excerpt[] + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "hotel", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"San Francisco\"", + "inclusion": 3, + "low": "\"San Francisco\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`hotel`.`city`))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT city FROM `travel-sample`.inventory.hotel\nWHERE city = \"San Francisco\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q13.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q13.n1ql new file mode 100644 index 000000000..8ec01607f --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q13.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT city FROM hotel +WHERE city = "San Francisco"; -- <1> \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q1a.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q1a.n1ql new file mode 100644 index 000000000..942be567b --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q1a.n1ql @@ -0,0 +1,3 @@ +SELECT * FROM airport +USE INDEX (ai_airport_day_faa) +WHERE airportname LIKE "San Francisco%"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q2.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q2.n1ql new file mode 100644 index 000000000..a5a294ab5 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q2.n1ql @@ -0,0 +1 @@ +SELECT * FROM airport WHERE city = "San Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q2a.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q2a.n1ql new file mode 100644 index 000000000..749fc9f27 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q2a.n1ql @@ -0,0 +1,3 @@ +SELECT * FROM airport +USE INDEX (ai_airport_day_faa) +WHERE city = "San Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q3.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q3.n1ql new file mode 100644 index 000000000..92cee7d28 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q3.n1ql @@ -0,0 +1 @@ +SELECT * FROM airport WHERE faa = "SFO"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q3a.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q3a.n1ql new file mode 100644 index 000000000..7584a7a96 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q3a.n1ql @@ -0,0 +1,3 @@ +SELECT * FROM airport +USE INDEX (ai_airport_day_faa) +WHERE faa = "SFO"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5.jsonc new file mode 100644 index 000000000..e145fb6d9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5.jsonc @@ -0,0 +1,68 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "ai_self", + "index_id": "1243095ed73061b5", + "index_projection": { + "primary_key": true + }, + "keyspace": "airport", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[\"faa\", \"SFO\"]", + "inclusion": 3, + "low": "[\"faa\", \"SFO\"]" + } + ] + } + ], + "using": "gsi" + } +// end::excerpt[] + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "airport", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`airport`.`faa`) = \"SFO\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "text": "SELECT * FROM `travel-sample`.inventory.airport\nUSE INDEX (ai_self)\nWHERE faa = \"SFO\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5.n1ql new file mode 100644 index 000000000..3321f2a88 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT * FROM airport +USE INDEX (ai_self) +WHERE faa = "SFO"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5a.jsonc b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5a.jsonc new file mode 100644 index 000000000..6d7932a55 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5a.jsonc @@ -0,0 +1,68 @@ +// tag::excerpt[] +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "ai_self", + "index_id": "1243095ed73061b5", + "index_projection": { + "primary_key": true + }, + "keyspace": "airport", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "[\"tz\", \"Europe/Paris\"]", + "inclusion": 3, + "low": "[\"tz\", \"Europe/Paris\"]" + } + ] + } + ], + "using": "gsi" + } +// end::excerpt[] + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "airport", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`airport`.`tz`) = \"Europe/Paris\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "text": "SELECT *\nFROM `travel-sample`.inventory.airport\nUSE INDEX (ai_self)\nWHERE tz = \"Europe/Paris\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5a.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5a.n1ql new file mode 100644 index 000000000..a96e20b61 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q5a.n1ql @@ -0,0 +1,4 @@ +EXPLAIN SELECT * +FROM airport +USE INDEX (ai_self) +WHERE tz = "Europe/Paris"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q6.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q6.n1ql new file mode 100644 index 000000000..dce64570f --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q6.n1ql @@ -0,0 +1,3 @@ +SELECT * FROM airport +WHERE faa = "SFO" +AND city IS NOT MISSING; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q7.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q7.n1ql new file mode 100644 index 000000000..3f46da8d3 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q7.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city FROM hotel +USE INDEX (def_inventory_hotel_city) +WHERE city = "San Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q8.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q8.n1ql new file mode 100644 index 000000000..2875d6ea7 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q8.n1ql @@ -0,0 +1,3 @@ +EXPLAIN SELECT city FROM hotel +USE INDEX (ai_city) +WHERE city = "San Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q9.n1ql b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q9.n1ql new file mode 100644 index 000000000..032d22cc1 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/adaptive-idx-q9.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT META(t).id FROM landmark t +WHERE t.geo.alt > 1000 AND t.activity = "see"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/advise-setup.n1ql b/modules/n1ql/examples/n1ql-language-reference/advise-setup.n1ql new file mode 100644 index 000000000..5bc7bf9f8 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/advise-setup.n1ql @@ -0,0 +1 @@ +UPDATE STATISTICS FOR INDEX default:`travel-sample`.inventory.hotel.def_inventory_hotel_primary; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/alter-idx-move.jsonc b/modules/n1ql/examples/n1ql-language-reference/alter-idx-move.jsonc new file mode 100644 index 000000000..914332edb --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/alter-idx-move.jsonc @@ -0,0 +1,3 @@ +{ + "results": [] +} \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/alter-idx-move.n1ql b/modules/n1ql/examples/n1ql-language-reference/alter-idx-move.n1ql new file mode 100644 index 000000000..327e2cfda --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/alter-idx-move.n1ql @@ -0,0 +1,2 @@ +ALTER INDEX def_inventory_airport_faa ON airport +WITH {"action": "move", "nodes": ["192.168.10.11:8091"]}; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/build-idx-all.n1ql b/modules/n1ql/examples/n1ql-language-reference/build-idx-all.n1ql new file mode 100644 index 000000000..fc77fc44a --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/build-idx-all.n1ql @@ -0,0 +1,7 @@ +BUILD INDEX ON landmark (( -- <1> + SELECT RAW name -- <2> + FROM system:indexes + WHERE keyspace_id = 'landmark' + AND scope_id = 'inventory' + AND bucket_id = 'travel-sample' + AND state = 'deferred' )); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/build-idx-error.jsonc b/modules/n1ql/examples/n1ql-language-reference/build-idx-error.jsonc new file mode 100644 index 000000000..8f70aeecc --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/build-idx-error.jsonc @@ -0,0 +1,7 @@ +[ + { + "code": 5000, + "msg": "GSI CreateIndex() - cause: Encountered transient error. Index creation will be retried in background. Error: Index ... will retry building in the background for reason: Build Already In Progress. Keyspace ...", + "query": "..." + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/build-idx-multiple.n1ql b/modules/n1ql/examples/n1ql-language-reference/build-idx-multiple.n1ql new file mode 100644 index 000000000..6a62515c9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/build-idx-multiple.n1ql @@ -0,0 +1 @@ +BUILD INDEX ON hotel(idx_landmark_name, idx_landmark_primary); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/build-idx-single.n1ql b/modules/n1ql/examples/n1ql-language-reference/build-idx-single.n1ql new file mode 100644 index 000000000..5d39c7207 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/build-idx-single.n1ql @@ -0,0 +1 @@ +BUILD INDEX ON landmark(idx_landmark_country) USING GSI; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/build-pri-single.n1ql b/modules/n1ql/examples/n1ql-language-reference/build-pri-single.n1ql new file mode 100644 index 000000000..a90eebecb --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/build-pri-single.n1ql @@ -0,0 +1 @@ +BUILD INDEX ON hotel(idx_hotel_primary) USING GSI; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/check-idx-defer.jsonc b/modules/n1ql/examples/n1ql-language-reference/check-idx-defer.jsonc new file mode 100644 index 000000000..b55f383a9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/check-idx-defer.jsonc @@ -0,0 +1,18 @@ +[ + { + "indexes": { + "bucket_id": "travel-sample", + "datastore_id": "http://127.0.0.1:8091", + "id": "d079aec40eb0c6cc", + "index_key": [ + "`country`" + ], + "keyspace_id": "landmark", + "name": "idx_landmark_country", + "namespace_id": "default", + "scope_id": "inventory", + "state": "deferred", // <1> + "using": "gsi" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/check-idx-defer.n1ql b/modules/n1ql/examples/n1ql-language-reference/check-idx-defer.n1ql new file mode 100644 index 000000000..1e658f2f9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/check-idx-defer.n1ql @@ -0,0 +1 @@ +SELECT * FROM system:indexes WHERE name="idx_landmark_country"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/check-idx-online.jsonc b/modules/n1ql/examples/n1ql-language-reference/check-idx-online.jsonc new file mode 100644 index 000000000..d96d88c12 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/check-idx-online.jsonc @@ -0,0 +1,18 @@ +[ + { + "indexes": { + "bucket_id": "travel-sample", + "datastore_id": "http://127.0.0.1:8091", + "id": "d079aec40eb0c6cc", + "index_key": [ + "`country`" + ], + "keyspace_id": "landmark", + "name": "idx_landmark_country", + "namespace_id": "default", + "scope_id": "inventory", + "state": "online", // <1> + "using": "gsi" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/check-idx-online.n1ql b/modules/n1ql/examples/n1ql-language-reference/check-idx-online.n1ql new file mode 100644 index 000000000..1e658f2f9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/check-idx-online.n1ql @@ -0,0 +1 @@ +SELECT * FROM system:indexes WHERE name="idx_landmark_country"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/check-pri-defer.n1ql b/modules/n1ql/examples/n1ql-language-reference/check-pri-defer.n1ql new file mode 100644 index 000000000..01a31ff9d --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/check-pri-defer.n1ql @@ -0,0 +1 @@ +SELECT * FROM system:indexes WHERE name="idx_hotel_primary"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/check-pri-online.n1ql b/modules/n1ql/examples/n1ql-language-reference/check-pri-online.n1ql new file mode 100644 index 000000000..01a31ff9d --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/check-pri-online.n1ql @@ -0,0 +1 @@ +SELECT * FROM system:indexes WHERE name="idx_hotel_primary"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-collection.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-collection.n1ql new file mode 100644 index 000000000..dbfcf484f --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-collection.n1ql @@ -0,0 +1,11 @@ +/* tag::context[] */ +\UNSET -query_context; +/* end::context[] */ + +/* tag::query[] */ +CREATE INDEX idx_airport_over1000 + ON `travel-sample`.inventory.airport(geo.alt) + WHERE geo.alt > 1000 + USING GSI + WITH {"nodes": ["127.0.0.1:8091"]}; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-default.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-default.n1ql new file mode 100644 index 000000000..8f5183455 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-default.n1ql @@ -0,0 +1,11 @@ +/* tag::context[] */ +\UNSET -query_context; +/* end::context[] */ + +/* tag::query[] */ +CREATE INDEX idx_default_over1000 + ON `travel-sample`(geo.alt) + WHERE geo.alt > 1000 + USING GSI + WITH {"nodes": ["127.0.0.1:8091"]}; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-1.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-1.n1ql new file mode 100644 index 000000000..837fca5b3 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-1.n1ql @@ -0,0 +1,4 @@ +CREATE INDEX idx_landmark_country + ON landmark(country) + USING GSI + WITH {"defer_build":true}; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-2.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-2.n1ql new file mode 100644 index 000000000..3083a2826 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-2.n1ql @@ -0,0 +1,4 @@ +CREATE INDEX idx_landmark_name + ON landmark(name) + USING GSI + WITH {"defer_build":true}; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-3.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-3.n1ql new file mode 100644 index 000000000..68c031479 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-defer-3.n1ql @@ -0,0 +1,4 @@ +CREATE PRIMARY INDEX idx_landmark_primary + ON landmark + USING GSI + WITH {"defer_build":true}; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-include.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-include.n1ql new file mode 100644 index 000000000..9e7a3d0b7 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-include.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX idx_airport_include +ON airport(district INCLUDE MISSING, name); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-missing.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-missing.n1ql new file mode 100644 index 000000000..c37fb77b4 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-missing.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX idx_airport_missing +ON airport(district, name); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-name.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-name.n1ql new file mode 100644 index 000000000..7addbf964 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-name.n1ql @@ -0,0 +1 @@ +CREATE INDEX `idx-name` ON airline(name); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-node.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-node.n1ql new file mode 100644 index 000000000..fba22aa5e --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-node.n1ql @@ -0,0 +1,5 @@ +CREATE INDEX idx_airport_over1000 + ON airport(geo.alt) + WHERE geo.alt > 1000 + USING GSI + WITH {"nodes": ["127.0.0.1:8091"]}; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-idx-predicate.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-idx-predicate.n1ql new file mode 100644 index 000000000..639d5a8ca --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-idx-predicate.n1ql @@ -0,0 +1,2 @@ +CREATE INDEX `idx_image_direct_url` +ON landmark(`image_direct_url`); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-pri-collection.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-pri-collection.n1ql new file mode 100644 index 000000000..527419ba7 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-pri-collection.n1ql @@ -0,0 +1,7 @@ +/* tag::context[] */ +\UNSET -query_context; +/* end::context[] */ + +/* tag::query[] */ +CREATE PRIMARY INDEX idx_airport_primary ON `travel-sample`.inventory.airport USING GSI; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-pri-default.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-pri-default.n1ql new file mode 100644 index 000000000..7624601b0 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-pri-default.n1ql @@ -0,0 +1,7 @@ +/* tag::context[] */ +\UNSET -query_context; +/* end::context[] */ + +/* tag::query[] */ +CREATE PRIMARY INDEX idx_default_primary ON `travel-sample` USING GSI; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-pri-defer.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-pri-defer.n1ql new file mode 100644 index 000000000..3ff9fc601 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-pri-defer.n1ql @@ -0,0 +1,4 @@ +CREATE PRIMARY INDEX idx_hotel_primary + ON hotel + USING GSI + WITH {"defer_build":true}; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-pri-name.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-pri-name.n1ql new file mode 100644 index 000000000..0a77ad1f3 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-pri-name.n1ql @@ -0,0 +1 @@ +CREATE PRIMARY INDEX travel_primary ON airline; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-pri-nameless.jsonc b/modules/n1ql/examples/n1ql-language-reference/create-pri-nameless.jsonc new file mode 100644 index 000000000..c9f4975e0 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-pri-nameless.jsonc @@ -0,0 +1,17 @@ +[ + { + "indexes": { + "bucket_id": "travel-sample", + "datastore_id": "http://127.0.0.1:8091", + "id": "c6f4ec5d935e1626", + "index_key": [], + "is_primary": true, + "keyspace_id": "airline", + "name": "#primary", + "namespace_id": "default", + "scope_id": "inventory", + "state": "online", + "using": "gsi" + } + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/create-pri-nameless.n1ql b/modules/n1ql/examples/n1ql-language-reference/create-pri-nameless.n1ql new file mode 100644 index 000000000..77f82eece --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/create-pri-nameless.n1ql @@ -0,0 +1,6 @@ +/* tag::query[] */ +CREATE PRIMARY INDEX ON airline; +/* end::query[] */ +/* tag::check[] */ +SELECT * FROM system:indexes WHERE name = '#primary'; +/* end::check[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-idx-alt.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-idx-alt.n1ql new file mode 100644 index 000000000..e9d1e501d --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-idx-alt.n1ql @@ -0,0 +1 @@ +DROP INDEX airline.`idx-name`; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-idx-collection.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-idx-collection.n1ql new file mode 100644 index 000000000..ad24341b2 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-idx-collection.n1ql @@ -0,0 +1,15 @@ +/* tag::context[] */ +\UNSET -query_context; +/* end::context[] */ + +/* tag::tmp[] */ +CREATE INDEX `idx-name` ON `travel-sample`.inventory.airline(name) USING GSI; +/* end::tmp[] */ + +/* tag::query[] */ +DROP INDEX default:`travel-sample`.inventory.airline.`idx-name`; +/* end::query[] */ + +/* tag::alt[] */ +DROP INDEX `idx-name` ON `travel-sample`.inventory.airline; +/* end::alt[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-idx-default.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-idx-default.n1ql new file mode 100644 index 000000000..c2e9e138c --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-idx-default.n1ql @@ -0,0 +1,17 @@ +/* tag::context[] */ +\UNSET -query_context; +/* end::context[] */ + +/* tag::tmp[] */ +CREATE INDEX `idx-callsign` ON `travel-sample`(callsign) USING GSI; +SELECT * FROM system:indexes WHERE name="idx-callsign"; +/* end::tmp[] */ + +/* tag::query[] */ +DROP INDEX `travel-sample`.`idx-callsign` USING GSI; +SELECT * FROM system:indexes WHERE name="idx-callsign"; +/* end::query[] */ + +/* tag::alt[] */ +DROP INDEX `idx-callsign` ON `travel-sample` USING GSI; +/* end::alt[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-idx-name.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-idx-name.n1ql new file mode 100644 index 000000000..74b94da8e --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-idx-name.n1ql @@ -0,0 +1 @@ +DROP INDEX `idx-name` ON airline; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-pri-alt.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-pri-alt.n1ql new file mode 100644 index 000000000..1552089eb --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-pri-alt.n1ql @@ -0,0 +1 @@ +DROP INDEX airline.travel_primary; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-pri-name.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-pri-name.n1ql new file mode 100644 index 000000000..49f4c22fc --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-pri-name.n1ql @@ -0,0 +1 @@ +DROP INDEX travel_primary ON airline; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/drop-pri-nameless.n1ql b/modules/n1ql/examples/n1ql-language-reference/drop-pri-nameless.n1ql new file mode 100644 index 000000000..138af9614 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/drop-pri-nameless.n1ql @@ -0,0 +1,6 @@ +/* tag::query[] */ +DROP PRIMARY INDEX ON airline; +/* end::query[] */ +/* tag::check[] */ +SELECT * FROM system:indexes WHERE name = '#primary'; +/* end::check[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/explain-idx-filter.jsonc b/modules/n1ql/examples/n1ql-language-reference/explain-idx-filter.jsonc new file mode 100644 index 000000000..1b95c2f70 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/explain-idx-filter.jsonc @@ -0,0 +1,91 @@ +// tag::include[] +[ + { + "cardinality": 1.0842021724855044e-19, + "cost": 1.0974078994531663e-16, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`airport`.`district`))", + "cover ((`airport`.`name`))", + "cover ((meta(`airport`).`id`))" + ], + "index": "idx_airport_missing", // <.> +// end::include[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "4c49c415d261e427", + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "airport", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1.0842021724855044e-19, + "cost": 1.0974003878801727e-16, + "fr_cost": 1.0974003878801727e-16, + "size": 12 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "index_key": "`district`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(cover ((`airport`.`district`)) is not missing)", + "optimizer_estimates": { + "cardinality": 1.0842021724855044e-19, + "cost": 1.0974041436666695e-16, + "fr_cost": 1.0974041436666695e-16, + "size": 12 + } + }, + { + "#operator": "InitialProject", + "discard_original": true, + "optimizer_estimates": { + "cardinality": 1.0842021724855044e-19, + "cost": 1.0974078994531663e-16, + "fr_cost": 1.0974078994531663e-16, + "size": 12 + }, + "preserve_order": true, + "result_terms": [ + { + "expr": "cover ((`airport`.`district`))" + } + ] + } + ] + } +// tag::include[] + } + ] + }, + "text": "SELECT district FROM airport\nWHERE district IS NOT MISSING;" + } +] +// end::include[] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/explain-idx-filter.n1ql b/modules/n1ql/examples/n1ql-language-reference/explain-idx-filter.n1ql new file mode 100644 index 000000000..9e279eb52 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/explain-idx-filter.n1ql @@ -0,0 +1,2 @@ +EXPLAIN SELECT district FROM airport +WHERE district IS NOT MISSING; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/explain-idx-include.jsonc b/modules/n1ql/examples/n1ql-language-reference/explain-idx-include.jsonc new file mode 100644 index 000000000..912faf417 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/explain-idx-include.jsonc @@ -0,0 +1,80 @@ +// tag::include[] +[ + { + "cardinality": 1968, + "cost": 761.4521745648723, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`airport`.`district`))", + "cover ((`airport`.`name`))", + "cover ((meta(`airport`).`id`))" + ], + "index": "idx_airport_include", // <.> +// end::include[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "index_id": "d3ee8615205a69e9", + "index_projection": { + "entry_keys": [ + 0 + ] + }, + "keyspace": "airport", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1968, + "cost": 751.2261465969856, + "fr_cost": 12.375623041970014, + "size": 27 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "index_key": "`district`" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "discard_original": true, + "optimizer_estimates": { + "cardinality": 1968, + "cost": 761.4521745648723, + "fr_cost": 12.380819194392721, + "size": 27 + }, + "preserve_order": true, + "result_terms": [ + { + "expr": "cover ((`airport`.`district`))" + } + ] + } + ] + } +// tag::include[] + } + ] + }, + "text": "SELECT district FROM airport;" + } +] +// end::include[] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/explain-idx-missing.jsonc b/modules/n1ql/examples/n1ql-language-reference/explain-idx-missing.jsonc new file mode 100644 index 000000000..19e1cab00 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/explain-idx-missing.jsonc @@ -0,0 +1,77 @@ +// tag::include[] +[ + { + "cardinality": 1968, + "cost": 2234.798843874139, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_airport_primary", // <.> + "index_projection": { + "primary_key": true + }, +// end::include[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "keyspace": "airport", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1968, + "cost": 362.3057953674344, + "fr_cost": 12.1780009122802, + "size": 12 + }, + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "early_projection": [ + "district" + ], + "keyspace": "airport", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1968, + "cost": 2201.112110105488, + "fr_cost": 25.106256153508888, + "size": 293 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "discard_original": true, + "optimizer_estimates": { + "cardinality": 1968, + "cost": 2234.798843874139, + "fr_cost": 25.12337339627751, + "size": 293 + }, + "preserve_order": true, + "result_terms": [ + { + "expr": "(`airport`.`district`)" + } + ] + } + ] + } +// tag::include[] + } + ] + }, + "text": "SELECT district FROM airport;" + } +] +// end::include[] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/explain-idx-missing.n1ql b/modules/n1ql/examples/n1ql-language-reference/explain-idx-missing.n1ql new file mode 100644 index 000000000..4614986d1 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/explain-idx-missing.n1ql @@ -0,0 +1 @@ +EXPLAIN SELECT district FROM airport; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/meta-idx-cas.n1ql b/modules/n1ql/examples/n1ql-language-reference/meta-idx-cas.n1ql new file mode 100644 index 000000000..ac6caebdc --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/meta-idx-cas.n1ql @@ -0,0 +1 @@ +CREATE INDEX idx_hotel_cas ON hotel (META().cas); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/meta-idx-expire.n1ql b/modules/n1ql/examples/n1ql-language-reference/meta-idx-expire.n1ql new file mode 100644 index 000000000..e6aa4d806 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/meta-idx-expire.n1ql @@ -0,0 +1 @@ +CREATE INDEX idx_airline_expire ON airline (META().expiration); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/meta-idx-id.n1ql b/modules/n1ql/examples/n1ql-language-reference/meta-idx-id.n1ql new file mode 100644 index 000000000..8b37ccdfb --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/meta-idx-id.n1ql @@ -0,0 +1 @@ +CREATE INDEX idx_hotel_id ON hotel (META().id); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/partition-idx.n1ql b/modules/n1ql/examples/n1ql-language-reference/partition-idx.n1ql new file mode 100644 index 000000000..4a4e97023 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/partition-idx.n1ql @@ -0,0 +1,3 @@ +CREATE INDEX idx ON airline +(country, name, id) + PARTITION BY HASH(META().id); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/select-idx-filter.n1ql b/modules/n1ql/examples/n1ql-language-reference/select-idx-filter.n1ql new file mode 100644 index 000000000..1bf991962 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/select-idx-filter.n1ql @@ -0,0 +1,2 @@ +SELECT image_direct_url FROM landmark +WHERE image_direct_url IS NOT MISSING; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-1.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-1.n1ql new file mode 100644 index 000000000..6f6807de7 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-1.n1ql @@ -0,0 +1,2 @@ +SELECT t1.city FROM landmark t1 +WHERE t1.city IN (SELECT RAW city FROM airport); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-10.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-10.n1ql new file mode 100644 index 000000000..cbfd26d9c --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-10.n1ql @@ -0,0 +1 @@ +SELECT x.alt FROM (SELECT geo from airport )[*].geo AS x LIMIT 2; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-11.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-11.n1ql new file mode 100644 index 000000000..8af59c06e --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-11.n1ql @@ -0,0 +1 @@ + SELECT x FROM [{"a" : 1, "b" : {"c" : 2}}, {"a" : 3, "b" : {"d" : 4}}][*].b AS x LIMIT 2; diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-12.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-12.n1ql new file mode 100644 index 000000000..0178340f9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-12.n1ql @@ -0,0 +1,2 @@ +SELECT t1.city, t1.geo.alt FROM airport t1 +WHERE (SELECT RAW t2.alt FROM airport.geo t2)[0] > 4000; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-13.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-13.n1ql new file mode 100644 index 000000000..88f7d37e6 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-13.n1ql @@ -0,0 +1,2 @@ +SELECT t1.city, t1.geo.alt FROM airport t1 +WHERE (SELECT RAW t2.alt FROM t1.geo t2)[0] > 4000; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-14.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-14.n1ql new file mode 100644 index 000000000..5d6fc68ca --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-14.n1ql @@ -0,0 +1,4 @@ +SELECT name, cnt_reviewers FROM hotel AS t +LET cnt_reviewers = (SELECT raw count(*) FROM hotel tmp USE KEYS meta(t).id + UNNEST tmp.reviews s WHERE s.ratings.Overall >= 4)[0] +WHERE cnt_reviewers >= 6 ORDER BY cnt_reviewers DESC LIMIT 10; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-2.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-2.n1ql new file mode 100644 index 000000000..8862707be --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-2.n1ql @@ -0,0 +1,6 @@ +SELECT t1.country, array_agg(t1.city), sum(t1.city_cnt) as apnum +FROM (SELECT city, city_cnt, array_agg(airportname) as apnames, country + FROM airport GROUP BY city, country + LETTING city_cnt = count(city)) AS t1 +WHERE t1.city_cnt > 5 +GROUP BY t1.country; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-3.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-3.n1ql new file mode 100644 index 000000000..3b82c64b0 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-3.n1ql @@ -0,0 +1 @@ +SELECT array_max((SELECT count(city) as cnt FROM airport GROUP BY city)[*].cnt); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-5.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-5.n1ql new file mode 100644 index 000000000..67e8f7887 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-5.n1ql @@ -0,0 +1 @@ +SELECT t1.city, t1.name FROM landmark t1 WHERE t1.city IN SPLIT(t1.name); \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-6.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-6.n1ql new file mode 100644 index 000000000..5abb8a4f2 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-6.n1ql @@ -0,0 +1 @@ +SELECT count(*) FROM airport t WHERE (SELECT RAW t.geo.alt FROM t t1)[0] > 6000; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-7.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-7.n1ql new file mode 100644 index 000000000..54f07b1dc --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-7.n1ql @@ -0,0 +1 @@ +SELECT array_length((SELECT RAW t1.geo.alt FROM airport t1)) FROM airport LIMIT 4; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-8.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-8.n1ql new file mode 100644 index 000000000..720226ac9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-8.n1ql @@ -0,0 +1 @@ +SELECT array_length((SELECT RAW t1.geo.alt FROM t t1)) FROM airport t; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/subquery-9.n1ql b/modules/n1ql/examples/n1ql-language-reference/subquery-9.n1ql new file mode 100644 index 000000000..1bf2037f9 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/subquery-9.n1ql @@ -0,0 +1 @@ +SELECT array_length((SELECT RAW t1.geo.alt FROM airport)) FROM airport; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/udf-locations-define.n1ql b/modules/n1ql/examples/n1ql-language-reference/udf-locations-define.n1ql new file mode 100644 index 000000000..4c5a8f8f6 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/udf-locations-define.n1ql @@ -0,0 +1,4 @@ +CREATE FUNCTION locations(vActivity) { ( + SELECT id, name, address, city + FROM landmark + WHERE activity = vActivity) }; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/udf-locations-query.jsonc b/modules/n1ql/examples/n1ql-language-reference/udf-locations-query.jsonc new file mode 100644 index 000000000..fe629e03d --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/udf-locations-query.jsonc @@ -0,0 +1,22 @@ +[ + { + "city": "Gillingham", + "name": "Hollywood Bowl" + }, + { + "city": "Gillingham", + "name": "Thai Won Mien" + }, + { + "city": "Gillingham", + "name": "Spice Court" + }, + { + "city": "Gillingham", + "name": "Beijing Inn" + }, + { + "city": "Gillingham", + "name": "Ossie's Fish and Chips" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/udf-locations-query.n1ql b/modules/n1ql/examples/n1ql-language-reference/udf-locations-query.n1ql new file mode 100644 index 000000000..f652cb649 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/udf-locations-query.n1ql @@ -0,0 +1,3 @@ +SELECT l.name, l.city +FROM locations("eat") AS l +WHERE l.city = "Gillingham"; \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/udf-locations-test.jsonc b/modules/n1ql/examples/n1ql-language-reference/udf-locations-test.jsonc new file mode 100644 index 000000000..f5ad57e61 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/udf-locations-test.jsonc @@ -0,0 +1,10338 @@ +// tag::excerpt[] +[ + [ + { + "address": "Prince Arthur Road, ME4 4UG", + "city": "Gillingham", + "id": 10019, + "name": "Royal Engineers Museum" + }, + { + "address": "84 rue Claude Monet", + "city": "Giverny", + "id": 10061, + "name": "Monet's House" + }, +// end::excerpt[] +{ + "address": "2 rue Blanche Hoschedé-Monet", + "city": "Giverny", + "id": 10062, + "name": "Natural Mechanical Museum" + }, + { + "address": "Cathedral Square, Castle Street", + "city": "Glasgow", + "id": 10082, + "name": "Glasgow Cathedral" + }, + { + "address": "George Square", + "city": "Glasgow", + "id": 10083, + "name": "City Chambers" + }, + { + "address": "At the junction of Trongate, Saltmarket, High Street, Gallowgate and London Road", + "city": "Glasgow", + "id": 10084, + "name": "Glasgow Cross" + }, + { + "address": "St Enoch Square, Argyle and Buchanan Streets", + "city": "Glasgow", + "id": 10085, + "name": "St Enoch Subway Station" + }, + { + "address": "Gordon Street", + "city": "Glasgow", + "id": 10086, + "name": "Glasgow Central Station" + }, + { + "address": "217 Sauchiehall St", + "city": "Glasgow", + "id": 10087, + "name": "Willow Tea Rooms" + }, + { + "address": "167 Renfrew St", + "city": "Glasgow", + "id": 10088, + "name": "Glasgow School of Art" + }, + { + "address": "North St", + "city": "Glasgow", + "id": 10089, + "name": "Mitchell Library" + }, + { + "address": null, + "city": "Glasgow", + "id": 10090, + "name": "Tradeston Pedestrian Bridge" + }, + { + "address": null, + "city": "Glasgow", + "id": 10091, + "name": "Kingston Bridge" + }, + { + "address": null, + "city": "Glasgow", + "id": 10092, + "name": "Clyde Arc" + }, + { + "address": "Exhibition Way", + "city": "Glasgow", + "id": 10093, + "name": "Clyde Auditorium" + }, + { + "address": "University Avenue, West End", + "city": "Glasgow", + "id": 10094, + "name": "Glasgow University" + }, + { + "address": null, + "city": "Glasgow", + "id": 10095, + "name": "Park Circus" + }, + { + "address": "225 Scotland St", + "city": "Glasgow", + "id": 10096, + "name": "Scotland Street School" + }, + { + "address": "Bellahouston Park", + "city": "Glasgow", + "id": 10097, + "name": "House for an Art Lover" + }, + { + "address": "61-63 Netherlee Rd", + "city": "Glasgow", + "id": 10098, + "name": "Holmwood House" + }, + { + "address": "2060 Pollokshaws Rd, Pollok Country Park", + "city": "Glasgow", + "id": 10099, + "name": "Burrell Collection" + }, + { + "address": "Royal Exchange Square", + "city": "Glasgow", + "id": 10100, + "name": "Gallery of Modern Art" + }, + { + "address": "30 Bell St", + "city": "Glasgow", + "id": 10101, + "name": "Glasgow Police Museum" + }, + { + "address": "50 Pacific Quay", + "city": "Glasgow", + "id": 10102, + "name": "Glasgow Science Centre" + }, + { + "address": "University Avenue, University Of Glasgow", + "city": "Glasgow", + "id": 10103, + "name": "Hunterian Museum and Art Gallery" + }, + { + "address": "Argyle Street, West End", + "city": "Glasgow", + "id": 10104, + "name": "Kelvingrove Art Gallery and Museum" + }, + { + "address": "Glasgow Green", + "city": "Glasgow", + "id": 10105, + "name": "People's Palace and Winter Gardens" + }, + { + "address": "3 Castle Street", + "city": "Glasgow", + "id": 10106, + "name": "Provand's Lordship" + }, + { + "address": "100 Pointhouse Place", + "city": "Glasgow", + "id": 10107, + "name": "Riverside Museum" + }, + { + "address": "Pointhouse Quay", + "city": "Glasgow", + "id": 10108, + "name": "Tall Ship" + }, + { + "address": "Trongate 103", + "city": "Glasgow", + "id": 10109, + "name": "Sharmanka" + }, + { + "address": "2 Castle Street", + "city": "Glasgow", + "id": 10110, + "name": "St. Mungo's Museum of Religious Life and Art" + }, + { + "address": "Trongate 103", + "city": "Glasgow", + "id": 10111, + "name": "Street Level Photoworks" + }, + { + "address": "145 Buccleuch Street", + "city": "Glasgow", + "id": 10112, + "name": "Tenement House" + }, + { + "address": "28 King Street", + "city": "Glasgow", + "id": 10113, + "name": "Transmission Gallery" + }, + { + "address": "11 Mitchell Lane", + "city": "Glasgow", + "id": 10114, + "name": "The Lighthouse" + }, + { + "address": null, + "city": "Glasgow", + "id": 10115, + "name": "Glasgow Green" + }, + { + "address": "West End", + "city": "Glasgow", + "id": 10116, + "name": "Kelvingrove Park" + }, + { + "address": "730 Great Western Road, West End", + "city": "Glasgow", + "id": 10117, + "name": "Botanic Gardens" + }, + { + "address": "Victoria Park Drive North, West End", + "city": "Glasgow", + "id": 10118, + "name": "Victoria Park" + }, + { + "address": "Victoria Park Drive North", + "city": "Glasgow", + "id": 10119, + "name": "Fossil Grove" + }, + { + "address": "Flenders Road", + "city": "Clarkston", + "id": 10120, + "name": "Greenbank House and Gardens" + }, + { + "address": "Main Street PH49 4HS", + "city": "Glencoe", + "id": 10140, + "name": "Glencoe Museum" + }, + { + "address": null, + "city": "Highland", + "id": 10141, + "name": "The new National Trust visitor centre" + }, + { + "address": "High Street West", + "city": "Glossop", + "id": 10155, + "name": "Wren Nest Mill" + }, + { + "address": "Melandra Castle Rd, Gamesley", + "city": "Glossop", + "id": 10156, + "name": "Ardotalia" + }, + { + "address": "Hascombe Road, Godalming, GU8 4AD", + "city": "Surrey", + "id": 10165, + "name": "Winkworth Arboretum" + }, + { + "address": "DG16 5EA", + "city": "Gretna Green", + "id": 10481, + "name": "Gretna Green Story Museum" + }, + { + "address": null, + "city": "Gullane", + "id": 10596, + "name": "Gullane Bents" + }, + { + "address": "East Fortune Airfield, East Lothian", + "city": "East Lothian", + "id": 10597, + "name": "The National Museum of Flight" + }, + { + "address": null, + "city": "East Lothian", + "id": 10598, + "name": "Dirleton Castle" + }, + { + "address": "Rhiw, Pwllheli, LL53 8AB", + "city": "Gwynedd", + "id": 10622, + "name": "Plas yn Rhiw" + }, + { + "address": "Bangor, LL57 4HN", + "city": "Gwynedd", + "id": 10623, + "name": "Penrhyn Castle" + }, + { + "address": "Haydon Bridge, NE47 6NN", + "city": "Northumberland", + "id": 10844, + "name": "Housesteads" + }, + { + "address": null, + "city": "Northumberland", + "id": 10845, + "name": "Vindolanda" + }, + { + "address": "Chollerford, NE46 4EU", + "city": "Northumberland", + "id": 10846, + "name": "Chesters" + }, + { + "address": null, + "city": "Northumberland", + "id": 10847, + "name": "Mithraeum" + }, + { + "address": null, + "city": "Armagh", + "id": 1092, + "name": "St Patrick's Cathedral (Church of Ireland)" + }, + { + "address": null, + "city": "Armagh", + "id": 1093, + "name": "St Patrick's Cathedral (Roman Catholic)" + }, + { + "address": null, + "city": "Armagh", + "id": 1094, + "name": "Armagh County Museum" + }, + { + "address": "Housesteads Roman Fort, Haydon Bridge, NE47 6NN", + "city": "Northumberland", + "id": 10946, + "name": "Housesteads Roman Fort" + }, + { + "address": "81 Killylea Road", + "city": "Armagh", + "id": 1095, + "name": "Navan Fort" + }, + { + "address": null, + "city": "Armagh", + "id": 1096, + "name": "Armagh Public Library" + }, + { + "address": "Castle Road, Pevensey, BN24 5LE", + "city": "Pevensey", + "id": 11237, + "name": "Pevensey Castle" + }, + { + "address": "Station Road", + "city": "Hayfield", + "id": 11318, + "name": "Hayfield Countryside Centre" + }, + { + "address": null, + "city": "Derbyshire", + "id": 11319, + "name": "Kinder Scout" + }, + { + "address": null, + "city": "Derbyshire", + "id": 11320, + "name": "Bowden Bridge" + }, + { + "address": null, + "city": "Helensburgh", + "id": 11368, + "name": "Hill House" + }, + { + "address": "Glenarn Road, Rhu, G84 8LL", + "city": "Rhu", + "id": 11369, + "name": "Glenarn" + }, + { + "address": null, + "city": "Helensburgh", + "id": 11370, + "name": "Henry Bell Monument" + }, + { + "address": "14 Castle Gate, YO62 5AB", + "city": "Helmsley", + "id": 11390, + "name": "Helmsley Castle" + }, + { + "address": "Rievaulx, YO62 5LB", + "city": "North Yorkshire", + "id": 11391, + "name": "Rievaulx Abbey" + }, + { + "address": null, + "city": "Hexham", + "id": 11495, + "name": "Hexham Abbey" + }, + { + "address": "Church St", + "city": "Ashbourne", + "id": 1151, + "name": "Ashbourne Pegg's almshouses" + }, + { + "address": "Church Street", + "city": "Ashbourne", + "id": 1152, + "name": "Owfield Almshouses" + }, + { + "address": "Church Street", + "city": "Ashbourne", + "id": 1153, + "name": "The Elizabethan Grammar School" + }, + { + "address": "6925 Hollywood Blvd", + "city": "Los Angeles", + "id": 11752, + "name": "Grauman's Chinese Theater" + }, + { + "address": null, + "city": "Los Angeles", + "id": 11753, + "name": "Hollywood Sign" + }, + { + "address": "1750 Vine St", + "city": "Los Angeles", + "id": 11754, + "name": "Capitol Records Building" + }, + { + "address": "6767 Hollywood Blvd", + "city": "Los Angeles", + "id": 11755, + "name": "Hollywood Wax Museum" + }, + { + "address": "1355 N Caheunga Blvd", + "city": "Los Angeles", + "id": 11756, + "name": "Los Angeles Fire Department Hollywood Museum 27" + }, + { + "address": "6780 Hollywood Blvd", + "city": "Los Angeles", + "id": 11757, + "name": "Ripley's Believe it or Not" + }, + { + "address": "along Hollywood Blvd and also Vine St", + "city": "Los Angeles", + "id": 11758, + "name": "Walk of Fame" + }, + { + "address": null, + "city": "Holyhead", + "id": 11793, + "name": "Holyhead Breakwater Country Park" + }, + { + "address": "The Skerries", + "city": "Isle of Anglesey", + "id": 11794, + "name": "Skerries Lighthouse" + }, + { + "address": "53 Billet Lane, Hornchurch, RM11 1AX", + "city": "Hornchurch", + "id": 11947, + "name": "Fairkytes Arts Centre" + }, + { + "address": "Billet Lane, Hornchurch, RM11 1QT", + "city": "Hornchurch", + "id": 11948, + "name": "Queen's Theatre" + }, + { + "address": "St Mary's Lane, Upminster, RM14 2QR", + "city": "Upminster", + "id": 11949, + "name": "Old Chapel" + }, + { + "address": "Hall Lane, Upminster, RM14 2TX", + "city": "Upminster", + "id": 11950, + "name": "Tithe Barn Museum" + }, + { + "address": "St Mary's Lane, Upminster, RM14 2QL", + "city": "Upminster", + "id": 11951, + "name": "Upminster Windmill" + }, + { + "address": "The Broadway, Rainham, RM13 9YN", + "city": "Rainham", + "id": 11952, + "name": "Rainham Hall" + }, + { + "address": "Hornchurch Road, Hornchurch, RM12 4AD", + "city": "Hornchurch", + "id": 11953, + "name": "Harrow Lodge Park" + }, + { + "address": "Squadrons Approach, Hornchurch, RM12 6TS", + "city": "Hornchurch", + "id": 11954, + "name": "Hornchurch Country Park" + }, + { + "address": "Bridge Avenue, Upminster, RM14 2LX", + "city": "Upminster", + "id": 11955, + "name": "Hornchurch Stadium" + }, + { + "address": "Marsden Moor Estate Office and Exhibition Room, Station Road, Marsden, HD7 6DH", + "city": "Marsden", + "id": 12011, + "name": "Marsden Moor Estate" + }, + { + "address": null, + "city": "Aberdeenshire", + "id": 12066, + "name": "Huntly Castle" + }, + { + "address": "AB54 4NQ", + "city": "Aberdeenshire", + "id": 12067, + "name": "Leith Hall" + }, + { + "address": null, + "city": "Inverness", + "id": 12231, + "name": "Inverness Castle" + }, + { + "address": null, + "city": "Inverness", + "id": 12232, + "name": "Inverness Museum & Art Gallery" + }, + { + "address": null, + "city": "Inverness", + "id": 12233, + "name": "Old High Church" + }, + { + "address": "16 Clachnaharry Road IV3 8QH", + "city": "Inverness", + "id": 12234, + "name": "Ship Space" + }, + { + "address": "Bught Lane", + "city": "Inverness", + "id": 12235, + "name": "Inverness Botanic Gardens" + }, + { + "address": "Nr Ironbridge, TF8 7BW", + "city": "Buildwas", + "id": 12314, + "name": "Buildwas Abbey" + }, + { + "address": "Port Ellen, PA42 7EA", + "city": "Argyll and Bute", + "id": 12331, + "name": "Ardbeg" + }, + { + "address": null, + "city": "Bowmore", + "id": 12332, + "name": "Bowmore Distillery" + }, + { + "address": null, + "city": "Bruichladdich", + "id": 12333, + "name": "Bruichladdich" + }, + { + "address": "Port Askaig, Isle of Islay, PA46 7RL", + "city": "Caolila", + "id": 12334, + "name": "Caol Ila Distillery" + }, + { + "address": "Rockside Farm, Bruichladdich, PA49 7UT", + "city": "Argyll and Bute", + "id": 12335, + "name": "Kilchoman" + }, + { + "address": "Port Ellen, Isle of Islay, PA42 7DZ", + "city": "Argyll and Bute", + "id": 12336, + "name": "Lagavulin Distillery" + }, + { + "address": null, + "city": "Brodick", + "id": 12338, + "name": "Brodick Castle, Garden & Country Park" + }, + { + "address": null, + "city": "North Ayrshire", + "id": 12339, + "name": "Arran Brewery" + }, + { + "address": "Home Farm, Brodick, Isle of Arran, KA27 8DD", + "city": "North Ayrshire", + "id": 12340, + "name": "Island Cheese Company" + }, + { + "address": "Kerrycroy, Isle of Bute", + "city": "Argyll and Bute", + "id": 12341, + "name": "Mount Stuart House" + }, + { + "address": "Rothesay", + "city": "Rothesay", + "id": 12342, + "name": "Rothesay Castle" + }, + { + "address": "Liberty Road, Castletown, DT5 1AZ", + "city": "Dorset", + "id": 12354, + "name": "Portland Castle" + }, + { + "address": "York Ave, East Cowes, PO32 6JX", + "city": "East Cowes", + "id": 12355, + "name": "Osborne House" + }, + { + "address": "Castle Hill, Carisbrooke, PO30 1XY", + "city": "Newport", + "id": 12356, + "name": "Carisbrooke Castle" + }, + { + "address": "St. Mary's", + "city": "Rocky Hill", + "id": 12358, + "name": "Harry's Walls" + }, + { + "address": "5050 Santa Fe Drive", + "city": "Atwater", + "id": 1257, + "name": "Castle Air Museum" + }, + { + "address": "Place du palais des papes", + "city": "Avignon", + "id": 1348, + "name": "Papal Palace" + }, + { + "address": null, + "city": "Avignon", + "id": 1349, + "name": "Le Pont Saint-Benezet" + }, + { + "address": "Bradford Road, Riddlesden, Keighley, BD20 5EL", + "city": "Riddlesden", + "id": 13664, + "name": "East Riddlesden Hall" + }, + { + "address": "Ayot St Lawrence, near Welwyn, AL6 9BX", + "city": "Hertfordshire", + "id": 1367, + "name": "Shaw's Corner" + }, + { + "address": "Castle Green, Off Castle Road, CV8 1NE", + "city": "Kenilworth", + "id": 13673, + "name": "Kenilworth Castle" + }, + { + "address": "Southey Works", + "city": "Keswick", + "id": 13697, + "name": "The Cumberland Pencil Museum" + }, + { + "address": "Station Road, CA12 4NF", + "city": "Keswick", + "id": 13698, + "name": "Keswick Museum & Art Gallery" + }, + { + "address": "Brewery Lane, CA12 5BY", + "city": "Keswick", + "id": 13699, + "name": "Keswick Brewery Tours" + }, + { + "address": null, + "city": "King's Lynn", + "id": 14001, + "name": "Greyfriars tower" + }, + { + "address": null, + "city": "King's Lynn", + "id": 14002, + "name": "Lynn Museum" + }, + { + "address": null, + "city": "King's Lynn", + "id": 14003, + "name": "Red Mount Chapel" + }, + { + "address": "PE35 6EH", + "city": "Norfolk", + "id": 14004, + "name": "Sandringham House" + }, + { + "address": null, + "city": "Knaresborough", + "id": 14214, + "name": "The castle" + }, + { + "address": "Prophecy Lodge, High Bridge HG5 8DD", + "city": "Knaresborough", + "id": 14215, + "name": "Mother Shipton's Cave and the Petrifying Well" + }, + { + "address": "Knutsford, Cheshire, WA16 6QN", + "city": "Cheshire East", + "id": 14221, + "name": "Tatton Park" + }, + { + "address": "90A King St., Knutsford", + "city": "Knutsford", + "id": 14222, + "name": "Knutsford Heritage Centre" + }, + { + "address": "29 Bloomgate, ML11 9ET", + "city": "Lanark", + "id": 15136, + "name": "Lanark Museum" + }, + { + "address": "Castlegate", + "city": "Lanark", + "id": 15137, + "name": "The Girnin Dug" + }, + { + "address": null, + "city": "Crossford", + "id": 15138, + "name": "Craignethan Castle" + }, + { + "address": "665 W Lancaster Blvd.", + "city": "Lancaster", + "id": 15140, + "name": "Museum of Art and History" + }, + { + "address": "557 W Lancaster Blvd.", + "city": "Lancaster", + "id": 15141, + "name": "Western Hotel Museum" + }, + { + "address": "750 W Lancaster Blvd.", + "city": "Lancaster", + "id": 15142, + "name": "Lancaster Performing Arts Center" + }, + { + "address": "43000 30th Street East", + "city": "Lancaster", + "id": 15143, + "name": "National Soccer Center" + }, + { + "address": "Custom House, St George's Quay", + "city": "Lancaster", + "id": 15149, + "name": "Lancaster Maritime Museum" + }, + { + "address": "Castle Lodge, PL15 7DR", + "city": "Launceston", + "id": 15389, + "name": "Launceston Castle" + }, + { + "address": null, + "city": "Lerwick", + "id": 15531, + "name": "Lerwick Town Hall" + }, + { + "address": null, + "city": "Lerwick", + "id": 15532, + "name": "Fort Charlotte" + }, + { + "address": null, + "city": "Lerwick", + "id": 15533, + "name": "Clickimin Broch" + }, + { + "address": null, + "city": "Lerwick", + "id": 15534, + "name": "Shetland Museum" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 15552, + "name": "Butt of Lewis Lighthouse" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 15553, + "name": "Callinish Standing Stones" + }, + { + "address": null, + "city": "Carloway", + "id": 15554, + "name": "Carloway Broch" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 15555, + "name": "Black House Museum at Arnol." + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 15556, + "name": "Garenin Historic village" + }, + { + "address": "Kenneth Street [[Stornoway]] HS1 2DS", + "city": "Stornoway", + "id": 15557, + "name": "An Lanntair Art Centre" + }, + { + "address": "Water Lane, Woolsthorpe by Colsterworth, near Grantham, NG33 5PD", + "city": "Colsterworth", + "id": 15733, + "name": "Woolsthorpe Manor" + }, + { + "address": "Grantham, NG32 2LS", + "city": "Lincolnshire", + "id": 15734, + "name": "Belton House" + }, + { + "address": "Sleaford Road, Tattershall, LN4 4LR", + "city": "Tattershall", + "id": 15735, + "name": "Tattershall Castle" + }, + { + "address": "Gunby, Spilsby, PE23 5SS", + "city": "Lincolnshire", + "id": 15736, + "name": "Gunby Hall and Gardens" + }, + { + "address": "Castlegate, Grantham, NG31 6SS", + "city": "Grantham", + "id": 15737, + "name": "Grantham House" + }, + { + "address": "38 West Street, Easton on the Hill, near Stamford, PE9 3LS", + "city": "Easton on the Hill", + "id": 15738, + "name": "Priest's House" + }, + { + "address": "Minster Yard, Lincoln, LN2 1PU", + "city": "Lincoln", + "id": 15739, + "name": "Lincoln Medieval Bishop's Palace" + }, + { + "address": "Thornton Curtis, Ulceby, DN39 6TU", + "city": "North Lincolnshire", + "id": 15740, + "name": "Thornton Abbey and Gatehouse" + }, + { + "address": "Gainsborough, DN21 2NB", + "city": "Gainsborough", + "id": 15741, + "name": "Gainsborough Old Hall" + }, + { + "address": "Barton-upon-Humber, DN18 5EX", + "city": "Barton-upon-Humber", + "id": 15742, + "name": "St Peter's Church" + }, + { + "address": "PE22 0SY", + "city": "Sibsey", + "id": 15743, + "name": "Sibsey Trader Mill" + }, + { + "address": null, + "city": "Lincolnshire", + "id": 15744, + "name": "Bolingbroke Castle" + }, + { + "address": null, + "city": "Tattershall", + "id": 15745, + "name": "Tattershall College" + }, + { + "address": null, + "city": "Hibaldstow", + "id": 15746, + "name": "Gainsthorpe Medieval Village" + }, + { + "address": "TD15 2RX", + "city": "Holy Island", + "id": 15747, + "name": "Lindisfarne Priory" + }, + { + "address": "TD15 2SH", + "city": "Northumberland", + "id": 15748, + "name": "Lindisfarne Castle" + }, + { + "address": null, + "city": "Liverpool", + "id": 15843, + "name": "Royal Liver Building" + }, + { + "address": "The Pierhead", + "city": "Liverpool", + "id": 15844, + "name": "Canada Boulevard" + }, + { + "address": null, + "city": "Liverpool", + "id": 15845, + "name": "Albert Dock" + }, + { + "address": "Albert Dock, L3 4AQ", + "city": "Liverpool", + "id": 15846, + "name": "Merseyside Maritime Museum" + }, + { + "address": "Albert Dock, L3 4BB", + "city": "Liverpool", + "id": 15847, + "name": "Tate Liverpool" + }, + { + "address": "Albert Dock, L3 4AD", + "city": "Liverpool", + "id": 15848, + "name": "The Beatles Story" + }, + { + "address": "Lime St", + "city": "Liverpool", + "id": 15849, + "name": "St. George's Hall" + }, + { + "address": "William Brown Street, L3 8EN", + "city": "Liverpool", + "id": 15850, + "name": "World Museum Liverpool" + }, + { + "address": null, + "city": "Liverpool", + "id": 15851, + "name": "Liverpool Central Library" + }, + { + "address": "William Brown Street, L3 8EL", + "city": "Liverpool", + "id": 15852, + "name": "Walker Art Gallery" + }, + { + "address": null, + "city": "Liverpool", + "id": 15853, + "name": "Liverpool Town Hall" + }, + { + "address": "Ashton Street, L69 3DR", + "city": "Liverpool", + "id": 15854, + "name": "Victoria Gallery & Museum" + }, + { + "address": "The Old Stable Yard, Smithdown Lane, L7 3EE", + "city": "Liverpool", + "id": 15855, + "name": "Williamson's Tunnels" + }, + { + "address": "School Lane, L1 3BX", + "city": "Liverpool", + "id": 15856, + "name": "The Bluecoat" + }, + { + "address": null, + "city": "Liverpool", + "id": 15857, + "name": "Our Lady and St. Nicholas church" + }, + { + "address": "Cathedral House, Mount Pleasant, L3 5TQ", + "city": "Liverpool", + "id": 15858, + "name": "Metropolitan Cathedral of Christ the King" + }, + { + "address": "St James Mount, L1 7AZ", + "city": "Liverpool", + "id": 15859, + "name": "Liverpool Cathedral" + }, + { + "address": null, + "city": "Liverpool", + "id": 15860, + "name": "Princes Road Synagogue" + }, + { + "address": "Princess Road, Toxteth, Liverpool L8 1XB", + "city": "Liverpool", + "id": 15861, + "name": "Greek Orthodox Church of St Nicholas" + }, + { + "address": "11 Wolstenholme Square, L1 4JJ", + "city": "Liverpool", + "id": 15862, + "name": "Wolstenholme Creative Space" + }, + { + "address": "The Walk, Speke, L24 1XD", + "city": "Speke", + "id": 15863, + "name": "Speke Hall" + }, + { + "address": "SA19 6RT", + "city": "Carmarthenshire", + "id": 15950, + "name": "Dinefwr" + }, + { + "address": "Llanfairpwll, Anglesey, LL61 6DQ", + "city": "Isle of Anglesey", + "id": 15953, + "name": "Plas Newydd Country House and Gardens" + }, + { + "address": "LL20 8AW", + "city": "Llangollen", + "id": 15958, + "name": "Plas Newydd" + }, + { + "address": null, + "city": "Lochmaddy", + "id": 15969, + "name": "Taigh Chearsabhagh" + }, + { + "address": "2295 Purisima Rd", + "city": "Lompoc", + "id": 16025, + "name": "La Purisima Mission State Historic Park" + }, + { + "address": "1-8 Russell Sq, WC1B 5BE", + "city": "London", + "id": 16044, + "name": "The Russell Hotel" + }, + { + "address": null, + "city": "London", + "id": 16046, + "name": "Bank of England" + }, + { + "address": null, + "city": "London", + "id": 16047, + "name": "Mansion House" + }, + { + "address": null, + "city": "London", + "id": 16048, + "name": "Monument" + }, + { + "address": null, + "city": "London", + "id": 16049, + "name": "Old Bailey" + }, + { + "address": "Ludgate Hill", + "city": "London", + "id": 16050, + "name": "St Paul's Cathedral" + }, + { + "address": null, + "city": "Greater London", + "id": 16051, + "name": "Tower Bridge" + }, + { + "address": null, + "city": "London", + "id": 16052, + "name": "Tower of London" + }, + { + "address": "Byward St, EC3R 5BJ", + "city": "London", + "id": 16053, + "name": "All Hallows by the Tower" + }, + { + "address": "38 City Road, EC1Y 1AU", + "city": "London", + "id": 16054, + "name": "Bunhill Fields" + }, + { + "address": "Fournier St", + "city": "London", + "id": 16055, + "name": "Christ Church" + }, + { + "address": "Little Britain, City of London", + "city": "London", + "id": 16056, + "name": "Postman's Park" + }, + { + "address": "Lower Thames St, EC3R 6DN", + "city": "London", + "id": 16057, + "name": "St Magnus the Martyr" + }, + { + "address": "Rood Ln and Eastcheap EC3", + "city": "London", + "id": 16058, + "name": "St Margaret Pattens" + }, + { + "address": "St Mary at Hill, EC3R 8EE", + "city": "London", + "id": 16059, + "name": "St Mary-at-Hill" + }, + { + "address": "1 Bow Lane, EC4M 9EE", + "city": "London", + "id": 16060, + "name": "St Mary le Bow" + }, + { + "address": "39 Walbrook, EC4N 8BN", + "city": "London", + "id": 16061, + "name": "St Stephen Walbrook" + }, + { + "address": "Inner Temple Ln, EC4Y 7BB", + "city": "London", + "id": 16062, + "name": "Temple" + }, + { + "address": "London Wall (NB: this is a street!)", + "city": "London", + "id": 16063, + "name": "Museum of London" + }, + { + "address": "Guildhall Yard (off Gresham St)", + "city": "Guildhall Yd", + "id": 16064, + "name": "Guildhall Art Gallery and Roman Amphitheatre" + }, + { + "address": "17 Gough Square, EC4A 3DE", + "city": "London", + "id": 16065, + "name": "Dr Johnson's House" + }, + { + "address": "Silk St", + "city": "London", + "id": 16066, + "name": "Barbican Centre" + }, + { + "address": "Guildhall Library, Aldermanbury, EC2P 2EJ", + "city": "London", + "id": 16067, + "name": "Clockmaker's Museum" + }, + { + "address": "St. Mary Axe", + "city": "London", + "id": 16068, + "name": "Baltic Exchange" + }, + { + "address": "St. Katherines Dock", + "city": "London", + "id": 16069, + "name": "International Petroleum Exchange" + }, + { + "address": "1 Lime St", + "city": "London", + "id": 16070, + "name": "Lloyds of London" + }, + { + "address": "Paternoster Sq", + "city": "London", + "id": 16071, + "name": "London Stock Exchange" + }, + { + "address": "13-14 Basinghall St", + "city": "London", + "id": 16072, + "name": "London Bullion Market Association" + }, + { + "address": "56 Leadenhall St", + "city": "London", + "id": 16073, + "name": "London Metal Exchange" + }, + { + "address": "Cannon St", + "city": "London", + "id": 16074, + "name": "London Stone" + }, + { + "address": "Bride Ln, EC4Y 8EE", + "city": "London", + "id": 16075, + "name": "St Bride Printing Library" + }, + { + "address": "30 St. Mary Axe", + "city": "London", + "id": 16076, + "name": "Swiss Re" + }, + { + "address": "51 Lime St", + "city": "London", + "id": 16077, + "name": "Willis Building" + }, + { + "address": "122 Leadenhall", + "city": "London", + "id": 16078, + "name": "Leadenhall Building" + }, + { + "address": "20 Fenchurch Street", + "city": "London", + "id": 16079, + "name": "20 Fenchurch Street" + }, + { + "address": "Victoria Embankment, along the Thames", + "city": "London", + "id": 16098, + "name": "Cleopatra's Needle" + }, + { + "address": null, + "city": "Loughton", + "id": 16103, + "name": "Epping Forest" + }, + { + "address": "Vestry Road, E17 9NH", + "city": "London", + "id": 16104, + "name": "Vestry House Museum" + }, + { + "address": null, + "city": "London", + "id": 16105, + "name": "Walthamstow Village" + }, + { + "address": "Lloyd Park, Forest Rd, E17 4PP", + "city": "London", + "id": 16106, + "name": "William Morris Gallery" + }, + { + "address": "Clements Rd, IG1 1EA", + "city": "Ilford", + "id": 16107, + "name": "Redbridge Central Library & Museum" + }, + { + "address": null, + "city": "Ilford", + "id": 16108, + "name": "Valentines Park" + }, + { + "address": "King William Walk", + "city": "London", + "id": 16116, + "name": "The Cutty Sark" + }, + { + "address": "Court Yard, Eltham, SE9 5QE", + "city": "London", + "id": 16117, + "name": "Eltham Palace" + }, + { + "address": "12 Croom's Hill, SE10 8ER", + "city": "London", + "id": 16118, + "name": "The Fan Museum" + }, + { + "address": null, + "city": "London", + "id": 16119, + "name": "Greenwich Park" + }, + { + "address": "Romney Rd SE10 9NF", + "city": "London", + "id": 16120, + "name": "The National Maritime Museum" + }, + { + "address": "Flamsteed House", + "city": "London", + "id": 16121, + "name": "The Royal Observatory" + }, + { + "address": "Old Royal Naval College, 2 Cutty Sark Gdns, SE10 9NN", + "city": "London", + "id": 16122, + "name": "The Royal Naval College" + }, + { + "address": "Chesterfield Walk, SE10 8QX", + "city": "Chesterfield Walk", + "id": 16123, + "name": "Rangers House" + }, + { + "address": "Mare Street, E8 1EA", + "city": "London", + "id": 16128, + "name": "Hackney Town Hall" + }, + { + "address": "2 & 4 Homerton High St, E9 6JQ", + "city": "London", + "id": 16129, + "name": "Sutton House" + }, + { + "address": "Lower Clapton Rd, E5 0PD", + "city": "London", + "id": 16130, + "name": "St John-at-Hackney Community Space Centre" + }, + { + "address": "Chelsea Harbour, SW10 0XG", + "city": "London", + "id": 16133, + "name": "Chelsea Harbour Design Centre" + }, + { + "address": "Bishop's Ave, SW6 6EA", + "city": "London", + "id": 16134, + "name": "Fulham Palace" + }, + { + "address": "20 Baron's Court Road, W14 9DT", + "city": "London", + "id": 16135, + "name": "Gandhi's Student Accommodation" + }, + { + "address": null, + "city": "London", + "id": 16136, + "name": "Hurlingham Park" + }, + { + "address": "Harrow Road, W10 4RA", + "city": "London", + "id": 16137, + "name": "Kensal Green Cemetery" + }, + { + "address": "Palliser Rd, W14 9EQ", + "city": "London", + "id": 16138, + "name": "Queens Club" + }, + { + "address": "Padderswick Rd", + "city": "London", + "id": 16139, + "name": "Ravenscourt Park" + }, + { + "address": null, + "city": "London", + "id": 16140, + "name": "Wormwood Scrubs" + }, + { + "address": "2 Willow Rd, NW3 1TH", + "city": "London", + "id": 16181, + "name": "2 Willow Road" + }, + { + "address": "Hampstead Gr, NW3 6SP", + "city": "London", + "id": 16182, + "name": "Fenton House" + }, + { + "address": "Hampstead Ln, NW3 7JR", + "city": "London", + "id": 16183, + "name": "Kenwood House" + }, + { + "address": "38 City Road, EC1Y 1AU", + "city": "London", + "id": 16184, + "name": "Bunhill Fields Burial Ground" + }, + { + "address": "Gray's Inn Rd, WC1", + "city": "London", + "id": 16185, + "name": "The Honourable Society of Gray's Inn" + }, + { + "address": "Lincoln's Inn Fields, WC2A 3TL", + "city": "London", + "id": 16186, + "name": "The Honorable Society of Lincoln's Inn" + }, + { + "address": "Myddelton Sq, EC1R", + "city": "London", + "id": 16187, + "name": "Myddelton Square Park" + }, + { + "address": "Strand", + "city": "London", + "id": 16188, + "name": "Royal Courts of Justice" + }, + { + "address": "High Holborn, WC1V 7QH", + "city": "London", + "id": 16189, + "name": "Staple Inn" + }, + { + "address": "Inner Temple, Fleet St, EC4Y 7HL", + "city": "London", + "id": 16190, + "name": "Temple Church" + }, + { + "address": "49 City Rd, EC1Y 1AU", + "city": "London", + "id": 16191, + "name": "Wesley's Chapel and Leysian Mission" + }, + { + "address": "35-43 Lincoln's Inn Fields, WC2A 3PE", + "city": "London", + "id": 16192, + "name": "Hunterian Museum" + }, + { + "address": "245 St John St, EC1V 4NB", + "city": "London", + "id": 16193, + "name": "Islington Museum" + }, + { + "address": "St John’s Gate, St John’s Lane, EC1M 4DA", + "city": "London", + "id": 16194, + "name": "Museum of the Order of St John" + }, + { + "address": "13 Lincoln's Inn Fields WC2A 3BP", + "city": "London", + "id": 16195, + "name": "Sir John Soane's Museum" + }, + { + "address": "Somerset House, Strand WC2R 1LA", + "city": "London", + "id": 16196, + "name": "Somerset House" + }, + { + "address": "Emirates Stadium, Highbury House, 75 Drayton Pk, N5 1BU", + "city": "London", + "id": 16240, + "name": "The Arsenal Museum" + }, + { + "address": null, + "city": "London", + "id": 16241, + "name": "City Road Basin Plaza" + }, + { + "address": "44a Pentonville Rd, N1 9BY", + "city": "London", + "id": 16242, + "name": "Crafts Council" + }, + { + "address": "191 Drayton Pk, N5 1PH", + "city": "London", + "id": 16243, + "name": "Gillespie Park Ecology Centre" + }, + { + "address": null, + "city": "London", + "id": 16244, + "name": "Highgate Wood" + }, + { + "address": "14 Wharf Rd, N1 7RW", + "city": "London", + "id": 16245, + "name": "Parasol Unit" + }, + { + "address": "16 Wharf Rd, N1 7RW", + "city": "London", + "id": 16246, + "name": "Victoria Miro Gallery" + }, + { + "address": "119a Whitepark Road, Ballintoy, BT54 6LS", + "city": "Moyle", + "id": 1625, + "name": "Carrick-a-rede Rope Bridge" + }, + { + "address": "575 Wandsworth Road, Lambeth, London, London, SW8 3JD", + "city": "London", + "id": 16254, + "name": "575 Wandsworth Road" + }, + { + "address": "Apsley Way, Hyde Park Corner, W1J 7JZ", + "city": "London", + "id": 16260, + "name": "Wellington Arch" + }, + { + "address": "149 Piccadilly, Hyde Park Corner, London, W1J 7NT", + "city": "London", + "id": 16261, + "name": "Apsley House" + }, + { + "address": "Capel Manor Gardens, Bullsmoor Lane, Enfield, Middlesex, EN1 4RQ", + "city": "Waltham Cross", + "id": 16263, + "name": "Capel Manor Gardens" + }, + { + "address": null, + "city": "Enfield", + "id": 16264, + "name": "Forty Hall & Estate" + }, + { + "address": null, + "city": "Harrow", + "id": 16265, + "name": "Harrow School" + }, + { + "address": null, + "city": "Harrow", + "id": 16266, + "name": "Harrow on the Hill" + }, + { + "address": null, + "city": "Stanmore", + "id": 16267, + "name": "Bentley Priory Nature Reserve" + }, + { + "address": null, + "city": "London", + "id": 16268, + "name": "Alexandra Palace" + }, + { + "address": "Stadium Way", + "city": "Wembley", + "id": 16269, + "name": "Wembley Stadium" + }, + { + "address": "Lordship Ln", + "city": "London", + "id": 16270, + "name": "Bruce Castle & Museum" + }, + { + "address": null, + "city": "London", + "id": 16271, + "name": "Tottenham Marsh" + }, + { + "address": "Park Ln", + "city": "London", + "id": 16272, + "name": "White Hart Lane" + }, + { + "address": null, + "city": "Edgware", + "id": 16273, + "name": "RAF Museum" + }, + { + "address": null, + "city": "London", + "id": 16275, + "name": "Holland Park" + }, + { + "address": "12 Holland Park Rd, W14 8LZ", + "city": "London", + "id": 16276, + "name": "Leighton House" + }, + { + "address": "53 Holland Park, W11 3RS", + "city": "London", + "id": 16277, + "name": "Maharajah Duleep Singh's House" + }, + { + "address": "Ham St, Ham, TW10 7RS", + "city": "Richmond", + "id": 16280, + "name": "Ham House & Garden" + }, + { + "address": "Richmond Rd, TW1 2NL", + "city": "Twickenham", + "id": 16281, + "name": "Marble Hill House" + }, + { + "address": "Red House Lane, Bexleyheath, DA6 8JF", + "city": "Bexleyheath", + "id": 16282, + "name": "Red House" + }, + { + "address": "Luxted Rd, Downe, BR6 7JT", + "city": "Downe", + "id": 16283, + "name": "Down House" + }, + { + "address": "Lambeth Palace Rd, SE1 7LB", + "city": "London", + "id": 16284, + "name": "Garden Museum" + }, + { + "address": "Lambeth Palace, SE1 7JU", + "city": "London", + "id": 16285, + "name": "Lambeth Palace" + }, + { + "address": null, + "city": "London", + "id": 16286, + "name": "Archbishop's Park" + }, + { + "address": "Westminster Bridge, south east side", + "city": "London", + "id": 16287, + "name": "The South Bank Lion" + }, + { + "address": "Belvedere Rd", + "city": "London", + "id": 16288, + "name": "County Hall" + }, + { + "address": "County Hall, Belvedere Rd", + "city": "London", + "id": 16289, + "name": "Sea Life London Aquarium" + }, + { + "address": "County Hall, Westminster Bridge Rd, SE1 7PB", + "city": "London", + "id": 16290, + "name": "London Dungeon" + }, + { + "address": "Westminster Bridge Rd", + "city": "London", + "id": 16291, + "name": "London Eye" + }, + { + "address": "Belvedere Rd", + "city": "London", + "id": 16292, + "name": "Southbank Centre" + }, + { + "address": null, + "city": "London", + "id": 16293, + "name": "Queen Elizabeth Hall" + }, + { + "address": "Queen's Walk", + "city": "London", + "id": 16294, + "name": "Undercroft" + }, + { + "address": "Belvedere Rd", + "city": "London", + "id": 16295, + "name": "BFI Southbank" + }, + { + "address": "Belvedere Rd", + "city": "London", + "id": 16296, + "name": "National Theatre" + }, + { + "address": "1 Charlie Chaplin Walk", + "city": "London", + "id": 16297, + "name": "BFI IMAX Cinema" + }, + { + "address": null, + "city": "London", + "id": 16298, + "name": "OXO Tower" + }, + { + "address": "The Queen's Walk", + "city": "London", + "id": 16299, + "name": "City Hall" + }, + { + "address": "Morgan's Ln", + "city": "London", + "id": 16300, + "name": "HMS Belfast" + }, + { + "address": "1 Clink St, SE1 9DG", + "city": "London", + "id": 16301, + "name": "Clink Prison Museum" + }, + { + "address": "Corner of Clink St and Storey St", + "city": "London", + "id": 16302, + "name": "Winchester Palace" + }, + { + "address": null, + "city": "London", + "id": 16303, + "name": "The Golden Hind" + }, + { + "address": "London Bridge", + "city": "London", + "id": 16304, + "name": "Southwark Cathedral" + }, + { + "address": "Bankside", + "city": "London", + "id": 16305, + "name": "Tate Modern" + }, + { + "address": "94a Southwark Bridge Rd, SE1 0EG", + "city": "London", + "id": 16306, + "name": "London Fire Brigade Museum" + }, + { + "address": "Concert Hall Approach, 150-152 Hungerford Arches", + "city": "London", + "id": 16307, + "name": "Topolski Century" + }, + { + "address": "Belvedere Rd", + "city": "London", + "id": 16308, + "name": "Hayward Gallery" + }, + { + "address": "2-4 Tooley St", + "city": "London", + "id": 16309, + "name": "The London Bridge Experience" + }, + { + "address": null, + "city": "London", + "id": 16310, + "name": "The Old Operating Theatre" + }, + { + "address": "83 Bermondsey St", + "city": "London", + "id": 16311, + "name": "Fashion & Textile Museum" + }, + { + "address": "Shad Thames", + "city": "London", + "id": 16312, + "name": "Design Museum" + }, + { + "address": "Cromwell Rd", + "city": "London", + "id": 16352, + "name": "Victoria and Albert Museum" + }, + { + "address": "Cromwell Rd", + "city": "London", + "id": 16353, + "name": "Natural History Museum" + }, + { + "address": "Exhibition Rd", + "city": "London", + "id": 16354, + "name": "Science Museum" + }, + { + "address": "Cromwell Rd", + "city": "London", + "id": 16355, + "name": "The Geological Museum" + }, + { + "address": "66 Royal Hospital Rd SW3 4HS", + "city": "London", + "id": 16356, + "name": "Chelsea Physic Garden" + }, + { + "address": null, + "city": "London", + "id": 16357, + "name": "The Serpentine" + }, + { + "address": null, + "city": "London", + "id": 16358, + "name": "Speakers Corner" + }, + { + "address": null, + "city": "London", + "id": 16359, + "name": "Albert Memorial" + }, + { + "address": null, + "city": "London", + "id": 16360, + "name": "Elfin Oak" + }, + { + "address": "Palace Green, W8 4PX", + "city": "London", + "id": 16361, + "name": "Kensington Palace" + }, + { + "address": null, + "city": "London", + "id": 16362, + "name": "The Round Pond" + }, + { + "address": null, + "city": "London", + "id": 16363, + "name": "The Serpentine Gallery" + }, + { + "address": "99 High Street Kensington, W8 5SA", + "city": "London", + "id": 16364, + "name": "Kensington Roof Gardens" + }, + { + "address": "Cheyne Walk", + "city": "London", + "id": 16365, + "name": "Roper's Garden" + }, + { + "address": "153 Cromwell Road, SW5 0TQ", + "city": "London", + "id": 16366, + "name": "Alfred Hitchcock's House" + }, + { + "address": "18 St Leonard’s Terrace, SW3 4QG", + "city": "London", + "id": 16367, + "name": "Bram Stoker's House" + }, + { + "address": "23 Tedworth Square, SW3 5DR", + "city": "London", + "id": 16368, + "name": "Mark Twain's House" + }, + { + "address": "34 Tite Street, SW3 4JA", + "city": "London", + "id": 16369, + "name": "Oscar Wilde's House" + }, + { + "address": "Donovan Court, Drayton Gardens, SW10 9QS", + "city": "London", + "id": 16370, + "name": "Rosalind Franklin's House" + }, + { + "address": "3 Kensington Court Gardens, W8 5QE", + "city": "London", + "id": 16371, + "name": "T. S. Elliot's House" + }, + { + "address": "39 Harrington Gardens, SW7 4JU", + "city": "London", + "id": 16372, + "name": "Sir William Gilbert's House" + }, + { + "address": "28 Hyde Park Gate, SW7 5DJ", + "city": "London", + "id": 16373, + "name": "Sir Winston Churchill's House" + }, + { + "address": "aka Kensington Palace Gardens", + "city": "London", + "id": 16374, + "name": "Billionaries' Row" + }, + { + "address": "Brompton Rd, SW7 2RP", + "city": "London", + "id": 16375, + "name": "Brompton Oratory" + }, + { + "address": "24 Cheyne Row, SW3 5HL", + "city": "London", + "id": 16376, + "name": "Carlyle's House" + }, + { + "address": "64 Cheyne Walk, SW3 5LT", + "city": "London", + "id": 16377, + "name": "Chelsea Old Church" + }, + { + "address": "Cheyne Walk, SW3 5AZ", + "city": "London", + "id": 16378, + "name": "Crosby Hall" + }, + { + "address": "Royal Hospital Rd", + "city": "London", + "id": 16379, + "name": "Royal Hospital" + }, + { + "address": "entrances on Old Brompton Road and Fulham Rd", + "city": "London", + "id": 16380, + "name": "Brompton Cemetery" + }, + { + "address": "Kensington High Street, W8", + "city": "London", + "id": 16381, + "name": "Penfold Post Box" + }, + { + "address": "Earls Court Road, outside Earl's Court station", + "city": "London", + "id": 16382, + "name": "Police Box" + }, + { + "address": "Kensington Gore, SW7 2EU", + "city": "London", + "id": 16383, + "name": "Royal College of Art" + }, + { + "address": "Prince Consort Rd, SW7 2BS", + "city": "London", + "id": 16384, + "name": "Royal College of Music" + }, + { + "address": "Duke Of York's HQ, King's Road, SW3 4RY", + "city": "London", + "id": 16385, + "name": "Saatchi Gallery" + }, + { + "address": "Chesterfield Walk, SE10 8QX", + "city": "Chesterfield Walk", + "id": 16462, + "name": "Rangers House" + }, + { + "address": "Burlington Lane, Chiswick,", + "city": "London", + "id": 16466, + "name": "Chiswick House and Gardens" + }, + { + "address": "Parliament Sq", + "city": "London", + "id": 16467, + "name": "Palace of Westminster" + }, + { + "address": null, + "city": "London", + "id": 16468, + "name": "Elizabeth Tower" + }, + { + "address": "Abingdon Street, SW1P 3JX", + "city": "London", + "id": 16469, + "name": "The Jewel Tower" + }, + { + "address": null, + "city": "London", + "id": 16470, + "name": "Buckingham Palace" + }, + { + "address": null, + "city": "London", + "id": 16471, + "name": "St James's Palace" + }, + { + "address": null, + "city": "London", + "id": 16472, + "name": "Henry VII Lady Chapel" + }, + { + "address": "Parliament Sq", + "city": "London", + "id": 16473, + "name": "St. Margaret's Church" + }, + { + "address": null, + "city": "Deans Yd", + "id": 16474, + "name": "Westminster Abbey" + }, + { + "address": "Millbank", + "city": "London", + "id": 16475, + "name": "Tate Britain" + }, + { + "address": null, + "city": "London", + "id": 16476, + "name": "Green Park" + }, + { + "address": null, + "city": "London", + "id": 16477, + "name": "St. James's Park" + }, + { + "address": "Apsley Way, Hyde Park Corner, W1J 7JZ", + "city": "London", + "id": 16478, + "name": "Wellington Arch" + }, + { + "address": "South-east corner, Belgrave Sq", + "city": "London", + "id": 16479, + "name": "Simón Bolívar" + }, + { + "address": "Corner of Denbigh St and St George's Drive", + "city": "London", + "id": 16480, + "name": "Thomas Cubitt" + }, + { + "address": "42 Francis Street, SW1P 1QW", + "city": "London", + "id": 16481, + "name": "Westminster Cathedral" + }, + { + "address": "Whitehall SW1A 2ER", + "city": "London", + "id": 16482, + "name": "Banqueting House" + }, + { + "address": "Clive Steps, King Charles St SW1A 2AQ", + "city": "London", + "id": 16483, + "name": "Cabinet War Rooms and Churchill Museum" + }, + { + "address": null, + "city": "London", + "id": 16484, + "name": "Downing Street" + }, + { + "address": null, + "city": "London", + "id": 16485, + "name": "Whitehall" + }, + { + "address": "701 S. Main Street", + "city": "Lone Pine", + "id": 16531, + "name": "Museum of Lone Pine Film History" + }, + { + "address": "100 Aquarium Way", + "city": "Long Beach", + "id": 16532, + "name": "Aquarium of the Pacific" + }, + { + "address": "1126 Queens Highway", + "city": "Long Beach", + "id": 16533, + "name": "Queen Mary" + }, + { + "address": "2300 East Ocean Boulevard", + "city": "Long Beach", + "id": 16534, + "name": "Long Beach Museum of Art" + }, + { + "address": "4600 Virginia Road", + "city": "Long Beach", + "id": 16535, + "name": "Rancho Los Cerritos Historic Adobe" + }, + { + "address": null, + "city": "Long Beach", + "id": 16536, + "name": "Naples Island" + }, + { + "address": "1445 Peterson Ave.", + "city": "Long Beach", + "id": 16537, + "name": "Long Beach Firefighter's Museum" + }, + { + "address": "6400 E. Bixby Hill Rd.", + "city": "Long Beach", + "id": 16538, + "name": "Rancho Los Alamitos Museum" + }, + { + "address": "628 Alamitos Ave.", + "city": "Long Beach", + "id": 16539, + "name": "Museum of Latin American Art" + }, + { + "address": null, + "city": "Los Angeles", + "id": 16564, + "name": "Chinatown" + }, + { + "address": null, + "city": "Los Angeles", + "id": 16565, + "name": "Little Tokyo" + }, + { + "address": null, + "city": "Los Angeles", + "id": 16566, + "name": "Olvera Street" + }, + { + "address": "250 S Grand Ave", + "city": "Los Angeles", + "id": 16567, + "name": "Museum of Contemporary Art (MOCA)" + }, + { + "address": "152 N Central Ave", + "city": "Los Angeles", + "id": 16568, + "name": "Geffen Contemporary" + }, + { + "address": "369 E 1st St", + "city": "Los Angeles", + "id": 16569, + "name": "Japanese American National Museum" + }, + { + "address": "134 Paseo de la Plaza", + "city": "Los Angeles", + "id": 16570, + "name": "Old Plaza Firehouse" + }, + { + "address": "800 W Olympic Blvd", + "city": "Los Angeles", + "id": 16571, + "name": "Grammy Museum" + }, + { + "address": "919 S Grand Ave", + "city": "Los Angeles", + "id": 16572, + "name": "Fashion Institute of Design & Merchandising" + }, + { + "address": "630 W 5th St", + "city": "Los Angeles", + "id": 16573, + "name": "The Los Angeles Central Public Library" + }, + { + "address": "135 N Grand Ave", + "city": "Los Angeles", + "id": 16574, + "name": "Music Center and Disney Hall" + }, + { + "address": "304 S Broadway", + "city": "Los Angeles", + "id": 16575, + "name": "The Bradbury Building" + }, + { + "address": "555 W Temple St", + "city": "Los Angeles", + "id": 16576, + "name": "The Cathedral of Our Lady of the Angels" + }, + { + "address": "633 W 5th St", + "city": "Los Angeles", + "id": 16577, + "name": "Library Tower" + }, + { + "address": "7th St, between Broadway and Hill", + "city": "Los Angeles", + "id": 16578, + "name": "St. Vincent Court" + }, + { + "address": null, + "city": "Los Angeles", + "id": 16579, + "name": "The Theater District" + }, + { + "address": null, + "city": "Los Angeles", + "id": 16580, + "name": "Union Station" + }, + { + "address": "Balmoral Estates, Ballater, AB35 5T", + "city": "Aberdeenshire", + "id": 1661, + "name": "Balmoral Castle" + }, + { + "address": "1765 E 107th St", + "city": "Los Angeles", + "id": 16641, + "name": "Watts Towers of Simon Rodia" + }, + { + "address": "665 W Jefferson Blvd", + "city": "Los Angeles", + "id": 16642, + "name": "Shrine Auditorium" + }, + { + "address": "900 Exposition Blvd", + "city": "Los Angeles", + "id": 16643, + "name": "Natural History Museum of Los Angeles County" + }, + { + "address": "700 Exposition Park Dr", + "city": "Los Angeles", + "id": 16644, + "name": "California Science Center" + }, + { + "address": "3911 S Figueroa St", + "city": "Los Angeles", + "id": 16645, + "name": "Los Angeles Memorial Coliseum" + }, + { + "address": "1200 Getty Center Dr", + "city": "Los Angeles", + "id": 16649, + "name": "Getty Center" + }, + { + "address": "9786 W. Pico Blvd", + "city": "Los Angeles", + "id": 16650, + "name": "Museum of Tolerance" + }, + { + "address": "10899 Wilshire Blvd", + "city": "Los Angeles", + "id": 16651, + "name": "Armand Hammer Museum of Art and Culture Center" + }, + { + "address": "2000 Avenue of the Stars", + "city": "Los Angeles", + "id": 16652, + "name": "Annenberg Space for Photography" + }, + { + "address": "5905 Wilshire Blvd", + "city": "Los Angeles", + "id": 16688, + "name": "Los Angeles County Museum of Art (LACMA)" + }, + { + "address": "5801 Wilshire Blvd", + "city": "Los Angeles", + "id": 16689, + "name": "Page Museum at the La Brea Tar Pits" + }, + { + "address": "6060 Wilshire Blvd", + "city": "Los Angeles", + "id": 16690, + "name": "Petersen Automotive Museum" + }, + { + "address": "148 N La Brea Ave", + "city": "Los Angeles", + "id": 16691, + "name": "Fahey/Klein Gallery" + }, + { + "address": "4 Tait Avenue", + "city": "Los Gatos", + "id": 16711, + "name": "Los Gatos Art Museum" + }, + { + "address": "Calshot Road, Calshot, SO45 1BR", + "city": "Calshot", + "id": 17001, + "name": "Calshot Castle" + }, + { + "address": "place St Jean", + "city": "Lyon", + "id": 17032, + "name": "St Jean Cathedral" + }, + { + "address": "rue de la Bombarde/rue Mandelot/rue des Estrées", + "city": "Lyon-5E-Arrondissement", + "id": 17033, + "name": "St Jean archaeological garden" + }, + { + "address": "place de Fourvière", + "city": "Lyon", + "id": 17034, + "name": "Fourvière basilica" + }, + { + "address": "place de Fourvière", + "city": "Lyon", + "id": 17035, + "name": "Esplanade de Fourvière" + }, + { + "address": "24255 Pacific Coast Highway", + "city": "Malibu", + "id": 17296, + "name": "Pepperdine University" + }, + { + "address": "Market Building, Thomas Street, Northern Quarter, Manchester", + "city": "Manchester", + "id": 17391, + "name": "Chinese Arts Centre" + }, + { + "address": "Charlotte Street", + "city": "Manchester", + "id": 17392, + "name": "The Portico Library and Gallery" + }, + { + "address": "Faulkner Street, Chinatown", + "city": "Manchester", + "id": 17393, + "name": "Imperial Chinese Archway" + }, + { + "address": "Sackville Street", + "city": "Manchester", + "id": 17394, + "name": "Whitworth Gardens" + }, + { + "address": null, + "city": "Manchester", + "id": 17395, + "name": "Manchester Cathedral" + }, + { + "address": null, + "city": "Manchester", + "id": 17396, + "name": "Chetham's School of Music & Library" + }, + { + "address": "102 Oldham Street", + "city": "Manchester", + "id": 17397, + "name": "The Frog and Bucket" + }, + { + "address": null, + "city": "Manchester", + "id": 17398, + "name": "Manchester Art Gallery" + }, + { + "address": null, + "city": "Manchester", + "id": 17399, + "name": "St. Ann's Church" + }, + { + "address": "St. Ann's Square", + "city": "Manchester", + "id": 17400, + "name": "Royal Exchange" + }, + { + "address": "13755 Fiji Way", + "city": "Marina del Rey", + "id": 17575, + "name": "Fisherman's Village" + }, + { + "address": "13650 Mindanao Way", + "city": "Marina del Rey", + "id": 17576, + "name": "Burton Chace Park" + }, + { + "address": null, + "city": "Los Angeles", + "id": 17577, + "name": "Ballona Wetlands" + }, + { + "address": "Matlock", + "city": "Matlock", + "id": 17662, + "name": "Peak Rail" + }, + { + "address": null, + "city": "Derbyshire", + "id": 17663, + "name": "Heights of Abraham" + }, + { + "address": null, + "city": "Merced", + "id": 17934, + "name": "Merced National Wildlife Refuge" + }, + { + "address": "place d'Armes", + "city": "Metz", + "id": 17955, + "name": "Cathedrale St-Etienne" + }, + { + "address": null, + "city": "Metz", + "id": 17956, + "name": "Place d'Armes" + }, + { + "address": "2 rue Haute-Pierre, 57000 Metz", + "city": "Metz", + "id": 17957, + "name": "La Maison de Verlaine à Metz" + }, + { + "address": null, + "city": "Monmouthshire", + "id": 18817, + "name": "Kymin" + }, + { + "address": "886 Cannery Row", + "city": "Monterey", + "id": 18840, + "name": "Monterey Bay Aquarium" + }, + { + "address": "20 Custom House Plaza", + "city": "Monterey", + "id": 18841, + "name": "Monterey State Historic Park" + }, + { + "address": "20 Custom House Plaza", + "city": "Monterey", + "id": 18842, + "name": "Pacific House Museum" + }, + { + "address": "P.O. Box 803 (End of Mission Road) Jolon, CA 93928", + "city": "Jolon", + "id": 18846, + "name": "Mission San Antonio de Padua" + }, + { + "address": null, + "city": "Montgomery", + "id": 18984, + "name": "St Nicholas Parish Church" + }, + { + "address": null, + "city": "Powys", + "id": 18985, + "name": "Montgomeryshire War Memorial" + }, + { + "address": null, + "city": "Beaumont-du-Ventoux", + "id": 19194, + "name": "Sainte-Croix Chapel" + }, + { + "address": null, + "city": "Malaucène", + "id": 19195, + "name": "Source du Groseau" + }, + { + "address": null, + "city": "Batsford", + "id": 19216, + "name": "Batsford Arboretum" + }, + { + "address": "British School House, Broadway Road, GL56 0BG.", + "city": "Moreton-in-Marsh", + "id": 19217, + "name": "Wellington Aviation Museum" + }, + { + "address": "5 Sheinton Street, TF13 6HS", + "city": "Much Wenlock", + "id": 19299, + "name": "Wenlock Priory" + }, + { + "address": null, + "city": "Lochdon", + "id": 19321, + "name": "Duart Castle" + }, + { + "address": "Gruline", + "city": "Gruline", + "id": 19322, + "name": "Macquarie Mausoleum" + }, + { + "address": null, + "city": "Musselburgh", + "id": 19732, + "name": "Newhailes House" + }, + { + "address": "24 Inveresk Village, Musselburgh, EH21 7TE", + "city": "Inveresk", + "id": 19733, + "name": "Inveresk Lodge Garden" + }, + { + "address": null, + "city": "Nancy", + "id": 19931, + "name": "Place Stanislas" + }, + { + "address": "Grand Rue", + "city": "Nancy", + "id": 19932, + "name": "La Porte de la Craffe" + }, + { + "address": null, + "city": "Nancy", + "id": 19933, + "name": "Arc de Triomphe" + }, + { + "address": null, + "city": "Nancy", + "id": 19934, + "name": "Villa Majorelle" + }, + { + "address": "5 rue des Brice", + "city": "Nancy", + "id": 19935, + "name": "Les Glycines" + }, + { + "address": "3, place Stanislas", + "city": "Nancy", + "id": 19936, + "name": "Musée des Beaux-Arts" + }, + { + "address": "36-38, rue du Sergent Blandan", + "city": "Nancy", + "id": 19937, + "name": "Musée de l'Ecole de Nancy" + }, + { + "address": null, + "city": "Nancy", + "id": 19938, + "name": "Parc de la Pépinière" + }, + { + "address": null, + "city": "Nantes", + "id": 19949, + "name": "Land Hemisphere" + }, + { + "address": null, + "city": "Donnington", + "id": 20115, + "name": "Donnington Castle" + }, + { + "address": "Harts Lane, Burghclere, near Newbury, RG20 9JT", + "city": "Hampshire", + "id": 20116, + "name": "Sandham Memorial Chapel" + }, + { + "address": null, + "city": "Newcastle", + "id": 20117, + "name": "Newcastle Harbour" + }, + { + "address": null, + "city": "Tyne and Wear", + "id": 20126, + "name": "Tyne Bridge" + }, + { + "address": null, + "city": "Tyne and Wear", + "id": 20127, + "name": "Gateshead Millennium Bridge" + }, + { + "address": null, + "city": "Newcastle upon Tyne", + "id": 20128, + "name": "Remains of the Castle Keep" + }, + { + "address": null, + "city": "Newcastle upon Tyne", + "id": 20129, + "name": "Central Arcade" + }, + { + "address": null, + "city": "Newcastle upon Tyne", + "id": 20130, + "name": "Grainger Town" + }, + { + "address": null, + "city": "Newcastle upon Tyne", + "id": 20131, + "name": "Grey's Monument" + }, + { + "address": null, + "city": "Newcastle upon Tyne", + "id": 20132, + "name": "St Nicholas Cathedral" + }, + { + "address": "Northumbria University, Sandyford Road, Newcastle, NE1 8ST", + "city": "Newcastle upon Tyne", + "id": 20133, + "name": "University Gallery and Baring Wing" + }, + { + "address": "Barras Bridge, NE2 4PT", + "city": "Newcastle upon Tyne", + "id": 20134, + "name": "Great North Museum" + }, + { + "address": "Gateshead Quays, South Shore Road, Gateshead", + "city": "Gateshead", + "id": 20135, + "name": "BALTIC Centre for Contemporary Art" + }, + { + "address": "30 Lime Street, Ouseburn Valley, NE1 2PQ", + "city": "Newcastle upon Tyne", + "id": 20136, + "name": "Seven Stories, the Centre for Children's Books" + }, + { + "address": "Stoddart St", + "city": "Newcastle upon Tyne", + "id": 20137, + "name": "The Biscuit Factory" + }, + { + "address": "The Quadrangle, Newcastle University", + "city": "Newcastle upon Tyne", + "id": 20138, + "name": "The Hatton Gallery" + }, + { + "address": "Times Square", + "city": "Newcastle upon Tyne", + "id": 20139, + "name": "Centre For Life" + }, + { + "address": "Blandford Square, NE1 4JA", + "city": "Newcastle upon Tyne", + "id": 20140, + "name": "Discovery Museum" + }, + { + "address": "Pier Road, Tynemouth, NE30 4BZ", + "city": "Tynemouth", + "id": 20141, + "name": "Tynemouth Castle and Priory" + }, + { + "address": null, + "city": "South Lanarkshire", + "id": 20148, + "name": "Bonnington Linn" + }, + { + "address": null, + "city": "South Lanarkshire", + "id": 20149, + "name": "Corra Linn" + }, + { + "address": null, + "city": "Lanark", + "id": 20150, + "name": "Dundaff Linn" + }, + { + "address": "Castle Hill, PO30 1XY", + "city": "Newport", + "id": 20338, + "name": "Carisbrooke Castle" + }, + { + "address": "NP10 8YW", + "city": "Duffryn", + "id": 20354, + "name": "Tredegar House" + }, + { + "address": null, + "city": "Nice", + "id": 20405, + "name": "Colline du Château" + }, + { + "address": "405, Promenade des Anglais", + "city": "Nice", + "id": 20406, + "name": "Musée des Arts asiatiques" + }, + { + "address": "405 Promenade des Anglais", + "city": "Nice", + "id": 20407, + "name": "Parc Phoenix" + }, + { + "address": null, + "city": "Nice", + "id": 20408, + "name": "Musée Chagall" + }, + { + "address": "164, ave des Arenes de Cimiez", + "city": "Nice", + "id": 20409, + "name": "Musée Matisse" + }, + { + "address": null, + "city": "Nice", + "id": 20410, + "name": "Musée d'Archeologie de Nice" + }, + { + "address": null, + "city": "East Lothian", + "id": 20599, + "name": "Tantallon Castle" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 20729, + "name": "Balranald RSPB reserve" + }, + { + "address": null, + "city": "Lochmaddy", + "id": 20730, + "name": "Taigh Chearsabhagh" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 20731, + "name": "Barpa Langass" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 20732, + "name": "Pobull Finn" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 20733, + "name": "Dun An Sticir" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 20734, + "name": "Scolpaig Tower" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 20735, + "name": "Teampull Na Trionaid" + }, + { + "address": "Summerbridge, Harrogate, HG3 4DW", + "city": "North Yorkshire", + "id": 20782, + "name": "Brimham Rocks" + }, + { + "address": "12426 Mapledale Street", + "city": "Norwalk", + "id": 20784, + "name": "Hargitt House Museum" + }, + { + "address": null, + "city": "Oban", + "id": 20944, + "name": "McCaig’s Tower" + }, + { + "address": null, + "city": "Argyll and Bute", + "id": 20945, + "name": "Dunollie Castle" + }, + { + "address": null, + "city": "Argyll and Bute", + "id": 20946, + "name": "Dunstaffnage Castle" + }, + { + "address": null, + "city": "Oban", + "id": 20947, + "name": "War & Peace Museum" + }, + { + "address": "Corran Esplanade", + "city": "Oban", + "id": 20948, + "name": "St Columba's Cathedral" + }, + { + "address": null, + "city": "Oban", + "id": 20949, + "name": "Cathedral Church of St John the Divine" + }, + { + "address": "Stafford St", + "city": "Oban", + "id": 20950, + "name": "Oban Distillery" + }, + { + "address": "4050 Mission Avenue", + "city": "Oceanside", + "id": 20975, + "name": "Mission San Luis Rey de Francia" + }, + { + "address": "Llangollen", + "city": "Denbighshire", + "id": 21033, + "name": "Valle Crucis Abbey" + }, + { + "address": "Froncysyllte", + "city": "Wrexham", + "id": 21034, + "name": "Pontcysyllte Aqueduct World Heritage Site" + }, + { + "address": "Llanthony Crosseny, Abergavenny NP7 8UD", + "city": "Monmouthshire", + "id": 21048, + "name": "White Castle" + }, + { + "address": "Monmouth", + "city": "Monmouth", + "id": 21051, + "name": "Monnow Bridge & Gate" + }, + { + "address": null, + "city": "Tintern", + "id": 21055, + "name": "Tintern Abbey" + }, + { + "address": "Chepstow", + "city": "Chepstow", + "id": 21057, + "name": "Chepstow Castle" + }, + { + "address": null, + "city": "Inyo County", + "id": 21180, + "name": "Cottonwood Charcoal Kilns" + }, + { + "address": "13280 Chapman Ave.", + "city": "Garden Grove", + "id": 21222, + "name": "Crystal Cathedral" + }, + { + "address": null, + "city": "Orange", + "id": 21223, + "name": "Roman theatre" + }, + { + "address": null, + "city": "Orange", + "id": 21224, + "name": "Triumphal arch" + }, + { + "address": null, + "city": "Orange", + "id": 21225, + "name": "Musée d'Orange" + }, + { + "address": null, + "city": "Orange", + "id": 21226, + "name": "Colline Saint Eutrope" + }, + { + "address": "North end of Bidwell Canyon Rd.", + "city": "Oroville", + "id": 21271, + "name": "Bidwell Bar Bridge" + }, + { + "address": "917 Kelly Ridge Road", + "city": "Oroville", + "id": 21272, + "name": "Lake Oroville Visitor Center" + }, + { + "address": null, + "city": "Oxford", + "id": 21505, + "name": "Bodleian Library" + }, + { + "address": "Radcliffe Square", + "city": "Oxford", + "id": 21506, + "name": "Radcliffe Camera" + }, + { + "address": null, + "city": "Oxford", + "id": 21507, + "name": "Hertford Bridge" + }, + { + "address": "Broad St", + "city": "Oxford", + "id": 21508, + "name": "Sheldonian Theatre" + }, + { + "address": "St Giles', Oxford OX1 3NA", + "city": "Oxford", + "id": 21509, + "name": "Taylorian Institute" + }, + { + "address": "OX1 1DP", + "city": "Oxford", + "id": 21510, + "name": "Christ Church" + }, + { + "address": "eastern end of High St", + "city": "Oxford", + "id": 21511, + "name": "Magdalen College" + }, + { + "address": "Beaumont St", + "city": "Oxford", + "id": 21512, + "name": "Ashmolean Museum" + }, + { + "address": null, + "city": "Oxford", + "id": 21513, + "name": "Christ Church Picture Gallery" + }, + { + "address": "30 Pembroke St", + "city": "Oxford", + "id": 21514, + "name": "Modern Art Oxford" + }, + { + "address": null, + "city": "Oxford", + "id": 21515, + "name": "Museum of Oxford" + }, + { + "address": "Broad St, Oxford OX1 3AZ", + "city": "Oxford", + "id": 21516, + "name": "Museum of the History of Science" + }, + { + "address": "Parks Rd", + "city": "Oxford", + "id": 21517, + "name": "Oxford University Museum of Natural History" + }, + { + "address": "South Parks Rd", + "city": "Oxford", + "id": 21518, + "name": "Pitt Rivers Museum" + }, + { + "address": null, + "city": "Oxford", + "id": 21519, + "name": "Oxford University Parks" + }, + { + "address": "17895 Pacific Coast Highway", + "city": "Los Angeles", + "id": 21523, + "name": "J. Paul Getty Villa" + }, + { + "address": "2503 E. Avenue P", + "city": "Palmdale", + "id": 21550, + "name": "Blackbird Air Park" + }, + { + "address": null, + "city": "Paris", + "id": 21601, + "name": "Arc de Triomphe de l'Étoile" + }, + { + "address": null, + "city": "Paris", + "id": 21602, + "name": "Eiffel Tower" + }, + { + "address": null, + "city": "Paris-4E-Arrondissement", + "id": 21603, + "name": "Notre Dame Cathedral" + }, + { + "address": null, + "city": "Paris", + "id": 21609, + "name": "Ile aux Cygnes" + }, + { + "address": null, + "city": "Paris", + "id": 21611, + "name": "Statue de la Liberté" + }, + { + "address": "28 Rue de la Convention", + "city": "Paris", + "id": 21612, + "name": "St Christophe de Javel" + }, + { + "address": "31 Rue des Bergers", + "city": "Paris", + "id": 21613, + "name": "Galerie Michèle Broutta" + }, + { + "address": "18, Rue Antoine Bourdelle", + "city": "Paris", + "id": 21614, + "name": "Musée Bourdelle" + }, + { + "address": "15 Square de Vergennes", + "city": "Paris", + "id": 21615, + "name": "Musée Mendjisky" + }, + { + "address": "Institut Pasteur, 25, rue du Dr-Roux", + "city": "Paris", + "id": 21616, + "name": "Musée Pasteur" + }, + { + "address": "1, place des Cinq Martyrs du Lycée Buffon", + "city": "Paris-15E-Arrondissement", + "id": 21617, + "name": "Jardin atlantique" + }, + { + "address": "2, rue Cauchy", + "city": "Paris", + "id": 21618, + "name": "Parc André Citroën" + }, + { + "address": null, + "city": "Paris", + "id": 21619, + "name": "Parc des Expositions" + }, + { + "address": null, + "city": "Paris", + "id": 21658, + "name": "Palais du Trocadéro" + }, + { + "address": "2 rue Louis-Boilly, 16th", + "city": "Paris", + "id": 21659, + "name": "Musée Marmottan" + }, + { + "address": null, + "city": "Paris", + "id": 21660, + "name": "Jardin d'Acclimatation" + }, + { + "address": null, + "city": "Paris", + "id": 21683, + "name": "Colonne Vendôme" + }, + { + "address": null, + "city": "Paris", + "id": 21684, + "name": "La Conciergerie" + }, + { + "address": null, + "city": "Paris", + "id": 21685, + "name": "Église Saint-Eustache" + }, + { + "address": null, + "city": "Paris", + "id": 21686, + "name": "Jardin des Tuileries" + }, + { + "address": null, + "city": "Paris-1ER-Arrondissement", + "id": 21687, + "name": "Le Palais Royal" + }, + { + "address": "4 blvd du Palais", + "city": "Paris", + "id": 21688, + "name": "Sainte-Chapelle" + }, + { + "address": null, + "city": "Paris", + "id": 21689, + "name": "Jeu de Paume" + }, + { + "address": "107, rue de Rivoli", + "city": "Paris", + "id": 21690, + "name": "Musée des Arts décoratifs" + }, + { + "address": "21, rue Hérold", + "city": "Paris", + "id": 21691, + "name": "Musée en Herbe" + }, + { + "address": "Place du Carrousel", + "city": "Paris", + "id": 21692, + "name": "Musée du Louvre" + }, + { + "address": null, + "city": "Paris", + "id": 21693, + "name": "L'Orangerie" + }, + { + "address": "Ile de la Cité 6, Place du Parvis Notre Dame", + "city": "Paris", + "id": 21752, + "name": "Notre-Dame de Paris" + }, + { + "address": "Place de la Hôtel de Ville", + "city": "Paris", + "id": 21753, + "name": "Hôtel de Ville" + }, + { + "address": "Rue de Rivoli", + "city": "Paris", + "id": 21754, + "name": "Tour St Jacques" + }, + { + "address": null, + "city": "Paris", + "id": 21755, + "name": "la Bastille" + }, + { + "address": "17, rue Geoffroy l’Asnier", + "city": "Paris", + "id": 21756, + "name": "Le Mémorial de la Shoah" + }, + { + "address": "Place George Pompidou", + "city": "Paris", + "id": 21757, + "name": "Centre Georges Pompidou" + }, + { + "address": "6, Place des Vosges", + "city": "Paris", + "id": 21758, + "name": "Maison de Victor Hugo" + }, + { + "address": "62 rue Saint-Antoine", + "city": "Paris", + "id": 21759, + "name": "Hôtel de Sully" + }, + { + "address": "3 place St-Germain-des-Prés", + "city": "Paris", + "id": 21786, + "name": "Eglise Saint-Germain-des-Prés" + }, + { + "address": "15 rue de Vaugirard", + "city": "Paris", + "id": 21787, + "name": "Palais du Luxembourg" + }, + { + "address": "75 rue Bonaparte", + "city": "Paris", + "id": 21788, + "name": "Eglise de Saint Sulpice" + }, + { + "address": "6 rue de Fürstenberg", + "city": "Paris", + "id": 21789, + "name": "Musée national Eugène Delacroix" + }, + { + "address": "33, quai d'Orsay", + "city": "Paris", + "id": 21797, + "name": "l'Assemblée Nationale" + }, + { + "address": "6, boul des Invalides", + "city": "Paris", + "id": 21798, + "name": "Hôtel des Invalides" + }, + { + "address": null, + "city": "Paris", + "id": 21799, + "name": "La Tour Eiffel" + }, + { + "address": "129, rue de Grenelle", + "city": "Paris", + "id": 21800, + "name": "Musée de l'Armée" + }, + { + "address": "1, rue de la Légion d'Honneur / rue de Lille", + "city": "Paris", + "id": 21801, + "name": "Musée d'Orsay" + }, + { + "address": "37, quai Branly", + "city": "Paris", + "id": 21802, + "name": "Musée du quai Branly" + }, + { + "address": "79, rue de Varenne", + "city": "Paris", + "id": 21803, + "name": "Musée Rodin" + }, + { + "address": null, + "city": "Paris", + "id": 21804, + "name": "Les Egouts de Paris" + }, + { + "address": "Place de l'Étoile, Place Charles de Gaulle", + "city": "Paris", + "id": 21810, + "name": "l'Arc de Triomphe" + }, + { + "address": "place de la Madeleine", + "city": "Paris", + "id": 21811, + "name": "Église de la Madeleine" + }, + { + "address": null, + "city": "Paris", + "id": 21812, + "name": "Elysee Palace" + }, + { + "address": null, + "city": "Paris", + "id": 21813, + "name": "Le Grand Palais" + }, + { + "address": "Avenue Winston Churchill", + "city": "Paris-8E-Arrondissement", + "id": 21814, + "name": "Musée du Petit Palais" + }, + { + "address": "Avenue Franklin D. Roosevelt", + "city": "Paris", + "id": 21815, + "name": "Palais de la decouverte" + }, + { + "address": "38, av Matignon", + "city": "Paris", + "id": 21816, + "name": "Jerome de Noirmont" + }, + { + "address": null, + "city": "Paris", + "id": 21817, + "name": "Musée Jacquemart-André" + }, + { + "address": null, + "city": "Paris-8E-Arrondissement", + "id": 21818, + "name": "Parc Monceau" + }, + { + "address": "1 Le Parvis de La Défense", + "city": "Puteaux", + "id": 21861, + "name": "Grande Arche de la Defense" + }, + { + "address": null, + "city": "Puteaux", + "id": 21862, + "name": "Center of New Industries and Technologies" + }, + { + "address": "15, place de La Défense", + "city": "Courbevoie", + "id": 21863, + "name": "La Defense Museum" + }, + { + "address": null, + "city": "Puteaux", + "id": 21864, + "name": "Notre-Dame de Pentecôte" + }, + { + "address": null, + "city": "Nanterre", + "id": 21865, + "name": "Tours Aillaud" + }, + { + "address": null, + "city": "Nanterre", + "id": 21866, + "name": "Parc André Malraux" + }, + { + "address": "28 Rue de l'Église", + "city": "Puteaux", + "id": 21867, + "name": "Nanterre Cathedral" + }, + { + "address": null, + "city": "Courbevoie", + "id": 21868, + "name": "Pavillon des Indes" + }, + { + "address": null, + "city": "Puteaux", + "id": 21869, + "name": "Théâtre des Hauts-de-Seine" + }, + { + "address": null, + "city": "Cornwall", + "id": 22080, + "name": "Chysauster Ancient Village" + }, + { + "address": "Scone", + "city": "Stable Yd", + "id": 22197, + "name": "Scone Palace" + }, + { + "address": null, + "city": "Perth", + "id": 22198, + "name": "St. John's Kirk" + }, + { + "address": "North Methven Street, PH1 5PP", + "city": "Perth", + "id": 22199, + "name": "St Ninian's Cathedral" + }, + { + "address": "Balhousie Castle, Hay Street.", + "city": "Perth", + "id": 22200, + "name": "The Black Watch Museum" + }, + { + "address": "78 George Street", + "city": "Perth", + "id": 22201, + "name": "Perth Museum & Art Gallery" + }, + { + "address": "Marshall Place", + "city": "Perth", + "id": 22202, + "name": "Fergusson Gallery" + }, + { + "address": "PE1 1XS", + "city": "Peterborough", + "id": 22213, + "name": "Peterborough Cathedral" + }, + { + "address": "The Droveway, Northey Road, PE6 7QJ", + "city": "Peterborough", + "id": 22214, + "name": "Flag Fen - Britain's Bronze Age Centre" + }, + { + "address": "St. Peter Street, AB42 1QD", + "city": "Peterhead", + "id": 22215, + "name": "Arbuthnot Museum" + }, + { + "address": null, + "city": "Cruden Bay", + "id": 22216, + "name": "Bullers o Buchan (Sea cliffs and caves)" + }, + { + "address": null, + "city": "Peterhead", + "id": 22217, + "name": "Peterhead Lido Beach" + }, + { + "address": "Bangor, Gwynedd, LL57 4HN", + "city": "Gwynedd", + "id": 2237, + "name": "Penrhyn Castle" + }, + { + "address": "Castlegate, YO18 7AX", + "city": "Pickering", + "id": 22397, + "name": "Pickering Castle" + }, + { + "address": "Pitlochry, PH16 5DR", + "city": "Perth and Kinross", + "id": 22457, + "name": "Pitlochry Dam and Fish Ladder" + }, + { + "address": null, + "city": "Los Angeles", + "id": 22538, + "name": "Ballona Wetlands" + }, + { + "address": null, + "city": "Plymouth", + "id": 22542, + "name": "The National Marine Aquarium" + }, + { + "address": null, + "city": "Plymouth", + "id": 22543, + "name": "Plymouth Hoe" + }, + { + "address": null, + "city": "Plymouth", + "id": 22544, + "name": "Smeaton’s Tower" + }, + { + "address": null, + "city": "Plymouth", + "id": 22545, + "name": "The Mayflower Steps" + }, + { + "address": null, + "city": "Plymouth", + "id": 22546, + "name": "The Barbican" + }, + { + "address": null, + "city": "Plymouth", + "id": 22547, + "name": "The Post-War City Centre" + }, + { + "address": null, + "city": "Plymouth", + "id": 22548, + "name": "The Royal William Yard" + }, + { + "address": "The Hoe", + "city": "Plymouth", + "id": 22549, + "name": "The Royal Citadel" + }, + { + "address": "Plympton, PL7 1UH", + "city": null, + "id": 22550, + "name": "Saltram House" + }, + { + "address": "Catherine Street", + "city": "Plymouth", + "id": 22551, + "name": "Plymouth Synagogue" + }, + { + "address": "Royal Parade", + "city": "Plymouth", + "id": 22552, + "name": "Plymouth Theatre Royal" + }, + { + "address": null, + "city": "Plymouth", + "id": 22553, + "name": "Crownhill Fort" + }, + { + "address": null, + "city": "Plymouth", + "id": 22554, + "name": "The Minster Church of St Andrew" + }, + { + "address": "Finewell Street", + "city": "Plymouth", + "id": 22555, + "name": "Prysten House" + }, + { + "address": "Armada Way, PL1 2EN", + "city": "Plymouth", + "id": 22556, + "name": "Christ The King Roman Catholic Church" + }, + { + "address": "Plympton", + "city": "Plymouth", + "id": 22557, + "name": "Plympton Castle" + }, + { + "address": null, + "city": "Plymouth", + "id": 22558, + "name": "Plymouth City Museum and Art Gallery" + }, + { + "address": null, + "city": "Plymouth", + "id": 22559, + "name": "Elizabethan House" + }, + { + "address": null, + "city": "Plymouth", + "id": 22560, + "name": "Merchant's House" + }, + { + "address": "Abbey Road", + "city": "Ceredigion", + "id": 22693, + "name": "Strata Florida Abbey" + }, + { + "address": "Poole Harbour, BH13 7EE", + "city": "Brownsea Island", + "id": 22694, + "name": "Brownsea Island" + }, + { + "address": "Wimborne Minster, BH21 4EA", + "city": "Dorset", + "id": 22695, + "name": "Kingston Lacy" + }, + { + "address": "LL48 6ET", + "city": "Portmeirion", + "id": 22792, + "name": "[[Portmeirion]] Village" + }, + { + "address": "Off Richborough Road, Sandwich, CT13 9JW", + "city": "Ash", + "id": 23548, + "name": "Richborough Roman Fort and Amphitheatre" + }, + { + "address": "Lower Basildon, Reading, RG8 9NR", + "city": "West Berkshire", + "id": 23632, + "name": "Basildon Park" + }, + { + "address": null, + "city": "Hampshire", + "id": 23633, + "name": "Silchester Roman Town" + }, + { + "address": "844 Sundial Bridge Drive", + "city": "Redding", + "id": 23635, + "name": "Turtle Bay Exploration Park" + }, + { + "address": "777 Cypress Avenue", + "city": "Redding", + "id": 23636, + "name": "Sculpture Gardens at City Hall" + }, + { + "address": "2850 Foothill Boulevard", + "city": "Redding", + "id": 23637, + "name": "Pilgrim Congregational Church" + }, + { + "address": null, + "city": "Ripon", + "id": 24102, + "name": "Cathedral" + }, + { + "address": null, + "city": "North Yorkshire", + "id": 24103, + "name": "Choristers' House" + }, + { + "address": null, + "city": "Rochester", + "id": 24161, + "name": "Rochester Cathedral" + }, + { + "address": "Castle Hill, ME1 1SW", + "city": "Rochester", + "id": 24162, + "name": "Rochester Castle" + }, + { + "address": "High St.", + "city": "Rochester", + "id": 24163, + "name": "Eastgate House Garden" + }, + { + "address": "17-19 Crow Lane, ME1 1RF", + "city": "Rochester", + "id": 24164, + "name": "Restoration House" + }, + { + "address": null, + "city": "Rochester", + "id": 24165, + "name": "Rochester Bridge" + }, + { + "address": "High Street, ME1 1PY", + "city": "Rochester", + "id": 24166, + "name": "Guildhall Museum" + }, + { + "address": "PH43 4RR", + "city": "Highland", + "id": 24602, + "name": "Kinloch Castle" + }, + { + "address": "Tudor Road", + "city": "Halton", + "id": 24610, + "name": "Norton Priory" + }, + { + "address": "Castle Rd, off Main St", + "city": "Runcorn", + "id": 24611, + "name": "Halton Castle" + }, + { + "address": null, + "city": "Higham Ferrers", + "id": 24613, + "name": "Chichele College" + }, + { + "address": null, + "city": "Saint-Florent", + "id": 24682, + "name": "Citadelle" + }, + { + "address": "Castlebay, HS9 5UZ", + "city": "Na h-Eileanan an Iar", + "id": 2485, + "name": "Kisimul Castle" + }, + { + "address": "HS9 5XD", + "city": "Na h-Eileanan an Iar", + "id": 2486, + "name": "Barra Heritage & Cultural Centre" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2487, + "name": "The airport" + }, + { + "address": null, + "city": "Timperley", + "id": 24876, + "name": "The Bridgewater Canal" + }, + { + "address": "Broad Road", + "city": "Sale", + "id": 24877, + "name": "Worthington Park" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2488, + "name": "The church" + }, + { + "address": "Castle Road, SP1 3SD", + "city": "Salisbury", + "id": 24883, + "name": "Old Sarum" + }, + { + "address": "The Close, SP1 2EL", + "city": "Salisbury", + "id": 24884, + "name": "Mompesson House" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2489, + "name": "Heaval" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2490, + "name": "Vatersay" + }, + { + "address": null, + "city": "Eoligarry", + "id": 2491, + "name": "Chapel of Cille Bharra" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2492, + "name": "Northbay" + }, + { + "address": "Manor Road, LA13 0PJ", + "city": "Barrow-in-Furness", + "id": 2500, + "name": "Furness Abbey" + }, + { + "address": "685 N. First Ave.", + "city": "Barstow", + "id": 2501, + "name": "Western America Railroad Museum" + }, + { + "address": "Silchester (''5 miles north of Basingstoke'')", + "city": "Hampshire", + "id": 2502, + "name": "Silchester Roman Town" + }, + { + "address": "Bath Assembly Rooms, Bennett Street, BA1 2QH", + "city": "Bath", + "id": 2507, + "name": "Museum of Costume" + }, + { + "address": "3525 7th Ave", + "city": "San Diego", + "id": 25081, + "name": "Marston House" + }, + { + "address": "in south Hillcrest at the end of Spruce Street, west of First Avenue", + "city": "San Diego", + "id": 25082, + "name": "Spruce Street Bridge" + }, + { + "address": "1649 El Prado", + "city": "San Diego", + "id": 25083, + "name": "San Diego History Center" + }, + { + "address": "2131 Pan American Plaza", + "city": "San Diego", + "id": 25084, + "name": "San Diego Hall of Champions Sports Museum" + }, + { + "address": "1649 El Prado", + "city": "San Diego", + "id": 25085, + "name": "San Diego Model Railroad Museum" + }, + { + "address": "2115 Park Blvd", + "city": "San Diego", + "id": 25086, + "name": "Veterans Museum & Memorial Center" + }, + { + "address": "2125 Park Blvd", + "city": "San Diego", + "id": 25087, + "name": "Centro Cultural de la Raza" + }, + { + "address": "1439 El Prado", + "city": "San Diego", + "id": 25088, + "name": "Mingei International Museum" + }, + { + "address": "1649 El Prado", + "city": "San Diego", + "id": 25089, + "name": "Museum of Photographic Arts" + }, + { + "address": "1439 El Prado", + "city": "San Diego", + "id": 25090, + "name": "San Diego Art Institute" + }, + { + "address": "1450 El Prado", + "city": "San Diego", + "id": 25091, + "name": "San Diego Museum of Art" + }, + { + "address": "1500 El Prado", + "city": "San Diego", + "id": 25092, + "name": "Timken Museum of Art" + }, + { + "address": "1875 El Prado", + "city": "San Diego", + "id": 25093, + "name": "Reuben H. Fleet Science Center" + }, + { + "address": "2001 Pan American Plaza", + "city": "San Diego", + "id": 25094, + "name": "San Diego Air and Space Museum" + }, + { + "address": "2080 Pan American Plaza", + "city": "San Diego", + "id": 25095, + "name": "San Diego Automotive Museum" + }, + { + "address": "1350 El Prado", + "city": "San Diego", + "id": 25096, + "name": "San Diego Museum of Man" + }, + { + "address": "1788 El Prado", + "city": "San Diego", + "id": 25097, + "name": "San Diego Natural History Museum" + }, + { + "address": "410 Island Avenue", + "city": "San Diego", + "id": 25121, + "name": "William Heath Davis House" + }, + { + "address": "1492 North Harbor Drive", + "city": "San Diego", + "id": 25122, + "name": "Maritime Museum of San Diego" + }, + { + "address": "1001 Kettner", + "city": "San Diego", + "id": 25123, + "name": "Museum of Contemporary Art San Diego" + }, + { + "address": "404 Third Avenue", + "city": "San Diego", + "id": 25124, + "name": "San Diego Chinese Historical Museum" + }, + { + "address": "1572 Columbia St.", + "city": "San Diego", + "id": 25125, + "name": "San Diego Firehouse Museum" + }, + { + "address": "910 N. Harbor Drive", + "city": "San Diego", + "id": 25126, + "name": "USS Midway Aircraft Carrier Museum" + }, + { + "address": "High Street, TN33 0AD", + "city": "Battle", + "id": 2517, + "name": "Battle Abbey and Battlefield" + }, + { + "address": "1008 Wall St", + "city": "San Diego", + "id": 25170, + "name": "Athenaeum Music & Arts Library" + }, + { + "address": "2300 Expedition Way", + "city": "San Diego", + "id": 25171, + "name": "Birch Aquarium at Scripps" + }, + { + "address": "1325 Coast Blvd", + "city": "San Diego", + "id": 25172, + "name": "The Cave Store" + }, + { + "address": "850 Coast Blvd", + "city": "San Diego", + "id": 25173, + "name": "Children's Pool Beach" + }, + { + "address": null, + "city": "San Diego", + "id": 25174, + "name": "Mount Soledad" + }, + { + "address": "700 Prospect Street", + "city": "San Diego", + "id": 25175, + "name": "Museum of Contemporary Art San Diego La Jolla" + }, + { + "address": "10010 N Torrey Pines Rd", + "city": "San Diego", + "id": 25176, + "name": "Salk Institute of Biological Studies" + }, + { + "address": "12600 North Torrey Pines Rd", + "city": "San Diego", + "id": 25177, + "name": "Torrey Pines State Natural Reserve" + }, + { + "address": "4061 Adams Ave", + "city": "San Diego", + "id": 25202, + "name": "Ken Cinema" + }, + { + "address": "500 SeaWorld Drive", + "city": "San Diego", + "id": 25215, + "name": "Sea World" + }, + { + "address": "15500 San Pasqual Valley Road", + "city": "San Diego", + "id": 25246, + "name": "San Diego Zoo Safari Park" + }, + { + "address": "15808 San Pasqual Valley Road", + "city": "Escondido", + "id": 25247, + "name": "San Pasqual Battlefield State Historic Park" + }, + { + "address": "10818 San Diego Mission Rd", + "city": "San Diego", + "id": 25265, + "name": "Mission San Diego de Alcala" + }, + { + "address": null, + "city": "San Diego", + "id": 25266, + "name": "Heritage Park" + }, + { + "address": null, + "city": "San Diego", + "id": 25267, + "name": "Immaculate Conception Church" + }, + { + "address": "2727 Presidio Dr", + "city": "San Diego", + "id": 25268, + "name": "Junipero Serra Museum" + }, + { + "address": "2510 Juan St", + "city": "San Diego", + "id": 25269, + "name": "Mormon Battalion Visitors' Center of San Diego" + }, + { + "address": "2384 San Diego Ave", + "city": "San Diego", + "id": 25270, + "name": "Sheriff's Museum" + }, + { + "address": "2482 San Diego Ave", + "city": "San Diego", + "id": 25271, + "name": "Whaley House" + }, + { + "address": "4002 Wallace St", + "city": "San Diego", + "id": 25272, + "name": "Robinson-Rose House Visitor Center" + }, + { + "address": "on San Diego Ave", + "city": "San Diego", + "id": 25273, + "name": "Altamirano-Pedrorena House" + }, + { + "address": null, + "city": "San Diego", + "id": 25274, + "name": "Black Hawk Smithy & Stable" + }, + { + "address": "4001 Mason St", + "city": "San Diego", + "id": 25275, + "name": "Casa de Estudillo" + }, + { + "address": "2767 San Diego Ave", + "city": "San Diego", + "id": 25276, + "name": "Light-Freeman House" + }, + { + "address": "3966 Mason St", + "city": "San Diego", + "id": 25277, + "name": "Mason Street Schoolhouse" + }, + { + "address": "2731 San Diego Ave", + "city": "San Diego", + "id": 25278, + "name": "San Diego Courthouse" + }, + { + "address": null, + "city": "San Diego", + "id": 25279, + "name": "San Diego Union Museum" + }, + { + "address": "on Calhoun between Twiggs and Mason", + "city": "San Diego", + "id": 25280, + "name": "Seeley Stable Museum" + }, + { + "address": "2733 San Diego Ave", + "city": "San Diego", + "id": 25281, + "name": "Wells Fargo History Museum" + }, + { + "address": "north of Cabrillo National Monument", + "city": "San Diego", + "id": 25305, + "name": "Fort Rosecrans" + }, + { + "address": "Off Richborough Road, CT13 9JW", + "city": "Ash", + "id": 25332, + "name": "Richborough Roman Fort and Amphitheatre" + }, + { + "address": null, + "city": "San Francisco", + "id": 25333, + "name": "Bernal Hill" + }, + { + "address": "429 Castro St", + "city": "San Francisco", + "id": 25357, + "name": "The Castro Theatre" + }, + { + "address": "1800 Market St", + "city": "San Francisco", + "id": 25358, + "name": "LGBT Community Center" + }, + { + "address": "4127 18th St", + "city": "San Francisco", + "id": 25359, + "name": "GLBT History Museum" + }, + { + "address": "199 Museum Way", + "city": "San Francisco", + "id": 25360, + "name": "Randall Museum" + }, + { + "address": "56 Ross Alley", + "city": "San Francisco", + "id": 25393, + "name": "Golden Gate Fortune Cookie Factory" + }, + { + "address": "261 Columbus Ave", + "city": "San Francisco", + "id": 25394, + "name": "City Lights Bookstore" + }, + { + "address": "Jack Kerouac Alley", + "city": "San Francisco", + "id": 25395, + "name": "Jack Kerouac Alley" + }, + { + "address": null, + "city": "San Francisco", + "id": 25396, + "name": "Filbert Steps" + }, + { + "address": "750 Kearny St, 3rd floor", + "city": "San Francisco", + "id": 25397, + "name": "Chinese Culture Center" + }, + { + "address": "965 Clay St", + "city": "San Francisco", + "id": 25398, + "name": "Chinese Historical Society of America Museum" + }, + { + "address": "Pier 15, 698 The Embarcadero", + "city": "San Francisco", + "id": 25399, + "name": "Exploratorium" + }, + { + "address": "661 Jackson St", + "city": "San Francisco", + "id": 25400, + "name": "Stylers Art Gallery" + }, + { + "address": "540 Broadway St", + "city": "San Francisco", + "id": 25401, + "name": "Beat Museum" + }, + { + "address": "1435 Stockton St", + "city": "San Francisco", + "id": 25402, + "name": "North Beach Museum" + }, + { + "address": "660 California St", + "city": "San Francisco", + "id": 25403, + "name": "Old St. Mary's Church" + }, + { + "address": "125 Waverly Pl, 4th floor", + "city": "San Francisco", + "id": 25404, + "name": "Tin How Temple" + }, + { + "address": "109 Waverly Pl", + "city": "San Francisco", + "id": 25405, + "name": "Norras Temple" + }, + { + "address": "30 Beckett St", + "city": "San Francisco", + "id": 25406, + "name": "Ma-Tsu Temple" + }, + { + "address": "15 Waverly Pl", + "city": "San Francisco", + "id": 25407, + "name": "First Chinese Baptist Church" + }, + { + "address": "720 Washington St", + "city": "San Francisco", + "id": 25408, + "name": "Buddhas Universal Church" + }, + { + "address": "855 Stockton St", + "city": "San Francisco", + "id": 25409, + "name": "Kong Chow Temple" + }, + { + "address": "610 Vallejo St", + "city": "San Francisco", + "id": 25410, + "name": "St. Francis of Assisi Church" + }, + { + "address": "666 Filbert St", + "city": "San Francisco", + "id": 25411, + "name": "Sts. Peter and Paul Church" + }, + { + "address": "Grant Ave", + "city": "San Francisco", + "id": 25412, + "name": "Chinatown Gate" + }, + { + "address": "743 Washington St", + "city": "San Francisco", + "id": 25413, + "name": "Bank of Canton" + }, + { + "address": null, + "city": "San Francisco", + "id": 25414, + "name": "Sing Fat Building and Sing Chong Building" + }, + { + "address": "701 Grant Ave", + "city": "San Francisco", + "id": 25415, + "name": "Bank of America" + }, + { + "address": "451 Pacific Ave", + "city": "San Francisco", + "id": 25416, + "name": "Engine No. 1 — Firehouse" + }, + { + "address": "916 Kearny St", + "city": "San Francisco", + "id": 25417, + "name": "Columbus Tower/Sentinel Building" + }, + { + "address": "1 Telegraph Hill Blvd", + "city": "San Francisco", + "id": 25418, + "name": "Coit Tower" + }, + { + "address": null, + "city": "San Francisco", + "id": 25419, + "name": "Portsmouth Square" + }, + { + "address": null, + "city": "San Francisco", + "id": 25420, + "name": "St. Mary's Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 25421, + "name": "Woh Hei Yuen Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 25422, + "name": "Ping Yen Mural" + }, + { + "address": "827 Stockton St", + "city": "San Francisco", + "id": 25423, + "name": "Chinese Railroad Workers Mural" + }, + { + "address": null, + "city": "San Francisco", + "id": 25424, + "name": "Washington Square" + }, + { + "address": null, + "city": "San Francisco", + "id": 25425, + "name": "Juana Briones Monument" + }, + { + "address": null, + "city": "San Francisco", + "id": 25426, + "name": "Pioneer Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 25427, + "name": "Sydney G. Walton Square" + }, + { + "address": "1160 Battery St", + "city": "San Francisco", + "id": 25428, + "name": "Levi's Plaza Park" + }, + { + "address": "N13 , 61160", + "city": "La Cambe", + "id": 2543, + "name": "Cimetière Militaire Allemand" + }, + { + "address": "1170 Market St", + "city": "San Francisco", + "id": 25512, + "name": "The Art Institute of California — San Francisco" + }, + { + "address": "200 Larkin St", + "city": "San Francisco", + "id": 25513, + "name": "Asian Art Museum" + }, + { + "address": "750 Post St", + "city": "San Francisco", + "id": 25514, + "name": "John Pence Gallery" + }, + { + "address": "1007 Market St", + "city": "San Francisco", + "id": 25515, + "name": "Luggage Store Gallery" + }, + { + "address": "War Memorial Veterans Building, 401 Van Ness Ave, 4th Floor", + "city": "San Francisco", + "id": 25516, + "name": "Museum of Performance & Design" + }, + { + "address": "War Memorial Veterans Building, 401 Van Ness Ave", + "city": "San Francisco", + "id": 25517, + "name": "San Francisco Arts Commission Gallery" + }, + { + "address": null, + "city": "San Francisco", + "id": 25518, + "name": "Civic Center Plaza" + }, + { + "address": null, + "city": "San Francisco", + "id": 25519, + "name": "James Lick (Pioneer) Monument" + }, + { + "address": "201 Van Ness Ave", + "city": "San Francisco", + "id": 25520, + "name": "Large Four Piece Reclining Figure" + }, + { + "address": null, + "city": "San Francisco", + "id": 25521, + "name": "Sgt. John Macaulay Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 25522, + "name": "United Nations Plaza" + }, + { + "address": "650 Geary St", + "city": "San Francisco", + "id": 25523, + "name": "Alcazar Theater" + }, + { + "address": "1 Dr. Carlton B. Goodlett Pl", + "city": "San Francisco", + "id": 25524, + "name": "City Hall" + }, + { + "address": "50 United Nations Plaza", + "city": "San Francisco", + "id": 25525, + "name": "Federal Office Building" + }, + { + "address": "100 Larkin St", + "city": "San Francisco", + "id": 25526, + "name": "San Francisco Public Library - Main Library" + }, + { + "address": "Pier 39", + "city": "San Francisco", + "id": 25603, + "name": "Aquarium of the Bay" + }, + { + "address": "Pier 39's West Marina", + "city": "San Francisco", + "id": 25604, + "name": "The sea lions" + }, + { + "address": "the Crystal Geyser Alpine Spring Water Center Stage", + "city": "San Francisco", + "id": 25605, + "name": "Street performers" + }, + { + "address": "Pier 45", + "city": "San Francisco", + "id": 25606, + "name": "USS Pampanito Submarine" + }, + { + "address": "Pier 45", + "city": "San Francisco", + "id": 25607, + "name": "SS Jeremiah O'Brien" + }, + { + "address": "Pier 45", + "city": "San Francisco", + "id": 25608, + "name": "Amusing America Exhibit" + }, + { + "address": "Pier 45, Shed A", + "city": "San Francisco", + "id": 25609, + "name": "Musee Mecanique" + }, + { + "address": "Pier 45", + "city": "San Francisco", + "id": 25610, + "name": "Fishermen's and Seamen's Chapel" + }, + { + "address": "145 Jefferson Street", + "city": "San Francisco", + "id": 25611, + "name": "Madame Tussauds San Francisco" + }, + { + "address": "175 Jefferson St", + "city": "San Francisco", + "id": 25612, + "name": "Ripley's Believe It Or Not! Museum" + }, + { + "address": null, + "city": "San Francisco", + "id": 25613, + "name": "Fish Alley" + }, + { + "address": "Del Monte Square", + "city": "San Francisco", + "id": 25614, + "name": "The Cannery" + }, + { + "address": "The Cannery, Del Monte Square", + "city": "San Francisco", + "id": 25615, + "name": "Visitor Center" + }, + { + "address": null, + "city": "San Francisco", + "id": 25616, + "name": "Hyde St Pier" + }, + { + "address": null, + "city": "San Francisco", + "id": 25617, + "name": "Maritime Museum" + }, + { + "address": null, + "city": "San Francisco", + "id": 25618, + "name": "Aquatic Park and Municipal Pier" + }, + { + "address": "900 North Point St", + "city": "San Francisco", + "id": 25619, + "name": "Ghirardelli Square" + }, + { + "address": "3119 Fillmore St", + "city": "San Francisco", + "id": 25677, + "name": "The Six Gallery" + }, + { + "address": "at the end of Yacht Rd", + "city": "San Francisco", + "id": 25678, + "name": "Wave Organ" + }, + { + "address": "1 Yacht Rd", + "city": "San Francisco", + "id": 25679, + "name": "Golden Gate Yacht Club" + }, + { + "address": "700 Marina Blvd", + "city": "San Francisco", + "id": 25680, + "name": "St Francis Yacht Club" + }, + { + "address": null, + "city": "San Francisco", + "id": 25681, + "name": "Alta Plaza Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 25682, + "name": "Lafayette Park" + }, + { + "address": "1843 Union St", + "city": "San Francisco", + "id": 25683, + "name": "Hourian Art Galleries" + }, + { + "address": "2036 Union St", + "city": "San Francisco", + "id": 25684, + "name": "Images of the North" + }, + { + "address": "1771 Union St", + "city": "San Francisco", + "id": 25685, + "name": "Wonders of Tibet" + }, + { + "address": "1990 California St", + "city": "San Francisco", + "id": 25686, + "name": "Atherton House" + }, + { + "address": "2007 Franklin St", + "city": "San Francisco", + "id": 25687, + "name": "Haas Lilienthal House" + }, + { + "address": "2475 Pacific Ave", + "city": "San Francisco", + "id": 25688, + "name": "The Leale House" + }, + { + "address": "2645 Gough St", + "city": "San Francisco", + "id": 25689, + "name": "The Octagon House" + }, + { + "address": "1801 Green St", + "city": "San Francisco", + "id": 25690, + "name": "San Francisco Public Library — Golden Gate Valley Branch" + }, + { + "address": "2080 Washington St", + "city": "San Francisco", + "id": 25691, + "name": "Spreckles Mansion" + }, + { + "address": "2963 Webster St", + "city": "San Francisco", + "id": 25692, + "name": "Vedanta Temple" + }, + { + "address": "Fort Mason Center, Building C", + "city": "San Francisco", + "id": 25693, + "name": "Museo ItaloAmericano" + }, + { + "address": "Fort Mason Center, Landmark Building A", + "city": "San Francisco", + "id": 25694, + "name": "San Francisco Museum Of Modern Art — Artists Gallery" + }, + { + "address": "Landmark Building A", + "city": "San Francisco", + "id": 25695, + "name": "The Long Now Foundation Museum" + }, + { + "address": "1802 Hays St", + "city": "San Francisco", + "id": 25696, + "name": "Arion Press" + }, + { + "address": "Battery Chamberlin Rd", + "city": "San Francisco", + "id": 25697, + "name": "Battery Chamberlin" + }, + { + "address": "1199 East Beach", + "city": "San Francisco", + "id": 25698, + "name": "Crissy Field Center" + }, + { + "address": "Marine Dr", + "city": "San Francisco", + "id": 25699, + "name": "Fort Point National Historic Site" + }, + { + "address": "991 Marine Dr", + "city": "San Francisco", + "id": 25700, + "name": "Gulf of the Farallones National Marine Sanctuary" + }, + { + "address": "104 Montgomery St", + "city": "San Francisco", + "id": 25701, + "name": "Walt Disney Family Museum" + }, + { + "address": "Building 50, Moraga Ave", + "city": "San Francisco", + "id": 25702, + "name": "William Penn Mott, Jr. Visitor Center" + }, + { + "address": null, + "city": "San Francisco", + "id": 25703, + "name": "Battery East" + }, + { + "address": "Cowles St", + "city": "San Francisco", + "id": 25704, + "name": "Cavalry Stables and Pet Cemetery" + }, + { + "address": "Crissy Field, 603 Mason St", + "city": "San Francisco", + "id": 25705, + "name": "Crissy Airfield" + }, + { + "address": "Ruckman Ave", + "city": "San Francisco", + "id": 25706, + "name": "Fort Winfield Scott" + }, + { + "address": "Infantry Terrace", + "city": "San Francisco", + "id": 25707, + "name": "Infantry Row" + }, + { + "address": "Letterman Dr", + "city": "San Francisco", + "id": 25708, + "name": "Letterman Complex" + }, + { + "address": "Lincoln Blvd", + "city": "San Francisco", + "id": 25709, + "name": "Main Post" + }, + { + "address": "Pershing Dr", + "city": "San Francisco", + "id": 25710, + "name": "Pershing Square" + }, + { + "address": "Wedemeyer St and 15th Ave", + "city": "San Francisco", + "id": 25711, + "name": "Public Health Service Hospital" + }, + { + "address": "1 Lincoln Blvd", + "city": "San Francisco", + "id": 25712, + "name": "San Francisco National Cemetery" + }, + { + "address": "at Kobbe Ave and Lincoln Blvd", + "city": "San Francisco", + "id": 25713, + "name": "West Coast Memorial to the Missing of World War II" + }, + { + "address": "135 Fisher Loop", + "city": "San Francisco", + "id": 25714, + "name": "The Golden Gate Club" + }, + { + "address": "50 Moraga Ave", + "city": "San Francisco", + "id": 25715, + "name": "Officers Club" + }, + { + "address": "Funston Ave", + "city": "San Francisco", + "id": 25716, + "name": "Old Post Hospital" + }, + { + "address": "3301 Lyon St", + "city": "San Francisco", + "id": 25717, + "name": "Palace of Fine Arts" + }, + { + "address": "Fisher Loop, Building 130", + "city": "San Francisco", + "id": 25718, + "name": "Post Interfaith Chapel" + }, + { + "address": "Gibson Rd", + "city": "San Francisco", + "id": 25719, + "name": "Baker Beach" + }, + { + "address": null, + "city": "San Francisco", + "id": 25720, + "name": "Coastal Bluffs" + }, + { + "address": "El Polin Loop", + "city": "San Francisco", + "id": 25721, + "name": "El Polin Spring" + }, + { + "address": "Arguello Blvd and Washington Blvd", + "city": "San Francisco", + "id": 25722, + "name": "Inspiration Point" + }, + { + "address": null, + "city": "San Francisco", + "id": 25723, + "name": "Lobos Creek Valley" + }, + { + "address": null, + "city": "San Francisco", + "id": 25724, + "name": "Lovers' Lane" + }, + { + "address": null, + "city": "San Francisco", + "id": 25725, + "name": "Mountain Lake" + }, + { + "address": "300 Finley Rd", + "city": "San Francisco", + "id": 25726, + "name": "Presidio Golf Course" + }, + { + "address": null, + "city": "San Francisco", + "id": 25814, + "name": "Buena Vista Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 25815, + "name": "Hippie Hill" + }, + { + "address": "1550 Page St", + "city": "San Francisco", + "id": 25816, + "name": ""Hippie Temptation" house" + }, + { + "address": "1828 Page St", + "city": "San Francisco", + "id": 25817, + "name": "Ron Donovan house" + }, + { + "address": "879 Haight St", + "city": "San Francisco", + "id": 25818, + "name": "Flipper house" + }, + { + "address": null, + "city": "San Francisco", + "id": 25819, + "name": "731 Buena Vista West" + }, + { + "address": "264 Downey St", + "city": "San Francisco", + "id": 25820, + "name": "Michael McClure house" + }, + { + "address": null, + "city": "San Francisco", + "id": 25821, + "name": "1235 Masonic Ave" + }, + { + "address": "32 Delmar St", + "city": "San Francisco", + "id": 25822, + "name": "Sid Vicious house" + }, + { + "address": null, + "city": "San Francisco", + "id": 25823, + "name": "Duboce Park" + }, + { + "address": "3321 16th St", + "city": "San Francisco", + "id": 25866, + "name": "Mission Dolores" + }, + { + "address": "3543 18th St, #8", + "city": "San Francisco", + "id": 25867, + "name": "The Women's Building" + }, + { + "address": "between 24th, 25th, Harrison, and Treat", + "city": "San Francisco", + "id": 25868, + "name": "Balmy Alley" + }, + { + "address": null, + "city": "San Francisco", + "id": 25869, + "name": "Clarion Alley" + }, + { + "address": "2857 24th St", + "city": "San Francisco", + "id": 25870, + "name": "Galeria de la Raza" + }, + { + "address": "1201 Mason Street", + "city": "San Francisco", + "id": 25929, + "name": "Cable Car Museum" + }, + { + "address": "between Hyde and Leavenworth", + "city": "San Francisco", + "id": 25930, + "name": "Lombard Street" + }, + { + "address": null, + "city": "San Francisco", + "id": 25931, + "name": "Filbert Street" + }, + { + "address": "between Hyde and Leavenworth", + "city": "San Francisco", + "id": 25932, + "name": "Francisco Street" + }, + { + "address": "1100 California Street", + "city": "San Francisco", + "id": 25933, + "name": "Grace Cathedral" + }, + { + "address": "1111 California Street", + "city": "San Francisco", + "id": 25934, + "name": "Nob Hill Masonic Center" + }, + { + "address": "747 Howard St", + "city": "San Francisco", + "id": 25971, + "name": "Moscone Center" + }, + { + "address": null, + "city": "San Francisco", + "id": 25972, + "name": "Charles Looff Carousel" + }, + { + "address": "101 4th St", + "city": "San Francisco", + "id": 25973, + "name": "Metreon" + }, + { + "address": "701 Mission St", + "city": "San Francisco", + "id": 25974, + "name": "Yerba Buena Center for the Arts" + }, + { + "address": null, + "city": "San Francisco", + "id": 25975, + "name": "Yerba Buena Gardens" + }, + { + "address": "221 4th St", + "city": "San Francisco", + "id": 25976, + "name": "Children's Creativity Museum" + }, + { + "address": "934 Brannan St", + "city": "San Francisco", + "id": 25977, + "name": "SOMArts Cultural Center" + }, + { + "address": "151 3rd St", + "city": "San Francisco", + "id": 25978, + "name": "San Francisco Museum of Modern Art (SFMOMA)" + }, + { + "address": "655 Mission St", + "city": "San Francisco", + "id": 25979, + "name": "Cartoon Art Museum" + }, + { + "address": "678 Mission St", + "city": "San Francisco", + "id": 25980, + "name": "California Historical Society Museum" + }, + { + "address": "685 Mission St", + "city": "San Francisco", + "id": 25981, + "name": "Museum of the African Diaspora" + }, + { + "address": "736 Mission St", + "city": "San Francisco", + "id": 25982, + "name": "Contemporary Jewish Museum" + }, + { + "address": "along Park Street between 2nd and 3rd Streets", + "city": "San Francisco", + "id": 25983, + "name": "South Park" + }, + { + "address": "1705 Mariposa Street", + "city": "San Francisco", + "id": 26031, + "name": "Anchor Steam Brewery" + }, + { + "address": "4705 Third Street", + "city": "San Francisco", + "id": 26032, + "name": "Bayview Opera House" + }, + { + "address": null, + "city": "San Francisco", + "id": 26033, + "name": "Bayview Hill Park" + }, + { + "address": "1150 Carroll Avenue", + "city": "San Francisco", + "id": 26034, + "name": "Candlestick Point State Recreation Area" + }, + { + "address": "Pier 98", + "city": "San Francisco", + "id": 26035, + "name": "Heron's Head Park" + }, + { + "address": "Pier 98", + "city": "San Francisco", + "id": 26036, + "name": "The EcoCenter at Heron's Head Park" + }, + { + "address": "881 Innes Avenue", + "city": "San Francisco", + "id": 26037, + "name": "Hunter's Point Springs-Albion Brewery" + }, + { + "address": null, + "city": "San Francisco", + "id": 26038, + "name": "John McLaren Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 26039, + "name": "San Francisco Naval Shipyard" + }, + { + "address": "1195 Evans Ave", + "city": "San Francisco", + "id": 26040, + "name": "Speakeasy Ales & Lagers Brewery" + }, + { + "address": "between 20th and 22nd Street", + "city": "San Francisco", + "id": 26041, + "name": "Vermont Street" + }, + { + "address": "1090 Point Lobos Avenue", + "city": "San Francisco", + "id": 26054, + "name": "Cliff House" + }, + { + "address": "surrounded by 14th and 15th Avenues along Noriega Street in the Sunset district", + "city": "San Francisco", + "id": 26055, + "name": "Grand View Park" + }, + { + "address": "on a steep pedestrian only section of Moraga Street between 15th and 16th Avenue", + "city": "San Francisco", + "id": 26056, + "name": "Moraga Street Stairs" + }, + { + "address": "located just north of the intersection of Lake and Funston at the southern end of the Presidio park", + "city": "San Francisco", + "id": 26057, + "name": "Mountain Lake Park" + }, + { + "address": "along Sloat Boulevard between 19th and 34th Avenues", + "city": "San Francisco", + "id": 26058, + "name": "Sigmund Stern Grove" + }, + { + "address": "at the intersection of Bowling Green and Middle Drive East", + "city": "San Francisco", + "id": 26059, + "name": "AIDS Memorial Grove" + }, + { + "address": "1000 Great Hwy", + "city": "San Francisco", + "id": 26060, + "name": "Beach Chalet and Park Chalet" + }, + { + "address": "along John F Kennedy Drive between 36th Avenue and Chain of Lakes Drive", + "city": "San Francisco", + "id": 26061, + "name": "Buffalo Paddock" + }, + { + "address": "55 Music Concourse Dr.", + "city": "San Francisco", + "id": 26062, + "name": "California Academy of Sciences" + }, + { + "address": "just off Bowling Green Drive north of MLK Drive", + "city": "San Francisco", + "id": 26063, + "name": "Children's Playground" + }, + { + "address": "100 John F Kennedy Drive", + "city": "San Francisco", + "id": 26064, + "name": "Conservatory of Flowers" + }, + { + "address": "50 Hagiwara Tea Garden Drive", + "city": "San Francisco", + "id": 26065, + "name": "de Young Museum" + }, + { + "address": "next to the Beach Chalet", + "city": "San Francisco", + "id": 26066, + "name": "Dutch Windmill" + }, + { + "address": "on Hagiwara Tea Garden Drive just north of MLK Drive", + "city": "San Francisco", + "id": 26067, + "name": "Japanese Tea Garden" + }, + { + "address": "between John F. Kennedy Drive and Park Presidio Drive, just west of the de Young Museum", + "city": "San Francisco", + "id": 26068, + "name": "Rose Garden" + }, + { + "address": "main entrance on 9th Avenue just north of Lincoln Way, secondary entrance at the Friend Gate at MLK Drive and Hagiwara Tea Garden Drive", + "city": "San Francisco", + "id": 26069, + "name": "San Francisco Botanical Gardens" + }, + { + "address": "at Martin Luther King Jr. Drive and Middle Drive East", + "city": "San Francisco", + "id": 26070, + "name": "Shakespeare Garden" + }, + { + "address": "on the northern side of the park near 36th Avenue", + "city": "San Francisco", + "id": 26071, + "name": "Spreckels Lake" + }, + { + "address": null, + "city": "San Francisco", + "id": 26072, + "name": "Stow Lake" + }, + { + "address": "34th Avenue and El Camino del Mar", + "city": "San Francisco", + "id": 26073, + "name": "Legion of Honor Museum" + }, + { + "address": "Rue de l'Hôtel-Dieu 21200 Beaune", + "city": "Beaune", + "id": 2612, + "name": "The Hotel-Dieu" + }, + { + "address": null, + "city": "San Francisco", + "id": 26143, + "name": "City College of San Francisco" + }, + { + "address": null, + "city": "San Francisco", + "id": 26144, + "name": "Fort Funston" + }, + { + "address": null, + "city": "San Francisco", + "id": 26145, + "name": "Glen Canyon Park" + }, + { + "address": null, + "city": "San Francisco", + "id": 26146, + "name": "Mt. Davidson Park" + }, + { + "address": "on Sloat Boulevard at 47th Avenue", + "city": "San Francisco", + "id": 26147, + "name": "San Francisco Zoo" + }, + { + "address": "accessible by car or on foot via Twin Peaks Boulevard", + "city": "San Francisco", + "id": 26148, + "name": "Twin Peaks" + }, + { + "address": "Castle Lane, MK40 3XD", + "city": "Bedford", + "id": 2615, + "name": "The Higgins Bedford" + }, + { + "address": "Park Avenue", + "city": "Bedford", + "id": 2616, + "name": "Bedford Park" + }, + { + "address": null, + "city": "Bedford", + "id": 2617, + "name": "Castle Mound" + }, + { + "address": null, + "city": "San Francisco", + "id": 26170, + "name": "Embarcadero Center" + }, + { + "address": "One Ferry Building", + "city": "San Francisco", + "id": 26171, + "name": "Ferry Building" + }, + { + "address": "49 Geary St", + "city": "San Francisco", + "id": 26172, + "name": "Fraenkel Gallery" + }, + { + "address": "608 Commercial St", + "city": "San Francisco", + "id": 26173, + "name": "Pacific Heritage Museum" + }, + { + "address": "77 Steuart St", + "city": "San Francisco", + "id": 26174, + "name": "San Francisco Railway Museum" + }, + { + "address": "Montgomery and Washington", + "city": "San Francisco", + "id": 26175, + "name": "Transamerica Pyramid" + }, + { + "address": null, + "city": "San Francisco", + "id": 26176, + "name": "Union Square" + }, + { + "address": "420 Montgomery St", + "city": "San Francisco", + "id": 26177, + "name": "Wells Fargo History Museum" + }, + { + "address": "St Pauls Square, MK40 1SQ", + "city": "Bedford", + "id": 2618, + "name": "St Paul's Church" + }, + { + "address": null, + "city": "Bedford", + "id": 2619, + "name": "Priory Park" + }, + { + "address": "Willington, Church End, near Bedford, MK44 3PX", + "city": "Bedford", + "id": 2620, + "name": "Willington Dovecote and Stables" + }, + { + "address": "between Steiner, Scott, Fulton and Hayes Streets", + "city": "San Francisco", + "id": 26239, + "name": "Alamo Square Park" + }, + { + "address": "762 Fulton Street", + "city": "San Francisco", + "id": 26240, + "name": "African American Historical and Cultural Society" + }, + { + "address": null, + "city": "San Francisco", + "id": 26241, + "name": "Japantown" + }, + { + "address": "1881 Post Street", + "city": "San Francisco", + "id": 26242, + "name": "Sundance Kabuki 8 Theater" + }, + { + "address": "on Webster Street over Geary Boulevard", + "city": "San Francisco", + "id": 26243, + "name": "Webster Bridge" + }, + { + "address": "428 South Mission Drive", + "city": "San Gabriel", + "id": 26266, + "name": "San Gabriel Mission" + }, + { + "address": "Naglee Ave between Dana Ave and Garden Dr", + "city": "San Jose", + "id": 26279, + "name": "San Jose Municipal Rose Garden" + }, + { + "address": "26801 Ortega Hwy", + "city": "San Juan Capistrano", + "id": 26280, + "name": "Mission San Juan Capistrano" + }, + { + "address": "31831 Los Rios St.", + "city": "San Juan Capistrano", + "id": 26281, + "name": "O'Neill Museum" + }, + { + "address": "728 Monterey St", + "city": "San Luis Obispo", + "id": 26283, + "name": "Mission San Luis Obispo de Tolosa" + }, + { + "address": "1140 West Mission Rd.", + "city": "San Marcos", + "id": 26285, + "name": "Boehm Gallery @ Palomar College" + }, + { + "address": "1151 Oxford Road", + "city": "San Marino", + "id": 26287, + "name": "Huntington Library, Art Collection, and Botanical Gardens" + }, + { + "address": "775 Mission St.", + "city": "San Miguel", + "id": 26288, + "name": "Mission San Miguel" + }, + { + "address": "700 S. Mission Street", + "city": "San Miguel", + "id": 26289, + "name": "Rios-Caledonia Adobe" + }, + { + "address": "1104 Fifth Avenue", + "city": "San Rafael", + "id": 26343, + "name": "Mission San Rafael Arcangel" + }, + { + "address": "1100 Anacapa St", + "city": "Santa Barbara", + "id": 26367, + "name": "Santa Barbara County Courthouse" + }, + { + "address": "2201 Laguna St", + "city": "Santa Barbara", + "id": 26368, + "name": "Santa Barbara Mission" + }, + { + "address": "2559 Puesta Del Sol", + "city": "Santa Barbara", + "id": 26369, + "name": "Santa Barbara Museum of Natural History" + }, + { + "address": "1130 State Street", + "city": "Santa Barbara", + "id": 26370, + "name": "Santa Barbara Museum of Art" + }, + { + "address": "123 East Canon Perdido St", + "city": "Santa Barbara", + "id": 26371, + "name": "Presidio of Santa Barbara" + }, + { + "address": null, + "city": "Santa Barbara", + "id": 26372, + "name": "Stearns Wharf" + }, + { + "address": "21 West Anapamu St", + "city": "Santa Barbara", + "id": 26373, + "name": "Karpeles Museum" + }, + { + "address": "16 1/2 Helena Avenue", + "city": "Santa Barbara", + "id": 26374, + "name": "Santa Barbara Surfing Museum" + }, + { + "address": "500 El Camino Real", + "city": "Santa Clara", + "id": 26419, + "name": "Mission Santa Clara" + }, + { + "address": "126 High St", + "city": "Santa Cruz", + "id": 26420, + "name": "Mission Santa Cruz" + }, + { + "address": "2525 Michigan Ave", + "city": "Santa Monica", + "id": 26451, + "name": "Bergamot Station Arts Center" + }, + { + "address": "516 Colorado Ave", + "city": "Santa Monica", + "id": 26452, + "name": "Angels Attic Museum" + }, + { + "address": "3100 Airport Ave", + "city": "Santa Monica", + "id": 26453, + "name": "Museum of Flying" + }, + { + "address": "3223 Donald Douglas Loop South", + "city": "Santa Monica", + "id": 26454, + "name": "View Decks at Santa Monica Airport (KSMO)" + }, + { + "address": "Castle St", + "city": "Smiddy Closs", + "id": 26684, + "name": "Scalloway Museum" + }, + { + "address": "2150 Green Hill Rd", + "city": "Sebastopol", + "id": 26854, + "name": "Sturgeon's Steam Powered Saw Mill" + }, + { + "address": null, + "city": "Semur-en-Auxois", + "id": 26991, + "name": "Tour de l'Orle d'Or" + }, + { + "address": "21140 Rue de l'Hopital", + "city": "Semur-en-Auxois", + "id": 26992, + "name": "Hotel de Chassey" + }, + { + "address": "TN15 0RP", + "city": "Kent", + "id": 27000, + "name": "Knole House" + }, + { + "address": "Mapleton Road, Westerham, TN16 1PS", + "city": "Kent", + "id": 27001, + "name": "Chartwell" + }, + { + "address": "4595 Cochran Street", + "city": "Simi Valley", + "id": 27350, + "name": "Grandma Prisbrey's Bottle Village" + }, + { + "address": null, + "city": "Argyll and Bute", + "id": 27580, + "name": "Skipness Castle and Chapel" + }, + { + "address": "Gwynedd LL41 3NB", + "city": "Gwynedd", + "id": 27625, + "name": "Llechwedd Slate Mines" + }, + { + "address": "36641 Fort Romie Road", + "city": "Soledad", + "id": 27686, + "name": "Mission Soledad" + }, + { + "address": "1760 Mission Dr", + "city": "Solvang", + "id": 27740, + "name": "Mission Santa Ines" + }, + { + "address": "114 East Spain Street", + "city": "Sonoma", + "id": 27764, + "name": "Mission San Francisco Solano" + }, + { + "address": "476 1st St E", + "city": "Sonoma", + "id": 27765, + "name": "Sebastiani Theatre" + }, + { + "address": "Arnold Field", + "city": "Sonoma", + "id": 27766, + "name": "Sonoma Stompers" + }, + { + "address": "551 Broadway", + "city": "Sonoma", + "id": 27767, + "name": "Sonoma Valley Museum of Art" + }, + { + "address": "Bridgefoot", + "city": "Belper", + "id": 2805, + "name": "Belper North Mill" + }, + { + "address": "58 French Street, SO14 2AT", + "city": "Southampton", + "id": 28076, + "name": "Medieval Merchants House" + }, + { + "address": "Calshot Road, Calshot, SO45 1BR", + "city": "Calshot", + "id": 28077, + "name": "Calshot Castle" + }, + { + "address": "[[Buckingham]], MK18 5EQ", + "city": "Buckinghamshire", + "id": 28138, + "name": "Stowe" + }, + { + "address": "Hadleigh (''nearest station: Leigh-on-Sea'')", + "city": "Essex", + "id": 28151, + "name": "Hadleigh Castle" + }, + { + "address": null, + "city": "Queensferry", + "id": 28161, + "name": "The Forth Bridge" + }, + { + "address": null, + "city": null, + "id": 28162, + "name": "The Forth Road Bridge" + }, + { + "address": null, + "city": "Queensferry", + "id": 28163, + "name": "The Queensferry Crossing" + }, + { + "address": null, + "city": "Queensferry", + "id": 28164, + "name": "St Mary's Episcopal Church" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 28173, + "name": "Our Lady of the Isles" + }, + { + "address": "Kildonan", + "city": "Na h-Eileanan an Iar", + "id": 28174, + "name": "Kildonan Museum" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2818, + "name": "Borve Castle" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 2819, + "name": "Linaclete School" + }, + { + "address": null, + "city": "Saint Albans", + "id": 28218, + "name": "Cathedral and Abbey Church of St Alban" + }, + { + "address": null, + "city": "Saint Albans", + "id": 28219, + "name": "Clock Tower" + }, + { + "address": "Hatfield Road", + "city": "Saint Albans", + "id": 28220, + "name": "Museum of St Albans" + }, + { + "address": null, + "city": "Saint Albans", + "id": 28221, + "name": "Verulamium Museum" + }, + { + "address": "North Street", + "city": "Saint Andrews", + "id": 28224, + "name": "St Salvator's Quad" + }, + { + "address": "South Street", + "city": "Saint Andrews", + "id": 28225, + "name": "St Mary's Quad" + }, + { + "address": "Canongate, St Andrews KY16 8RT", + "city": "Saint Andrews", + "id": 28226, + "name": "St Andrews Botanic Gardens" + }, + { + "address": "12-16 North Street", + "city": "Saint Andrews", + "id": 28227, + "name": "St Andrews Preservation Trust Museum and Gardens" + }, + { + "address": "Bruce Embankment", + "city": "Saint Andrews", + "id": 28228, + "name": "British Golf Museum" + }, + { + "address": "The Scores", + "city": "Saint Andrews", + "id": 28229, + "name": "Aquarium" + }, + { + "address": "Kinburn Park, Doubledykes Road", + "city": "Kinburn", + "id": 28230, + "name": "St Andrews Museum" + }, + { + "address": "Near the Cathedral", + "city": "Saint Andrews", + "id": 28231, + "name": "St Andrews Castle" + }, + { + "address": "North Street", + "city": "Saint Andrews", + "id": 28232, + "name": "St Andrews Cathedral and St Rule's Tower" + }, + { + "address": null, + "city": "Fife", + "id": 28233, + "name": "West Sands (beach)" + }, + { + "address": null, + "city": "Saint Andrews", + "id": 28234, + "name": "East Sands (beach)" + }, + { + "address": null, + "city": "Saint Andrews", + "id": 28235, + "name": "Castle Sands (beach)" + }, + { + "address": "Intersection of 1st St. and G St", + "city": "Benicia", + "id": 2827, + "name": "Benicia Capitol State Historic Park" + }, + { + "address": "Ayot St Lawrence, near Welwyn, AL6 9BX", + "city": "Hertfordshire", + "id": 28286, + "name": "Shaw's Corner" + }, + { + "address": null, + "city": "Stirling", + "id": 28298, + "name": "Stirling Castle" + }, + { + "address": "Abbey Craig (1 mile North East of Stirling in Bridge of Allan)", + "city": "Stirling", + "id": 28299, + "name": "Wallace Monument" + }, + { + "address": null, + "city": "Stirling", + "id": 28300, + "name": "Cambuskenneth Abbey" + }, + { + "address": null, + "city": "Stirling", + "id": 28301, + "name": "Church of the Holy Rude" + }, + { + "address": "Glasgow Road, Stirling", + "city": "Whins of Milton", + "id": 28302, + "name": "Bannockburn" + }, + { + "address": "Castle Wynd", + "city": "Stirling", + "id": 28303, + "name": "Argyll's Lodging" + }, + { + "address": "St John Street", + "city": "Stirling", + "id": 28304, + "name": "Stirling Old Town Jail" + }, + { + "address": "Dumbarton Road, FK8 2RQ", + "city": "Stirling", + "id": 28305, + "name": "Smith Art Gallery and Museum" + }, + { + "address": "Disley, SK12 2NR", + "city": "Cheshire East", + "id": 28622, + "name": "Lyme Park" + }, + { + "address": "31 Market Place, SK1 1ES", + "city": "Stockport", + "id": 28623, + "name": "Staircase House" + }, + { + "address": "Turncroft Lane, Offerton, SK1 4AR", + "city": "Stockport", + "id": 28624, + "name": "Vernon Park and Museum" + }, + { + "address": "Edward Street, SK1 3XE", + "city": "Stockport", + "id": 28625, + "name": "Stockport Town Hall" + }, + { + "address": null, + "city": "Stockport", + "id": 28626, + "name": "Stockport Viaduct" + }, + { + "address": "61 Chestergate, SK1 1NE", + "city": "Stockport", + "id": 28627, + "name": "Air raid shelters" + }, + { + "address": null, + "city": "Aberdeenshire", + "id": 28639, + "name": "Dunnottar Castle" + }, + { + "address": null, + "city": "Stornoway", + "id": 28652, + "name": "An Lanntair Art Centre" + }, + { + "address": null, + "city": "Stornoway", + "id": 28653, + "name": "Lews Castle" + }, + { + "address": null, + "city": "Saint-Raphaël", + "id": 28675, + "name": "Dramont beach" + }, + { + "address": "The Square, Strathpeffer IV14 9DL", + "city": "Strathpeffer", + "id": 28678, + "name": "Spa Pavillion" + }, + { + "address": null, + "city": "Strathpeffer", + "id": 28679, + "name": "Pump Room" + }, + { + "address": null, + "city": "Strathpeffer", + "id": 28680, + "name": "Highland Museum of Childhood" + }, + { + "address": null, + "city": "Highland", + "id": 28681, + "name": "Castle Leod" + }, + { + "address": "Burdon Road, SR1 1PP", + "city": "Sunderland", + "id": 28869, + "name": "Sunderland Museum & Winter Gardens" + }, + { + "address": null, + "city": "Sunderland", + "id": 28870, + "name": "National Glass Centre" + }, + { + "address": "North Bridge Street, SR5 1AP", + "city": "Sunderland", + "id": 28871, + "name": "Monkwearmouth Station Museum" + }, + { + "address": "Aberdulais, Neath, Neath Port Talbot, SA10 8EU", + "city": "Aberdulais", + "id": 28961, + "name": "Aberdulais Falls and Tin Works" + }, + { + "address": null, + "city": "Oxfordshire", + "id": 28964, + "name": "Whitehorse Hill" + }, + { + "address": "Fire Fly Ave, SN2 2EY", + "city": "Swindon", + "id": 28965, + "name": "Steam: The Great Western Railway Museum" + }, + { + "address": "6-7 Theatre Square, SN1 1QN", + "city": "Swindon", + "id": 28966, + "name": "Museum of Computing @ Swindon" + }, + { + "address": null, + "city": "Swindon", + "id": 28967, + "name": "Railway Village" + }, + { + "address": null, + "city": "Glen Morangie", + "id": 29225, + "name": "Glenmorangie Distillery" + }, + { + "address": "Lydford, EX20 4BH", + "city": "Lydford", + "id": 29712, + "name": "Lydford Gorge" + }, + { + "address": "Quay Hill, Tenby, SA70 7BX", + "city": "Tenby", + "id": 30013, + "name": "Tudor Merchant's House" + }, + { + "address": "Tenby", + "city": "Tenby", + "id": 30014, + "name": "North Beach" + }, + { + "address": "2001 Thousand Oaks Boulevard", + "city": "Thousand Oaks", + "id": 30118, + "name": "Gardens of the World" + }, + { + "address": "51 South Ventu Park Road", + "city": "Thousand Oaks", + "id": 30119, + "name": "Stagecoach Inn Museum" + }, + { + "address": "2100 East Thousand Oaks Boulevard", + "city": "Thousand Oaks", + "id": 30120, + "name": "Thousand Oaks Civic Arts Plaza" + }, + { + "address": null, + "city": "Tintern", + "id": 30175, + "name": "Tintern Abbey" + }, + { + "address": "Upper Square, Hynish, PA77 6UQ", + "city": "Argyll and Bute", + "id": 30244, + "name": "Skerryvore Lighthouse Museum" + }, + { + "address": null, + "city": "Argyll and Bute", + "id": 30245, + "name": "The Ringing Stone" + }, + { + "address": null, + "city": "Scarinish", + "id": 30246, + "name": "An Turas" + }, + { + "address": "office: 317 Mesquite Avenue, Needles 92363 (7:30-3:30 weekdays)", + "city": "Needles", + "id": 30581, + "name": "Havasu National Wildlife Refuge" + }, + { + "address": "Castle Street, TQ9 5NU", + "city": "Totnes", + "id": 30648, + "name": "Totnes Castle" + }, + { + "address": "Farleigh Hungerford village, nr Trowbridge, BA2 7RS", + "city": "Somerset", + "id": 31081, + "name": "Farleigh Hungerford Castle" + }, + { + "address": "Lamberhurst, Tunbridge Wells, TN3 8JN", + "city": "Lamberhurst", + "id": 31293, + "name": "Scotney Castle and Gardens" + }, + { + "address": "6760 National Park Dr., Twentynine Palms, CA", + "city": "Twentynine Palms", + "id": 31541, + "name": "Old Schoolhouse Museum" + }, + { + "address": null, + "city": null, + "id": 31571, + "name": "Castell-y-Bere" + }, + { + "address": "Sheffield Park, TN22 3QX", + "city": "East Sussex", + "id": 31614, + "name": "Sheffield Park Gardens" + }, + { + "address": "1595 Railroad Ave", + "city": "Vallejo", + "id": 31960, + "name": "Mare Island Shoreline Heritage Preserve" + }, + { + "address": null, + "city": "Vallejo", + "id": 31961, + "name": "Mare Island San Pablo Bay Trail" + }, + { + "address": null, + "city": "Los Angeles", + "id": 32151, + "name": "Canals" + }, + { + "address": null, + "city": "Los Angeles", + "id": 32152, + "name": "Abbot Kinney" + }, + { + "address": null, + "city": "Los Angeles", + "id": 32153, + "name": "Ocean Front Walk" + }, + { + "address": "211 E. Main St", + "city": "Ventura", + "id": 32178, + "name": "Mission San Buenaventura" + }, + { + "address": "100 E. Main St.", + "city": "Ventura", + "id": 32179, + "name": "Museum of Ventura County" + }, + { + "address": "432 N. Ventura Avenue", + "city": "Ventura", + "id": 32180, + "name": "Bell Arts Factory" + }, + { + "address": "777 N. Olive Street", + "city": "Ventura", + "id": 32181, + "name": "Ventura Hot Glass Studio" + }, + { + "address": "Olivas Adobe Historical Parkmore info 4200 Olivas Park Drive, Ventura, CA 93003", + "city": "Ventura", + "id": 32182, + "name": "Olivas Adobe" + }, + { + "address": "501 Poli Street #109, Ventura, CA 93001", + "city": "Ventura", + "id": 32183, + "name": "Ventura City Hall" + }, + { + "address": null, + "city": "Verdun", + "id": 32202, + "name": "Châtel Gate" + }, + { + "address": null, + "city": "Verdun", + "id": 32203, + "name": "Notre-Dame de Verdun" + }, + { + "address": "Doncaster Road, Nostell, near Wakefield, WF4 1QE", + "city": "Nostell", + "id": 32968, + "name": "Nostell Priory" + }, + { + "address": "Kingsdown Road, CT14 7LJ", + "city": "Walmer", + "id": 32973, + "name": "Walmer Castle and Gardens" + }, + { + "address": "near Mere, BA12 6QF", + "city": "Wiltshire", + "id": 32987, + "name": "Stourhead" + }, + { + "address": "The Avenue, Washington Village, Washington, Tyne & Wear, NE38 7LE", + "city": "Washington", + "id": 33068, + "name": "Washington Old Hall" + }, + { + "address": "Chester Road, Penshaw, County Durham, DH4 7NJ", + "city": "Houghton le Spring", + "id": 33069, + "name": "Penshaw Monument" + }, + { + "address": "Albany Way NE37 1BJ", + "city": "Washington", + "id": 33070, + "name": "Washington 'F' Pit mining museum" + }, + { + "address": "DH9 0RG", + "city": "County Durham", + "id": 33071, + "name": "Beamish Open Air Museum" + }, + { + "address": null, + "city": "Watford", + "id": 33131, + "name": "Warner Bros. Studio Tour" + }, + { + "address": null, + "city": "Watford", + "id": 33132, + "name": "Watford Football Club" + }, + { + "address": "Welshpool, SY21 8RF", + "city": "Welshpool", + "id": 33174, + "name": "Powis Castle and Garden" + }, + { + "address": "Winter Gardens Royal Parade, Weston-Super-Mare BS23 1AJ", + "city": "Weston-super-Mare", + "id": 33253, + "name": "Tourist Information Centre" + }, + { + "address": "Marine Parade", + "city": "Weston-super-Mare", + "id": 33254, + "name": "The Grand Pier" + }, + { + "address": "Beach Lawns, Weston-super-Mare, BS23 1AT", + "city": "Weston-super-Mare", + "id": 33255, + "name": "The Wheel of Weston" + }, + { + "address": "Burlington Street", + "city": "Weston-super-Mare", + "id": 33256, + "name": "North Somerset Museum" + }, + { + "address": "The Heliport, Locking Moor Road", + "city": "Weston-super-Mare", + "id": 33257, + "name": "Helicopter Museum" + }, + { + "address": "Brean", + "city": "Brean", + "id": 33258, + "name": "Brean Down" + }, + { + "address": null, + "city": "Weston-super-Mare", + "id": 33259, + "name": "Marine Lake" + }, + { + "address": "Marine Parade", + "city": "Weston-super-Mare", + "id": 33260, + "name": "Seaquarium" + }, + { + "address": "Knightstone Harbour", + "city": "Weston-super-Mare", + "id": 33261, + "name": "Boat Trips" + }, + { + "address": "13421 E. Camilla Street", + "city": "Whittier", + "id": 33318, + "name": "The Jonathan Bailey House" + }, + { + "address": "6003 Pioneer Blvd", + "city": "Whittier", + "id": 33319, + "name": "Pio Pico State Historic Park" + }, + { + "address": "6757 Greenleaf Avenue", + "city": "Whittier", + "id": 33320, + "name": "Rocky Cola Cafe" + }, + { + "address": "6755 Newlin Avenue", + "city": "Whittier", + "id": 33321, + "name": "Whittier Museum" + }, + { + "address": "12417 E. Philadelphia Street", + "city": "Whittier", + "id": 33322, + "name": "Whittier High School" + }, + { + "address": null, + "city": "Highland", + "id": 33344, + "name": "Castle of Old Wick" + }, + { + "address": null, + "city": "Highland", + "id": 33345, + "name": "Cairn o'Get" + }, + { + "address": "Ebenezer Place", + "city": "Wick", + "id": 33346, + "name": "World's Shortest Street" + }, + { + "address": "Styal, Wilmslow, SK9 4LA", + "city": "Cheshire East", + "id": 33421, + "name": "Quarry Bank Mill & Styal Estate" + }, + { + "address": "Bridge Street, SO23 0EJ", + "city": "Winchester", + "id": 33422, + "name": "Winchester City Mill" + }, + { + "address": null, + "city": "Winchester", + "id": 33423, + "name": "Wolvesey Castle" + }, + { + "address": "Windsor Road, near Old Windsor, SL4 2JL", + "city": "Englefield Green", + "id": 33428, + "name": "Runnymede" + }, + { + "address": "Coldwell Street, DE4 4FB", + "city": "Wirksworth", + "id": 33520, + "name": "Ecclesbourne Valley Railway" + }, + { + "address": "Porter Lane", + "city": "Wirksworth", + "id": 33521, + "name": "National Stone Centre" + }, + { + "address": null, + "city": "Derbyshire", + "id": 33522, + "name": "Derbyshire Eco Centre" + }, + { + "address": "Prenton Park, Prenton Rd West, Birkenhead, CH42 9PY", + "city": "Birkenhead", + "id": 33525, + "name": "Tranmere Rovers Football Club" + }, + { + "address": "Brimstage Wirral CH63 6JA", + "city": "Birkenhead", + "id": 33526, + "name": "Brimstage Hall Courtyard" + }, + { + "address": "Station Road, Thurstaston, Merseyside TH61 0HN", + "city": "Thurstaston", + "id": 33527, + "name": "Wirral Country Park" + }, + { + "address": "Park Drive, Birkenhead, CH41 4HY", + "city": "Birkenhead", + "id": 33528, + "name": "Birkenhead Park" + }, + { + "address": "4 Priory Street, Birkenhead, Merseyside, CH41 5JH", + "city": "Birkenhead", + "id": 33529, + "name": "Birkenhead Priory" + }, + { + "address": "Wightwick Bank, WV6 8EE", + "city": "Wolverhampton", + "id": 33551, + "name": "Wightwick Manor and Gardens" + }, + { + "address": "Woodstock, Oxfordshire OX20 1PP", + "city": "Blenheim Palace Grounds", + "id": 33559, + "name": "Blenheim Palace" + }, + { + "address": "Friar Street, Worcester, WR1 2LZ", + "city": "Worcester", + "id": 33561, + "name": "Greyfriars' House and Garden" + }, + { + "address": "Worcester Road, Great Witley, Worcestershire, WR6 6JT", + "city": "Great Witley", + "id": 33562, + "name": "Witley Court and Gardens" + }, + { + "address": "Erddig, near Wrexham, LL13 0YT", + "city": "Marchwiel", + "id": 33571, + "name": "Erddig Hall" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 3362, + "name": "Giant MacAskill Monument" + }, + { + "address": "West High Down, Alum Bay, Isle of Wight, PO39 0JH", + "city": "West High Down", + "id": 33666, + "name": "The Needles Old Battery and New Battery" + }, + { + "address": "Parade, TD15 1DF", + "city": "Berwick-upon-Tweed", + "id": 3370, + "name": "Berwick Barracks and Main Guard" + }, + { + "address": "Beverly Drive and Santa Monica Blvd", + "city": "Beverly Hills", + "id": 3379, + "name": "Fig Tree" + }, + { + "address": null, + "city": "Beverly Hills", + "id": 3380, + "name": "Rodeo Drive" + }, + { + "address": null, + "city": "Minster Yd", + "id": 33856, + "name": "York Minster" + }, + { + "address": "Leeman Road, YO26 4XJ", + "city": "York", + "id": 33857, + "name": "National Railway Museum" + }, + { + "address": "Tower Street, YO1 9SA", + "city": "York", + "id": 33858, + "name": "Clifford's Tower" + }, + { + "address": null, + "city": "York", + "id": 33859, + "name": "York Maze" + }, + { + "address": "Minster Yard, YO1 7JL", + "city": "York", + "id": 33860, + "name": "Treasurer's House" + }, + { + "address": "Aldborough, Boroughbridge, YO51 9ES", + "city": "North Yorkshire", + "id": 33862, + "name": "Aldborough Roman Villa" + }, + { + "address": "Pier 15, 698 The Embarcadero", + "city": "San Francisco", + "id": 34196, + "name": "Exploratorium" + }, + { + "address": "Egerton Road, Bexhill On Sea, East Sussex TN39 3HL", + "city": "Bexhill", + "id": 3429, + "name": "Bexhill Museum" + }, + { + "address": "East (Andrews) Park, Southampton", + "city": "Southampton", + "id": 34552, + "name": "Titanic Engineers' Memorial" + }, + { + "address": "9300 Cherry Ave, Fontana", + "city": "Fontana", + "id": 34759, + "name": "Auto Club Speedway" + }, + { + "address": "Abandoibarra etorbidea, 2", + "city": "Saint-Marcel-sur-Aude", + "id": 3484, + "name": "Guggenheim Museum" + }, + { + "address": "Pier 15, 698 The Embarcadero", + "city": "San Francisco", + "id": 34870, + "name": "Exploratorium" + }, + { + "address": "Pier 15, 698 The Embarcadero", + "city": "San Francisco", + "id": 34871, + "name": "Exploratorium" + }, + { + "address": "Market Hill, MK18 1JX", + "city": "Buckingham", + "id": 34873, + "name": "Buckingham Old Gaol" + }, + { + "address": "Market Hill, MK18 1JX", + "city": "Buckingham", + "id": 34874, + "name": "Chantry Chapel" + }, + { + "address": "New Inn Farm, Stowe, MK18 5EQ", + "city": "Buckinghamshire", + "id": 34875, + "name": "Stowe Landscaped Gardens" + }, + { + "address": "Castle Hill, MK18 1BS", + "city": "Buckingham", + "id": 34876, + "name": "St Peter and St Paul Parish Church" + }, + { + "address": "Torr Top Street/Union St/Station Rd", + "city": "New Mills", + "id": 34913, + "name": "Torrs Riverside Park" + }, + { + "address": "Rock Lane, New Mills SK22 3BN", + "city": "New Mills", + "id": 34914, + "name": "New Mills Heritage & Information Centre" + }, + { + "address": "117 Dye House Lane", + "city": "New Mills", + "id": 34915, + "name": "The Drunkard's Reform" + }, + { + "address": "High Street SK22 4BR", + "city": "New Mills", + "id": 34916, + "name": "Masons Arms plaque" + }, + { + "address": null, + "city": "Ceredigion", + "id": 34953, + "name": "Devils Bridge Waterfall" + }, + { + "address": null, + "city": "Ceredigion", + "id": 34954, + "name": "Hafod Estate" + }, + { + "address": "Brabyn's Brow", + "city": "Marple Bridge", + "id": 34960, + "name": "Brabyn's Park" + }, + { + "address": null, + "city": "Romiley", + "id": 34961, + "name": "Marple Aqueduct (Peak Forest Canal)" + }, + { + "address": null, + "city": "Ospringe", + "id": 34966, + "name": "National Fruit Collection at Brogdale Farm" + }, + { + "address": null, + "city": "Ospringe", + "id": 34967, + "name": "Mad Cat Brewery" + }, + { + "address": "Preston Street, ME13 8NS", + "city": "Kent", + "id": 34968, + "name": "Maison Dieu" + }, + { + "address": "Trinity Rd, Aston", + "city": "Birmingham", + "id": 3497, + "name": "Aston Hall" + }, + { + "address": "University of Birmingham, Edgbaston B15 2TS", + "city": "Birmingham", + "id": 3498, + "name": "Barber Institute of Fine Arts" + }, + { + "address": null, + "city": "Methlick", + "id": 34980, + "name": "Haddo House" + }, + { + "address": null, + "city": "Aberdeenshire", + "id": 34981, + "name": "Gight Castle" + }, + { + "address": "BT54 6BT", + "city": "Moyle", + "id": 34982, + "name": "RSPB Seabird Centre" + }, + { + "address": null, + "city": "Moyle", + "id": 34983, + "name": "St Thomas Church of Ireland" + }, + { + "address": "Chamberlain Square B3 3DH", + "city": "Birmingham", + "id": 3499, + "name": "Birmingham Museum & Art Gallery" + }, + { + "address": "Blickling, NR11 6NF", + "city": "Blickling", + "id": 34996, + "name": "Blickling Estate" + }, + { + "address": null, + "city": "Aberdour", + "id": 35, + "name": "Aberdour Castle" + }, + { + "address": "1 Oozells Square, Brindleyplace B1 2HS", + "city": "Birmingham", + "id": 3500, + "name": "IKON Gallery" + }, + { + "address": "Cole Bank Rd, Hall Green B13 OBD", + "city": "Birmingham", + "id": 3501, + "name": "Sarehole Mill" + }, + { + "address": "4, Brook Street", + "city": "Birmingham", + "id": 3502, + "name": "Royal Birmingham Society of Artists" + }, + { + "address": "Bossiney Road, PL34 0HE", + "city": "Tintagel", + "id": 35025, + "name": "Tintagel Castle" + }, + { + "address": "4800 Hollywood Blvd", + "city": "Los Angeles", + "id": 35026, + "name": "Barnsdall Art Park" + }, + { + "address": null, + "city": "Los Angeles", + "id": 35027, + "name": "Echo Park" + }, + { + "address": null, + "city": "Los Angeles", + "id": 35028, + "name": "Griffith Park" + }, + { + "address": "2800 E Observatory Ave", + "city": "Los Angeles", + "id": 35029, + "name": "Griffith Park Observatory" + }, + { + "address": "Soho Ave, Handsworth, B18 5LB", + "city": "Birmingham", + "id": 3503, + "name": "Soho House" + }, + { + "address": "4700 Western Heritage Way", + "city": "Los Angeles", + "id": 35030, + "name": "The Autry in Griffith Park" + }, + { + "address": null, + "city": "Los Angeles", + "id": 35031, + "name": "MacArthur Park" + }, + { + "address": null, + "city": "Los Angeles", + "id": 35032, + "name": "Angelino Heights" + }, + { + "address": "Millennium Point, Curzon St", + "city": null, + "id": 3504, + "name": "Thinktank" + }, + { + "address": "75-79 Vyse Street, Hockley, Birmingham, B18 6HA", + "city": "Birmingham", + "id": 3505, + "name": "Museum of the Jewellery Quarter" + }, + { + "address": "Chester Road, Castle Vale", + "city": "Birmingham", + "id": 3506, + "name": "Jaguar Castle Bromwich Assembly" + }, + { + "address": null, + "city": "Rednal", + "id": 3507, + "name": "MG Birmingham" + }, + { + "address": "Sharpitor, TQ8 8LW", + "city": "Devon", + "id": 35076, + "name": "Overbeck's" + }, + { + "address": "Bodiam, near Robertsbridge, TN32 5UA", + "city": "Bodiam", + "id": 35079, + "name": "Bodiam Castle" + }, + { + "address": "Linden Rd, Bournville B30 2LU", + "city": "Birmingham", + "id": 3508, + "name": "Cadbury World" + }, + { + "address": "Colmore Row", + "city": "Birmingham", + "id": 3509, + "name": "Birmingham Cathedral" + }, + { + "address": "Osler St, Ladywood", + "city": "Birmingham", + "id": 3510, + "name": "Birmingham Peace Pagoda" + }, + { + "address": "St Chad's Queensway", + "city": "Birmingham", + "id": 3511, + "name": "St Chad's Cathedral" + }, + { + "address": "Bull Ring", + "city": "Birmingham", + "id": 3512, + "name": "St Martin in the Bull Ring" + }, + { + "address": "Lionel St", + "city": "Birmingham", + "id": 3513, + "name": "BT Tower" + }, + { + "address": "Cambridge St / Centenary Square", + "city": "Birmingham", + "id": 3514, + "name": "Library of Birmingham" + }, + { + "address": "17 & 19 Newhall Street", + "city": "Birmingham", + "id": 3515, + "name": "Bell Edison Telephone Building" + }, + { + "address": null, + "city": "Birmingham", + "id": 3516, + "name": "Birmingham Back to Backs" + }, + { + "address": "188 High St, Deritend", + "city": "Birmingham", + "id": 3517, + "name": "The Old Crown" + }, + { + "address": null, + "city": "Birmingham", + "id": 3518, + "name": "Curzon Street station" + }, + { + "address": null, + "city": "Birmingham", + "id": 3519, + "name": "Rotunda" + }, + { + "address": "Margaret Street", + "city": "Birmingham", + "id": 3520, + "name": "Birmingham School of Art" + }, + { + "address": "Corporation Street", + "city": "Birmingham", + "id": 3521, + "name": "Victoria Law Courts" + }, + { + "address": "196-224 Corporation Street", + "city": "Birmingham", + "id": 3522, + "name": "Methodist Central Hall" + }, + { + "address": "122-124 Colmore Row", + "city": "Birmingham", + "id": 3523, + "name": "Hudson's Coffee House" + }, + { + "address": "1-7 Constitution Hill", + "city": "Birmingham", + "id": 3524, + "name": "Red Palace" + }, + { + "address": "Westbourne Rd, Edgbaston", + "city": "Birmingham", + "id": 3525, + "name": "Birmingham Botanical Gardens & Glasshouses" + }, + { + "address": "Pershore Rd, B5 7RL", + "city": "Birmingham", + "id": 3526, + "name": "Birmingham Nature Centre" + }, + { + "address": "Pershore Rd", + "city": "Birmingham", + "id": 3527, + "name": "Cannon Hill Park" + }, + { + "address": null, + "city": "Birmingham", + "id": 3528, + "name": "Moseley Bog & Joy's Wood Nature Reserve" + }, + { + "address": "Brindleyplace", + "city": "Birmingham", + "id": 3529, + "name": "National Sea Life Centre" + }, + { + "address": "20 Tanhouse Ave, Great Barr, B43 5AG", + "city": "West Bromwich", + "id": 3530, + "name": "RSPB Sandwell Valley" + }, + { + "address": "Sutton Coldfield", + "city": "Sutton Coldfield", + "id": 3531, + "name": "Sutton Park" + }, + { + "address": "Bartley Green", + "city": "Birmingham", + "id": 3532, + "name": "Woodgate Valley Country Park" + }, + { + "address": "55-63 Hurst Street/50-54 Inge Street, Birmingham, West Midlands, B5 4TE", + "city": "Birmingham", + "id": 3533, + "name": "Birmingham Back to Backs" + }, + { + "address": "Woodhead", + "city": "Derbyshire", + "id": 35665, + "name": "St James Chapel" + }, + { + "address": null, + "city": "Derbyshire", + "id": 35666, + "name": "Woodhead Tunnels" + }, + { + "address": "Ty Croes", + "city": "Isle of Anglesey", + "id": 35697, + "name": "Barclodiad y Gawres" + }, + { + "address": "2 Avenue César Geoffray", + "city": "Vaison-la-Romaine", + "id": 35845, + "name": "Roman bridge" + }, + { + "address": "18 Avenue Général de Gaulle", + "city": "Vaison-la-Romaine", + "id": 35846, + "name": "Archaeological site Villasse" + }, + { + "address": "78 Avenue Jules Ferry", + "city": "Vaison-la-Romaine", + "id": 35847, + "name": "Cathédrale Notre-Dame-de-Nazareth" + }, + { + "address": "1 Chemin de Barbanot", + "city": "Vaison-la-Romaine", + "id": 35848, + "name": "Castle of the Counts of Toulouse" + }, + { + "address": "Avenue de Saint-Quenin", + "city": "Vaison-la-Romaine", + "id": 35849, + "name": "Saint Quenin chapel" + }, + { + "address": "Petite Rue", + "city": "Vaison-la-Romaine", + "id": 35850, + "name": "Old clock tower" + }, + { + "address": null, + "city": "Aberdour", + "id": 36, + "name": "The Silver Sands Beach" + }, + { + "address": null, + "city": "San Francisco", + "id": 36047, + "name": "Cable Car Museum" + }, + { + "address": "100 Pointhouse Place, [[Glasgow]], [[Scotland]] UK", + "city": "Glasgow", + "id": 36048, + "name": "Glasgow Riverside Museum" + }, + { + "address": null, + "city": "London", + "id": 36050, + "name": "London Transport Museum" + }, + { + "address": "15151 San Fernando Mission Blvd", + "city": "Los Angeles", + "id": 36141, + "name": "Mission San Fernando Rey de España" + }, + { + "address": "Hendon Mill, Hallam Rd, BB9 8AD", + "city": "Nelson", + "id": 36150, + "name": "British in India Museum" + }, + { + "address": "Harle Syke, Burnley, BB10 2HX", + "city": "Briercliffe", + "id": 36151, + "name": "Queen Street Mill Textile Museum" + }, + { + "address": null, + "city": "Motherwell", + "id": 36511, + "name": "Strathclyde Country Park" + }, + { + "address": "31 Coursington Rd, Motherwell ML1 1PP", + "city": "Motherwell", + "id": 36512, + "name": "Motherwell Cathedral" + }, + { + "address": "Motherwell Heritage Centre High Road Motherwell ML1 3HU", + "city": "Motherwell", + "id": 36513, + "name": "North Lanarkshire Heritage Centre" + }, + { + "address": "Civic Centre Motherwell ML1 1AB", + "city": "Motherwell", + "id": 36514, + "name": "Motherwell Civic Centre and Concert Hall" + }, + { + "address": "50 Netherton Street, Wishaw ML2 0DP", + "city": "Wishaw", + "id": 36520, + "name": "Wishaw General Hospital" + }, + { + "address": "Church Stret, Chesham, Buckinghamshire", + "city": "Chesham", + "id": 36722, + "name": "St Mary's Church" + }, + { + "address": "Waters Road, Marsden, Huddersfield, HD7 6NQ", + "city": "West Yorkshire", + "id": 36748, + "name": "Standedge Tunnel & Visitor Centre" + }, + { + "address": "rue du Quesnoy", + "city": "Saint-Waast-la-Vallée", + "id": 36858, + "name": "Carrière des Nerviens Regional Nature Reserve" + }, + { + "address": null, + "city": "Aberdour", + "id": 37, + "name": "Aberdour Railway Station" + }, + { + "address": "1180 N. Main Street", + "city": "Bishop", + "id": 3707, + "name": "Bishop Mural Society" + }, + { + "address": "PA78 6TB", + "city": "Argyll and Bute", + "id": 37074, + "name": "RSPB Bird Reserve" + }, + { + "address": null, + "city": "Argyll and Bute", + "id": 37075, + "name": "Breachacha Castle" + }, + { + "address": "4.5 mi (7.2 km) north of Bishop, off U.S. Hwy 6", + "city": "Bishop", + "id": 3708, + "name": "Laws Railroad Museum and Historic Site" + }, + { + "address": "Ludgate Hill", + "city": "London", + "id": 37123, + "name": "St Paul's Cathedral" + }, + { + "address": "38 City Rd, EC1Y 1AU", + "city": "London", + "id": 37124, + "name": "Bunhill Fields Burial Ground" + }, + { + "address": "West Smithfield, EC1A 9DS", + "city": "London", + "id": 37125, + "name": "St Bartholomew-the-Great" + }, + { + "address": "Aldersgate St, EC1A 4EU", + "city": "London", + "id": 37126, + "name": "St Botolph's Aldersgate" + }, + { + "address": "Fore St, Cripplegate, EC2Y 8DA", + "city": "London", + "id": 37127, + "name": "St Giles-without-Cripplegate" + }, + { + "address": "49 City Rd, EC1Y 1AU", + "city": "London", + "id": 37128, + "name": "Wesley's Chapel and Leysian Mission" + }, + { + "address": "Holborn Viaduct, London", + "city": "London", + "id": 37129, + "name": "St Sepulchre-without-Newgate" + }, + { + "address": "Threadneedle St", + "city": "London", + "id": 37130, + "name": "Bank of England Museum" + }, + { + "address": "3F, Robin Brook Centre, EC1A 7BE", + "city": "London", + "id": 37131, + "name": "Barts Pathology Museum" + }, + { + "address": "Guildhall Library, Aldermanbury EC2P 2EJ", + "city": "London", + "id": 37132, + "name": "Clockmaker's Museum" + }, + { + "address": "Guildhall Yard (off Gresham St)", + "city": "Guildhall Yd", + "id": 37133, + "name": "Guildhall Art Gallery and Roman Amphitheatre" + }, + { + "address": "London Wall (NB: this is a street!)", + "city": "London", + "id": 37134, + "name": "Museum of London" + }, + { + "address": "St John’s Gate, St John’s Lane, EC1M 4DA", + "city": "London", + "id": 37135, + "name": "Museum of the Order of St John" + }, + { + "address": "Fore St", + "city": "London", + "id": 37136, + "name": "Blitz Plaque" + }, + { + "address": "Paternoster Sq", + "city": "London", + "id": 37137, + "name": "London Stock Exchange" + }, + { + "address": null, + "city": "London", + "id": 37138, + "name": "London Wall" + }, + { + "address": null, + "city": "London", + "id": 37139, + "name": "Old Bailey" + }, + { + "address": "ExCeL, Docklands, E16 1XL", + "city": "London", + "id": 37175, + "name": "72nd World Science Fiction Convention" + }, + { + "address": null, + "city": "Downpatrick", + "id": 37279, + "name": "Down Cathedral" + }, + { + "address": "The Mall, English Street", + "city": "Downpatrick", + "id": 37280, + "name": "Down County Museum" + }, + { + "address": null, + "city": "Downpatrick", + "id": 37281, + "name": "St Patrick's Centre" + }, + { + "address": "Inch Abbey Road", + "city": "County Down", + "id": 37282, + "name": "Inch Abbey" + }, + { + "address": null, + "city": "County Down", + "id": 37283, + "name": "Ballynoe Stone Circle" + }, + { + "address": "off the Struell Wells Road", + "city": "County Down", + "id": 37284, + "name": "Struell Wells" + }, + { + "address": null, + "city": "Lymm", + "id": 37303, + "name": "Lymm Dam" + }, + { + "address": null, + "city": "Lymm", + "id": 37304, + "name": "Lymm Cross" + }, + { + "address": null, + "city": "Warrington", + "id": 37305, + "name": "Thelwall Viaduct" + }, + { + "address": "Ferry Lane, Thelwall", + "city": "Warrington", + "id": 37306, + "name": "Manchester Ship Canal" + }, + { + "address": null, + "city": "North Warnborough", + "id": 37441, + "name": "Odiham Castle" + }, + { + "address": null, + "city": "Odiham", + "id": 37442, + "name": "All Saints Church" + }, + { + "address": "Avenue du château de Malmaison", + "city": "Rueil-Malmaison", + "id": 37444, + "name": "Château de Malmaison" + }, + { + "address": "10818 San Diego Mission Rd, San Diego, CA", + "city": "San Diego", + "id": 37504, + "name": "Mission San Diego de Alcala" + }, + { + "address": "4050 Mission Avenue, Oceanside, CA", + "city": "Oceanside", + "id": 37505, + "name": "Mission San Luis Rey de Francia" + }, + { + "address": "26801 Ortega Hwy, San Juan Capistrano, CA", + "city": "San Juan Capistrano", + "id": 37506, + "name": "Mission San Juan Capistrano" + }, + { + "address": "428 South Mission Drive, San Gabriel, CA", + "city": "San Gabriel", + "id": 37507, + "name": "Mission San Gabriel Arcangel" + }, + { + "address": "15151 San Fernando Mission Blvd, Mission Hills, CA", + "city": "Los Angeles", + "id": 37508, + "name": "Mission San Fernando Rey de España" + }, + { + "address": "211 E. Main St, Ventura, CA", + "city": "Ventura", + "id": 37509, + "name": "Mission San Buenaventura" + }, + { + "address": "2201 Laguna St, Santa Barbara, CA", + "city": "Santa Barbara", + "id": 37510, + "name": "Mission Santa Barbara" + }, + { + "address": "1760 Mission Dr, Solvang, CA", + "city": "Solvang", + "id": 37511, + "name": "Mission Santa Ines" + }, + { + "address": "2295 Purisima Rd, Lompoc, CA", + "city": "Lompoc", + "id": 37512, + "name": "Mission La Purisima Concepcion de Maria Santisima" + }, + { + "address": "728 Monterey St., San Luis Obispo, CA", + "city": "San Luis Obispo", + "id": 37513, + "name": "Mission San Luis Obispo de Tolosa" + }, + { + "address": "775 Mission St., San Miguel, CA", + "city": "San Miguel", + "id": 37514, + "name": "Mission San Miguel" + }, + { + "address": "P.O. Box 803 (End of Mission Road) Jolon, CA 93928", + "city": "Jolon", + "id": 37515, + "name": "Mission San Antonio de Padua" + }, + { + "address": "36641 Fort Romie Road, Soledad, CA", + "city": "Soledad", + "id": 37516, + "name": "Mission Nuestra Senora de la Soledad" + }, + { + "address": "3080 Rio Road, Carmel, CA", + "city": "Carmel-by-the-Sea", + "id": 37517, + "name": "Mission San Carlos Borromeo de Carmelo" + }, + { + "address": "126 High St, Santa Cruz, CA", + "city": "Santa Cruz", + "id": 37518, + "name": "Mission Santa Cruz" + }, + { + "address": "406 2nd Street, San Juan Bautista, CA", + "city": "Watsonville", + "id": 37519, + "name": "Mission San Juan Bautista" + }, + { + "address": "500 El Camino Real, Santa Clara, CA", + "city": "Santa Clara", + "id": 37520, + "name": "Mission Santa Clara" + }, + { + "address": "43300 Mission Blvd, Fremont, CA", + "city": "Fremont", + "id": 37521, + "name": "Mission San Jose" + }, + { + "address": "3321 16th St, San Francisco, CA", + "city": "San Francisco", + "id": 37522, + "name": "Mission Dolores" + }, + { + "address": "1104 Fifth Ave, San Rafael", + "city": "San Rafael", + "id": 37523, + "name": "Mission San Rafael Arcangel" + }, + { + "address": "114 East Spain Street", + "city": "Sonoma", + "id": 37524, + "name": "Mission San Francisco Solano" + }, + { + "address": "26876 Mulholland Highway, Calabasas, CA, 91302", + "city": "Calabasas", + "id": 37579, + "name": "King Gillette Ranch" + }, + { + "address": "4121 Potrero Road Newbury Park, CA 91320", + "city": "Ventura County", + "id": 37580, + "name": "Satwiwa Cultural Center" + }, + { + "address": "1925 Las Virgenes Road, Calabasas, CA 91302", + "city": "Agoura Hills", + "id": 37581, + "name": "Malibu Creek State Park" + }, + { + "address": "2903 Cornell Road, Agoura Hills, CA, 91301", + "city": "Agoura Hills", + "id": 37582, + "name": "Paramount Ranch" + }, + { + "address": "406 2nd St", + "city": "Watsonville", + "id": 37602, + "name": "Mission San Juan Bautista" + }, + { + "address": "200 Washington St", + "city": "San Juan Bautista", + "id": 37603, + "name": "San Juan Bautista State Historic Park" + }, + { + "address": "11440 N. Topanga Canyon Blvd", + "city": "Topanga", + "id": 37643, + "name": "Topanga Days" + }, + { + "address": null, + "city": "Blythe", + "id": 3780, + "name": "Blythe Intaglios" + }, + { + "address": "9045 Lincoln Blvd", + "city": "Los Angeles", + "id": 37875, + "name": "Ben Maltz Gallery" + }, + { + "address": null, + "city": "Pembrokeshire", + "id": 37997, + "name": "The Blue Lagoon" + }, + { + "address": null, + "city": "Pembrokeshire", + "id": 37998, + "name": "Traeth Llyfn Beach" + }, + { + "address": null, + "city": "Aberdour", + "id": 38, + "name": "Old School Sensory Garden" + }, + { + "address": "Llandysul Library, Canolfan Ceredigion, Llandysul, SA44 4QS", + "city": "Llandysul", + "id": 38015, + "name": "Llandysul & District Local History Society Exhibition" + }, + { + "address": "Chapel Street, Pont Tyweli, Sir Gaerfyrddin / Carmarthenshire, SA44 4AH", + "city": "Pontwelly", + "id": 38016, + "name": "Pwerdy-Powerhouse Community and Arts Centre" + }, + { + "address": null, + "city": "Moss Beach", + "id": 38034, + "name": "Fitzgerald Marine Reserve" + }, + { + "address": null, + "city": "South Lanarkshire", + "id": 38429, + "name": "Cameronian Monument" + }, + { + "address": null, + "city": "South Lanarkshire", + "id": 38430, + "name": "Douglas Castle" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 38436, + "name": "Bostadh Iron Age House" + }, + { + "address": null, + "city": null, + "id": 38437, + "name": "Callanish VIII (Cleitir)" + }, + { + "address": null, + "city": null, + "id": 38438, + "name": "Bernera Bridge" + }, + { + "address": null, + "city": "Na h-Eileanan an Iar", + "id": 38439, + "name": "Norse Mill and lobster ponds" + }, + { + "address": null, + "city": "Pembrokeshire", + "id": 38524, + "name": "St Lawrence’s Church" + }, + { + "address": null, + "city": "Glasgow", + "id": 38951, + "name": "Commonwealth Sports Arena (Emirates Arena)" + }, + { + "address": null, + "city": "Glasgow", + "id": 38952, + "name": "Sir Chris Hoy Velodrome" + }, + { + "address": null, + "city": "Glasgow", + "id": 38953, + "name": "Glasgow Green Hockey Centre" + }, + { + "address": null, + "city": "Glasgow", + "id": 38954, + "name": "Tollcross International Swimming Centre" + }, + { + "address": null, + "city": "Glasgow", + "id": 38955, + "name": "Celtic Park" + }, + { + "address": null, + "city": "Glasgow", + "id": 38956, + "name": "Hampden Park" + }, + { + "address": null, + "city": "Glasgow", + "id": 38957, + "name": "Ibrox" + }, + { + "address": "Exhibition Way, Finnieston, Glasgow, G3 8YW", + "city": "Glasgow", + "id": 38958, + "name": "The Hydro" + }, + { + "address": "21 Dalkeith Rd, Edinburgh, EH16 5BB", + "city": "Edinburgh", + "id": 38959, + "name": "Royal Commonwealth Pool" + }, + { + "address": "Baring Street, NE33 2BB", + "city": "South Shields", + "id": 39128, + "name": "Arbeia Roman Fort" + }, + { + "address": "Ocean Road, NE33 2JA", + "city": "South Shields", + "id": 39129, + "name": "South Shields Museum and art Gallery" + }, + { + "address": "Coast Road, Whitburn, Sunderland, SR6 7NH", + "city": "Tyne and Wear", + "id": 39130, + "name": "Souter Lighthouse and The Leas" + }, + { + "address": null, + "city": "Penycwm", + "id": 39190, + "name": "Penycwm" + }, + { + "address": null, + "city": "Saint Marys Island", + "id": 39485, + "name": "St Mary's Island" + }, + { + "address": null, + "city": "Whitley Bay", + "id": 39486, + "name": "Beach and Promenade" + }, + { + "address": "Castle View, NE42 6NA", + "city": "Prudhoe", + "id": 39646, + "name": "Prudhoe Castle" + }, + { + "address": "Etnam Street, Leominster HR6 8AL", + "city": "Leominster", + "id": 39651, + "name": "Leominster Museum" + }, + { + "address": null, + "city": "Leominster", + "id": 39652, + "name": "Grange Court" + }, + { + "address": null, + "city": "Tadcaster", + "id": 39827, + "name": "St Mary's Church" + }, + { + "address": "Colton, LA12 8AX", + "city": "Cumbria", + "id": 3990, + "name": "Stott Park Bobbin Mill" + }, + { + "address": "1, place Jacques Faizant", + "city": "Saint-Claude", + "id": 39956, + "name": "Musée de la Pipe et du Diamant" + }, + { + "address": null, + "city": "Septmoncel", + "id": 39957, + "name": "Chapeau de Gendarme" + }, + { + "address": "Rhosmeirch", + "city": "Rhosmeirch", + "id": 39999, + "name": "Oriel Ynys Môn" + }, + { + "address": "Takeley, Bishop's Stortford, CM22 6NE", + "city": "Essex", + "id": 4000, + "name": "Hatfield Forest" + }, + { + "address": null, + "city": "Flint", + "id": 40009, + "name": "Flint castle" + }, + { + "address": null, + "city": "Flintshire", + "id": 40010, + "name": "Dee Estuary - Point of Ayr RSPB nature reserve" + }, + { + "address": null, + "city": "Flintshire", + "id": 40011, + "name": "Point of Ayr lighthouse" + }, + { + "address": "Colwyn Bay", + "city": "Colwyn Bay", + "id": 40014, + "name": "Victoria Pier" + }, + { + "address": null, + "city": null, + "id": 40016, + "name": "Llandudno Pier" + }, + { + "address": null, + "city": "Conwy", + "id": 40018, + "name": "Conwy bridges" + }, + { + "address": null, + "city": "Conwy", + "id": 40019, + "name": "Conwy castle" + }, + { + "address": "Bangor", + "city": null, + "id": 40020, + "name": "Garth Pier" + }, + { + "address": null, + "city": "Beaumaris", + "id": 40021, + "name": "Beaumaris Pier" + }, + { + "address": null, + "city": "Beaumaris", + "id": 40022, + "name": "Beaumaris Castle" + }, + { + "address": null, + "city": null, + "id": 40023, + "name": "Trwyn Du Lighthouse" + }, + { + "address": null, + "city": "Red Wharf Bay", + "id": 40025, + "name": "Red Wharf Bay" + }, + { + "address": null, + "city": "Amlwch", + "id": 40027, + "name": "Amlwch lighthouse" + }, + { + "address": null, + "city": "Holyhead", + "id": 40029, + "name": "Holyhead Mail Pier Light" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 40030, + "name": "South Stack Lighthouse" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 40031, + "name": "South Stack Cliffs RSPB reserve" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 40033, + "name": "Holyhead Mountain Hut Circles" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 40036, + "name": "Valley Wetlands RSPB reserve" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 40037, + "name": "Barclodiad y Gawres" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 40038, + "name": "Llanddwyn Island Lighthouse" + }, + { + "address": null, + "city": null, + "id": 40040, + "name": "Britannia Bridge" + }, + { + "address": null, + "city": "Bangor", + "id": 40041, + "name": "Menai Suspension Bridge" + }, + { + "address": null, + "city": "Ty'n Y Cei", + "id": 40042, + "name": "Caernarfon Castle" + }, + { + "address": null, + "city": "Criccieth", + "id": 40046, + "name": "Criccieth Castle" + }, + { + "address": null, + "city": "Harlech", + "id": 40047, + "name": "Harlech Castle" + }, + { + "address": null, + "city": "Gwynedd", + "id": 40049, + "name": "Barmouth Bridge" + }, + { + "address": null, + "city": "Powys", + "id": 40051, + "name": "Cors Dyfi nature reserve" + }, + { + "address": null, + "city": "Ceredigion", + "id": 40052, + "name": "Ynys-hir RSPB reserve" + }, + { + "address": null, + "city": "Furnace", + "id": 40053, + "name": "Dyfi Furnace" + }, + { + "address": null, + "city": "Ceredigion", + "id": 40054, + "name": "Ynyslas" + }, + { + "address": "Aberystwyth", + "city": "Aberystwyth", + "id": 40057, + "name": "Royal Pier" + }, + { + "address": null, + "city": "Newport", + "id": 40063, + "name": "Carreg Coetan Arthur Burial Chamber" + }, + { + "address": null, + "city": "Pembrokeshire", + "id": 40064, + "name": "Strumble Head Lighthouse" + }, + { + "address": null, + "city": "Saint Annes Head", + "id": 40068, + "name": "St. Ann's Head Lighthouse" + }, + { + "address": null, + "city": "Burry Port", + "id": 40078, + "name": "Burry Port Harbour Lighthouse" + }, + { + "address": null, + "city": "Burry Port", + "id": 40079, + "name": "Whiteford Lighthouse" + }, + { + "address": null, + "city": "The Mumbles", + "id": 40084, + "name": "Mumbles Pier" + }, + { + "address": null, + "city": "Neath Port Talbot", + "id": 40085, + "name": "Port Talbot Steelworks" + }, + { + "address": null, + "city": "Vale of Glamorgan", + "id": 40088, + "name": "Ogmore Castle" + }, + { + "address": null, + "city": "Vale of Glamorgan", + "id": 40089, + "name": "Dunraven Bay and Park" + }, + { + "address": null, + "city": "Marcross", + "id": 40090, + "name": "Nash Point Lighthouse" + }, + { + "address": null, + "city": "Penarth", + "id": 40092, + "name": "Penarth Pier" + }, + { + "address": null, + "city": "Newport", + "id": 40094, + "name": "Newport Transporter Bridge" + }, + { + "address": null, + "city": "Newport", + "id": 40095, + "name": "Newport Wetlands" + }, + { + "address": null, + "city": "Chepstow", + "id": 40096, + "name": "Chepstow Castle" + }, + { + "address": null, + "city": "Ceredigion", + "id": 40134, + "name": "Bwlch Nant yr Arian Forest Visitor Centre" + }, + { + "address": null, + "city": "Ceredigion", + "id": 40135, + "name": "Silvermountain experience" + }, + { + "address": null, + "city": "Gwynedd", + "id": 40166, + "name": "Iron age fort" + }, + { + "address": null, + "city": "Flint", + "id": 40169, + "name": "Flint castle" + }, + { + "address": "Bwlch Lane", + "city": "Isle of Anglesey", + "id": 40175, + "name": "Treetops Public House" + }, + { + "address": "Marianglas, Capel Coch", + "city": "Capel Coch", + "id": 40176, + "name": "The Parciau Arms" + }, + { + "address": null, + "city": "Bangor", + "id": 40180, + "name": "Menai Suspension Bridge" + }, + { + "address": "Menai Bridge", + "city": "Menai Bridge", + "id": 40181, + "name": "Church Island" + }, + { + "address": "Penmynydd Rd, Menai Bridge", + "city": "Isle of Anglesey", + "id": 40182, + "name": "Pili Palas" + }, + { + "address": null, + "city": "Amlwch Port", + "id": 40253, + "name": "Copper Kingdom Centre" + }, + { + "address": null, + "city": "Amlwch", + "id": 40254, + "name": "Our Lady Star of the Sea and St Winefride" + }, + { + "address": "place Maurice Charretier", + "city": "Carpentras", + "id": 40332, + "name": "Carpentras synagogue" + }, + { + "address": null, + "city": "Carpentras", + "id": 40333, + "name": "Notre-Dame de Santé chapel" + }, + { + "address": null, + "city": "Carpentras", + "id": 40334, + "name": "former Archbishopric" + }, + { + "address": null, + "city": "Carpentras", + "id": 40335, + "name": "Carpentras Cathedral" + }, + { + "address": null, + "city": "Carpentras", + "id": 40336, + "name": "La Charité" + }, + { + "address": null, + "city": "Carpentras", + "id": 40337, + "name": "Porte d'Orange" + }, + { + "address": null, + "city": "Carpentras", + "id": 40338, + "name": "aqueduct carries the canal Carpentras" + }, + { + "address": "34 rue Bel Air", + "city": "Carpentras", + "id": 40339, + "name": "Graineterie Roux" + }, + { + "address": null, + "city": "Carpentras", + "id": 40340, + "name": "Ancient Roman arch" + }, + { + "address": null, + "city": "Carpentras", + "id": 40341, + "name": "The Israelite cemetery" + }, + { + "address": null, + "city": "Carpentras", + "id": 40342, + "name": "Hôtel-Dieu" + }, + { + "address": null, + "city": "Carpentras", + "id": 40343, + "name": "Inguimbertine library" + }, + { + "address": "20, rue du docteur Tallet", + "city": "L'Isle-sur-la-Sorgue", + "id": 40376, + "name": "Campredon museum" + }, + { + "address": "Place de la Liberté", + "city": "L'Isle-sur-la-Sorgue", + "id": 40377, + "name": "Collégiale Notre-Dame-des-Anges" + }, + { + "address": "377 Chemin du Cimetière Israélite", + "city": "L'Isle-sur-la-Sorgue", + "id": 40378, + "name": "Old Hebrew cemetery" + }, + { + "address": null, + "city": "L'Isle-sur-la-Sorgue", + "id": 40379, + "name": "Le partage des Eaux de la Sorgue" + }, + { + "address": "Penderyn", + "city": "Powys", + "id": 4040, + "name": "Sgwd yr Eira Waterfall" + }, + { + "address": null, + "city": "Powys", + "id": 4041, + "name": "Pen Y Fan" + }, + { + "address": null, + "city": "London", + "id": 40425, + "name": "St. Giles-without-Cripplegate" + }, + { + "address": "London Wall", + "city": "London", + "id": 40426, + "name": "Museum of London" + }, + { + "address": "Little Britain, City of London", + "city": "London", + "id": 40427, + "name": "Postman's Park" + }, + { + "address": null, + "city": "London", + "id": 40428, + "name": "Old Bailey" + }, + { + "address": null, + "city": "London", + "id": 40429, + "name": "St. Martin Within Ludgate" + }, + { + "address": "Ludgate Hill", + "city": "London", + "id": 40430, + "name": "St. Paul's Cathedral" + }, + { + "address": "under Blackfriars bridge", + "city": "London", + "id": 40431, + "name": "Mouth of the River Fleet" + }, + { + "address": null, + "city": "London", + "id": 40432, + "name": "Millennium Bridge" + }, + { + "address": null, + "city": "London", + "id": 40433, + "name": "Pudding Lane" + }, + { + "address": "Lower Thames St, EC3R 6DN", + "city": "London", + "id": 40434, + "name": "St. Magnus the Martyr" + }, + { + "address": null, + "city": "London", + "id": 40435, + "name": "Monument" + }, + { + "address": null, + "city": "London", + "id": 40436, + "name": "Tower of London" + }, + { + "address": "30 St. Mary Axe", + "city": "London", + "id": 40437, + "name": "30 St. Mary Axe" + }, + { + "address": null, + "city": "London", + "id": 40438, + "name": "Mitre Square" + }, + { + "address": null, + "city": "Eyam", + "id": 40580, + "name": "Eyam Hall Manor House" + }, + { + "address": "Church Street", + "city": "Eyam", + "id": 40581, + "name": "Plague Cottages" + }, + { + "address": null, + "city": "Vittel", + "id": 40661, + "name": "Parc Thermal" + }, + { + "address": "42 Quai de Dogneville", + "city": "Épinal", + "id": 40671, + "name": "Musée de l'Image/Imagerie d'Épinal" + }, + { + "address": "12841 Sonoma Highway", + "city": "Glen Ellen", + "id": 40675, + "name": "Quarryhill Botanical Garden" + }, + { + "address": "2400 London Ranch Road", + "city": "Glen Ellen", + "id": 40676, + "name": "Jack London State Historic Park" + }, + { + "address": "29355 Arnold Drive", + "city": "Petaluma", + "id": 40677, + "name": "Sonoma Raceway" + }, + { + "address": "6201 Channel Drive, Santa Rosa", + "city": "Santa Rosa", + "id": 40678, + "name": "Annadel State Park" + }, + { + "address": "3000 Los Alamos Rd", + "city": "Santa Rosa", + "id": 40679, + "name": "Hood Mountain Regional park" + }, + { + "address": "13630 Sonoma Hwy", + "city": "Glen Ellen", + "id": 40680, + "name": "Sonoma Valley Regional Park" + }, + { + "address": "2605 Adobe Canyon Rd, Kenwood", + "city": "Saint Helena", + "id": 40681, + "name": "Sugarloaf Ridge" + }, + { + "address": "Abbey Craig", + "city": "Stirling", + "id": 4097, + "name": "Wallace Monument" + }, + { + "address": null, + "city": "Perth and Kinross", + "id": 41, + "name": "Wade's Bridge" + }, + { + "address": "52-55 Trafalgar St", + "city": "Brighton", + "id": 4111, + "name": "Brighton Toy and Model Museum" + }, + { + "address": "Great Western Dockyard, Gas Ferry Road", + "city": "Bristol", + "id": 4118, + "name": "Brunel's SS Great Britain" + }, + { + "address": "Anchor Road, Harbourside", + "city": "Bristol", + "id": 4119, + "name": "At-Bristol" + }, + { + "address": "Anchor road, Harbourside", + "city": "Bristol", + "id": 4120, + "name": "Blue Reef Aquarium" + }, + { + "address": "Guthry Road, Clifton", + "city": "Bristol", + "id": 4121, + "name": "Bristol Zoo Gardens" + }, + { + "address": null, + "city": "Royal Military Academy", + "id": 41213, + "name": "Sandhurst Military Academy" + }, + { + "address": "Bridge Rd, Leigh Woods, BS8 3PA", + "city": "Leigh Woods", + "id": 4122, + "name": "Clifton Suspension Bridge" + }, + { + "address": "Church Square", + "city": "Derbyshire", + "id": 41222, + "name": "Melbourne Hall" + }, + { + "address": null, + "city": "Bristol", + "id": 4123, + "name": "Cabot Tower" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41235, + "name": "Swtan heritage museum" + }, + { + "address": "near Bristol, Bristol,", + "city": "North Somerset", + "id": 4124, + "name": "Leigh Woods" + }, + { + "address": "Llynnon Mill, Llanddeusant", + "city": "Llanddeusant", + "id": 41240, + "name": "Llynon Windmill" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41242, + "name": "Llanddwyn Island Lighthouse" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41244, + "name": "Valley Wetlands RSPB reserve" + }, + { + "address": null, + "city": "Brynsiencyn", + "id": 41245, + "name": "Anglesey Sea Zoo" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41246, + "name": "Bryn Celli Ddu" + }, + { + "address": "Cribinau", + "city": "Isle of Anglesey", + "id": 41248, + "name": "St Cwyfan" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41250, + "name": "South Stack Lighthouse" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41251, + "name": "South Stack Cliffs RSPB reserve" + }, + { + "address": null, + "city": "Isle of Anglesey", + "id": 41252, + "name": "Holyhead Mountain Hut Circles" + }, + { + "address": null, + "city": null, + "id": 41256, + "name": "Trwyn Du Lighthouse" + }, + { + "address": null, + "city": "Shardlow", + "id": 41269, + "name": "Shardlow Heritage Centre" + }, + { + "address": "Victoria Road, Dodford, near Bromsgrove, B61 9BU", + "city": "Dodford", + "id": 4129, + "name": "Rosedene Cottage" + }, + { + "address": "Aberfeldy Distillery, PH15 2EB", + "city": "Perth and Kinross", + "id": 42, + "name": "Dewar's World of Whisky" + }, + { + "address": null, + "city": "Perth and Kinross", + "id": 43, + "name": "Castle Menzies" + }, + { + "address": "8039 Beach Blvd", + "city": "Buena Park", + "id": 4388, + "name": "Independence Hall at Knott's Berry Farm" + }, + { + "address": null, + "city": "Aberfeldy", + "id": 44, + "name": "Plastic Footbridge over the River Tay" + }, + { + "address": "131 High Street, KY3 9AA", + "city": "Burntisland", + "id": 4442, + "name": "Museum of Communication" + }, + { + "address": null, + "city": "Burntisland", + "id": 4443, + "name": "The Links" + }, + { + "address": "The Rotunda, Horringer, Bury St Edmunds, IP29 5QE", + "city": "Suffolk", + "id": 4446, + "name": "Ickworth House and Parks" + }, + { + "address": null, + "city": "Buxton", + "id": 4448, + "name": "Buxton Crescent" + }, + { + "address": null, + "city": "Buxton", + "id": 4449, + "name": "Pavilion Garden" + }, + { + "address": null, + "city": "Buxton", + "id": 4450, + "name": "Poole's Cavern" + }, + { + "address": null, + "city": "Derbyshire", + "id": 4451, + "name": "Solomon's Temple" + }, + { + "address": null, + "city": "Buxton", + "id": 4452, + "name": "Buxton Opera House" + }, + { + "address": "Sturt Road", + "city": "Frimley Green", + "id": 4935, + "name": "Frimley Lodge Park" + }, + { + "address": "Longport, CT1 1PF", + "city": "Canterbury", + "id": 5033, + "name": "St Augustine's Abbey" + }, + { + "address": "Cardiff Bay", + "city": "Cardiff", + "id": 5076, + "name": "The Norwegian Church" + }, + { + "address": null, + "city": "Carlisle", + "id": 5086, + "name": "Carlisle Cathedral" + }, + { + "address": "Castle Way, CA3 8UR", + "city": "The Castle", + "id": 5087, + "name": "Carlisle Castle" + }, + { + "address": "One Legoland Drive", + "city": "Carlsbad", + "id": 5090, + "name": "Legoland California" + }, + { + "address": null, + "city": "Carlsbad", + "id": 5091, + "name": "Flower Fields" + }, + { + "address": "3080 Rio Road", + "city": "Carmel-by-the-Sea", + "id": 5099, + "name": "Mission San Carlos Borromeo de Carmelo" + }, + { + "address": "26304 Ocean View Ave", + "city": "Carmel-by-the-Sea", + "id": 5100, + "name": "Tor House" + }, + { + "address": null, + "city": "Carmel-by-the-Sea", + "id": 5101, + "name": "Point Lobos" + }, + { + "address": "26364 Carmel Rancho Ln", + "city": "Carmel-by-the-Sea", + "id": 5102, + "name": "The Barnyard" + }, + { + "address": null, + "city": "Santa Margarita", + "id": 5115, + "name": "Goodwin Education Center" + }, + { + "address": null, + "city": "Santa Margarita", + "id": 5116, + "name": "Painted Rock" + }, + { + "address": null, + "city": "Santa Margarita", + "id": 5117, + "name": "Soda Lake" + }, + { + "address": null, + "city": "McKittrick", + "id": 5118, + "name": "Wallace Creek Trail" + }, + { + "address": null, + "city": "Dumfries and Galloway", + "id": 5183, + "name": "Threave Estate and Gardens" + }, + { + "address": "Kelton Mains, Castle Douglas", + "city": "Mains of Kelton", + "id": 5184, + "name": "Threave Castle" + }, + { + "address": null, + "city": "Castle Douglas", + "id": 5185, + "name": "Carlingwark Loch" + }, + { + "address": "Market Place, S33 8WQ", + "city": "Derbyshire", + "id": 5195, + "name": "Peveril Castle" + }, + { + "address": null, + "city": "Derbyshire", + "id": 5197, + "name": "Mam Tor" + }, + { + "address": null, + "city": "Derbyshire", + "id": 5198, + "name": "Cave Dale" + }, + { + "address": "STF Abisko Mountain Station, Sweden", + "city": "San Francisco", + "id": 52, + "name": "Aurora Sky Station" + }, + { + "address": "Bridge Street", + "city": "Castletown", + "id": 5205, + "name": "Nautical Museum" + }, + { + "address": null, + "city": "Chamonix-Mont-Blanc", + "id": 5307, + "name": "Jacques Belmat memorial" + }, + { + "address": "La résidence 89 avenue Michel Croz", + "city": "Chamonix-Mont-Blanc", + "id": 5308, + "name": "Musée alpin" + }, + { + "address": "615 allée du Recteur Payot", + "city": "Chamonix-Mont-Blanc", + "id": 5309, + "name": "Musée des Cristaux - Espace Tairraz" + }, + { + "address": "Yanworth, GL54 3LJ", + "city": "Gloucestershire", + "id": 5472, + "name": "Chedworth Roman Villa" + }, + { + "address": null, + "city": "Cheltenham", + "id": 5481, + "name": "Promenade" + }, + { + "address": null, + "city": "Cheltenham", + "id": 5482, + "name": "Imperial Gardens" + }, + { + "address": null, + "city": "Cheltenham", + "id": 5483, + "name": "Pittville Park" + }, + { + "address": null, + "city": "Gloucestershire", + "id": 5484, + "name": "Cleeve Hill" + }, + { + "address": "Clarence St, GL50 3JT", + "city": "Cheltenham", + "id": 5485, + "name": "Art Gallery and Museum" + }, + { + "address": "4 Clarence Rd, GL52 2AY", + "city": "Cheltenham", + "id": 5486, + "name": "Holst Birthplace Museum" + }, + { + "address": null, + "city": "Shurdington", + "id": 5487, + "name": "Crickley Hill and Barrow Wake" + }, + { + "address": null, + "city": "Shurdington", + "id": 5488, + "name": "Leckhampton Hill" + }, + { + "address": "Clarence St, GL50 3P", + "city": "Cheltenham", + "id": 5489, + "name": "St. Mary's Church" + }, + { + "address": "WA14 4SJ", + "city": "Dunham Massey", + "id": 551, + "name": "Dunham Massey" + }, + { + "address": "Knutsford, Cheshire, WA16 6QN", + "city": "Cheshire East", + "id": 552, + "name": "Tatton Park" + }, + { + "address": "Stockport Road, Timperley", + "city": "Timperley", + "id": 553, + "name": "Frank Sidebottom Statue" + }, + { + "address": "Creative Surgery, Normans Place, Altrincham", + "city": "Altrincham", + "id": 554, + "name": "Art With a Heart" + }, + { + "address": "Regent Road, Altrincham", + "city": "Altrincham", + "id": 555, + "name": "Bravest Little Street in England" + }, + { + "address": "Linmere, Northwich, CW8 2JD", + "city": "Delamere", + "id": 5566, + "name": "Delamere Forest Park" + }, + { + "address": "Knutsford, Cheshire, WA16 6QN", + "city": "Cheshire East", + "id": 5567, + "name": "Tatton Park" + }, + { + "address": "Church Way", + "city": "Chesterfield", + "id": 5568, + "name": "St Mary's and All Saint Church" + }, + { + "address": "High Street, Old Whittington", + "city": "Old Whittington", + "id": 5569, + "name": "Revolution House" + }, + { + "address": "St Helen's Close", + "city": "Chesterfield", + "id": 5570, + "name": "George Stephensons' Grave" + }, + { + "address": "Doe Lea", + "city": "Doe Lea", + "id": 5571, + "name": "Hardwick Hall" + }, + { + "address": null, + "city": "Chesterfield", + "id": 5572, + "name": "Queen's Park" + }, + { + "address": "525 Esplanade", + "city": "Chico", + "id": 5811, + "name": "Bidwell Mansion State Historic Park" + }, + { + "address": "Chastleton, near Moreton-in-Marsh, GL56 0SU", + "city": "Oxfordshire", + "id": 5849, + "name": "Chastleton House" + }, + { + "address": "Chirk, LL14 5AF", + "city": "Chirk", + "id": 5851, + "name": "Chirk Castle" + }, + { + "address": "Cotswold Avenue, Cirencester", + "city": "Cirencester", + "id": 6065, + "name": "The Roman Amphitheatre" + }, + { + "address": "Park Street, Cirencester", + "city": "Cirencester", + "id": 6066, + "name": "Corinium Museum" + }, + { + "address": null, + "city": "Cirencester", + "id": 6067, + "name": "Parish Church of St John the Baptist" + }, + { + "address": null, + "city": "Cirencester", + "id": 6068, + "name": "Abbey Grounds" + }, + { + "address": "5919 Clayton Road", + "city": "Clayton", + "id": 6135, + "name": "Clayton City Hall" + }, + { + "address": null, + "city": "Lancashire", + "id": 6168, + "name": "Sawley Abbey" + }, + { + "address": null, + "city": "Colmar", + "id": 6216, + "name": "Maison des Tetes" + }, + { + "address": null, + "city": "Colmar", + "id": 6217, + "name": "Maison Pfister" + }, + { + "address": "1, rue d' Unterlinden", + "city": "Colmar", + "id": 6218, + "name": "Unterlinden Museum" + }, + { + "address": "Castle Street, LL32 8AY", + "city": "Conwy", + "id": 6350, + "name": "Aberconwy House" + }, + { + "address": "Corchester Lane, NE45 5NT", + "city": "Corbridge", + "id": 6866, + "name": "Corbridge Roman Site" + }, + { + "address": null, + "city": "Corbridge", + "id": 6867, + "name": "Roman Bridge" + }, + { + "address": "Gwithian, near [[Hayle]], TR27 5ED", + "city": "Cornwall", + "id": 6906, + "name": "Godrevy" + }, + { + "address": "1500 Orange Avenue", + "city": "Coronado", + "id": 6913, + "name": "Hotel del Coronado" + }, + { + "address": "1100 Orange Avenue", + "city": "Coronado", + "id": 6914, + "name": "Coronado Museum of History & Art" + }, + { + "address": "Chastleton, near Moreton-in-Marsh, GL56 0SU", + "city": "Oxfordshire", + "id": 6936, + "name": "Chastleton House" + }, + { + "address": "York Ave, East Cowes, PO32 6JX", + "city": "East Cowes", + "id": 6979, + "name": "Osborne House" + }, + { + "address": "Mill Lane", + "city": "Cromford", + "id": 7002, + "name": "Cromford Mill" + }, + { + "address": null, + "city": "Derbyshire", + "id": 7003, + "name": "Masson Mill" + }, + { + "address": null, + "city": "Cromford", + "id": 7004, + "name": "Cromford Wharf" + }, + { + "address": null, + "city": "Highland", + "id": 7019, + "name": "Culloden Battlefield" + }, + { + "address": "9336 W Washington Blvd", + "city": "Culver City", + "id": 7020, + "name": "Culver Studios" + }, + { + "address": "9341 Venice Blvd", + "city": "Los Angeles", + "id": 7021, + "name": "Museum of Jurassic Technology" + }, + { + "address": "10101 Jefferson Blvd", + "city": "Culver City", + "id": 7022, + "name": "Star Eco Station" + }, + { + "address": "5741 Buckingham Parkway, Suite E", + "city": "Culver City", + "id": 7023, + "name": "The Wende Museum" + }, + { + "address": "4130 Overland Ave", + "city": "Culver City", + "id": 7024, + "name": "Mayme A. Clayton Library and Museum" + }, + { + "address": "Veterans Memorial Building, 4117 Overland Ave", + "city": "Culver City", + "id": 7025, + "name": "Culver City Historical Society" + }, + { + "address": "3861 Clarington Ave", + "city": "Culver City", + "id": 7026, + "name": "Sony Pictures Child Care Center" + }, + { + "address": "10185 Culver Blvd", + "city": "Culver City", + "id": 7027, + "name": "Game Show Building" + }, + { + "address": "Castle Road, TQ6 0JN", + "city": "Dartmouth", + "id": 7177, + "name": "Dartmouth Castle" + }, + { + "address": "5357 Rue du Comté Louis de Rohan Chabot", + "city": "Ranville", + "id": 7352, + "name": "Ranville War Cemetery" + }, + { + "address": null, + "city": "Hermanville-sur-Mer", + "id": 7353, + "name": "Hermanville War Cemetery" + }, + { + "address": null, + "city": "Courseulles-sur-Mer", + "id": 7354, + "name": "Beny-sur-mer Canadian War Cemetery" + }, + { + "address": null, + "city": "Colleville-sur-Mer", + "id": 7355, + "name": "Normandy American Cemetery" + }, + { + "address": null, + "city": "Sannerville", + "id": 7356, + "name": "Banneviile-la-Campagne War Cemetery" + }, + { + "address": null, + "city": "Urville", + "id": 7357, + "name": "Grainville-Langannerie Polish Cemetery" + }, + { + "address": null, + "city": "Cintheaux", + "id": 7358, + "name": "Bretteville-sur-Laize Canadian War Cemetery" + }, + { + "address": null, + "city": "Cheux", + "id": 7359, + "name": "Saint Manvieu War Cemetery" + }, + { + "address": null, + "city": "Bayeux", + "id": 7360, + "name": "Bayeux War Cemetery" + }, + { + "address": null, + "city": "La Cambe", + "id": 7361, + "name": "La Cambe German War Cemetery" + }, + { + "address": null, + "city": "Orglandes", + "id": 7362, + "name": "Orglandes German War Cemetery" + }, + { + "address": "Marine Road, CT14 7BA", + "city": "Walmer", + "id": 7364, + "name": "Deal Castle" + }, + { + "address": null, + "city": "Inyo County", + "id": 7365, + "name": "Artist Drive" + }, + { + "address": null, + "city": "Inyo County", + "id": 7366, + "name": "Badwater" + }, + { + "address": null, + "city": "Inyo County", + "id": 7367, + "name": "Dante's View" + }, + { + "address": null, + "city": "Inyo County", + "id": 7368, + "name": "Devil's Golf Course" + }, + { + "address": null, + "city": "Inyo County", + "id": 7369, + "name": "Natural Bridge" + }, + { + "address": null, + "city": "Inyo County", + "id": 7370, + "name": "Salt Creek" + }, + { + "address": null, + "city": "Furnace Creek", + "id": 7371, + "name": "Visitor Center And Museum" + }, + { + "address": null, + "city": "Inyo County", + "id": 7372, + "name": "Zabriskie Point" + }, + { + "address": null, + "city": "Inyo County", + "id": 7373, + "name": "Darwin Falls" + }, + { + "address": null, + "city": "Inyo County", + "id": 7374, + "name": "Mosaic Canyon" + }, + { + "address": null, + "city": "Death Valley", + "id": 7375, + "name": "Sand Dunes" + }, + { + "address": null, + "city": "Inyo County", + "id": 7376, + "name": "Scotty's Castle" + }, + { + "address": null, + "city": "Inyo County", + "id": 7377, + "name": "Ubehebe Crater" + }, + { + "address": null, + "city": "Panamint", + "id": 7378, + "name": "Barker Ranch" + }, + { + "address": null, + "city": "Inyo County", + "id": 7379, + "name": "Charcoal Kilns" + }, + { + "address": null, + "city": "Inyo County", + "id": 7380, + "name": "Eureka Sand Dunes" + }, + { + "address": null, + "city": "Inyo County", + "id": 7381, + "name": "Racetrack Playa" + }, + { + "address": null, + "city": "Inyo County", + "id": 7382, + "name": "Tea Kettle Junction" + }, + { + "address": null, + "city": "Inyo County", + "id": 7383, + "name": "Telescope Peak" + }, + { + "address": "The Market Place, DE1 2FS", + "city": "Derby", + "id": 7733, + "name": "Derby Market Hall" + }, + { + "address": null, + "city": "Derby", + "id": 7734, + "name": "Derby Arboretum" + }, + { + "address": "194 Osmaston Road", + "city": "Derby", + "id": 7735, + "name": "Royal Crown Derby" + }, + { + "address": "Silk Mill Lane", + "city": "Derby", + "id": 7736, + "name": "The Silk Mill, formerly Derby Industrial Museum" + }, + { + "address": "The Strand", + "city": "Derby", + "id": 7737, + "name": "Derby Museum and Art Gallery" + }, + { + "address": "41 Friargate", + "city": "Derby", + "id": 7738, + "name": "Pickfords House" + }, + { + "address": null, + "city": "Derby", + "id": 7739, + "name": "Derby Cathedral" + }, + { + "address": "Bridge Gate", + "city": "Derby", + "id": 7740, + "name": "St Mary's Chapel" + }, + { + "address": "Borrowash Road, Elvaston", + "city": "Elvaston", + "id": 7741, + "name": "Elvaston Castle Country Park" + }, + { + "address": "Union Hall Place, Derry", + "city": "Londonderry", + "id": 7772, + "name": "Tower Museum" + }, + { + "address": "Foyle Road, Derry", + "city": "Londonderry", + "id": 7773, + "name": "Railway museum" + }, + { + "address": "Harbour Square, Derry.", + "city": "Londonderry", + "id": 7774, + "name": "Harbour Museum" + }, + { + "address": "Butcher Street, Derry", + "city": "Londonderry", + "id": 7775, + "name": "Genealogy Centre" + }, + { + "address": "Glenfada Park, Derry", + "city": "Londonderry", + "id": 7776, + "name": "Free Derry Museum" + }, + { + "address": "Fountain, Derry", + "city": "Londonderry", + "id": 7777, + "name": "Old Gaol" + }, + { + "address": "Society Street, Derry.", + "city": "Londonderry", + "id": 7778, + "name": "Apprentice Boys Memorial Hall" + }, + { + "address": "Castle Hill, Conisbrough, DN12 3BU", + "city": "Conisbrough", + "id": 8027, + "name": "Conisbrough Castle" + }, + { + "address": "Higher Bockhampton, DT2 8QJ", + "city": "Dorset", + "id": 8092, + "name": "Hardy's Cottage" + }, + { + "address": "Alington Avenue, DT1 2AB", + "city": "Dorchester", + "id": 8093, + "name": "Max Gate" + }, + { + "address": "The Square, Corfe Castle, Wareham, BH20 5EZ", + "city": "Corfe Castle", + "id": 8121, + "name": "Corfe Castle" + }, + { + "address": "Poole Harbour, Poole, BH13 7EE", + "city": "Brownsea Island", + "id": 8122, + "name": "Brownsea Island" + }, + { + "address": "Cerne Abbas, DT2 7AL", + "city": "Cerne Abbas", + "id": 8123, + "name": "Cerne Abbas Giant" + }, + { + "address": "Studland, near Swanage", + "city": null, + "id": 8124, + "name": "Studland Beach" + }, + { + "address": "Castle Hill, CT16 1HU", + "city": "Dover", + "id": 8147, + "name": "Dover Castle" + }, + { + "address": null, + "city": "Dumbarton", + "id": 8335, + "name": "Dumbarton Castle" + }, + { + "address": "Castle Street, G82 1QS", + "city": "Dumbarton", + "id": 8336, + "name": "Denny Ship Model Experiment Tank" + }, + { + "address": null, + "city": "Dumbarton", + "id": 8337, + "name": "Levengrove Park" + }, + { + "address": null, + "city": "Argyll and Bute", + "id": 8338, + "name": "Geilston Gardens" + }, + { + "address": null, + "city": "Dumfries and Galloway", + "id": 8341, + "name": "Grey Mare's Tail Waterfall" + }, + { + "address": null, + "city": "Caerlaverock", + "id": 8342, + "name": "Caerlaverock Castle" + }, + { + "address": null, + "city": "Dunfermline", + "id": 8383, + "name": "Dunfermline Abbey" + }, + { + "address": null, + "city": "Dunfermline", + "id": 8384, + "name": "Carnegie Library" + }, + { + "address": "East Port, KY12 7JA", + "city": "Dunfermline", + "id": 8385, + "name": "The original Carnegie Hall" + }, + { + "address": "West Hoathly Road, RH19 4NE", + "city": "East Grinstead", + "id": 8527, + "name": "Standen" + }, + { + "address": "3800 Homer St", + "city": "Los Angeles", + "id": 8530, + "name": "Heritage Square" + }, + { + "address": "200 E Ave 43", + "city": "Los Angeles", + "id": 8531, + "name": "Lummis House" + }, + { + "address": "6045 York Blvd", + "city": "Los Angeles", + "id": 8532, + "name": "Los Angeles Police Museum" + }, + { + "address": "234 Museum Dr", + "city": "Los Angeles", + "id": 8533, + "name": "Southwest Museum" + }, + { + "address": null, + "city": "Battle", + "id": 8545, + "name": "Battle Abbey and battlefield" + }, + { + "address": "Bodiam, near [[Robertsbridge]], TN32 5UA", + "city": "Bodiam", + "id": 8546, + "name": "Bodiam Castle" + }, + { + "address": null, + "city": "Pevensey", + "id": 8547, + "name": "Pevensey Castle" + }, + { + "address": "Rodmell, Lewes, BN7 3HF", + "city": "Rodmell", + "id": 8548, + "name": "Monk's House" + }, + { + "address": "Bateman's Lane, Burwash, TN19 7DS", + "city": "Burwash", + "id": 8549, + "name": "Bateman's" + }, + { + "address": "West Street, Rye, TN31 7ES", + "city": "Rye", + "id": 8550, + "name": "Lamb House" + }, + { + "address": "East Fortune Airfield, East Lothian", + "city": "East Lothian", + "id": 8560, + "name": "The Museum of Flight" + }, + { + "address": "Pencaitland, Tranent, East Lothian, EH34 5ET", + "city": "Pencaitland", + "id": 8561, + "name": "Glenkinchie Distillery" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8562, + "name": "Duddingston Village" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8563, + "name": "Duddingston Loch" + }, + { + "address": "Old Church Lane, EH15 3PX", + "city": "Edinburgh", + "id": 8564, + "name": "Dr Neil's (Secret) Garden" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8565, + "name": "Portobello" + }, + { + "address": "Ocean Terminal", + "city": "Edinburgh", + "id": 8568, + "name": "Royal Yacht Britannia" + }, + { + "address": "East Princes Street Gardens", + "city": "Edinburgh", + "id": 8577, + "name": "The Scott Monument" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8578, + "name": "Old Calton Burial Ground" + }, + { + "address": "The Mound", + "city": "Edinburgh", + "id": 8579, + "name": "National Gallery of Scotland" + }, + { + "address": "1 Queen Street", + "city": "Edinburgh", + "id": 8580, + "name": "The Scottish National Portrait Gallery" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8581, + "name": "The Dean Village" + }, + { + "address": "7 Charlotte Square", + "city": "Edinburgh", + "id": 8582, + "name": "The Georgian House" + }, + { + "address": "13 George Street", + "city": "Edinburgh", + "id": 8583, + "name": "St Andrew's & St George's West Church" + }, + { + "address": "1a Rutland Place", + "city": "Edinburgh", + "id": 8584, + "name": "Edinburgh Gin Distillery" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8585, + "name": "Dundas Street Independent Art Galleries" + }, + { + "address": "Castlehill", + "city": "Edinburgh", + "id": 8611, + "name": "Edinburgh Castle" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8612, + "name": "Abbey and Palace of Holyroodhouse" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8613, + "name": "St Giles' Cathedral" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8614, + "name": "Mary King's Close" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8615, + "name": "North Bridge" + }, + { + "address": "Lawnmarket", + "city": "Edinburgh", + "id": 8616, + "name": "Gladstone's Land" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8617, + "name": "Greyfriars Kirkyard" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8618, + "name": "The Scottish Parliament" + }, + { + "address": "Castle Hill", + "city": "Edinburgh", + "id": 8619, + "name": "Camera Obscura" + }, + { + "address": "31 Market Street", + "city": "Edinburgh", + "id": 8620, + "name": "The Edinburgh Dungeon" + }, + { + "address": "354 Castlehill", + "city": "Edinburgh", + "id": 8621, + "name": "The Scotch Whisky Experience" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8622, + "name": "National Museum of Scotland" + }, + { + "address": "University of Edinburgh, Doorway 3, Medical School, Teviot Place", + "city": "Edinburgh", + "id": 8623, + "name": "Anatomical Museum" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8624, + "name": "The Reid Museum of Instruments" + }, + { + "address": "45 Market Street", + "city": "Edinburgh", + "id": 8625, + "name": "Fruitmarket Gallery" + }, + { + "address": "Nicolson Street", + "city": "Edinburgh", + "id": 8626, + "name": "Surgeons' Hall Museums" + }, + { + "address": "2 Market Street", + "city": "Edinburgh", + "id": 8627, + "name": "City Art Centre" + }, + { + "address": "163 Canongate", + "city": "Edinburgh", + "id": 8628, + "name": "The Peoples' Story Museum" + }, + { + "address": "42 High Street", + "city": "Edinburgh", + "id": 8629, + "name": "Museum of Childhood" + }, + { + "address": "142 Cannongate", + "city": "Edinburgh", + "id": 8630, + "name": "Museum of Edinburgh" + }, + { + "address": "Lady Stair's Close", + "city": "Edinburgh", + "id": 8631, + "name": "The Writers' Museum" + }, + { + "address": "Blackford Hill", + "city": "Edinburgh", + "id": 8665, + "name": "The Royal Observatory" + }, + { + "address": "Roslin, Midlothian", + "city": "Roslin", + "id": 8666, + "name": "Rosslyn Chapel" + }, + { + "address": "26a Dryden Road, Bilston Glen Ind Estate, Loanhead", + "city": "Loanhead", + "id": 8667, + "name": "Stewart Brewing" + }, + { + "address": "Swanston, Fairmilehead", + "city": "Edinburgh", + "id": 8668, + "name": "Swanston Village" + }, + { + "address": "Inverleith Row (East Gate) / Arboretum Place (West Gate).", + "city": "Edinburgh", + "id": 8686, + "name": "Royal Botanic Garden" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8687, + "name": "Patriothall Gallery, WASPS" + }, + { + "address": null, + "city": "Edinburgh", + "id": 8688, + "name": "St Bernard's Well" + }, + { + "address": "74 Belford Rd", + "city": "Edinburgh", + "id": 8693, + "name": "Scottish National Gallery of Modern Art" + }, + { + "address": "Roseburn Street", + "city": "Edinburgh", + "id": 8694, + "name": "Murrayfield Stadium" + }, + { + "address": "134 Corstorphine Road", + "city": "Edinburgh", + "id": 8695, + "name": "Edinburgh Zoo" + }, + { + "address": "2a Cramond Road South, Davidson's Mains", + "city": "Edinburgh", + "id": 8696, + "name": "Lauriston Castle" + }, + { + "address": "Kirk Loan, Corstorphine", + "city": "Edinburgh", + "id": 8697, + "name": "Corstorphine Old Parish Church" + }, + { + "address": "BT92 1DB", + "city": "Demesne", + "id": 8932, + "name": "Florence Court" + }, + { + "address": "Upper Lough Erne, Newtownbutler, BT92 8AP", + "city": "Fermanagh", + "id": 8933, + "name": "Crom" + }, + { + "address": "Great Bookham, near Dorking, RH5 6BD", + "city": "Great Bookham", + "id": 8964, + "name": "Polesden Lacey" + }, + { + "address": "The Old Fort, Box Hill Road, Box Hill, Tadworth, KT20 7LB", + "city": "Brockham", + "id": 8965, + "name": "Box Hill" + }, + { + "address": null, + "city": "Gwynedd", + "id": 9061, + "name": "Barmouth Bridge" + }, + { + "address": null, + "city": "Camelon", + "id": 9073, + "name": "Falkirk Wheel" + }, + { + "address": null, + "city": "Grangemouth", + "id": 9074, + "name": "The Kelpies" + }, + { + "address": null, + "city": "Falkirk", + "id": 9075, + "name": "Antonine Wall" + }, + { + "address": null, + "city": "Falkirk", + "id": 9076, + "name": "The Steeple" + }, + { + "address": null, + "city": "Fontainebleau", + "id": 9286, + "name": "Château de Fontainebleau" + }, + { + "address": null, + "city": "Fontainebleau", + "id": 9287, + "name": "Forêt de Fontainebleau" + }, + { + "address": "Boulevard de Constance", + "city": "Fontainebleau", + "id": 9288, + "name": "INSEAD" + }, + { + "address": null, + "city": "Northumberland", + "id": 9329, + "name": "Ford Castle" + }, + { + "address": "TD12 4TN", + "city": "Northumberland", + "id": 9330, + "name": "Etal Castle" + }, + { + "address": null, + "city": "Northumberland", + "id": 9331, + "name": "Heatherslaw Corn Mill" + }, + { + "address": null, + "city": "Northumberland", + "id": 9332, + "name": "Heatherslaw Visitor Centre" + }, + { + "address": null, + "city": "Northumberland", + "id": 9333, + "name": "Flodden Battlefield" + }, + { + "address": "34600 Ardenwood Blvd.", + "city": "Newark", + "id": 9621, + "name": "Ardenwood Historic Farm" + }, + { + "address": "43300 Mission Blvd.", + "city": "Fremont", + "id": 9622, + "name": "Mission San Jose and Museum" + }, + { + "address": "1900 Associated Road", + "city": "Fullerton", + "id": 9650, + "name": "Fullerton Arboretum" + }, + { + "address": "1201 W. Malvern Ave.", + "city": "Fullerton", + "id": 9651, + "name": "Muckenthaler Cultural Center" + }, + { + "address": "Parnell Street, DN21 2NB", + "city": "Gainsborough", + "id": 9692, + "name": "Gainsborough Old Hall" + }, + { + "address": null, + "city": "Gateshead", + "id": 9729, + "name": "BALTIC" + }, + { + "address": null, + "city": "Tyne and Wear", + "id": 9730, + "name": "The Gateshead Millennium bridge" + }, + { + "address": null, + "city": "Gateshead", + "id": 9731, + "name": "The Sage Gateshead" + }, + { + "address": "Prince Consort Road, Gateshead", + "city": "Gateshead", + "id": 9732, + "name": "Shipley Art Gallery" + }, + { + "address": null, + "city": "Metrocentre", + "id": 9733, + "name": "Metro Centre" + }, + { + "address": "43201 35th St. W.", + "city": "Lancaster", + "id": 980, + "name": "Prime Desert Woodland Preserve" + } + ] +] \ No newline at end of file diff --git a/modules/n1ql/examples/n1ql-language-reference/udf-locations-test.n1ql b/modules/n1ql/examples/n1ql-language-reference/udf-locations-test.n1ql new file mode 100644 index 000000000..88d655e87 --- /dev/null +++ b/modules/n1ql/examples/n1ql-language-reference/udf-locations-test.n1ql @@ -0,0 +1 @@ +EXECUTE FUNCTION locations("see"); \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-cover.jsonc b/modules/n1ql/examples/select/ansi-join-cover.jsonc new file mode 100644 index 000000000..d585e5b7d --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-cover.jsonc @@ -0,0 +1,2637 @@ +// tag::extract[] +[ + { + "airline": "AH", + "destinationairport": "ALG", + "route_id": "route_10186" + }, + { + "airline": "AI", + "destinationairport": "BOM", + "route_id": "route_10570" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "airline": "AI", + "destinationairport": "DEL", + "route_id": "route_10571" + }, + { + "airline": "AI", + "destinationairport": "JFK", + "route_id": "route_10572" + }, + { + "airline": "AM", + "destinationairport": "MEX", + "route_id": "route_11032" + }, + { + "airline": "AT", + "destinationairport": "CMN", + "route_id": "route_12192" + }, + { + "airline": "AT", + "destinationairport": "TNG", + "route_id": "route_12193" + }, + { + "airline": "AY", + "destinationairport": "ARN", + "route_id": "route_12774" + }, + { + "airline": "AY", + "destinationairport": "ATL", + "route_id": "route_12775" + }, + { + "airline": "AY", + "destinationairport": "AUS", + "route_id": "route_12776" + }, + { + "airline": "AY", + "destinationairport": "BOS", + "route_id": "route_12777" + }, + { + "airline": "AY", + "destinationairport": "BWI", + "route_id": "route_12778" + }, + { + "airline": "AY", + "destinationairport": "DEN", + "route_id": "route_12779" + }, + { + "airline": "AY", + "destinationairport": "DFW", + "route_id": "route_12780" + }, + { + "airline": "AY", + "destinationairport": "EWR", + "route_id": "route_12781" + }, + { + "airline": "AY", + "destinationairport": "HEL", + "route_id": "route_12782" + }, + { + "airline": "AY", + "destinationairport": "IAD", + "route_id": "route_12783" + }, + { + "airline": "AY", + "destinationairport": "IAH", + "route_id": "route_12784" + }, + { + "airline": "AY", + "destinationairport": "JFK", + "route_id": "route_12785" + }, + { + "airline": "AY", + "destinationairport": "LAS", + "route_id": "route_12786" + }, + { + "airline": "AY", + "destinationairport": "LAX", + "route_id": "route_12787" + }, + { + "airline": "AY", + "destinationairport": "LIS", + "route_id": "route_12788" + }, + { + "airline": "AY", + "destinationairport": "MIA", + "route_id": "route_12789" + }, + { + "airline": "AY", + "destinationairport": "ORD", + "route_id": "route_12790" + }, + { + "airline": "AY", + "destinationairport": "PHL", + "route_id": "route_12791" + }, + { + "airline": "AY", + "destinationairport": "PHX", + "route_id": "route_12792" + }, + { + "airline": "AY", + "destinationairport": "RDU", + "route_id": "route_12793" + }, + { + "airline": "AY", + "destinationairport": "SAN", + "route_id": "route_12794" + }, + { + "airline": "AY", + "destinationairport": "SEA", + "route_id": "route_12795" + }, + { + "airline": "AY", + "destinationairport": "SFO", + "route_id": "route_12796" + }, + { + "airline": "AY", + "destinationairport": "YUL", + "route_id": "route_12797" + }, + { + "airline": "AY", + "destinationairport": "YVR", + "route_id": "route_12798" + }, + { + "airline": "AY", + "destinationairport": "YYC", + "route_id": "route_12799" + }, + { + "airline": "AY", + "destinationairport": "YYZ", + "route_id": "route_12800" + }, + { + "airline": "AZ", + "destinationairport": "FCO", + "route_id": "route_13454" + }, + { + "airline": "AZ", + "destinationairport": "LIN", + "route_id": "route_13455" + }, + { + "airline": "BA", + "destinationairport": "ABV", + "route_id": "route_14660" + }, + { + "airline": "BA", + "destinationairport": "ABZ", + "route_id": "route_14661" + }, + { + "airline": "BA", + "destinationairport": "ACC", + "route_id": "route_14662" + }, + { + "airline": "BA", + "destinationairport": "AGP", + "route_id": "route_14663" + }, + { + "airline": "BA", + "destinationairport": "ALA", + "route_id": "route_14664" + }, + { + "airline": "BA", + "destinationairport": "AMM", + "route_id": "route_14665" + }, + { + "airline": "BA", + "destinationairport": "AMS", + "route_id": "route_14666" + }, + { + "airline": "BA", + "destinationairport": "ARN", + "route_id": "route_14667" + }, + { + "airline": "BA", + "destinationairport": "ATH", + "route_id": "route_14668" + }, + { + "airline": "BA", + "destinationairport": "ATL", + "route_id": "route_14669" + }, + { + "airline": "BA", + "destinationairport": "AUH", + "route_id": "route_14670" + }, + { + "airline": "BA", + "destinationairport": "AUS", + "route_id": "route_14671" + }, + { + "airline": "BA", + "destinationairport": "BAH", + "route_id": "route_14672" + }, + { + "airline": "BA", + "destinationairport": "BCN", + "route_id": "route_14673" + }, + { + "airline": "BA", + "destinationairport": "BEY", + "route_id": "route_14674" + }, + { + "airline": "BA", + "destinationairport": "BGO", + "route_id": "route_14675" + }, + { + "airline": "BA", + "destinationairport": "BHD", + "route_id": "route_14676" + }, + { + "airline": "BA", + "destinationairport": "BKK", + "route_id": "route_14677" + }, + { + "airline": "BA", + "destinationairport": "BLQ", + "route_id": "route_14678" + }, + { + "airline": "BA", + "destinationairport": "BLR", + "route_id": "route_14679" + }, + { + "airline": "BA", + "destinationairport": "BOM", + "route_id": "route_14680" + }, + { + "airline": "BA", + "destinationairport": "BOS", + "route_id": "route_14681" + }, + { + "airline": "BA", + "destinationairport": "BRU", + "route_id": "route_14682" + }, + { + "airline": "BA", + "destinationairport": "BSL", + "route_id": "route_14683" + }, + { + "airline": "BA", + "destinationairport": "BUD", + "route_id": "route_14684" + }, + { + "airline": "BA", + "destinationairport": "BWI", + "route_id": "route_14685" + }, + { + "airline": "BA", + "destinationairport": "CAI", + "route_id": "route_14686" + }, + { + "airline": "BA", + "destinationairport": "CDG", + "route_id": "route_14687" + }, + { + "airline": "BA", + "destinationairport": "CPH", + "route_id": "route_14688" + }, + { + "airline": "BA", + "destinationairport": "CPT", + "route_id": "route_14689" + }, + { + "airline": "BA", + "destinationairport": "CTU", + "route_id": "route_14690" + }, + { + "airline": "BA", + "destinationairport": "DEL", + "route_id": "route_14691" + }, + { + "airline": "BA", + "destinationairport": "DEN", + "route_id": "route_14692" + }, + { + "airline": "BA", + "destinationairport": "DFW", + "route_id": "route_14693" + }, + { + "airline": "BA", + "destinationairport": "DME", + "route_id": "route_14694" + }, + { + "airline": "BA", + "destinationairport": "DUB", + "route_id": "route_14695" + }, + { + "airline": "BA", + "destinationairport": "DUS", + "route_id": "route_14696" + }, + { + "airline": "BA", + "destinationairport": "DXB", + "route_id": "route_14697" + }, + { + "airline": "BA", + "destinationairport": "EBB", + "route_id": "route_14698" + }, + { + "airline": "BA", + "destinationairport": "EDI", + "route_id": "route_14699" + }, + { + "airline": "BA", + "destinationairport": "EWR", + "route_id": "route_14700" + }, + { + "airline": "BA", + "destinationairport": "EZE", + "route_id": "route_14701" + }, + { + "airline": "BA", + "destinationairport": "FAO", + "route_id": "route_14702" + }, + { + "airline": "BA", + "destinationairport": "FCO", + "route_id": "route_14703" + }, + { + "airline": "BA", + "destinationairport": "FNA", + "route_id": "route_14704" + }, + { + "airline": "BA", + "destinationairport": "FRA", + "route_id": "route_14705" + }, + { + "airline": "BA", + "destinationairport": "GIB", + "route_id": "route_14706" + }, + { + "airline": "BA", + "destinationairport": "GIG", + "route_id": "route_14707" + }, + { + "airline": "BA", + "destinationairport": "GLA", + "route_id": "route_14708" + }, + { + "airline": "BA", + "destinationairport": "GOT", + "route_id": "route_14709" + }, + { + "airline": "BA", + "destinationairport": "GRU", + "route_id": "route_14710" + }, + { + "airline": "BA", + "destinationairport": "GVA", + "route_id": "route_14711" + }, + { + "airline": "BA", + "destinationairport": "GYD", + "route_id": "route_14712" + }, + { + "airline": "BA", + "destinationairport": "HAJ", + "route_id": "route_14713" + }, + { + "airline": "BA", + "destinationairport": "HAM", + "route_id": "route_14714" + }, + { + "airline": "BA", + "destinationairport": "HEL", + "route_id": "route_14715" + }, + { + "airline": "BA", + "destinationairport": "HKG", + "route_id": "route_14716" + }, + { + "airline": "BA", + "destinationairport": "HND", + "route_id": "route_14717" + }, + { + "airline": "BA", + "destinationairport": "HYD", + "route_id": "route_14718" + }, + { + "airline": "BA", + "destinationairport": "IAD", + "route_id": "route_14719" + }, + { + "airline": "BA", + "destinationairport": "IAH", + "route_id": "route_14720" + }, + { + "airline": "BA", + "destinationairport": "IBZ", + "route_id": "route_14721" + }, + { + "airline": "BA", + "destinationairport": "ICN", + "route_id": "route_14722" + }, + { + "airline": "BA", + "destinationairport": "IST", + "route_id": "route_14723" + }, + { + "airline": "BA", + "destinationairport": "JED", + "route_id": "route_14724" + }, + { + "airline": "BA", + "destinationairport": "JFK", + "route_id": "route_14725" + }, + { + "airline": "BA", + "destinationairport": "JMK", + "route_id": "route_14726" + }, + { + "airline": "BA", + "destinationairport": "JNB", + "route_id": "route_14727" + }, + { + "airline": "BA", + "destinationairport": "JTR", + "route_id": "route_14728" + }, + { + "airline": "BA", + "destinationairport": "KBP", + "route_id": "route_14729" + }, + { + "airline": "BA", + "destinationairport": "KWI", + "route_id": "route_14730" + }, + { + "airline": "BA", + "destinationairport": "LAD", + "route_id": "route_14731" + }, + { + "airline": "BA", + "destinationairport": "LAS", + "route_id": "route_14732" + }, + { + "airline": "BA", + "destinationairport": "LAX", + "route_id": "route_14733" + }, + { + "airline": "BA", + "destinationairport": "LBA", + "route_id": "route_14734" + }, + { + "airline": "BA", + "destinationairport": "LCA", + "route_id": "route_14735" + }, + { + "airline": "BA", + "destinationairport": "LED", + "route_id": "route_14736" + }, + { + "airline": "BA", + "destinationairport": "LIN", + "route_id": "route_14737" + }, + { + "airline": "BA", + "destinationairport": "LIS", + "route_id": "route_14738" + }, + { + "airline": "BA", + "destinationairport": "LOS", + "route_id": "route_14739" + }, + { + "airline": "BA", + "destinationairport": "LUX", + "route_id": "route_14740" + }, + { + "airline": "BA", + "destinationairport": "LYS", + "route_id": "route_14741" + }, + { + "airline": "BA", + "destinationairport": "MAA", + "route_id": "route_14742" + }, + { + "airline": "BA", + "destinationairport": "MAD", + "route_id": "route_14743" + }, + { + "airline": "BA", + "destinationairport": "MAN", + "route_id": "route_14744" + }, + { + "airline": "BA", + "destinationairport": "MEX", + "route_id": "route_14745" + }, + { + "airline": "BA", + "destinationairport": "MIA", + "route_id": "route_14746" + }, + { + "airline": "BA", + "destinationairport": "MRS", + "route_id": "route_14747" + }, + { + "airline": "BA", + "destinationairport": "MUC", + "route_id": "route_14748" + }, + { + "airline": "BA", + "destinationairport": "MXP", + "route_id": "route_14749" + }, + { + "airline": "BA", + "destinationairport": "NAS", + "route_id": "route_14750" + }, + { + "airline": "BA", + "destinationairport": "NBO", + "route_id": "route_14751" + }, + { + "airline": "BA", + "destinationairport": "NCE", + "route_id": "route_14752" + }, + { + "airline": "BA", + "destinationairport": "NCL", + "route_id": "route_14753" + }, + { + "airline": "BA", + "destinationairport": "NRT", + "route_id": "route_14754" + }, + { + "airline": "BA", + "destinationairport": "OPO", + "route_id": "route_14755" + }, + { + "airline": "BA", + "destinationairport": "ORD", + "route_id": "route_14756" + }, + { + "airline": "BA", + "destinationairport": "ORY", + "route_id": "route_14757" + }, + { + "airline": "BA", + "destinationairport": "OSL", + "route_id": "route_14758" + }, + { + "airline": "BA", + "destinationairport": "OTP", + "route_id": "route_14759" + }, + { + "airline": "BA", + "destinationairport": "PEK", + "route_id": "route_14760" + }, + { + "airline": "BA", + "destinationairport": "PHL", + "route_id": "route_14761" + }, + { + "airline": "BA", + "destinationairport": "PHX", + "route_id": "route_14762" + }, + { + "airline": "BA", + "destinationairport": "PMI", + "route_id": "route_14763" + }, + { + "airline": "BA", + "destinationairport": "PRG", + "route_id": "route_14764" + }, + { + "airline": "BA", + "destinationairport": "PSA", + "route_id": "route_14765" + }, + { + "airline": "BA", + "destinationairport": "PVG", + "route_id": "route_14766" + }, + { + "airline": "BA", + "destinationairport": "RDU", + "route_id": "route_14767" + }, + { + "airline": "BA", + "destinationairport": "RTM", + "route_id": "route_14768" + }, + { + "airline": "BA", + "destinationairport": "RUH", + "route_id": "route_14769" + }, + { + "airline": "BA", + "destinationairport": "SAN", + "route_id": "route_14770" + }, + { + "airline": "BA", + "destinationairport": "SEA", + "route_id": "route_14771" + }, + { + "airline": "BA", + "destinationairport": "SFO", + "route_id": "route_14772" + }, + { + "airline": "BA", + "destinationairport": "SIN", + "route_id": "route_14773" + }, + { + "airline": "BA", + "destinationairport": "SOF", + "route_id": "route_14774" + }, + { + "airline": "BA", + "destinationairport": "STR", + "route_id": "route_14775" + }, + { + "airline": "BA", + "destinationairport": "SVG", + "route_id": "route_14776" + }, + { + "airline": "BA", + "destinationairport": "TIP", + "route_id": "route_14777" + }, + { + "airline": "BA", + "destinationairport": "TLS", + "route_id": "route_14778" + }, + { + "airline": "BA", + "destinationairport": "TLV", + "route_id": "route_14779" + }, + { + "airline": "BA", + "destinationairport": "TXL", + "route_id": "route_14780" + }, + { + "airline": "BA", + "destinationairport": "VCE", + "route_id": "route_14781" + }, + { + "airline": "BA", + "destinationairport": "VIE", + "route_id": "route_14782" + }, + { + "airline": "BA", + "destinationairport": "WAW", + "route_id": "route_14783" + }, + { + "airline": "BA", + "destinationairport": "YUL", + "route_id": "route_14784" + }, + { + "airline": "BA", + "destinationairport": "YVR", + "route_id": "route_14785" + }, + { + "airline": "BA", + "destinationairport": "YYC", + "route_id": "route_14786" + }, + { + "airline": "BA", + "destinationairport": "YYZ", + "route_id": "route_14787" + }, + { + "airline": "BA", + "destinationairport": "ZAG", + "route_id": "route_14788" + }, + { + "airline": "BA", + "destinationairport": "ZRH", + "route_id": "route_14789" + }, + { + "airline": "4U", + "destinationairport": "CGN", + "route_id": "route_1501" + }, + { + "airline": "4U", + "destinationairport": "HAM", + "route_id": "route_1502" + }, + { + "airline": "4U", + "destinationairport": "STR", + "route_id": "route_1503" + }, + { + "airline": "4U", + "destinationairport": "TXL", + "route_id": "route_1504" + }, + { + "airline": "BG", + "destinationairport": "DAC", + "route_id": "route_15342" + }, + { + "airline": "BG", + "destinationairport": "ZYL", + "route_id": "route_15343" + }, + { + "airline": "BI", + "destinationairport": "DXB", + "route_id": "route_15379" + }, + { + "airline": "BR", + "destinationairport": "BKK", + "route_id": "route_15648" + }, + { + "airline": "BT", + "destinationairport": "LIN", + "route_id": "route_15757" + }, + { + "airline": "CA", + "destinationairport": "PEK", + "route_id": "route_16561" + }, + { + "airline": "CA", + "destinationairport": "PVG", + "route_id": "route_16562" + }, + { + "airline": "CI", + "destinationairport": "AMS", + "route_id": "route_17462" + }, + { + "airline": "CX", + "destinationairport": "HKG", + "route_id": "route_17978" + }, + { + "airline": "CY", + "destinationairport": "LCA", + "route_id": "route_18050" + }, + { + "airline": "CZ", + "destinationairport": "CAN", + "route_id": "route_18788" + }, + { + "airline": "DL", + "destinationairport": "ATL", + "route_id": "route_21166" + }, + { + "airline": "DL", + "destinationairport": "BOS", + "route_id": "route_21167" + }, + { + "airline": "DL", + "destinationairport": "DTW", + "route_id": "route_21168" + }, + { + "airline": "DL", + "destinationairport": "EWR", + "route_id": "route_21169" + }, + { + "airline": "DL", + "destinationairport": "IAD", + "route_id": "route_21170" + }, + { + "airline": "DL", + "destinationairport": "JFK", + "route_id": "route_21171" + }, + { + "airline": "DL", + "destinationairport": "LAX", + "route_id": "route_21172" + }, + { + "airline": "DL", + "destinationairport": "MIA", + "route_id": "route_21173" + }, + { + "airline": "DL", + "destinationairport": "MSP", + "route_id": "route_21174" + }, + { + "airline": "DL", + "destinationairport": "ORD", + "route_id": "route_21175" + }, + { + "airline": "DL", + "destinationairport": "SEA", + "route_id": "route_21176" + }, + { + "airline": "DL", + "destinationairport": "SFO", + "route_id": "route_21177" + }, + { + "airline": "EI", + "destinationairport": "BHD", + "route_id": "route_22987" + }, + { + "airline": "EI", + "destinationairport": "DUB", + "route_id": "route_22988" + }, + { + "airline": "EI", + "destinationairport": "ORK", + "route_id": "route_22989" + }, + { + "airline": "EI", + "destinationairport": "SNN", + "route_id": "route_22990" + }, + { + "airline": "EK", + "destinationairport": "DXB", + "route_id": "route_23284" + }, + { + "airline": "ET", + "destinationairport": "ADD", + "route_id": "route_23862" + }, + { + "airline": "ET", + "destinationairport": "YYZ", + "route_id": "route_23863" + }, + { + "airline": "EY", + "destinationairport": "AUH", + "route_id": "route_24208" + }, + { + "airline": "FB", + "destinationairport": "SOF", + "route_id": "route_24552" + }, + { + "airline": "FI", + "destinationairport": "KEF", + "route_id": "route_24768" + }, + { + "airline": "GF", + "destinationairport": "BAH", + "route_id": "route_29939" + }, + { + "airline": "GF", + "destinationairport": "DFW", + "route_id": "route_29940" + }, + { + "airline": "HY", + "destinationairport": "TAS", + "route_id": "route_32038" + }, + { + "airline": "IB", + "destinationairport": "ABZ", + "route_id": "route_32586" + }, + { + "airline": "IB", + "destinationairport": "ARN", + "route_id": "route_32587" + }, + { + "airline": "IB", + "destinationairport": "ATL", + "route_id": "route_32588" + }, + { + "airline": "IB", + "destinationairport": "AUH", + "route_id": "route_32589" + }, + { + "airline": "IB", + "destinationairport": "AUS", + "route_id": "route_32590" + }, + { + "airline": "IB", + "destinationairport": "BAH", + "route_id": "route_32591" + }, + { + "airline": "IB", + "destinationairport": "BCN", + "route_id": "route_32592" + }, + { + "airline": "IB", + "destinationairport": "BEY", + "route_id": "route_32593" + }, + { + "airline": "IB", + "destinationairport": "BHD", + "route_id": "route_32594" + }, + { + "airline": "IB", + "destinationairport": "BIO", + "route_id": "route_32595" + }, + { + "airline": "IB", + "destinationairport": "BKK", + "route_id": "route_32596" + }, + { + "airline": "IB", + "destinationairport": "BOS", + "route_id": "route_32597" + }, + { + "airline": "IB", + "destinationairport": "BUD", + "route_id": "route_32598" + }, + { + "airline": "IB", + "destinationairport": "BWI", + "route_id": "route_32599" + }, + { + "airline": "IB", + "destinationairport": "DEN", + "route_id": "route_32600" + }, + { + "airline": "IB", + "destinationairport": "DFW", + "route_id": "route_32601" + }, + { + "airline": "IB", + "destinationairport": "EDI", + "route_id": "route_32602" + }, + { + "airline": "IB", + "destinationairport": "EWR", + "route_id": "route_32603" + }, + { + "airline": "IB", + "destinationairport": "GLA", + "route_id": "route_32604" + }, + { + "airline": "IB", + "destinationairport": "GOT", + "route_id": "route_32605" + }, + { + "airline": "IB", + "destinationairport": "IAD", + "route_id": "route_32606" + }, + { + "airline": "IB", + "destinationairport": "IAH", + "route_id": "route_32607" + }, + { + "airline": "IB", + "destinationairport": "IBZ", + "route_id": "route_32608" + }, + { + "airline": "IB", + "destinationairport": "JFK", + "route_id": "route_32609" + }, + { + "airline": "IB", + "destinationairport": "LAS", + "route_id": "route_32610" + }, + { + "airline": "IB", + "destinationairport": "LAX", + "route_id": "route_32611" + }, + { + "airline": "IB", + "destinationairport": "LBA", + "route_id": "route_32612" + }, + { + "airline": "IB", + "destinationairport": "LCG", + "route_id": "route_32613" + }, + { + "airline": "IB", + "destinationairport": "MAD", + "route_id": "route_32614" + }, + { + "airline": "IB", + "destinationairport": "MAN", + "route_id": "route_32615" + }, + { + "airline": "IB", + "destinationairport": "MEX", + "route_id": "route_32616" + }, + { + "airline": "IB", + "destinationairport": "MIA", + "route_id": "route_32617" + }, + { + "airline": "IB", + "destinationairport": "NCL", + "route_id": "route_32618" + }, + { + "airline": "IB", + "destinationairport": "ORD", + "route_id": "route_32619" + }, + { + "airline": "IB", + "destinationairport": "ORY", + "route_id": "route_32620" + }, + { + "airline": "IB", + "destinationairport": "OSL", + "route_id": "route_32621" + }, + { + "airline": "IB", + "destinationairport": "PHL", + "route_id": "route_32622" + }, + { + "airline": "IB", + "destinationairport": "PHX", + "route_id": "route_32623" + }, + { + "airline": "IB", + "destinationairport": "PMI", + "route_id": "route_32624" + }, + { + "airline": "IB", + "destinationairport": "RDU", + "route_id": "route_32625" + }, + { + "airline": "IB", + "destinationairport": "RUH", + "route_id": "route_32626" + }, + { + "airline": "IB", + "destinationairport": "SAN", + "route_id": "route_32627" + }, + { + "airline": "IB", + "destinationairport": "SEA", + "route_id": "route_32628" + }, + { + "airline": "IB", + "destinationairport": "SFO", + "route_id": "route_32629" + }, + { + "airline": "IB", + "destinationairport": "SIN", + "route_id": "route_32630" + }, + { + "airline": "IB", + "destinationairport": "WAW", + "route_id": "route_32631" + }, + { + "airline": "IB", + "destinationairport": "YUL", + "route_id": "route_32632" + }, + { + "airline": "IB", + "destinationairport": "YVR", + "route_id": "route_32633" + }, + { + "airline": "IB", + "destinationairport": "YYC", + "route_id": "route_32634" + }, + { + "airline": "IB", + "destinationairport": "YYZ", + "route_id": "route_32635" + }, + { + "airline": "IR", + "destinationairport": "IKA", + "route_id": "route_33462" + }, + { + "airline": "J2", + "destinationairport": "GYD", + "route_id": "route_33777" + }, + { + "airline": "JJ", + "destinationairport": "GRU", + "route_id": "route_34359" + }, + { + "airline": "JL", + "destinationairport": "HND", + "route_id": "route_34697" + }, + { + "airline": "JL", + "destinationairport": "NRT", + "route_id": "route_34698" + }, + { + "airline": "JU", + "destinationairport": "BEG", + "route_id": "route_35381" + }, + { + "airline": "KC", + "destinationairport": "ALA", + "route_id": "route_35783" + }, + { + "airline": "KC", + "destinationairport": "TSE", + "route_id": "route_35784" + }, + { + "airline": "KE", + "destinationairport": "ICN", + "route_id": "route_36031" + }, + { + "airline": "KL", + "destinationairport": "AMS", + "route_id": "route_36751" + }, + { + "airline": "KL", + "destinationairport": "ATL", + "route_id": "route_36752" + }, + { + "airline": "KL", + "destinationairport": "BOS", + "route_id": "route_36753" + }, + { + "airline": "KL", + "destinationairport": "DTW", + "route_id": "route_36754" + }, + { + "airline": "KL", + "destinationairport": "JFK", + "route_id": "route_36755" + }, + { + "airline": "KL", + "destinationairport": "MSP", + "route_id": "route_36756" + }, + { + "airline": "KL", + "destinationairport": "SEA", + "route_id": "route_36757" + }, + { + "airline": "KM", + "destinationairport": "MLA", + "route_id": "route_37014" + }, + { + "airline": "KQ", + "destinationairport": "NBO", + "route_id": "route_37234" + }, + { + "airline": "KU", + "destinationairport": "JFK", + "route_id": "route_37431" + }, + { + "airline": "KU", + "destinationairport": "KWI", + "route_id": "route_37432" + }, + { + "airline": "LH", + "destinationairport": "DUS", + "route_id": "route_38490" + }, + { + "airline": "LH", + "destinationairport": "EWR", + "route_id": "route_38491" + }, + { + "airline": "LH", + "destinationairport": "FRA", + "route_id": "route_38492" + }, + { + "airline": "LH", + "destinationairport": "IAD", + "route_id": "route_38493" + }, + { + "airline": "LH", + "destinationairport": "IAH", + "route_id": "route_38494" + }, + { + "airline": "LH", + "destinationairport": "LAX", + "route_id": "route_38495" + }, + { + "airline": "LH", + "destinationairport": "MUC", + "route_id": "route_38496" + }, + { + "airline": "LH", + "destinationairport": "ORD", + "route_id": "route_38497" + }, + { + "airline": "LH", + "destinationairport": "SFO", + "route_id": "route_38498" + }, + { + "airline": "LH", + "destinationairport": "YEG", + "route_id": "route_38499" + }, + { + "airline": "LH", + "destinationairport": "YHZ", + "route_id": "route_38500" + }, + { + "airline": "LH", + "destinationairport": "YOW", + "route_id": "route_38501" + }, + { + "airline": "LH", + "destinationairport": "YUL", + "route_id": "route_38502" + }, + { + "airline": "LH", + "destinationairport": "YVR", + "route_id": "route_38503" + }, + { + "airline": "LH", + "destinationairport": "YYC", + "route_id": "route_38504" + }, + { + "airline": "LH", + "destinationairport": "YYT", + "route_id": "route_38505" + }, + { + "airline": "LH", + "destinationairport": "YYZ", + "route_id": "route_38506" + }, + { + "airline": "LN", + "destinationairport": "TIP", + "route_id": "route_39022" + }, + { + "airline": "LO", + "destinationairport": "WAW", + "route_id": "route_39100" + }, + { + "airline": "LX", + "destinationairport": "GVA", + "route_id": "route_39666" + }, + { + "airline": "LX", + "destinationairport": "ZRH", + "route_id": "route_39667" + }, + { + "airline": "LY", + "destinationairport": "TLV", + "route_id": "route_39849" + }, + { + "airline": "ME", + "destinationairport": "BEY", + "route_id": "route_40095" + }, + { + "airline": "MH", + "destinationairport": "DFW", + "route_id": "route_40699" + }, + { + "airline": "MH", + "destinationairport": "HEL", + "route_id": "route_40700" + }, + { + "airline": "MH", + "destinationairport": "JFK", + "route_id": "route_40701" + }, + { + "airline": "MH", + "destinationairport": "KUL", + "route_id": "route_40702" + }, + { + "airline": "MH", + "destinationairport": "RDU", + "route_id": "route_40703" + }, + { + "airline": "MK", + "destinationairport": "MRU", + "route_id": "route_40984" + }, + { + "airline": "MS", + "destinationairport": "CAI", + "route_id": "route_41301" + }, + { + "airline": "MS", + "destinationairport": "LXR", + "route_id": "route_41302" + }, + { + "airline": "9W", + "destinationairport": "BOM", + "route_id": "route_4173" + }, + { + "airline": "9W", + "destinationairport": "DEL", + "route_id": "route_4174" + }, + { + "airline": "MU", + "destinationairport": "AMS", + "route_id": "route_41837" + }, + { + "airline": "MU", + "destinationairport": "PVG", + "route_id": "route_41838" + }, + { + "airline": "NH", + "destinationairport": "HND", + "route_id": "route_43057" + }, + { + "airline": "NH", + "destinationairport": "LIS", + "route_id": "route_43058" + }, + { + "airline": "NH", + "destinationairport": "NRT", + "route_id": "route_43059" + }, + { + "airline": "NH", + "destinationairport": "WAW", + "route_id": "route_43060" + }, + { + "airline": "A3", + "destinationairport": "ATH", + "route_id": "route_4395" + }, + { + "airline": "NZ", + "destinationairport": "LAX", + "route_id": "route_43961" + }, + { + "airline": "NZ", + "destinationairport": "SFO", + "route_id": "route_43962" + }, + { + "airline": "OA", + "destinationairport": "ATH", + "route_id": "route_44272" + }, + { + "airline": "OS", + "destinationairport": "VIE", + "route_id": "route_44620" + }, + { + "airline": "OU", + "destinationairport": "RJK", + "route_id": "route_44826" + }, + { + "airline": "OU", + "destinationairport": "SPU", + "route_id": "route_44827" + }, + { + "airline": "OU", + "destinationairport": "ZAG", + "route_id": "route_44828" + }, + { + "airline": "OZ", + "destinationairport": "ICN", + "route_id": "route_45110" + }, + { + "airline": "PK", + "destinationairport": "ISB", + "route_id": "route_45884" + }, + { + "airline": "PK", + "destinationairport": "KHI", + "route_id": "route_45885" + }, + { + "airline": "PK", + "destinationairport": "LHE", + "route_id": "route_45886" + }, + { + "airline": "PR", + "destinationairport": "MNL", + "route_id": "route_46157" + }, + { + "airline": "QF", + "destinationairport": "DXB", + "route_id": "route_46975" + }, + { + "airline": "QR", + "destinationairport": "DOH", + "route_id": "route_47510" + }, + { + "airline": "RJ", + "destinationairport": "AMM", + "route_id": "route_48007" + }, + { + "airline": "RO", + "destinationairport": "OTP", + "route_id": "route_48075" + }, + { + "airline": "S4", + "destinationairport": "LIS", + "route_id": "route_48385" + }, + { + "airline": "SA", + "destinationairport": "JNB", + "route_id": "route_48907" + }, + { + "airline": "SK", + "destinationairport": "ARN", + "route_id": "route_50008" + }, + { + "airline": "SK", + "destinationairport": "CPH", + "route_id": "route_50009" + }, + { + "airline": "SK", + "destinationairport": "GOT", + "route_id": "route_50010" + }, + { + "airline": "SK", + "destinationairport": "OSL", + "route_id": "route_50011" + }, + { + "airline": "SK", + "destinationairport": "SVG", + "route_id": "route_50012" + }, + { + "airline": "SN", + "destinationairport": "BRU", + "route_id": "route_50340" + }, + { + "airline": "SQ", + "destinationairport": "SIN", + "route_id": "route_50492" + }, + { + "airline": "SU", + "destinationairport": "SVO", + "route_id": "route_50960" + }, + { + "airline": "SV", + "destinationairport": "JED", + "route_id": "route_51473" + }, + { + "airline": "SV", + "destinationairport": "RUH", + "route_id": "route_51474" + }, + { + "airline": "T5", + "destinationairport": "ASB", + "route_id": "route_51800" + }, + { + "airline": "TG", + "destinationairport": "ARN", + "route_id": "route_52163" + }, + { + "airline": "TG", + "destinationairport": "BKK", + "route_id": "route_52164" + }, + { + "airline": "TK", + "destinationairport": "IST", + "route_id": "route_52709" + }, + { + "airline": "TP", + "destinationairport": "LIS", + "route_id": "route_53681" + }, + { + "airline": "TU", + "destinationairport": "TUN", + "route_id": "route_54146" + }, + { + "airline": "UA", + "destinationairport": "EWR", + "route_id": "route_57042" + }, + { + "airline": "UA", + "destinationairport": "IAD", + "route_id": "route_57043" + }, + { + "airline": "UA", + "destinationairport": "IAH", + "route_id": "route_57044" + }, + { + "airline": "UA", + "destinationairport": "LAX", + "route_id": "route_57045" + }, + { + "airline": "UA", + "destinationairport": "ORD", + "route_id": "route_57046" + }, + { + "airline": "UA", + "destinationairport": "SFO", + "route_id": "route_57047" + }, + { + "airline": "AA", + "destinationairport": "ABZ", + "route_id": "route_5803" + }, + { + "airline": "AA", + "destinationairport": "ACC", + "route_id": "route_5804" + }, + { + "airline": "AA", + "destinationairport": "AGP", + "route_id": "route_5805" + }, + { + "airline": "AA", + "destinationairport": "AMS", + "route_id": "route_5806" + }, + { + "airline": "AA", + "destinationairport": "ARN", + "route_id": "route_5807" + }, + { + "airline": "AA", + "destinationairport": "ATH", + "route_id": "route_5808" + }, + { + "airline": "UL", + "destinationairport": "CMB", + "route_id": "route_58087" + }, + { + "airline": "AA", + "destinationairport": "ATL", + "route_id": "route_5809" + }, + { + "airline": "AA", + "destinationairport": "AUH", + "route_id": "route_5810" + }, + { + "airline": "AA", + "destinationairport": "AUS", + "route_id": "route_5811" + }, + { + "airline": "AA", + "destinationairport": "BAH", + "route_id": "route_5812" + }, + { + "airline": "AA", + "destinationairport": "BCN", + "route_id": "route_5813" + }, + { + "airline": "AA", + "destinationairport": "BGO", + "route_id": "route_5814" + }, + { + "airline": "AA", + "destinationairport": "BHD", + "route_id": "route_5815" + }, + { + "airline": "AA", + "destinationairport": "BLQ", + "route_id": "route_5816" + }, + { + "airline": "AA", + "destinationairport": "BLR", + "route_id": "route_5817" + }, + { + "airline": "AA", + "destinationairport": "BOM", + "route_id": "route_5818" + }, + { + "airline": "AA", + "destinationairport": "BOS", + "route_id": "route_5819" + }, + { + "airline": "AA", + "destinationairport": "BRU", + "route_id": "route_5820" + }, + { + "airline": "AA", + "destinationairport": "BSL", + "route_id": "route_5821" + }, + { + "airline": "AA", + "destinationairport": "BUD", + "route_id": "route_5822" + }, + { + "airline": "AA", + "destinationairport": "BWI", + "route_id": "route_5823" + }, + { + "airline": "AA", + "destinationairport": "CDG", + "route_id": "route_5824" + }, + { + "airline": "AA", + "destinationairport": "CLT", + "route_id": "route_5825" + }, + { + "airline": "AA", + "destinationairport": "CPH", + "route_id": "route_5826" + }, + { + "airline": "AA", + "destinationairport": "CPT", + "route_id": "route_5827" + }, + { + "airline": "UN", + "destinationairport": "ABZ", + "route_id": "route_58273" + }, + { + "airline": "UN", + "destinationairport": "BOS", + "route_id": "route_58274" + }, + { + "airline": "UN", + "destinationairport": "EDI", + "route_id": "route_58275" + }, + { + "airline": "UN", + "destinationairport": "JNB", + "route_id": "route_58276" + }, + { + "airline": "UN", + "destinationairport": "LAX", + "route_id": "route_58277" + }, + { + "airline": "UN", + "destinationairport": "MAN", + "route_id": "route_58278" + }, + { + "airline": "UN", + "destinationairport": "SFO", + "route_id": "route_58279" + }, + { + "airline": "AA", + "destinationairport": "DEL", + "route_id": "route_5828" + }, + { + "airline": "UN", + "destinationairport": "VKO", + "route_id": "route_58280" + }, + { + "airline": "AA", + "destinationairport": "DEN", + "route_id": "route_5829" + }, + { + "airline": "AA", + "destinationairport": "DFW", + "route_id": "route_5830" + }, + { + "airline": "AA", + "destinationairport": "DUB", + "route_id": "route_5831" + }, + { + "airline": "AA", + "destinationairport": "DUS", + "route_id": "route_5832" + }, + { + "airline": "AA", + "destinationairport": "DXB", + "route_id": "route_5833" + }, + { + "airline": "AA", + "destinationairport": "EBB", + "route_id": "route_5834" + }, + { + "airline": "AA", + "destinationairport": "EDI", + "route_id": "route_5835" + }, + { + "airline": "AA", + "destinationairport": "EWR", + "route_id": "route_5836" + }, + { + "airline": "AA", + "destinationairport": "FCO", + "route_id": "route_5837" + }, + { + "airline": "AA", + "destinationairport": "FRA", + "route_id": "route_5838" + }, + { + "airline": "AA", + "destinationairport": "GIB", + "route_id": "route_5839" + }, + { + "airline": "AA", + "destinationairport": "GLA", + "route_id": "route_5840" + }, + { + "airline": "AA", + "destinationairport": "GOT", + "route_id": "route_5841" + }, + { + "airline": "AA", + "destinationairport": "GVA", + "route_id": "route_5842" + }, + { + "airline": "AA", + "destinationairport": "HAJ", + "route_id": "route_5843" + }, + { + "airline": "AA", + "destinationairport": "HAM", + "route_id": "route_5844" + }, + { + "airline": "AA", + "destinationairport": "HEL", + "route_id": "route_5845" + }, + { + "airline": "AA", + "destinationairport": "HYD", + "route_id": "route_5846" + }, + { + "airline": "AA", + "destinationairport": "IAD", + "route_id": "route_5847" + }, + { + "airline": "AA", + "destinationairport": "IAH", + "route_id": "route_5848" + }, + { + "airline": "AA", + "destinationairport": "IST", + "route_id": "route_5849" + }, + { + "airline": "AA", + "destinationairport": "JFK", + "route_id": "route_5850" + }, + { + "airline": "AA", + "destinationairport": "JNB", + "route_id": "route_5851" + }, + { + "airline": "AA", + "destinationairport": "KUL", + "route_id": "route_5852" + }, + { + "airline": "AA", + "destinationairport": "KWI", + "route_id": "route_5853" + }, + { + "airline": "AA", + "destinationairport": "LAS", + "route_id": "route_5854" + }, + { + "airline": "AA", + "destinationairport": "LAX", + "route_id": "route_5855" + }, + { + "airline": "AA", + "destinationairport": "LBA", + "route_id": "route_5856" + }, + { + "airline": "AA", + "destinationairport": "LCA", + "route_id": "route_5857" + }, + { + "airline": "AA", + "destinationairport": "LIN", + "route_id": "route_5858" + }, + { + "airline": "AA", + "destinationairport": "LIS", + "route_id": "route_5859" + }, + { + "airline": "AA", + "destinationairport": "LUX", + "route_id": "route_5860" + }, + { + "airline": "AA", + "destinationairport": "LYS", + "route_id": "route_5861" + }, + { + "airline": "AA", + "destinationairport": "MAA", + "route_id": "route_5862" + }, + { + "airline": "AA", + "destinationairport": "MAN", + "route_id": "route_5863" + }, + { + "airline": "AA", + "destinationairport": "MIA", + "route_id": "route_5864" + }, + { + "airline": "AA", + "destinationairport": "MRS", + "route_id": "route_5865" + }, + { + "airline": "AA", + "destinationairport": "MUC", + "route_id": "route_5866" + }, + { + "airline": "AA", + "destinationairport": "MXP", + "route_id": "route_5867" + }, + { + "airline": "AA", + "destinationairport": "NBO", + "route_id": "route_5868" + }, + { + "airline": "AA", + "destinationairport": "NCE", + "route_id": "route_5869" + }, + { + "airline": "AA", + "destinationairport": "NCL", + "route_id": "route_5870" + }, + { + "airline": "AA", + "destinationairport": "ORD", + "route_id": "route_5871" + }, + { + "airline": "AA", + "destinationairport": "OSL", + "route_id": "route_5872" + }, + { + "airline": "AA", + "destinationairport": "OTP", + "route_id": "route_5873" + }, + { + "airline": "AA", + "destinationairport": "PHL", + "route_id": "route_5874" + }, + { + "airline": "AA", + "destinationairport": "PHX", + "route_id": "route_5875" + }, + { + "airline": "AA", + "destinationairport": "PRG", + "route_id": "route_5876" + }, + { + "airline": "AA", + "destinationairport": "PSA", + "route_id": "route_5877" + }, + { + "airline": "AA", + "destinationairport": "RDU", + "route_id": "route_5878" + }, + { + "airline": "AA", + "destinationairport": "RTM", + "route_id": "route_5879" + }, + { + "airline": "AA", + "destinationairport": "SAN", + "route_id": "route_5880" + }, + { + "airline": "AA", + "destinationairport": "SEA", + "route_id": "route_5881" + }, + { + "airline": "AA", + "destinationairport": "SFO", + "route_id": "route_5882" + }, + { + "airline": "AA", + "destinationairport": "SOF", + "route_id": "route_5883" + }, + { + "airline": "AA", + "destinationairport": "STR", + "route_id": "route_5884" + }, + { + "airline": "AA", + "destinationairport": "SVG", + "route_id": "route_5885" + }, + { + "airline": "AA", + "destinationairport": "TLS", + "route_id": "route_5886" + }, + { + "airline": "AA", + "destinationairport": "TXL", + "route_id": "route_5887" + }, + { + "airline": "AA", + "destinationairport": "VCE", + "route_id": "route_5888" + }, + { + "airline": "AA", + "destinationairport": "VIE", + "route_id": "route_5889" + }, + { + "airline": "AA", + "destinationairport": "WAW", + "route_id": "route_5890" + }, + { + "airline": "AA", + "destinationairport": "YUL", + "route_id": "route_5891" + }, + { + "airline": "AA", + "destinationairport": "YVR", + "route_id": "route_5892" + }, + { + "airline": "AA", + "destinationairport": "YYC", + "route_id": "route_5893" + }, + { + "airline": "AA", + "destinationairport": "YYZ", + "route_id": "route_5894" + }, + { + "airline": "AA", + "destinationairport": "ZAG", + "route_id": "route_5895" + }, + { + "airline": "AA", + "destinationairport": "ZRH", + "route_id": "route_5896" + }, + { + "airline": "US", + "destinationairport": "ATH", + "route_id": "route_59577" + }, + { + "airline": "US", + "destinationairport": "CLT", + "route_id": "route_59578" + }, + { + "airline": "US", + "destinationairport": "DFW", + "route_id": "route_59579" + }, + { + "airline": "US", + "destinationairport": "DOH", + "route_id": "route_59580" + }, + { + "airline": "US", + "destinationairport": "JFK", + "route_id": "route_59581" + }, + { + "airline": "US", + "destinationairport": "JNB", + "route_id": "route_59582" + }, + { + "airline": "US", + "destinationairport": "LAX", + "route_id": "route_59583" + }, + { + "airline": "US", + "destinationairport": "LIS", + "route_id": "route_59584" + }, + { + "airline": "US", + "destinationairport": "MIA", + "route_id": "route_59585" + }, + { + "airline": "US", + "destinationairport": "ORD", + "route_id": "route_59586" + }, + { + "airline": "US", + "destinationairport": "PHL", + "route_id": "route_59587" + }, + { + "airline": "US", + "destinationairport": "RDU", + "route_id": "route_59588" + }, + { + "airline": "VS", + "destinationairport": "ABZ", + "route_id": "route_61763" + }, + { + "airline": "VS", + "destinationairport": "ATL", + "route_id": "route_61764" + }, + { + "airline": "VS", + "destinationairport": "BOM", + "route_id": "route_61765" + }, + { + "airline": "VS", + "destinationairport": "BOS", + "route_id": "route_61766" + }, + { + "airline": "VS", + "destinationairport": "DEL", + "route_id": "route_61767" + }, + { + "airline": "VS", + "destinationairport": "DTW", + "route_id": "route_61768" + }, + { + "airline": "VS", + "destinationairport": "DXB", + "route_id": "route_61769" + }, + { + "airline": "VS", + "destinationairport": "EDI", + "route_id": "route_61770" + }, + { + "airline": "VS", + "destinationairport": "EWR", + "route_id": "route_61771" + }, + { + "airline": "VS", + "destinationairport": "HKG", + "route_id": "route_61772" + }, + { + "airline": "VS", + "destinationairport": "HND", + "route_id": "route_61773" + }, + { + "airline": "VS", + "destinationairport": "IAD", + "route_id": "route_61774" + }, + { + "airline": "VS", + "destinationairport": "JFK", + "route_id": "route_61775" + }, + { + "airline": "VS", + "destinationairport": "JNB", + "route_id": "route_61776" + }, + { + "airline": "VS", + "destinationairport": "LAX", + "route_id": "route_61777" + }, + { + "airline": "VS", + "destinationairport": "LOS", + "route_id": "route_61778" + }, + { + "airline": "VS", + "destinationairport": "MAN", + "route_id": "route_61779" + }, + { + "airline": "VS", + "destinationairport": "MIA", + "route_id": "route_61780" + }, + { + "airline": "VS", + "destinationairport": "MSP", + "route_id": "route_61781" + }, + { + "airline": "VS", + "destinationairport": "NRT", + "route_id": "route_61782" + }, + { + "airline": "VS", + "destinationairport": "ORD", + "route_id": "route_61783" + }, + { + "airline": "VS", + "destinationairport": "PEK", + "route_id": "route_61784" + }, + { + "airline": "VS", + "destinationairport": "PVG", + "route_id": "route_61785" + }, + { + "airline": "VS", + "destinationairport": "SEA", + "route_id": "route_61786" + }, + { + "airline": "VS", + "destinationairport": "SFO", + "route_id": "route_61787" + }, + { + "airline": "VS", + "destinationairport": "SIN", + "route_id": "route_61788" + }, + { + "airline": "VS", + "destinationairport": "VKO", + "route_id": "route_61789" + }, + { + "airline": "VY", + "destinationairport": "BIO", + "route_id": "route_62306" + }, + { + "airline": "VY", + "destinationairport": "LCG", + "route_id": "route_62307" + }, + { + "airline": "WY", + "destinationairport": "MCT", + "route_id": "route_65106" + }, + { + "airline": "AB", + "destinationairport": "BSL", + "route_id": "route_7393" + }, + { + "airline": "AB", + "destinationairport": "FRA", + "route_id": "route_7394" + }, + { + "airline": "AB", + "destinationairport": "HAJ", + "route_id": "route_7395" + }, + { + "airline": "AB", + "destinationairport": "HAM", + "route_id": "route_7396" + }, + { + "airline": "AB", + "destinationairport": "MUC", + "route_id": "route_7397" + }, + { + "airline": "AB", + "destinationairport": "ORY", + "route_id": "route_7398" + }, + { + "airline": "AB", + "destinationairport": "STR", + "route_id": "route_7399" + }, + { + "airline": "AB", + "destinationairport": "TXL", + "route_id": "route_7400" + }, + { + "airline": "AB", + "destinationairport": "VIE", + "route_id": "route_7401" + }, + { + "airline": "AB", + "destinationairport": "ZRH", + "route_id": "route_7402" + }, + { + "airline": "AC", + "destinationairport": "YEG", + "route_id": "route_7961" + }, + { + "airline": "AC", + "destinationairport": "YHZ", + "route_id": "route_7962" + }, + { + "airline": "AC", + "destinationairport": "YOW", + "route_id": "route_7963" + }, + { + "airline": "AC", + "destinationairport": "YUL", + "route_id": "route_7964" + }, + { + "airline": "AC", + "destinationairport": "YVR", + "route_id": "route_7965" + }, + { + "airline": "AC", + "destinationairport": "YYC", + "route_id": "route_7966" + }, + { + "airline": "AC", + "destinationairport": "YYT", + "route_id": "route_7967" + }, + { + "airline": "AC", + "destinationairport": "YYZ", + "route_id": "route_7968" + }, + { + "airline": "AF", + "destinationairport": "ATL", + "route_id": "route_9648" + }, + { + "airline": "AF", + "destinationairport": "BOS", + "route_id": "route_9649" + }, + { + "airline": "AF", + "destinationairport": "CDG", + "route_id": "route_9650" + }, + { + "airline": "AF", + "destinationairport": "DTW", + "route_id": "route_9651" + }, + { + "airline": "AF", + "destinationairport": "JFK", + "route_id": "route_9652" + }, + { + "airline": "AF", + "destinationairport": "MSP", + "route_id": "route_9653" + }, + { + "airline": "AF", + "destinationairport": "SEA", + "route_id": "route_9654" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-cover.n1ql b/modules/n1ql/examples/select/ansi-join-cover.n1ql new file mode 100644 index 000000000..cc8cebc6c --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-cover.n1ql @@ -0,0 +1,16 @@ +-- tag::default[] +CREATE INDEX def_inventory_route_sourceairport +ON route (sourceairport); +-- end::default[] + +-- tag::cover[] +CREATE INDEX idx_route_src_dst_airline +ON route (sourceairport, destinationairport, airline); +-- end::cover[] + +-- tag::query[] +SELECT META(route).id route_id, route.airline, route.destinationairport +FROM airport JOIN route ON route.sourceairport = airport.faa +WHERE airport.icao = "EGLL" +ORDER BY route_id; +-- end::query[] diff --git a/modules/n1ql/examples/select/ansi-join-expr.jsonc b/modules/n1ql/examples/select/ansi-join-expr.jsonc new file mode 100644 index 000000000..b3d2a8795 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-expr.jsonc @@ -0,0 +1,5 @@ +[ + { + "destinationairport": "KEF" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-expr.n1ql b/modules/n1ql/examples/select/ansi-join-expr.n1ql new file mode 100644 index 000000000..a01053ce8 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-expr.n1ql @@ -0,0 +1,7 @@ +SELECT DISTINCT expression.destinationairport +FROM airport JOIN [ + {"destinationairport": "KEF", "sourceairport": "SFO", "type": "route"}, + {"destinationairport": "KEF", "sourceairport": "LHR", "type": "route"} +] AS expression +ON airport.faa = expression.sourceairport +WHERE airport.city = "San Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-inner.jsonc b/modules/n1ql/examples/select/ansi-join-inner.jsonc new file mode 100644 index 000000000..713431988 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-inner.jsonc @@ -0,0 +1,1117 @@ +// tag::extract[] +[ + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ABQ" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ACV" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "AKL" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] +{ + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "AMS" + }, + { + "airlineid": "airline_137", + "destinationairport": "SFO", + "name": "Air France", + "sourceairport": "ATL" + }, + { + "airlineid": "airline_5347", + "destinationairport": "SFO", + "name": "Virgin Atlantic Airways", + "sourceairport": "ATL" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "ATL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ATL" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "ATL" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "ATL" + }, + { + "airlineid": "airline_3029", + "destinationairport": "SFO", + "name": "JetBlue Airways", + "sourceairport": "AUS" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "AUS" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "AUS" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "BFL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "BOI" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "BOS" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "BOS" + }, + { + "airlineid": "airline_3029", + "destinationairport": "SFO", + "name": "JetBlue Airways", + "sourceairport": "BOS" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "BUR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "BWI" + }, + { + "airlineid": "airline_137", + "destinationairport": "SFO", + "name": "Air France", + "sourceairport": "CDG" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "CDG" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "CDG" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "CEC" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "CIC" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "CLE" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "CLT" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "CLT" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "COS" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "CUN" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "CUN" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "CVG" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "DAL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "DCA" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "DCA" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "DEN" + }, + { + "airlineid": "airline_2468", + "destinationairport": "SFO", + "name": "Frontier Airlines", + "sourceairport": "DEN" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "DEN" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "DFW" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "DFW" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "DFW" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "DFW" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "DTW" + }, + { + "airlineid": "airline_3029", + "destinationairport": "SFO", + "name": "JetBlue Airways", + "sourceairport": "DXB" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "EUG" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "EWR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "EWR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "FAT" + }, + { + "airlineid": "airline_3029", + "destinationairport": "SFO", + "name": "JetBlue Airways", + "sourceairport": "FLL" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "FLL" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "FLL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "FLL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "FRA" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "GDL" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "HKG" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "HKG" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "HKG" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "HND" + }, + { + "airlineid": "airline_2688", + "destinationairport": "SFO", + "name": "Hawaiian Airlines", + "sourceairport": "HNL" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "HNL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "HNL" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "IAD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "IAD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "IAH" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ICN" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "ICN" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "ICN" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "IND" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "JFK" + }, + { + "airlineid": "airline_3029", + "destinationairport": "SFO", + "name": "JetBlue Airways", + "sourceairport": "JFK" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "JFK" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "JFK" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "JFK" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "JFK" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "KIX" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "KOA" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "LAS" + }, + { + "airlineid": "airline_2688", + "destinationairport": "SFO", + "name": "Hawaiian Airlines", + "sourceairport": "LAS" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "LAS" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "LAS" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "LAX" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "LAX" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "LAX" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "LAX" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "LAX" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "LAX" + }, + { + "airlineid": "airline_3029", + "destinationairport": "SFO", + "name": "JetBlue Airways", + "sourceairport": "LGB" + }, + { + "airlineid": "airline_5347", + "destinationairport": "SFO", + "name": "Virgin Atlantic Airways", + "sourceairport": "LHR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "LHR" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "LHR" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "LHR" + }, + { + "airlineid": "airline_1355", + "destinationairport": "SFO", + "name": "British Airways", + "sourceairport": "LHR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "LIH" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "LMT" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "MCI" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MCI" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "MCO" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MCO" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "MDW" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "MDW" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MEX" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "MEX" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MFR" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "MIA" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "MIA" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "MKE" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "MKE" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MOD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MRY" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MSP" + }, + { + "airlineid": "airline_4356", + "destinationairport": "SFO", + "name": "Sun Country Airlines", + "sourceairport": "MSP" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "MSP" + }, + { + "airlineid": "airline_137", + "destinationairport": "SFO", + "name": "Air France", + "sourceairport": "MSP" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MSY" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "MUC" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "NRT" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "OGG" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "OKC" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ONT" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "ORD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ORD" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "ORD" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "ORD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "OTH" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PDX" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "PDX" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "PDX" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "PEK" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PEK" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "PHL" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "PHL" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "PHL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PHL" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "PHX" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "PHX" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "PHX" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PHX" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PIT" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PSC" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "PSP" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "PSP" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PSP" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PVG" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "PVG" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "PVR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "PVR" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "PVR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "RDD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "RDM" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "RDU" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "RDU" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "RNO" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SAL" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "SAL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SAN" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "SAN" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "SAN" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SAT" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SBA" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SBP" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "SEA" + }, + { + "airlineid": "airline_24", + "destinationairport": "SFO", + "name": "American Airlines", + "sourceairport": "SEA" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "SEA" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SEA" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SJD" + }, + { + "airlineid": "airline_5331", + "destinationairport": "SFO", + "name": "Virgin America", + "sourceairport": "SJD" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SLC" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "SLC" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SMF" + }, + { + "airlineid": "airline_4547", + "destinationairport": "SFO", + "name": "Southwest Airlines", + "sourceairport": "SNA" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SNA" + }, + { + "airlineid": "airline_1316", + "destinationairport": "SFO", + "name": "AirTran Airways", + "sourceairport": "SNA" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "STL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "SYD" + }, + { + "airlineid": "airline_2009", + "destinationairport": "SFO", + "name": "Delta Air Lines", + "sourceairport": "TPE" + }, + { + "airlineid": "airline_5265", + "destinationairport": "SFO", + "name": "US Airways", + "sourceairport": "TPE" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "TPE" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "TUS" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "YEG" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "YUL" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "YVR" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "YYC" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "YYJ" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "YYZ" + }, + { + "airlineid": "airline_5209", + "destinationairport": "SFO", + "name": "United Airlines", + "sourceairport": "ZRH" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-inner.n1ql b/modules/n1ql/examples/select/ansi-join-inner.n1ql new file mode 100644 index 000000000..e80a1d272 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-inner.n1ql @@ -0,0 +1,6 @@ +SELECT route.airlineid, airline.name, route.sourceairport, route.destinationairport +FROM route +INNER JOIN airline +ON route.airlineid = META(airline).id +WHERE route.destinationairport = "SFO" +ORDER BY route.sourceairport; diff --git a/modules/n1ql/examples/select/ansi-join-lateral.jsonc b/modules/n1ql/examples/select/ansi-join-lateral.jsonc new file mode 100644 index 000000000..2d64def7a --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-lateral.jsonc @@ -0,0 +1,1117 @@ +// tag::extract[] +[ + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ABQ", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ACV", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "AKL", + "destinationairport": "SFO" + }, + // end::extract[] + // tag::ellipsis[] + // ... + // end::ellipsis[] + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "AMS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_137", + "name": "Air France", + "sourceairport": "ATL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5347", + "name": "Virgin Atlantic Airways", + "sourceairport": "ATL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "ATL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ATL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "ATL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "ATL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_3029", + "name": "JetBlue Airways", + "sourceairport": "AUS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "AUS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "AUS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "BFL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "BOI", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "BOS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "BOS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_3029", + "name": "JetBlue Airways", + "sourceairport": "BOS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "BUR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "BWI", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_137", + "name": "Air France", + "sourceairport": "CDG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "CDG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "CDG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "CEC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "CIC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "CLE", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "CLT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "CLT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "COS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "CUN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "CUN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "CVG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "DAL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "DCA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "DCA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "DEN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2468", + "name": "Frontier Airlines", + "sourceairport": "DEN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "DEN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "DFW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "DFW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "DFW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "DFW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "DTW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_3029", + "name": "JetBlue Airways", + "sourceairport": "DXB", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "EUG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "EWR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "EWR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "FAT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_3029", + "name": "JetBlue Airways", + "sourceairport": "FLL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "FLL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "FLL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "FLL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "FRA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "GDL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "HKG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "HKG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "HKG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "HND", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2688", + "name": "Hawaiian Airlines", + "sourceairport": "HNL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "HNL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "HNL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "IAD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "IAD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "IAH", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ICN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "ICN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "ICN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "IND", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "JFK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_3029", + "name": "JetBlue Airways", + "sourceairport": "JFK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "JFK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "JFK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "JFK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "JFK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "KIX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "KOA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "LAS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2688", + "name": "Hawaiian Airlines", + "sourceairport": "LAS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "LAS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "LAS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "LAX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "LAX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "LAX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "LAX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "LAX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "LAX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_3029", + "name": "JetBlue Airways", + "sourceairport": "LGB", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5347", + "name": "Virgin Atlantic Airways", + "sourceairport": "LHR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "LHR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "LHR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "LHR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1355", + "name": "British Airways", + "sourceairport": "LHR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "LIH", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "LMT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "MCI", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MCI", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "MCO", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MCO", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "MDW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "MDW", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MEX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "MEX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MFR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "MIA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "MIA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "MKE", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "MKE", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MOD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MRY", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4356", + "name": "Sun Country Airlines", + "sourceairport": "MSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "MSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_137", + "name": "Air France", + "sourceairport": "MSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MSY", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "MUC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "NRT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "OGG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "OKC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ONT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "ORD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ORD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "ORD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "ORD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "OTH", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PDX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "PDX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "PDX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "PEK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PEK", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "PHL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "PHL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "PHL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PHL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "PHX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "PHX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "PHX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PHX", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PIT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PSC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "PSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "PSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PSP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PVG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "PVG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "PVR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "PVR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "PVR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "RDD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "RDM", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "RDU", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "RDU", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "RNO", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SAL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "SAL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SAN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "SAN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "SAN", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SAT", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SBA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SBP", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "SEA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_24", + "name": "American Airlines", + "sourceairport": "SEA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "SEA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SEA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SJD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5331", + "name": "Virgin America", + "sourceairport": "SJD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SLC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "SLC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SMF", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_4547", + "name": "Southwest Airlines", + "sourceairport": "SNA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SNA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_1316", + "name": "AirTran Airways", + "sourceairport": "SNA", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "STL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "SYD", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_2009", + "name": "Delta Air Lines", + "sourceairport": "TPE", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5265", + "name": "US Airways", + "sourceairport": "TPE", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "TPE", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "TUS", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "YEG", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "YUL", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "YVR", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "YYC", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "YYJ", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "YYZ", + "destinationairport": "SFO" + }, + { + "airlineid": "airline_5209", + "name": "United Airlines", + "sourceairport": "ZRH", + "destinationairport": "SFO" + } +] diff --git a/modules/n1ql/examples/select/ansi-join-lateral.n1ql b/modules/n1ql/examples/select/ansi-join-lateral.n1ql new file mode 100644 index 000000000..e4c9d34bf --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-lateral.n1ql @@ -0,0 +1,9 @@ +SELECT route.airlineid, airline.name, route.sourceairport, route.destinationairport +FROM route JOIN LATERAL ( + SELECT airline1.name + FROM airline airline1 + WHERE route.airlineid = META(airline1).id +) AS airline +ON true +WHERE route.destinationairport = "SFO" +ORDER BY route.sourceairport; diff --git a/modules/n1ql/examples/select/ansi-join-left.jsonc b/modules/n1ql/examples/select/ansi-join-left.jsonc new file mode 100644 index 000000000..643eb7b8f --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-left.jsonc @@ -0,0 +1,22 @@ +[ + { + "Airport__Name": "Abbeville", + "Airport__Time": "Europe/Paris", + "Landmark_Name": null // <.> + }, + { + "Airport__Name": "Aberdeen Regional Airport", + "Airport__Time": "America/Chicago", + "Landmark_Name": null + }, + { + "Airport__Name": "Abilene Rgnl", + "Airport__Time": "America/Chicago", + "Landmark_Name": null + }, + { + "Airport__Name": "Abraham Lincoln Capital", + "Airport__Time": "America/Chicago", + "Landmark_Name": null + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-left.n1ql b/modules/n1ql/examples/select/ansi-join-left.n1ql new file mode 100644 index 000000000..c2d6c0901 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-left.n1ql @@ -0,0 +1,10 @@ +SELECT DISTINCT MIN(aport.airportname) AS Airport__Name, + MIN(aport.tz) AS Airport__Time, + MIN(lmark.name) AS Landmark_Name +FROM airport aport -- <.> +LEFT JOIN landmark lmark -- <.> + ON aport.city = lmark.city + AND lmark.country = "United States" +GROUP BY aport.airportname +ORDER BY aport.airportname +LIMIT 4; diff --git a/modules/n1ql/examples/select/ansi-join-right.jsonc b/modules/n1ql/examples/select/ansi-join-right.jsonc new file mode 100644 index 000000000..5b0a96580 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-right.jsonc @@ -0,0 +1,22 @@ +[ + { + "Airport__Name": "San Francisco Intl", + "Airport__Time": "America/Los_Angeles", + "Landmark_Name": ""Hippie Temptation" house" + }, + { + "Airport__Name": null, // <.> + "Airport__Time": null, + "Landmark_Name": "'The Argyll Arms Hotel" + }, + { + "Airport__Name": null, + "Airport__Time": null, + "Landmark_Name": "'Visit the Hut of the Shadows and other End of the Road sculptures" + }, + { + "Airport__Name": "London-Corbin Airport-MaGee Field", + "Airport__Time": "America/New_York", + "Landmark_Name": "02 Shepherd's Bush Empire" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-right.n1ql b/modules/n1ql/examples/select/ansi-join-right.n1ql new file mode 100644 index 000000000..b4f87ea52 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-right.n1ql @@ -0,0 +1,10 @@ +SELECT DISTINCT MIN(aport.airportname) AS Airport__Name, + MIN(aport.tz) AS Airport__Time, + MIN(lmark.name) AS Landmark_Name, +FROM airport aport -- <.> +RIGHT JOIN landmark lmark -- <.> + ON aport.city = lmark.city + AND aport.country = "United States" +GROUP BY lmark.name +ORDER BY lmark.name +LIMIT 4; \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-sub.jsonc b/modules/n1ql/examples/select/ansi-join-sub.jsonc new file mode 100644 index 000000000..c628f1bb8 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-sub.jsonc @@ -0,0 +1,319 @@ +// tag::extract[] +[ + { + "destinationairport": "HKG" + }, + { + "destinationairport": "ICN" + }, + { + "destinationairport": "ATL" + }, + { + "destinationairport": "BJX" + }, + { + "destinationairport": "GDL" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "destinationairport": "MEX" + }, + { + "destinationairport": "MLM" + }, + { + "destinationairport": "PVR" + }, + { + "destinationairport": "SJD" + }, + { + "destinationairport": "DFW" + }, + { + "destinationairport": "JFK" + }, + { + "destinationairport": "LAX" + }, + { + "destinationairport": "MIA" + }, + { + "destinationairport": "ORD" + }, + { + "destinationairport": "PDX" + }, + { + "destinationairport": "PSP" + }, + { + "destinationairport": "SEA" + }, + { + "destinationairport": "SAL" + }, + { + "destinationairport": "LHR" + }, + { + "destinationairport": "CDG" + }, + { + "destinationairport": "AUS" + }, + { + "destinationairport": "BOS" + }, + { + "destinationairport": "DXB" + }, + { + "destinationairport": "FLL" + }, + { + "destinationairport": "LGB" + }, + { + "destinationairport": "TPE" + }, + { + "destinationairport": "PEK" + }, + { + "destinationairport": "PVG" + }, + { + "destinationairport": "AMS" + }, + { + "destinationairport": "CVG" + }, + { + "destinationairport": "DTW" + }, + { + "destinationairport": "HNL" + }, + { + "destinationairport": "MSP" + }, + { + "destinationairport": "SLC" + }, + { + "destinationairport": "DUB" + }, + { + "destinationairport": "DEN" + }, + { + "destinationairport": "MDW" + }, + { + "destinationairport": "MKE" + }, + { + "destinationairport": "ORF" + }, + { + "destinationairport": "LAS" + }, + { + "destinationairport": "HND" + }, + { + "destinationairport": "FRA" + }, + { + "destinationairport": "MUC" + }, + { + "destinationairport": "ZRH" + }, + { + "destinationairport": "KIX" + }, + { + "destinationairport": "NRT" + }, + { + "destinationairport": "AKL" + }, + { + "destinationairport": "SYD" + }, + { + "destinationairport": "MNL" + }, + { + "destinationairport": "CPH" + }, + { + "destinationairport": "ABQ" + }, + { + "destinationairport": "ACV" + }, + { + "destinationairport": "BFL" + }, + { + "destinationairport": "BOI" + }, + { + "destinationairport": "BUR" + }, + { + "destinationairport": "BWI" + }, + { + "destinationairport": "CEC" + }, + { + "destinationairport": "CIC" + }, + { + "destinationairport": "CLE" + }, + { + "destinationairport": "COS" + }, + { + "destinationairport": "CUN" + }, + { + "destinationairport": "DCA" + }, + { + "destinationairport": "EUG" + }, + { + "destinationairport": "EWR" + }, + { + "destinationairport": "FAT" + }, + { + "destinationairport": "IAD" + }, + { + "destinationairport": "IAH" + }, + { + "destinationairport": "IND" + }, + { + "destinationairport": "KOA" + }, + { + "destinationairport": "LIH" + }, + { + "destinationairport": "LMT" + }, + { + "destinationairport": "MCI" + }, + { + "destinationairport": "MCO" + }, + { + "destinationairport": "MFR" + }, + { + "destinationairport": "MOD" + }, + { + "destinationairport": "MRY" + }, + { + "destinationairport": "MSY" + }, + { + "destinationairport": "OGG" + }, + { + "destinationairport": "OKC" + }, + { + "destinationairport": "ONT" + }, + { + "destinationairport": "OTH" + }, + { + "destinationairport": "PHL" + }, + { + "destinationairport": "PHX" + }, + { + "destinationairport": "PIT" + }, + { + "destinationairport": "PSC" + }, + { + "destinationairport": "RDD" + }, + { + "destinationairport": "RDM" + }, + { + "destinationairport": "RDU" + }, + { + "destinationairport": "RNO" + }, + { + "destinationairport": "SAN" + }, + { + "destinationairport": "SAT" + }, + { + "destinationairport": "SBA" + }, + { + "destinationairport": "SBP" + }, + { + "destinationairport": "SMF" + }, + { + "destinationairport": "SNA" + }, + { + "destinationairport": "STL" + }, + { + "destinationairport": "TUS" + }, + { + "destinationairport": "YEG" + }, + { + "destinationairport": "YUL" + }, + { + "destinationairport": "YVR" + }, + { + "destinationairport": "YYC" + }, + { + "destinationairport": "YYJ" + }, + { + "destinationairport": "YYZ" + }, + { + "destinationairport": "CLT" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-join-sub.n1ql b/modules/n1ql/examples/select/ansi-join-sub.n1ql new file mode 100644 index 000000000..46b4450bf --- /dev/null +++ b/modules/n1ql/examples/select/ansi-join-sub.n1ql @@ -0,0 +1,8 @@ +SELECT DISTINCT subquery.destinationairport +FROM airport +JOIN ( + SELECT destinationairport, sourceairport + FROM route +) AS subquery +ON airport.faa = subquery.sourceairport +WHERE airport.city = "San Francisco"; \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-nest-inner.jsonc b/modules/n1ql/examples/select/ansi-nest-inner.jsonc new file mode 100644 index 000000000..5fa6b7e2c --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest-inner.jsonc @@ -0,0 +1,8614 @@ +// tag::extract[] +[ + { + "a": { + "airportname": "Blagnac", + "city": "Toulouse", + "country": "France", + "faa": "TLS", + "geo": { + "alt": 499, + "lat": 43.629075, + "lon": 1.363819 + }, + "icao": "LFBO", + "id": 1273, + "type": "airport", + "tz": "Europe/Paris" + }, + "r": [ + { + "airline": "AH", + "airlineid": "airline_794", + "destinationairport": "ALG", + "distance": 787.299015326995, + "equipment": "736", + "id": 10265, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "schedule": [ + { + "day": 0, + "flight": "AH221", + "utc": "17:23:00" + }, + { + "day": 1, + "flight": "AH920", + "utc": "07:44:00" + }, + { + "day": 1, + "flight": "AH593", + "utc": "12:04:00" + }, + { + "day": 1, + "flight": "AH394", + "utc": "00:33:00" + }, + { + "day": 1, + "flight": "AH180", + "utc": "20:18:00" + }, + { + "day": 2, + "flight": "AH974", + "utc": "01:21:00" + }, + { + "day": 3, + "flight": "AH281", + "utc": "09:34:00" + }, + { + "day": 3, + "flight": "AH033", + "utc": "11:02:00" + }, + { + "day": 3, + "flight": "AH385", + "utc": "11:42:00" + }, + { + "day": 3, + "flight": "AH989", + "utc": "09:07:00" + }, + { + "day": 3, + "flight": "AH834", + "utc": "18:46:00" + }, + { + "day": 4, + "flight": "AH417", + "utc": "05:17:00" + }, + { + "day": 4, + "flight": "AH322", + "utc": "11:10:00" + }, + { + "day": 4, + "flight": "AH235", + "utc": "18:43:00" + }, + { + "day": 4, + "flight": "AH995", + "utc": "00:15:00" + }, + { + "day": 4, + "flight": "AH619", + "utc": "08:43:00" + }, + { + "day": 5, + "flight": "AH537", + "utc": "03:48:00" + }, + { + "day": 5, + "flight": "AH181", + "utc": "11:23:00" + }, + { + "day": 5, + "flight": "AH083", + "utc": "12:37:00" + }, + { + "day": 5, + "flight": "AH727", + "utc": "12:08:00" + }, + { + "day": 6, + "flight": "AH377", + "utc": "13:15:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" +// tag::extract[] + }, + { + "airline": "AH", + "airlineid": "airline_794", + "destinationairport": "ORN", + "distance": 906.1483088609814, + "equipment": "736", + "id": 10266, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "schedule": [ + { + "day": 0, + "flight": "AH152", + "utc": "14:02:00" + }, + { + "day": 0, + "flight": "AH864", + "utc": "11:48:00" + }, + { + "day": 0, + "flight": "AH922", + "utc": "11:03:00" + }, + { + "day": 1, + "flight": "AH633", + "utc": "13:22:00" + }, + { + "day": 1, + "flight": "AH450", + "utc": "05:32:00" + }, + { + "day": 1, + "flight": "AH343", + "utc": "05:17:00" + }, + { + "day": 2, + "flight": "AH869", + "utc": "17:26:00" + }, + { + "day": 2, + "flight": "AH175", + "utc": "13:56:00" + }, + { + "day": 3, + "flight": "AH243", + "utc": "22:54:00" + }, + { + "day": 3, + "flight": "AH778", + "utc": "09:53:00" + }, + { + "day": 3, + "flight": "AH049", + "utc": "02:20:00" + }, + { + "day": 3, + "flight": "AH930", + "utc": "05:40:00" + }, + { + "day": 3, + "flight": "AH206", + "utc": "10:03:00" + }, + { + "day": 4, + "flight": "AH125", + "utc": "16:15:00" + }, + { + "day": 4, + "flight": "AH533", + "utc": "10:50:00" + }, + { + "day": 4, + "flight": "AH494", + "utc": "10:36:00" + }, + { + "day": 4, + "flight": "AH759", + "utc": "17:10:00" + }, + { + "day": 5, + "flight": "AH267", + "utc": "22:16:00" + }, + { + "day": 5, + "flight": "AH769", + "utc": "09:13:00" + }, + { + "day": 5, + "flight": "AH116", + "utc": "09:19:00" + }, + { + "day": 5, + "flight": "AH949", + "utc": "02:28:00" + }, + { + "day": 5, + "flight": "AH624", + "utc": "03:51:00" + }, + { + "day": 6, + "flight": "AH597", + "utc": "02:23:00" + }, + { + "day": 6, + "flight": "AH523", + "utc": "05:32:00" + }, + { + "day": 6, + "flight": "AH615", + "utc": "00:19:00" + }, + { + "day": 6, + "flight": "AH453", + "utc": "19:08:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AT", + "airlineid": "airline_4248", + "destinationairport": "CMN", + "distance": 1379.8271930529227, + "equipment": "738 73G", + "id": 12271, + "schedule": [ + { + "day": 0, + "flight": "AT780", + "utc": "17:23:00" + }, + { + "day": 0, + "flight": "AT069", + "utc": "00:25:00" + }, + { + "day": 0, + "flight": "AT970", + "utc": "10:57:00" + }, + { + "day": 1, + "flight": "AT716", + "utc": "05:22:00" + }, + { + "day": 1, + "flight": "AT424", + "utc": "02:09:00" + }, + { + "day": 1, + "flight": "AT498", + "utc": "00:54:00" + }, + { + "day": 1, + "flight": "AT552", + "utc": "19:13:00" + }, + { + "day": 1, + "flight": "AT967", + "utc": "05:05:00" + }, + { + "day": 2, + "flight": "AT640", + "utc": "17:24:00" + }, + { + "day": 2, + "flight": "AT877", + "utc": "04:34:00" + }, + { + "day": 2, + "flight": "AT439", + "utc": "12:48:00" + }, + { + "day": 3, + "flight": "AT447", + "utc": "06:27:00" + }, + { + "day": 3, + "flight": "AT882", + "utc": "10:53:00" + }, + { + "day": 3, + "flight": "AT548", + "utc": "08:29:00" + }, + { + "day": 3, + "flight": "AT489", + "utc": "10:37:00" + }, + { + "day": 3, + "flight": "AT611", + "utc": "14:16:00" + }, + { + "day": 4, + "flight": "AT539", + "utc": "19:59:00" + }, + { + "day": 4, + "flight": "AT570", + "utc": "03:23:00" + }, + { + "day": 4, + "flight": "AT350", + "utc": "15:03:00" + }, + { + "day": 4, + "flight": "AT899", + "utc": "08:00:00" + }, + { + "day": 4, + "flight": "AT909", + "utc": "16:53:00" + }, + { + "day": 5, + "flight": "AT985", + "utc": "21:31:00" + }, + { + "day": 5, + "flight": "AT617", + "utc": "16:28:00" + }, + { + "day": 5, + "flight": "AT745", + "utc": "19:02:00" + }, + { + "day": 6, + "flight": "AT015", + "utc": "10:04:00" + }, + { + "day": 6, + "flight": "AT270", + "utc": "03:19:00" + }, + { + "day": 6, + "flight": "AT975", + "utc": "04:16:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AT", + "airlineid": "airline_4248", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "738", + "id": 12272, + "schedule": [ + { + "day": 0, + "flight": "AT223", + "utc": "10:06:00" + }, + { + "day": 1, + "flight": "AT187", + "utc": "20:12:00" + }, + { + "day": 2, + "flight": "AT379", + "utc": "14:45:00" + }, + { + "day": 2, + "flight": "AT950", + "utc": "08:07:00" + }, + { + "day": 2, + "flight": "AT921", + "utc": "22:15:00" + }, + { + "day": 2, + "flight": "AT122", + "utc": "06:39:00" + }, + { + "day": 3, + "flight": "AT413", + "utc": "21:46:00" + }, + { + "day": 3, + "flight": "AT974", + "utc": "13:14:00" + }, + { + "day": 3, + "flight": "AT805", + "utc": "22:18:00" + }, + { + "day": 3, + "flight": "AT558", + "utc": "15:35:00" + }, + { + "day": 4, + "flight": "AT919", + "utc": "11:11:00" + }, + { + "day": 4, + "flight": "AT380", + "utc": "14:20:00" + }, + { + "day": 4, + "flight": "AT588", + "utc": "12:03:00" + }, + { + "day": 4, + "flight": "AT762", + "utc": "16:07:00" + }, + { + "day": 5, + "flight": "AT423", + "utc": "12:28:00" + }, + { + "day": 6, + "flight": "AT554", + "utc": "15:05:00" + }, + { + "day": 6, + "flight": "AT145", + "utc": "07:36:00" + }, + { + "day": 6, + "flight": "AT179", + "utc": "05:51:00" + }, + { + "day": 6, + "flight": "AT460", + "utc": "02:34:00" + }, + { + "day": 6, + "flight": "AT648", + "utc": "16:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "320 319", + "id": 13715, + "schedule": [ + { + "day": 0, + "flight": "AZ503", + "utc": "10:59:00" + }, + { + "day": 0, + "flight": "AZ608", + "utc": "02:25:00" + }, + { + "day": 1, + "flight": "AZ013", + "utc": "21:09:00" + }, + { + "day": 1, + "flight": "AZ108", + "utc": "22:36:00" + }, + { + "day": 1, + "flight": "AZ730", + "utc": "17:38:00" + }, + { + "day": 2, + "flight": "AZ527", + "utc": "17:39:00" + }, + { + "day": 2, + "flight": "AZ506", + "utc": "21:44:00" + }, + { + "day": 2, + "flight": "AZ072", + "utc": "10:12:00" + }, + { + "day": 2, + "flight": "AZ661", + "utc": "21:42:00" + }, + { + "day": 3, + "flight": "AZ873", + "utc": "16:32:00" + }, + { + "day": 3, + "flight": "AZ005", + "utc": "18:21:00" + }, + { + "day": 3, + "flight": "AZ573", + "utc": "17:58:00" + }, + { + "day": 4, + "flight": "AZ318", + "utc": "10:20:00" + }, + { + "day": 4, + "flight": "AZ537", + "utc": "13:33:00" + }, + { + "day": 4, + "flight": "AZ187", + "utc": "14:18:00" + }, + { + "day": 4, + "flight": "AZ590", + "utc": "12:28:00" + }, + { + "day": 5, + "flight": "AZ997", + "utc": "22:03:00" + }, + { + "day": 6, + "flight": "AZ915", + "utc": "21:20:00" + }, + { + "day": 6, + "flight": "AZ927", + "utc": "17:48:00" + }, + { + "day": 6, + "flight": "AZ073", + "utc": "05:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "E75", + "id": 13716, + "schedule": [ + { + "day": 0, + "flight": "AZ121", + "utc": "02:19:00" + }, + { + "day": 0, + "flight": "AZ997", + "utc": "02:46:00" + }, + { + "day": 1, + "flight": "AZ068", + "utc": "15:00:00" + }, + { + "day": 1, + "flight": "AZ873", + "utc": "01:54:00" + }, + { + "day": 1, + "flight": "AZ441", + "utc": "06:02:00" + }, + { + "day": 1, + "flight": "AZ942", + "utc": "01:37:00" + }, + { + "day": 1, + "flight": "AZ399", + "utc": "20:15:00" + }, + { + "day": 2, + "flight": "AZ471", + "utc": "05:47:00" + }, + { + "day": 3, + "flight": "AZ641", + "utc": "09:17:00" + }, + { + "day": 3, + "flight": "AZ994", + "utc": "21:28:00" + }, + { + "day": 3, + "flight": "AZ237", + "utc": "04:09:00" + }, + { + "day": 3, + "flight": "AZ294", + "utc": "03:44:00" + }, + { + "day": 3, + "flight": "AZ683", + "utc": "20:27:00" + }, + { + "day": 4, + "flight": "AZ925", + "utc": "02:55:00" + }, + { + "day": 4, + "flight": "AZ713", + "utc": "14:45:00" + }, + { + "day": 5, + "flight": "AZ414", + "utc": "10:11:00" + }, + { + "day": 5, + "flight": "AZ163", + "utc": "07:30:00" + }, + { + "day": 5, + "flight": "AZ413", + "utc": "21:23:00" + }, + { + "day": 5, + "flight": "AZ535", + "utc": "04:02:00" + }, + { + "day": 5, + "flight": "AZ119", + "utc": "21:16:00" + }, + { + "day": 6, + "flight": "AZ610", + "utc": "12:40:00" + }, + { + "day": 6, + "flight": "AZ694", + "utc": "03:10:00" + }, + { + "day": 6, + "flight": "AZ190", + "utc": "12:47:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319 320 CRK", + "id": 13717, + "schedule": [ + { + "day": 0, + "flight": "AZ226", + "utc": "06:27:00" + }, + { + "day": 0, + "flight": "AZ102", + "utc": "15:40:00" + }, + { + "day": 0, + "flight": "AZ366", + "utc": "05:31:00" + }, + { + "day": 0, + "flight": "AZ469", + "utc": "23:10:00" + }, + { + "day": 0, + "flight": "AZ910", + "utc": "05:39:00" + }, + { + "day": 1, + "flight": "AZ643", + "utc": "13:50:00" + }, + { + "day": 1, + "flight": "AZ897", + "utc": "15:10:00" + }, + { + "day": 1, + "flight": "AZ167", + "utc": "15:00:00" + }, + { + "day": 1, + "flight": "AZ427", + "utc": "10:23:00" + }, + { + "day": 2, + "flight": "AZ472", + "utc": "07:02:00" + }, + { + "day": 3, + "flight": "AZ887", + "utc": "13:57:00" + }, + { + "day": 3, + "flight": "AZ694", + "utc": "20:32:00" + }, + { + "day": 3, + "flight": "AZ781", + "utc": "00:51:00" + }, + { + "day": 3, + "flight": "AZ633", + "utc": "22:00:00" + }, + { + "day": 4, + "flight": "AZ346", + "utc": "21:27:00" + }, + { + "day": 4, + "flight": "AZ570", + "utc": "15:59:00" + }, + { + "day": 4, + "flight": "AZ395", + "utc": "20:42:00" + }, + { + "day": 4, + "flight": "AZ009", + "utc": "15:01:00" + }, + { + "day": 4, + "flight": "AZ097", + "utc": "19:04:00" + }, + { + "day": 5, + "flight": "AZ363", + "utc": "01:15:00" + }, + { + "day": 5, + "flight": "AZ513", + "utc": "23:55:00" + }, + { + "day": 5, + "flight": "AZ311", + "utc": "10:51:00" + }, + { + "day": 5, + "flight": "AZ374", + "utc": "23:22:00" + }, + { + "day": 6, + "flight": "AZ027", + "utc": "10:27:00" + }, + { + "day": 6, + "flight": "AZ782", + "utc": "23:04:00" + }, + { + "day": 6, + "flight": "AZ869", + "utc": "01:27:00" + }, + { + "day": 6, + "flight": "AZ117", + "utc": "09:01:00" + }, + { + "day": 6, + "flight": "AZ365", + "utc": "11:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "VCE", + "distance": 894.3253403650848, + "equipment": "319 320", + "id": 13718, + "schedule": [ + { + "day": 0, + "flight": "AZ323", + "utc": "21:01:00" + }, + { + "day": 0, + "flight": "AZ639", + "utc": "06:08:00" + }, + { + "day": 0, + "flight": "AZ751", + "utc": "09:17:00" + }, + { + "day": 0, + "flight": "AZ418", + "utc": "10:51:00" + }, + { + "day": 0, + "flight": "AZ293", + "utc": "09:42:00" + }, + { + "day": 1, + "flight": "AZ294", + "utc": "11:55:00" + }, + { + "day": 1, + "flight": "AZ618", + "utc": "04:56:00" + }, + { + "day": 1, + "flight": "AZ919", + "utc": "00:38:00" + }, + { + "day": 2, + "flight": "AZ839", + "utc": "17:52:00" + }, + { + "day": 2, + "flight": "AZ252", + "utc": "23:45:00" + }, + { + "day": 3, + "flight": "AZ477", + "utc": "00:11:00" + }, + { + "day": 4, + "flight": "AZ903", + "utc": "15:47:00" + }, + { + "day": 4, + "flight": "AZ933", + "utc": "23:28:00" + }, + { + "day": 4, + "flight": "AZ320", + "utc": "18:22:00" + }, + { + "day": 4, + "flight": "AZ866", + "utc": "04:11:00" + }, + { + "day": 5, + "flight": "AZ877", + "utc": "21:44:00" + }, + { + "day": 5, + "flight": "AZ810", + "utc": "06:51:00" + }, + { + "day": 6, + "flight": "AZ910", + "utc": "12:05:00" + }, + { + "day": 6, + "flight": "AZ341", + "utc": "10:32:00" + }, + { + "day": 6, + "flight": "AZ544", + "utc": "18:04:00" + }, + { + "day": 6, + "flight": "AZ780", + "utc": "10:21:00" + }, + { + "day": 6, + "flight": "AZ392", + "utc": "07:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "BA", + "airlineid": "airline_1355", + "destinationairport": "LHR", + "distance": 883.3122325423356, + "equipment": "320 319 321", + "id": 14913, + "schedule": [ + { + "day": 0, + "flight": "BA098", + "utc": "11:01:00" + }, + { + "day": 0, + "flight": "BA391", + "utc": "05:10:00" + }, + { + "day": 0, + "flight": "BA960", + "utc": "22:58:00" + }, + { + "day": 1, + "flight": "BA681", + "utc": "10:42:00" + }, + { + "day": 1, + "flight": "BA255", + "utc": "14:13:00" + }, + { + "day": 1, + "flight": "BA715", + "utc": "02:32:00" + }, + { + "day": 1, + "flight": "BA860", + "utc": "13:23:00" + }, + { + "day": 1, + "flight": "BA241", + "utc": "12:27:00" + }, + { + "day": 2, + "flight": "BA737", + "utc": "18:30:00" + }, + { + "day": 2, + "flight": "BA602", + "utc": "15:35:00" + }, + { + "day": 2, + "flight": "BA709", + "utc": "12:21:00" + }, + { + "day": 2, + "flight": "BA796", + "utc": "11:08:00" + }, + { + "day": 2, + "flight": "BA067", + "utc": "00:28:00" + }, + { + "day": 3, + "flight": "BA111", + "utc": "00:08:00" + }, + { + "day": 3, + "flight": "BA920", + "utc": "14:33:00" + }, + { + "day": 3, + "flight": "BA469", + "utc": "18:09:00" + }, + { + "day": 3, + "flight": "BA122", + "utc": "05:40:00" + }, + { + "day": 3, + "flight": "BA194", + "utc": "11:45:00" + }, + { + "day": 4, + "flight": "BA481", + "utc": "19:41:00" + }, + { + "day": 4, + "flight": "BA430", + "utc": "01:39:00" + }, + { + "day": 4, + "flight": "BA439", + "utc": "07:02:00" + }, + { + "day": 5, + "flight": "BA287", + "utc": "08:08:00" + }, + { + "day": 5, + "flight": "BA097", + "utc": "04:45:00" + }, + { + "day": 6, + "flight": "BA177", + "utc": "00:26:00" + }, + { + "day": 6, + "flight": "BA703", + "utc": "23:45:00" + }, + { + "day": 6, + "flight": "BA326", + "utc": "15:49:00" + }, + { + "day": 6, + "flight": "BA238", + "utc": "23:31:00" + }, + { + "day": 6, + "flight": "BA717", + "utc": "07:18:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "4U", + "airlineid": "airline_2548", + "destinationairport": "HAM", + "distance": 1277.920368466386, + "equipment": "CRJ", + "id": 1638, + "schedule": [ + { + "day": 0, + "flight": "4U997", + "utc": "03:46:00" + }, + { + "day": 1, + "flight": "4U464", + "utc": "15:51:00" + }, + { + "day": 1, + "flight": "4U823", + "utc": "01:54:00" + }, + { + "day": 2, + "flight": "4U060", + "utc": "01:28:00" + }, + { + "day": 2, + "flight": "4U489", + "utc": "08:26:00" + }, + { + "day": 2, + "flight": "4U835", + "utc": "15:04:00" + }, + { + "day": 2, + "flight": "4U267", + "utc": "23:16:00" + }, + { + "day": 3, + "flight": "4U085", + "utc": "22:10:00" + }, + { + "day": 3, + "flight": "4U835", + "utc": "11:52:00" + }, + { + "day": 3, + "flight": "4U688", + "utc": "09:26:00" + }, + { + "day": 4, + "flight": "4U808", + "utc": "20:34:00" + }, + { + "day": 4, + "flight": "4U408", + "utc": "10:31:00" + }, + { + "day": 4, + "flight": "4U614", + "utc": "11:22:00" + }, + { + "day": 4, + "flight": "4U093", + "utc": "17:56:00" + }, + { + "day": 4, + "flight": "4U664", + "utc": "03:06:00" + }, + { + "day": 5, + "flight": "4U030", + "utc": "13:04:00" + }, + { + "day": 6, + "flight": "4U771", + "utc": "08:13:00" + }, + { + "day": 6, + "flight": "4U198", + "utc": "20:11:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "EI", + "airlineid": "airline_837", + "destinationairport": "DUB", + "distance": 1223.7865232537742, + "equipment": "320", + "id": 23056, + "schedule": [ + { + "day": 0, + "flight": "EI370", + "utc": "11:48:00" + }, + { + "day": 1, + "flight": "EI137", + "utc": "16:37:00" + }, + { + "day": 1, + "flight": "EI052", + "utc": "11:06:00" + }, + { + "day": 1, + "flight": "EI383", + "utc": "14:12:00" + }, + { + "day": 2, + "flight": "EI657", + "utc": "11:49:00" + }, + { + "day": 2, + "flight": "EI394", + "utc": "04:10:00" + }, + { + "day": 2, + "flight": "EI000", + "utc": "01:50:00" + }, + { + "day": 2, + "flight": "EI475", + "utc": "06:36:00" + }, + { + "day": 2, + "flight": "EI292", + "utc": "12:49:00" + }, + { + "day": 3, + "flight": "EI262", + "utc": "05:57:00" + }, + { + "day": 3, + "flight": "EI355", + "utc": "08:00:00" + }, + { + "day": 3, + "flight": "EI831", + "utc": "13:22:00" + }, + { + "day": 3, + "flight": "EI812", + "utc": "12:43:00" + }, + { + "day": 3, + "flight": "EI228", + "utc": "08:51:00" + }, + { + "day": 4, + "flight": "EI446", + "utc": "04:33:00" + }, + { + "day": 4, + "flight": "EI823", + "utc": "11:38:00" + }, + { + "day": 4, + "flight": "EI880", + "utc": "07:11:00" + }, + { + "day": 4, + "flight": "EI483", + "utc": "18:05:00" + }, + { + "day": 5, + "flight": "EI989", + "utc": "05:58:00" + }, + { + "day": 5, + "flight": "EI395", + "utc": "07:41:00" + }, + { + "day": 5, + "flight": "EI362", + "utc": "04:45:00" + }, + { + "day": 5, + "flight": "EI749", + "utc": "16:24:00" + }, + { + "day": 5, + "flight": "EI146", + "utc": "07:57:00" + }, + { + "day": 6, + "flight": "EI249", + "utc": "06:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ET", + "airlineid": "airline_2220", + "destinationairport": "FRA", + "distance": 895.9770471097812, + "equipment": "735", + "id": 23940, + "schedule": [ + { + "day": 0, + "flight": "ET478", + "utc": "13:07:00" + }, + { + "day": 0, + "flight": "ET739", + "utc": "11:40:00" + }, + { + "day": 0, + "flight": "ET520", + "utc": "10:18:00" + }, + { + "day": 1, + "flight": "ET223", + "utc": "07:18:00" + }, + { + "day": 2, + "flight": "ET473", + "utc": "02:16:00" + }, + { + "day": 3, + "flight": "ET341", + "utc": "11:18:00" + }, + { + "day": 3, + "flight": "ET928", + "utc": "05:33:00" + }, + { + "day": 3, + "flight": "ET563", + "utc": "06:17:00" + }, + { + "day": 3, + "flight": "ET107", + "utc": "23:11:00" + }, + { + "day": 4, + "flight": "ET204", + "utc": "22:10:00" + }, + { + "day": 4, + "flight": "ET428", + "utc": "12:06:00" + }, + { + "day": 4, + "flight": "ET246", + "utc": "18:11:00" + }, + { + "day": 5, + "flight": "ET964", + "utc": "02:06:00" + }, + { + "day": 5, + "flight": "ET452", + "utc": "02:36:00" + }, + { + "day": 5, + "flight": "ET362", + "utc": "00:43:00" + }, + { + "day": 5, + "flight": "ET098", + "utc": "02:52:00" + }, + { + "day": 6, + "flight": "ET378", + "utc": "11:31:00" + }, + { + "day": 6, + "flight": "ET541", + "utc": "03:24:00" + }, + { + "day": 6, + "flight": "ET010", + "utc": "05:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "F7", + "airlineid": "airline_2420", + "destinationairport": "GVA", + "distance": 472.80826589600406, + "equipment": "AT7", + "id": 24308, + "schedule": [ + { + "day": 0, + "flight": "F7903", + "utc": "21:43:00" + }, + { + "day": 0, + "flight": "F7859", + "utc": "02:36:00" + }, + { + "day": 1, + "flight": "F7360", + "utc": "18:52:00" + }, + { + "day": 1, + "flight": "F7401", + "utc": "04:33:00" + }, + { + "day": 2, + "flight": "F7127", + "utc": "02:17:00" + }, + { + "day": 2, + "flight": "F7772", + "utc": "06:20:00" + }, + { + "day": 2, + "flight": "F7056", + "utc": "04:56:00" + }, + { + "day": 2, + "flight": "F7884", + "utc": "10:25:00" + }, + { + "day": 2, + "flight": "F7191", + "utc": "03:20:00" + }, + { + "day": 3, + "flight": "F7235", + "utc": "16:22:00" + }, + { + "day": 4, + "flight": "F7619", + "utc": "03:09:00" + }, + { + "day": 4, + "flight": "F7421", + "utc": "15:49:00" + }, + { + "day": 4, + "flight": "F7915", + "utc": "18:59:00" + }, + { + "day": 5, + "flight": "F7759", + "utc": "09:56:00" + }, + { + "day": 6, + "flight": "F7515", + "utc": "09:50:00" + }, + { + "day": 6, + "flight": "F7400", + "utc": "00:10:00" + }, + { + "day": 6, + "flight": "F7362", + "utc": "08:47:00" + }, + { + "day": 6, + "flight": "F7098", + "utc": "21:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "AGP", + "distance": 919.3439362090616, + "equipment": "320", + "id": 32956, + "schedule": [ + { + "day": 0, + "flight": "IB587", + "utc": "19:18:00" + }, + { + "day": 1, + "flight": "IB830", + "utc": "07:20:00" + }, + { + "day": 1, + "flight": "IB966", + "utc": "00:13:00" + }, + { + "day": 1, + "flight": "IB923", + "utc": "20:53:00" + }, + { + "day": 1, + "flight": "IB151", + "utc": "01:03:00" + }, + { + "day": 1, + "flight": "IB479", + "utc": "21:56:00" + }, + { + "day": 2, + "flight": "IB950", + "utc": "20:52:00" + }, + { + "day": 3, + "flight": "IB517", + "utc": "01:57:00" + }, + { + "day": 3, + "flight": "IB242", + "utc": "01:46:00" + }, + { + "day": 3, + "flight": "IB875", + "utc": "08:31:00" + }, + { + "day": 4, + "flight": "IB828", + "utc": "09:25:00" + }, + { + "day": 4, + "flight": "IB676", + "utc": "01:32:00" + }, + { + "day": 5, + "flight": "IB943", + "utc": "15:51:00" + }, + { + "day": 6, + "flight": "IB384", + "utc": "22:30:00" + }, + { + "day": 6, + "flight": "IB278", + "utc": "18:51:00" + }, + { + "day": 6, + "flight": "IB511", + "utc": "23:39:00" + }, + { + "day": 6, + "flight": "IB429", + "utc": "18:51:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "BCN", + "distance": 265.8469587104912, + "equipment": "320", + "id": 32957, + "schedule": [ + { + "day": 0, + "flight": "IB518", + "utc": "10:08:00" + }, + { + "day": 1, + "flight": "IB011", + "utc": "18:40:00" + }, + { + "day": 1, + "flight": "IB839", + "utc": "09:11:00" + }, + { + "day": 1, + "flight": "IB767", + "utc": "14:32:00" + }, + { + "day": 2, + "flight": "IB958", + "utc": "17:49:00" + }, + { + "day": 2, + "flight": "IB055", + "utc": "02:06:00" + }, + { + "day": 2, + "flight": "IB718", + "utc": "12:09:00" + }, + { + "day": 2, + "flight": "IB544", + "utc": "19:50:00" + }, + { + "day": 2, + "flight": "IB221", + "utc": "02:53:00" + }, + { + "day": 3, + "flight": "IB596", + "utc": "01:30:00" + }, + { + "day": 3, + "flight": "IB433", + "utc": "21:32:00" + }, + { + "day": 3, + "flight": "IB996", + "utc": "04:23:00" + }, + { + "day": 4, + "flight": "IB575", + "utc": "04:54:00" + }, + { + "day": 4, + "flight": "IB743", + "utc": "16:36:00" + }, + { + "day": 4, + "flight": "IB335", + "utc": "18:23:00" + }, + { + "day": 5, + "flight": "IB775", + "utc": "12:25:00" + }, + { + "day": 5, + "flight": "IB949", + "utc": "19:00:00" + }, + { + "day": 5, + "flight": "IB955", + "utc": "07:08:00" + }, + { + "day": 5, + "flight": "IB309", + "utc": "19:11:00" + }, + { + "day": 6, + "flight": "IB228", + "utc": "18:42:00" + }, + { + "day": 6, + "flight": "IB195", + "utc": "06:02:00" + }, + { + "day": 6, + "flight": "IB721", + "utc": "01:06:00" + }, + { + "day": 6, + "flight": "IB313", + "utc": "05:19:00" + }, + { + "day": 6, + "flight": "IB797", + "utc": "19:35:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "MAD", + "distance": 535.7735390346035, + "equipment": "CRK CR9 CR2", + "id": 32958, + "schedule": [ + { + "day": 0, + "flight": "IB321", + "utc": "19:44:00" + }, + { + "day": 0, + "flight": "IB262", + "utc": "04:50:00" + }, + { + "day": 0, + "flight": "IB266", + "utc": "03:12:00" + }, + { + "day": 1, + "flight": "IB365", + "utc": "00:15:00" + }, + { + "day": 1, + "flight": "IB159", + "utc": "07:14:00" + }, + { + "day": 1, + "flight": "IB507", + "utc": "07:30:00" + }, + { + "day": 1, + "flight": "IB760", + "utc": "21:03:00" + }, + { + "day": 2, + "flight": "IB072", + "utc": "05:28:00" + }, + { + "day": 2, + "flight": "IB707", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "IB101", + "utc": "17:49:00" + }, + { + "day": 3, + "flight": "IB949", + "utc": "06:14:00" + }, + { + "day": 3, + "flight": "IB780", + "utc": "13:13:00" + }, + { + "day": 3, + "flight": "IB675", + "utc": "01:43:00" + }, + { + "day": 3, + "flight": "IB942", + "utc": "11:46:00" + }, + { + "day": 3, + "flight": "IB669", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "IB290", + "utc": "01:53:00" + }, + { + "day": 4, + "flight": "IB587", + "utc": "04:52:00" + }, + { + "day": 4, + "flight": "IB553", + "utc": "23:37:00" + }, + { + "day": 4, + "flight": "IB623", + "utc": "03:23:00" + }, + { + "day": 5, + "flight": "IB667", + "utc": "20:42:00" + }, + { + "day": 6, + "flight": "IB763", + "utc": "11:56:00" + }, + { + "day": 6, + "flight": "IB004", + "utc": "12:38:00" + }, + { + "day": 6, + "flight": "IB606", + "utc": "11:07:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "PMI", + "distance": 467.1315518195575, + "equipment": "320", + "id": 32959, + "schedule": [ + { + "day": 0, + "flight": "IB718", + "utc": "00:29:00" + }, + { + "day": 1, + "flight": "IB529", + "utc": "21:51:00" + }, + { + "day": 1, + "flight": "IB262", + "utc": "18:34:00" + }, + { + "day": 1, + "flight": "IB202", + "utc": "05:59:00" + }, + { + "day": 1, + "flight": "IB428", + "utc": "00:21:00" + }, + { + "day": 1, + "flight": "IB433", + "utc": "13:14:00" + }, + { + "day": 2, + "flight": "IB873", + "utc": "03:44:00" + }, + { + "day": 2, + "flight": "IB588", + "utc": "06:43:00" + }, + { + "day": 2, + "flight": "IB848", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "IB656", + "utc": "08:28:00" + }, + { + "day": 3, + "flight": "IB865", + "utc": "03:25:00" + }, + { + "day": 4, + "flight": "IB322", + "utc": "06:53:00" + }, + { + "day": 5, + "flight": "IB208", + "utc": "16:30:00" + }, + { + "day": 5, + "flight": "IB316", + "utc": "23:39:00" + }, + { + "day": 6, + "flight": "IB038", + "utc": "14:32:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "SVQ", + "distance": 922.9469580316244, + "equipment": "CR2 CR9", + "id": 32960, + "schedule": [ + { + "day": 0, + "flight": "IB226", + "utc": "15:38:00" + }, + { + "day": 1, + "flight": "IB907", + "utc": "20:45:00" + }, + { + "day": 1, + "flight": "IB223", + "utc": "13:32:00" + }, + { + "day": 2, + "flight": "IB285", + "utc": "21:42:00" + }, + { + "day": 2, + "flight": "IB825", + "utc": "11:24:00" + }, + { + "day": 2, + "flight": "IB376", + "utc": "21:47:00" + }, + { + "day": 2, + "flight": "IB239", + "utc": "04:40:00" + }, + { + "day": 2, + "flight": "IB103", + "utc": "19:33:00" + }, + { + "day": 3, + "flight": "IB475", + "utc": "20:31:00" + }, + { + "day": 3, + "flight": "IB732", + "utc": "03:24:00" + }, + { + "day": 3, + "flight": "IB618", + "utc": "02:15:00" + }, + { + "day": 3, + "flight": "IB718", + "utc": "01:24:00" + }, + { + "day": 3, + "flight": "IB258", + "utc": "16:40:00" + }, + { + "day": 4, + "flight": "IB007", + "utc": "06:47:00" + }, + { + "day": 4, + "flight": "IB963", + "utc": "08:06:00" + }, + { + "day": 4, + "flight": "IB695", + "utc": "23:29:00" + }, + { + "day": 4, + "flight": "IB756", + "utc": "22:37:00" + }, + { + "day": 4, + "flight": "IB555", + "utc": "04:34:00" + }, + { + "day": 5, + "flight": "IB480", + "utc": "19:14:00" + }, + { + "day": 5, + "flight": "IB436", + "utc": "15:11:00" + }, + { + "day": 5, + "flight": "IB561", + "utc": "19:43:00" + }, + { + "day": 6, + "flight": "IB324", + "utc": "15:17:00" + }, + { + "day": 6, + "flight": "IB656", + "utc": "17:44:00" + }, + { + "day": 6, + "flight": "IB649", + "utc": "01:49:00" + }, + { + "day": 6, + "flight": "IB616", + "utc": "04:28:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "KL", + "airlineid": "airline_3090", + "destinationairport": "AMS", + "distance": 997.4702942027754, + "equipment": "EMJ", + "id": 36938, + "schedule": [ + { + "day": 0, + "flight": "KL119", + "utc": "23:23:00" + }, + { + "day": 0, + "flight": "KL028", + "utc": "16:25:00" + }, + { + "day": 0, + "flight": "KL388", + "utc": "21:51:00" + }, + { + "day": 1, + "flight": "KL644", + "utc": "14:15:00" + }, + { + "day": 1, + "flight": "KL816", + "utc": "02:49:00" + }, + { + "day": 2, + "flight": "KL713", + "utc": "21:18:00" + }, + { + "day": 2, + "flight": "KL045", + "utc": "03:30:00" + }, + { + "day": 2, + "flight": "KL755", + "utc": "04:12:00" + }, + { + "day": 2, + "flight": "KL554", + "utc": "21:21:00" + }, + { + "day": 2, + "flight": "KL684", + "utc": "17:06:00" + }, + { + "day": 3, + "flight": "KL045", + "utc": "13:12:00" + }, + { + "day": 3, + "flight": "KL002", + "utc": "01:39:00" + }, + { + "day": 4, + "flight": "KL398", + "utc": "07:13:00" + }, + { + "day": 4, + "flight": "KL169", + "utc": "12:16:00" + }, + { + "day": 5, + "flight": "KL548", + "utc": "06:29:00" + }, + { + "day": 5, + "flight": "KL168", + "utc": "13:10:00" + }, + { + "day": 5, + "flight": "KL417", + "utc": "16:25:00" + }, + { + "day": 5, + "flight": "KL656", + "utc": "07:19:00" + }, + { + "day": 5, + "flight": "KL570", + "utc": "04:28:00" + }, + { + "day": 6, + "flight": "KL710", + "utc": "18:57:00" + }, + { + "day": 6, + "flight": "KL453", + "utc": "14:01:00" + }, + { + "day": 6, + "flight": "KL139", + "utc": "09:26:00" + }, + { + "day": 6, + "flight": "KL055", + "utc": "17:53:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LH", + "airlineid": "airline_3320", + "destinationairport": "FRA", + "distance": 895.9770471097812, + "equipment": "321 319 735 733", + "id": 38788, + "schedule": [ + { + "day": 0, + "flight": "LH182", + "utc": "17:57:00" + }, + { + "day": 0, + "flight": "LH378", + "utc": "23:48:00" + }, + { + "day": 0, + "flight": "LH719", + "utc": "04:51:00" + }, + { + "day": 0, + "flight": "LH093", + "utc": "07:33:00" + }, + { + "day": 1, + "flight": "LH478", + "utc": "09:22:00" + }, + { + "day": 1, + "flight": "LH690", + "utc": "17:45:00" + }, + { + "day": 1, + "flight": "LH047", + "utc": "09:16:00" + }, + { + "day": 2, + "flight": "LH452", + "utc": "03:47:00" + }, + { + "day": 3, + "flight": "LH567", + "utc": "11:45:00" + }, + { + "day": 3, + "flight": "LH798", + "utc": "16:08:00" + }, + { + "day": 3, + "flight": "LH960", + "utc": "03:04:00" + }, + { + "day": 4, + "flight": "LH025", + "utc": "08:49:00" + }, + { + "day": 4, + "flight": "LH057", + "utc": "21:14:00" + }, + { + "day": 4, + "flight": "LH531", + "utc": "14:33:00" + }, + { + "day": 4, + "flight": "LH326", + "utc": "03:01:00" + }, + { + "day": 5, + "flight": "LH896", + "utc": "13:43:00" + }, + { + "day": 5, + "flight": "LH430", + "utc": "05:54:00" + }, + { + "day": 5, + "flight": "LH970", + "utc": "04:56:00" + }, + { + "day": 5, + "flight": "LH631", + "utc": "09:26:00" + }, + { + "day": 6, + "flight": "LH333", + "utc": "14:35:00" + }, + { + "day": 6, + "flight": "LH238", + "utc": "16:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LH", + "airlineid": "airline_3320", + "destinationairport": "MUC", + "distance": 960.1175459963162, + "equipment": "E95 319 CR9", + "id": 38789, + "schedule": [ + { + "day": 0, + "flight": "LH106", + "utc": "12:56:00" + }, + { + "day": 0, + "flight": "LH636", + "utc": "05:06:00" + }, + { + "day": 0, + "flight": "LH300", + "utc": "09:20:00" + }, + { + "day": 1, + "flight": "LH996", + "utc": "19:29:00" + }, + { + "day": 1, + "flight": "LH746", + "utc": "10:57:00" + }, + { + "day": 2, + "flight": "LH391", + "utc": "16:36:00" + }, + { + "day": 2, + "flight": "LH079", + "utc": "23:31:00" + }, + { + "day": 2, + "flight": "LH340", + "utc": "10:39:00" + }, + { + "day": 2, + "flight": "LH192", + "utc": "07:48:00" + }, + { + "day": 3, + "flight": "LH563", + "utc": "18:53:00" + }, + { + "day": 3, + "flight": "LH371", + "utc": "08:50:00" + }, + { + "day": 4, + "flight": "LH679", + "utc": "08:56:00" + }, + { + "day": 4, + "flight": "LH078", + "utc": "09:08:00" + }, + { + "day": 4, + "flight": "LH655", + "utc": "14:38:00" + }, + { + "day": 4, + "flight": "LH223", + "utc": "21:54:00" + }, + { + "day": 5, + "flight": "LH253", + "utc": "19:19:00" + }, + { + "day": 5, + "flight": "LH525", + "utc": "15:57:00" + }, + { + "day": 5, + "flight": "LH597", + "utc": "17:13:00" + }, + { + "day": 5, + "flight": "LH315", + "utc": "11:20:00" + }, + { + "day": 6, + "flight": "LH220", + "utc": "03:43:00" + }, + { + "day": 6, + "flight": "LH436", + "utc": "07:44:00" + }, + { + "day": 6, + "flight": "LH405", + "utc": "02:54:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LS", + "airlineid": "airline_3026", + "destinationairport": "MAN", + "distance": 1113.7047637485857, + "equipment": "733", + "id": 39505, + "schedule": [ + { + "day": 0, + "flight": "LS423", + "utc": "10:40:00" + }, + { + "day": 0, + "flight": "LS623", + "utc": "17:06:00" + }, + { + "day": 0, + "flight": "LS249", + "utc": "04:44:00" + }, + { + "day": 1, + "flight": "LS652", + "utc": "21:17:00" + }, + { + "day": 1, + "flight": "LS967", + "utc": "07:51:00" + }, + { + "day": 1, + "flight": "LS903", + "utc": "00:46:00" + }, + { + "day": 1, + "flight": "LS677", + "utc": "05:11:00" + }, + { + "day": 1, + "flight": "LS052", + "utc": "12:41:00" + }, + { + "day": 2, + "flight": "LS007", + "utc": "21:49:00" + }, + { + "day": 2, + "flight": "LS939", + "utc": "23:49:00" + }, + { + "day": 2, + "flight": "LS302", + "utc": "07:34:00" + }, + { + "day": 3, + "flight": "LS621", + "utc": "05:51:00" + }, + { + "day": 4, + "flight": "LS175", + "utc": "02:50:00" + }, + { + "day": 4, + "flight": "LS573", + "utc": "03:49:00" + }, + { + "day": 4, + "flight": "LS528", + "utc": "04:27:00" + }, + { + "day": 4, + "flight": "LS210", + "utc": "19:08:00" + }, + { + "day": 5, + "flight": "LS706", + "utc": "05:35:00" + }, + { + "day": 5, + "flight": "LS663", + "utc": "23:00:00" + }, + { + "day": 5, + "flight": "LS217", + "utc": "04:32:00" + }, + { + "day": 5, + "flight": "LS585", + "utc": "02:15:00" + }, + { + "day": 5, + "flight": "LS163", + "utc": "05:21:00" + }, + { + "day": 6, + "flight": "LS299", + "utc": "05:12:00" + }, + { + "day": 6, + "flight": "LS259", + "utc": "20:44:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "LIL", + "distance": 781.8286754466159, + "equipment": "E70", + "id": 4627, + "schedule": [ + { + "day": 0, + "flight": "A5460", + "utc": "17:28:00" + }, + { + "day": 0, + "flight": "A5895", + "utc": "22:47:00" + }, + { + "day": 0, + "flight": "A5181", + "utc": "18:35:00" + }, + { + "day": 0, + "flight": "A5682", + "utc": "09:47:00" + }, + { + "day": 1, + "flight": "A5875", + "utc": "02:04:00" + }, + { + "day": 1, + "flight": "A5659", + "utc": "20:46:00" + }, + { + "day": 1, + "flight": "A5468", + "utc": "15:49:00" + }, + { + "day": 2, + "flight": "A5922", + "utc": "19:01:00" + }, + { + "day": 2, + "flight": "A5805", + "utc": "00:36:00" + }, + { + "day": 2, + "flight": "A5845", + "utc": "06:28:00" + }, + { + "day": 2, + "flight": "A5150", + "utc": "06:07:00" + }, + { + "day": 2, + "flight": "A5724", + "utc": "03:42:00" + }, + { + "day": 3, + "flight": "A5678", + "utc": "04:33:00" + }, + { + "day": 3, + "flight": "A5535", + "utc": "00:11:00" + }, + { + "day": 3, + "flight": "A5085", + "utc": "14:15:00" + }, + { + "day": 4, + "flight": "A5977", + "utc": "16:46:00" + }, + { + "day": 4, + "flight": "A5994", + "utc": "11:15:00" + }, + { + "day": 4, + "flight": "A5404", + "utc": "21:01:00" + }, + { + "day": 5, + "flight": "A5450", + "utc": "06:41:00" + }, + { + "day": 5, + "flight": "A5761", + "utc": "22:09:00" + }, + { + "day": 5, + "flight": "A5598", + "utc": "00:47:00" + }, + { + "day": 5, + "flight": "A5994", + "utc": "14:58:00" + }, + { + "day": 6, + "flight": "A5828", + "utc": "18:06:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "MRS", + "distance": 311.0670134047465, + "equipment": "AT5", + "id": 4628, + "schedule": [ + { + "day": 0, + "flight": "A5338", + "utc": "05:02:00" + }, + { + "day": 0, + "flight": "A5882", + "utc": "12:46:00" + }, + { + "day": 0, + "flight": "A5406", + "utc": "10:08:00" + }, + { + "day": 0, + "flight": "A5631", + "utc": "18:02:00" + }, + { + "day": 0, + "flight": "A5670", + "utc": "03:24:00" + }, + { + "day": 1, + "flight": "A5689", + "utc": "16:59:00" + }, + { + "day": 2, + "flight": "A5073", + "utc": "13:10:00" + }, + { + "day": 2, + "flight": "A5790", + "utc": "07:41:00" + }, + { + "day": 3, + "flight": "A5862", + "utc": "22:10:00" + }, + { + "day": 3, + "flight": "A5650", + "utc": "07:40:00" + }, + { + "day": 3, + "flight": "A5874", + "utc": "20:54:00" + }, + { + "day": 3, + "flight": "A5502", + "utc": "17:52:00" + }, + { + "day": 3, + "flight": "A5294", + "utc": "19:33:00" + }, + { + "day": 4, + "flight": "A5376", + "utc": "09:42:00" + }, + { + "day": 4, + "flight": "A5302", + "utc": "21:26:00" + }, + { + "day": 4, + "flight": "A5348", + "utc": "10:57:00" + }, + { + "day": 4, + "flight": "A5003", + "utc": "08:01:00" + }, + { + "day": 4, + "flight": "A5018", + "utc": "20:03:00" + }, + { + "day": 5, + "flight": "A5983", + "utc": "03:02:00" + }, + { + "day": 5, + "flight": "A5026", + "utc": "08:27:00" + }, + { + "day": 5, + "flight": "A5481", + "utc": "15:09:00" + }, + { + "day": 5, + "flight": "A5479", + "utc": "22:40:00" + }, + { + "day": 5, + "flight": "A5264", + "utc": "16:22:00" + }, + { + "day": 6, + "flight": "A5308", + "utc": "23:02:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "NCE", + "distance": 470.8031011808527, + "equipment": "AT7", + "id": 4629, + "schedule": [ + { + "day": 0, + "flight": "A5283", + "utc": "02:13:00" + }, + { + "day": 0, + "flight": "A5869", + "utc": "12:53:00" + }, + { + "day": 1, + "flight": "A5559", + "utc": "15:22:00" + }, + { + "day": 1, + "flight": "A5213", + "utc": "13:43:00" + }, + { + "day": 1, + "flight": "A5935", + "utc": "19:54:00" + }, + { + "day": 1, + "flight": "A5622", + "utc": "16:18:00" + }, + { + "day": 2, + "flight": "A5016", + "utc": "17:15:00" + }, + { + "day": 2, + "flight": "A5523", + "utc": "21:14:00" + }, + { + "day": 2, + "flight": "A5896", + "utc": "08:11:00" + }, + { + "day": 3, + "flight": "A5287", + "utc": "00:53:00" + }, + { + "day": 3, + "flight": "A5772", + "utc": "09:58:00" + }, + { + "day": 4, + "flight": "A5470", + "utc": "06:37:00" + }, + { + "day": 4, + "flight": "A5047", + "utc": "03:32:00" + }, + { + "day": 4, + "flight": "A5006", + "utc": "07:08:00" + }, + { + "day": 4, + "flight": "A5631", + "utc": "09:29:00" + }, + { + "day": 4, + "flight": "A5434", + "utc": "02:39:00" + }, + { + "day": 5, + "flight": "A5437", + "utc": "08:39:00" + }, + { + "day": 5, + "flight": "A5606", + "utc": "22:00:00" + }, + { + "day": 5, + "flight": "A5895", + "utc": "20:21:00" + }, + { + "day": 5, + "flight": "A5504", + "utc": "20:04:00" + }, + { + "day": 6, + "flight": "A5579", + "utc": "02:55:00" + }, + { + "day": 6, + "flight": "A5099", + "utc": "22:02:00" + }, + { + "day": 6, + "flight": "A5703", + "utc": "02:31:00" + }, + { + "day": 6, + "flight": "A5253", + "utc": "14:34:00" + }, + { + "day": 6, + "flight": "A5615", + "utc": "11:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "NTE", + "distance": 455.4490681425203, + "equipment": "CR7", + "id": 4630, + "schedule": [ + { + "day": 0, + "flight": "A5134", + "utc": "20:08:00" + }, + { + "day": 0, + "flight": "A5131", + "utc": "02:01:00" + }, + { + "day": 0, + "flight": "A5431", + "utc": "17:28:00" + }, + { + "day": 0, + "flight": "A5382", + "utc": "12:25:00" + }, + { + "day": 1, + "flight": "A5065", + "utc": "16:44:00" + }, + { + "day": 1, + "flight": "A5091", + "utc": "03:41:00" + }, + { + "day": 1, + "flight": "A5242", + "utc": "04:14:00" + }, + { + "day": 1, + "flight": "A5781", + "utc": "12:57:00" + }, + { + "day": 2, + "flight": "A5552", + "utc": "15:45:00" + }, + { + "day": 2, + "flight": "A5610", + "utc": "17:04:00" + }, + { + "day": 2, + "flight": "A5252", + "utc": "03:20:00" + }, + { + "day": 2, + "flight": "A5112", + "utc": "02:20:00" + }, + { + "day": 2, + "flight": "A5684", + "utc": "06:52:00" + }, + { + "day": 3, + "flight": "A5601", + "utc": "02:23:00" + }, + { + "day": 3, + "flight": "A5066", + "utc": "19:34:00" + }, + { + "day": 3, + "flight": "A5226", + "utc": "09:59:00" + }, + { + "day": 3, + "flight": "A5216", + "utc": "13:05:00" + }, + { + "day": 4, + "flight": "A5793", + "utc": "03:37:00" + }, + { + "day": 4, + "flight": "A5506", + "utc": "00:37:00" + }, + { + "day": 4, + "flight": "A5053", + "utc": "03:43:00" + }, + { + "day": 4, + "flight": "A5006", + "utc": "08:21:00" + }, + { + "day": 5, + "flight": "A5463", + "utc": "10:00:00" + }, + { + "day": 5, + "flight": "A5609", + "utc": "05:23:00" + }, + { + "day": 6, + "flight": "A5040", + "utc": "20:12:00" + }, + { + "day": 6, + "flight": "A5449", + "utc": "02:33:00" + }, + { + "day": 6, + "flight": "A5870", + "utc": "17:40:00" + }, + { + "day": 6, + "flight": "A5577", + "utc": "09:57:00" + }, + { + "day": 6, + "flight": "A5516", + "utc": "03:49:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "RNS", + "distance": 548.8740198503464, + "equipment": "CRJ CR7", + "id": 4631, + "schedule": [ + { + "day": 0, + "flight": "A5172", + "utc": "16:26:00" + }, + { + "day": 0, + "flight": "A5610", + "utc": "01:09:00" + }, + { + "day": 0, + "flight": "A5338", + "utc": "05:14:00" + }, + { + "day": 1, + "flight": "A5456", + "utc": "17:30:00" + }, + { + "day": 2, + "flight": "A5316", + "utc": "14:50:00" + }, + { + "day": 2, + "flight": "A5137", + "utc": "19:39:00" + }, + { + "day": 2, + "flight": "A5478", + "utc": "02:26:00" + }, + { + "day": 3, + "flight": "A5007", + "utc": "21:23:00" + }, + { + "day": 3, + "flight": "A5614", + "utc": "00:19:00" + }, + { + "day": 3, + "flight": "A5025", + "utc": "07:24:00" + }, + { + "day": 4, + "flight": "A5295", + "utc": "22:57:00" + }, + { + "day": 4, + "flight": "A5250", + "utc": "09:02:00" + }, + { + "day": 5, + "flight": "A5548", + "utc": "11:17:00" + }, + { + "day": 5, + "flight": "A5666", + "utc": "21:29:00" + }, + { + "day": 5, + "flight": "A5572", + "utc": "22:04:00" + }, + { + "day": 6, + "flight": "A5953", + "utc": "06:52:00" + }, + { + "day": 6, + "flight": "A5438", + "utc": "01:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "SE", + "airlineid": "airline_5479", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "332", + "id": 49359, + "schedule": [ + { + "day": 0, + "flight": "SE239", + "utc": "02:38:00" + }, + { + "day": 1, + "flight": "SE278", + "utc": "13:05:00" + }, + { + "day": 2, + "flight": "SE859", + "utc": "03:00:00" + }, + { + "day": 3, + "flight": "SE316", + "utc": "06:46:00" + }, + { + "day": 3, + "flight": "SE570", + "utc": "22:46:00" + }, + { + "day": 3, + "flight": "SE236", + "utc": "06:03:00" + }, + { + "day": 3, + "flight": "SE140", + "utc": "07:28:00" + }, + { + "day": 4, + "flight": "SE907", + "utc": "22:00:00" + }, + { + "day": 4, + "flight": "SE943", + "utc": "04:02:00" + }, + { + "day": 4, + "flight": "SE337", + "utc": "16:25:00" + }, + { + "day": 4, + "flight": "SE342", + "utc": "21:03:00" + }, + { + "day": 5, + "flight": "SE200", + "utc": "02:43:00" + }, + { + "day": 5, + "flight": "SE777", + "utc": "04:12:00" + }, + { + "day": 6, + "flight": "SE566", + "utc": "13:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "SN", + "airlineid": "airline_1531", + "destinationairport": "BRU", + "distance": 842.027454616631, + "equipment": "AR1", + "id": 50376, + "schedule": [ + { + "day": 0, + "flight": "SN526", + "utc": "17:16:00" + }, + { + "day": 0, + "flight": "SN650", + "utc": "05:15:00" + }, + { + "day": 1, + "flight": "SN990", + "utc": "22:21:00" + }, + { + "day": 2, + "flight": "SN199", + "utc": "12:46:00" + }, + { + "day": 2, + "flight": "SN329", + "utc": "14:46:00" + }, + { + "day": 3, + "flight": "SN504", + "utc": "19:57:00" + }, + { + "day": 3, + "flight": "SN802", + "utc": "13:25:00" + }, + { + "day": 3, + "flight": "SN769", + "utc": "10:36:00" + }, + { + "day": 3, + "flight": "SN806", + "utc": "06:33:00" + }, + { + "day": 4, + "flight": "SN332", + "utc": "07:50:00" + }, + { + "day": 4, + "flight": "SN147", + "utc": "05:19:00" + }, + { + "day": 4, + "flight": "SN036", + "utc": "19:01:00" + }, + { + "day": 4, + "flight": "SN184", + "utc": "19:45:00" + }, + { + "day": 4, + "flight": "SN395", + "utc": "00:58:00" + }, + { + "day": 5, + "flight": "SN532", + "utc": "15:37:00" + }, + { + "day": 6, + "flight": "SN973", + "utc": "16:37:00" + }, + { + "day": 6, + "flight": "SN605", + "utc": "05:06:00" + }, + { + "day": 6, + "flight": "SN450", + "utc": "20:54:00" + }, + { + "day": 6, + "flight": "SN822", + "utc": "23:11:00" + }, + { + "day": 6, + "flight": "SN149", + "utc": "01:59:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "BRS", + "distance": 914.710726420036, + "equipment": "ER4", + "id": 50746, + "schedule": [ + { + "day": 0, + "flight": "ST010", + "utc": "01:55:00" + }, + { + "day": 0, + "flight": "ST465", + "utc": "22:46:00" + }, + { + "day": 0, + "flight": "ST492", + "utc": "14:29:00" + }, + { + "day": 1, + "flight": "ST648", + "utc": "04:09:00" + }, + { + "day": 2, + "flight": "ST986", + "utc": "18:13:00" + }, + { + "day": 2, + "flight": "ST818", + "utc": "00:36:00" + }, + { + "day": 2, + "flight": "ST484", + "utc": "12:12:00" + }, + { + "day": 2, + "flight": "ST401", + "utc": "05:03:00" + }, + { + "day": 2, + "flight": "ST075", + "utc": "01:11:00" + }, + { + "day": 3, + "flight": "ST467", + "utc": "13:35:00" + }, + { + "day": 3, + "flight": "ST556", + "utc": "07:23:00" + }, + { + "day": 3, + "flight": "ST035", + "utc": "17:14:00" + }, + { + "day": 3, + "flight": "ST786", + "utc": "06:31:00" + }, + { + "day": 3, + "flight": "ST544", + "utc": "02:47:00" + }, + { + "day": 4, + "flight": "ST689", + "utc": "10:42:00" + }, + { + "day": 4, + "flight": "ST643", + "utc": "01:58:00" + }, + { + "day": 4, + "flight": "ST022", + "utc": "03:46:00" + }, + { + "day": 4, + "flight": "ST805", + "utc": "00:34:00" + }, + { + "day": 5, + "flight": "ST581", + "utc": "21:11:00" + }, + { + "day": 6, + "flight": "ST175", + "utc": "23:56:00" + }, + { + "day": 6, + "flight": "ST166", + "utc": "09:23:00" + }, + { + "day": 6, + "flight": "ST101", + "utc": "14:57:00" + }, + { + "day": 6, + "flight": "ST983", + "utc": "08:31:00" + }, + { + "day": 6, + "flight": "ST822", + "utc": "17:34:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "CEG", + "distance": 1108.5852832314715, + "equipment": "ER4", + "id": 50747, + "schedule": [ + { + "day": 0, + "flight": "ST127", + "utc": "21:02:00" + }, + { + "day": 0, + "flight": "ST839", + "utc": "22:35:00" + }, + { + "day": 0, + "flight": "ST267", + "utc": "14:02:00" + }, + { + "day": 0, + "flight": "ST016", + "utc": "10:17:00" + }, + { + "day": 1, + "flight": "ST623", + "utc": "07:52:00" + }, + { + "day": 1, + "flight": "ST105", + "utc": "00:34:00" + }, + { + "day": 1, + "flight": "ST459", + "utc": "02:07:00" + }, + { + "day": 1, + "flight": "ST170", + "utc": "18:29:00" + }, + { + "day": 1, + "flight": "ST830", + "utc": "21:49:00" + }, + { + "day": 2, + "flight": "ST884", + "utc": "21:53:00" + }, + { + "day": 3, + "flight": "ST924", + "utc": "04:55:00" + }, + { + "day": 3, + "flight": "ST261", + "utc": "01:16:00" + }, + { + "day": 3, + "flight": "ST016", + "utc": "04:50:00" + }, + { + "day": 3, + "flight": "ST260", + "utc": "04:46:00" + }, + { + "day": 4, + "flight": "ST863", + "utc": "10:59:00" + }, + { + "day": 4, + "flight": "ST200", + "utc": "03:30:00" + }, + { + "day": 4, + "flight": "ST152", + "utc": "07:31:00" + }, + { + "day": 5, + "flight": "ST738", + "utc": "05:45:00" + }, + { + "day": 5, + "flight": "ST453", + "utc": "00:23:00" + }, + { + "day": 5, + "flight": "ST503", + "utc": "02:00:00" + }, + { + "day": 6, + "flight": "ST286", + "utc": "16:11:00" + }, + { + "day": 6, + "flight": "ST878", + "utc": "19:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "XFW", + "distance": 1263.676446061964, + "equipment": "319", + "id": 50748, + "schedule": [ + { + "day": 0, + "flight": "ST732", + "utc": "23:31:00" + }, + { + "day": 1, + "flight": "ST711", + "utc": "12:54:00" + }, + { + "day": 1, + "flight": "ST553", + "utc": "08:51:00" + }, + { + "day": 2, + "flight": "ST603", + "utc": "02:06:00" + }, + { + "day": 3, + "flight": "ST345", + "utc": "05:04:00" + }, + { + "day": 3, + "flight": "ST401", + "utc": "20:24:00" + }, + { + "day": 4, + "flight": "ST317", + "utc": "00:48:00" + }, + { + "day": 4, + "flight": "ST133", + "utc": "14:45:00" + }, + { + "day": 4, + "flight": "ST217", + "utc": "08:52:00" + }, + { + "day": 4, + "flight": "ST471", + "utc": "01:06:00" + }, + { + "day": 4, + "flight": "ST213", + "utc": "06:59:00" + }, + { + "day": 5, + "flight": "ST277", + "utc": "00:10:00" + }, + { + "day": 5, + "flight": "ST056", + "utc": "10:50:00" + }, + { + "day": 5, + "flight": "ST553", + "utc": "07:18:00" + }, + { + "day": 5, + "flight": "ST673", + "utc": "06:34:00" + }, + { + "day": 5, + "flight": "ST729", + "utc": "20:03:00" + }, + { + "day": 6, + "flight": "ST737", + "utc": "20:09:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T3", + "airlineid": "airline_2117", + "destinationairport": "DIJ", + "distance": 498.1611053856414, + "equipment": "J41", + "id": 51783, + "schedule": [ + { + "day": 0, + "flight": "T3325", + "utc": "05:11:00" + }, + { + "day": 0, + "flight": "T3160", + "utc": "07:27:00" + }, + { + "day": 1, + "flight": "T3803", + "utc": "11:18:00" + }, + { + "day": 1, + "flight": "T3946", + "utc": "16:35:00" + }, + { + "day": 2, + "flight": "T3548", + "utc": "07:03:00" + }, + { + "day": 2, + "flight": "T3516", + "utc": "05:09:00" + }, + { + "day": 2, + "flight": "T3849", + "utc": "01:43:00" + }, + { + "day": 2, + "flight": "T3096", + "utc": "05:54:00" + }, + { + "day": 2, + "flight": "T3020", + "utc": "23:04:00" + }, + { + "day": 3, + "flight": "T3523", + "utc": "02:22:00" + }, + { + "day": 3, + "flight": "T3724", + "utc": "17:07:00" + }, + { + "day": 4, + "flight": "T3751", + "utc": "05:04:00" + }, + { + "day": 4, + "flight": "T3360", + "utc": "19:01:00" + }, + { + "day": 4, + "flight": "T3945", + "utc": "05:38:00" + }, + { + "day": 4, + "flight": "T3861", + "utc": "17:35:00" + }, + { + "day": 4, + "flight": "T3362", + "utc": "18:29:00" + }, + { + "day": 5, + "flight": "T3884", + "utc": "16:36:00" + }, + { + "day": 6, + "flight": "T3032", + "utc": "22:22:00" + }, + { + "day": 6, + "flight": "T3719", + "utc": "11:59:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T7", + "airlineid": "airline_4965", + "destinationairport": "ETZ", + "distance": 703.3976464387359, + "equipment": "BEH", + "id": 51823, + "schedule": [ + { + "day": 0, + "flight": "T7417", + "utc": "04:52:00" + }, + { + "day": 1, + "flight": "T7281", + "utc": "14:33:00" + }, + { + "day": 2, + "flight": "T7500", + "utc": "02:16:00" + }, + { + "day": 3, + "flight": "T7552", + "utc": "23:16:00" + }, + { + "day": 4, + "flight": "T7538", + "utc": "16:00:00" + }, + { + "day": 4, + "flight": "T7925", + "utc": "20:07:00" + }, + { + "day": 4, + "flight": "T7339", + "utc": "21:34:00" + }, + { + "day": 4, + "flight": "T7667", + "utc": "02:53:00" + }, + { + "day": 4, + "flight": "T7282", + "utc": "09:14:00" + }, + { + "day": 5, + "flight": "T7073", + "utc": "23:57:00" + }, + { + "day": 5, + "flight": "T7243", + "utc": "16:41:00" + }, + { + "day": 5, + "flight": "T7665", + "utc": "09:52:00" + }, + { + "day": 6, + "flight": "T7246", + "utc": "17:16:00" + }, + { + "day": 6, + "flight": "T7106", + "utc": "04:20:00" + }, + { + "day": 6, + "flight": "T7978", + "utc": "03:41:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T7", + "airlineid": "airline_4965", + "destinationairport": "MXP", + "distance": 623.5176024539427, + "equipment": "BEH", + "id": 51824, + "schedule": [ + { + "day": 0, + "flight": "T7538", + "utc": "03:44:00" + }, + { + "day": 0, + "flight": "T7420", + "utc": "11:59:00" + }, + { + "day": 1, + "flight": "T7941", + "utc": "21:37:00" + }, + { + "day": 1, + "flight": "T7079", + "utc": "21:14:00" + }, + { + "day": 1, + "flight": "T7359", + "utc": "04:57:00" + }, + { + "day": 1, + "flight": "T7298", + "utc": "06:52:00" + }, + { + "day": 2, + "flight": "T7045", + "utc": "19:21:00" + }, + { + "day": 2, + "flight": "T7446", + "utc": "12:35:00" + }, + { + "day": 2, + "flight": "T7316", + "utc": "21:56:00" + }, + { + "day": 2, + "flight": "T7357", + "utc": "01:13:00" + }, + { + "day": 3, + "flight": "T7759", + "utc": "22:58:00" + }, + { + "day": 3, + "flight": "T7030", + "utc": "14:17:00" + }, + { + "day": 3, + "flight": "T7422", + "utc": "16:16:00" + }, + { + "day": 4, + "flight": "T7772", + "utc": "03:34:00" + }, + { + "day": 4, + "flight": "T7581", + "utc": "06:16:00" + }, + { + "day": 4, + "flight": "T7321", + "utc": "02:39:00" + }, + { + "day": 4, + "flight": "T7634", + "utc": "19:07:00" + }, + { + "day": 5, + "flight": "T7988", + "utc": "16:22:00" + }, + { + "day": 5, + "flight": "T7714", + "utc": "03:48:00" + }, + { + "day": 6, + "flight": "T7317", + "utc": "14:36:00" + }, + { + "day": 6, + "flight": "T7616", + "utc": "08:05:00" + }, + { + "day": 6, + "flight": "T7528", + "utc": "19:38:00" + }, + { + "day": 6, + "flight": "T7837", + "utc": "19:16:00" + }, + { + "day": 6, + "flight": "T7113", + "utc": "18:40:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TK", + "airlineid": "airline_4951", + "destinationairport": "IST", + "distance": 2266.207133048303, + "equipment": "320 321", + "id": 52846, + "schedule": [ + { + "day": 0, + "flight": "TK981", + "utc": "05:00:00" + }, + { + "day": 0, + "flight": "TK948", + "utc": "06:35:00" + }, + { + "day": 0, + "flight": "TK175", + "utc": "18:26:00" + }, + { + "day": 0, + "flight": "TK266", + "utc": "23:13:00" + }, + { + "day": 1, + "flight": "TK518", + "utc": "23:14:00" + }, + { + "day": 1, + "flight": "TK527", + "utc": "15:43:00" + }, + { + "day": 2, + "flight": "TK409", + "utc": "00:18:00" + }, + { + "day": 3, + "flight": "TK211", + "utc": "05:35:00" + }, + { + "day": 4, + "flight": "TK068", + "utc": "02:47:00" + }, + { + "day": 5, + "flight": "TK348", + "utc": "14:15:00" + }, + { + "day": 6, + "flight": "TK439", + "utc": "03:54:00" + }, + { + "day": 6, + "flight": "TK927", + "utc": "11:17:00" + }, + { + "day": 6, + "flight": "TK779", + "utc": "20:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TP", + "airlineid": "airline_4869", + "destinationairport": "LIS", + "distance": 1029.4070254527778, + "equipment": "100 ER4", + "id": 53824, + "schedule": [ + { + "day": 0, + "flight": "TP104", + "utc": "22:19:00" + }, + { + "day": 1, + "flight": "TP439", + "utc": "20:47:00" + }, + { + "day": 1, + "flight": "TP157", + "utc": "11:59:00" + }, + { + "day": 1, + "flight": "TP990", + "utc": "22:45:00" + }, + { + "day": 1, + "flight": "TP931", + "utc": "16:42:00" + }, + { + "day": 1, + "flight": "TP064", + "utc": "01:01:00" + }, + { + "day": 2, + "flight": "TP512", + "utc": "12:47:00" + }, + { + "day": 3, + "flight": "TP779", + "utc": "06:59:00" + }, + { + "day": 3, + "flight": "TP439", + "utc": "01:48:00" + }, + { + "day": 3, + "flight": "TP368", + "utc": "06:34:00" + }, + { + "day": 3, + "flight": "TP374", + "utc": "05:51:00" + }, + { + "day": 3, + "flight": "TP960", + "utc": "12:04:00" + }, + { + "day": 4, + "flight": "TP587", + "utc": "05:51:00" + }, + { + "day": 4, + "flight": "TP963", + "utc": "05:26:00" + }, + { + "day": 4, + "flight": "TP701", + "utc": "14:33:00" + }, + { + "day": 4, + "flight": "TP505", + "utc": "02:35:00" + }, + { + "day": 5, + "flight": "TP466", + "utc": "16:41:00" + }, + { + "day": 5, + "flight": "TP691", + "utc": "07:18:00" + }, + { + "day": 5, + "flight": "TP147", + "utc": "11:43:00" + }, + { + "day": 6, + "flight": "TP192", + "utc": "21:25:00" + }, + { + "day": 6, + "flight": "TP555", + "utc": "14:32:00" + }, + { + "day": 6, + "flight": "TP159", + "utc": "01:18:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TS", + "airlineid": "airline_1317", + "destinationairport": "YUL", + "distance": 5727.754070420711, + "equipment": "310", + "id": 53980, + "schedule": [ + { + "day": 0, + "flight": "TS022", + "utc": "17:05:00" + }, + { + "day": 0, + "flight": "TS378", + "utc": "07:58:00" + }, + { + "day": 0, + "flight": "TS288", + "utc": "18:01:00" + }, + { + "day": 0, + "flight": "TS447", + "utc": "14:50:00" + }, + { + "day": 1, + "flight": "TS820", + "utc": "02:32:00" + }, + { + "day": 1, + "flight": "TS349", + "utc": "07:31:00" + }, + { + "day": 1, + "flight": "TS522", + "utc": "02:22:00" + }, + { + "day": 1, + "flight": "TS271", + "utc": "21:31:00" + }, + { + "day": 2, + "flight": "TS018", + "utc": "09:50:00" + }, + { + "day": 2, + "flight": "TS375", + "utc": "17:20:00" + }, + { + "day": 2, + "flight": "TS841", + "utc": "10:09:00" + }, + { + "day": 2, + "flight": "TS710", + "utc": "02:23:00" + }, + { + "day": 2, + "flight": "TS541", + "utc": "21:38:00" + }, + { + "day": 3, + "flight": "TS458", + "utc": "08:17:00" + }, + { + "day": 3, + "flight": "TS682", + "utc": "15:57:00" + }, + { + "day": 3, + "flight": "TS988", + "utc": "16:06:00" + }, + { + "day": 3, + "flight": "TS508", + "utc": "20:13:00" + }, + { + "day": 3, + "flight": "TS461", + "utc": "20:23:00" + }, + { + "day": 4, + "flight": "TS703", + "utc": "22:23:00" + }, + { + "day": 4, + "flight": "TS693", + "utc": "17:31:00" + }, + { + "day": 4, + "flight": "TS167", + "utc": "00:21:00" + }, + { + "day": 4, + "flight": "TS123", + "utc": "20:23:00" + }, + { + "day": 5, + "flight": "TS465", + "utc": "03:23:00" + }, + { + "day": 5, + "flight": "TS675", + "utc": "04:50:00" + }, + { + "day": 6, + "flight": "TS529", + "utc": "00:48:00" + }, + { + "day": 6, + "flight": "TS394", + "utc": "17:07:00" + }, + { + "day": 6, + "flight": "TS003", + "utc": "20:48:00" + }, + { + "day": 6, + "flight": "TS961", + "utc": "13:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TU", + "airlineid": "airline_4870", + "destinationairport": "TUN", + "distance": 1063.7112627835468, + "equipment": "736", + "id": 54192, + "schedule": [ + { + "day": 0, + "flight": "TU408", + "utc": "03:17:00" + }, + { + "day": 1, + "flight": "TU112", + "utc": "22:41:00" + }, + { + "day": 2, + "flight": "TU006", + "utc": "12:25:00" + }, + { + "day": 2, + "flight": "TU923", + "utc": "21:40:00" + }, + { + "day": 2, + "flight": "TU869", + "utc": "14:04:00" + }, + { + "day": 3, + "flight": "TU072", + "utc": "14:32:00" + }, + { + "day": 3, + "flight": "TU362", + "utc": "20:43:00" + }, + { + "day": 4, + "flight": "TU876", + "utc": "11:57:00" + }, + { + "day": 4, + "flight": "TU486", + "utc": "15:28:00" + }, + { + "day": 4, + "flight": "TU161", + "utc": "08:26:00" + }, + { + "day": 4, + "flight": "TU312", + "utc": "06:41:00" + }, + { + "day": 4, + "flight": "TU887", + "utc": "06:35:00" + }, + { + "day": 5, + "flight": "TU507", + "utc": "20:03:00" + }, + { + "day": 5, + "flight": "TU893", + "utc": "01:33:00" + }, + { + "day": 6, + "flight": "TU871", + "utc": "12:34:00" + }, + { + "day": 6, + "flight": "TU610", + "utc": "04:01:00" + }, + { + "day": 6, + "flight": "TU896", + "utc": "17:25:00" + }, + { + "day": 6, + "flight": "TU158", + "utc": "15:20:00" + }, + { + "day": 6, + "flight": "TU008", + "utc": "00:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BIA", + "distance": 669.8441063067557, + "equipment": "319", + "id": 55468, + "schedule": [ + { + "day": 0, + "flight": "U2494", + "utc": "14:35:00" + }, + { + "day": 0, + "flight": "U2177", + "utc": "19:05:00" + }, + { + "day": 1, + "flight": "U2900", + "utc": "03:08:00" + }, + { + "day": 1, + "flight": "U2439", + "utc": "02:58:00" + }, + { + "day": 1, + "flight": "U2722", + "utc": "00:10:00" + }, + { + "day": 1, + "flight": "U2651", + "utc": "06:08:00" + }, + { + "day": 1, + "flight": "U2905", + "utc": "17:10:00" + }, + { + "day": 2, + "flight": "U2882", + "utc": "12:51:00" + }, + { + "day": 2, + "flight": "U2455", + "utc": "20:21:00" + }, + { + "day": 2, + "flight": "U2814", + "utc": "22:11:00" + }, + { + "day": 3, + "flight": "U2437", + "utc": "04:39:00" + }, + { + "day": 3, + "flight": "U2356", + "utc": "14:44:00" + }, + { + "day": 3, + "flight": "U2823", + "utc": "17:08:00" + }, + { + "day": 3, + "flight": "U2605", + "utc": "09:37:00" + }, + { + "day": 3, + "flight": "U2285", + "utc": "20:14:00" + }, + { + "day": 4, + "flight": "U2088", + "utc": "13:05:00" + }, + { + "day": 4, + "flight": "U2248", + "utc": "07:03:00" + }, + { + "day": 4, + "flight": "U2031", + "utc": "08:47:00" + }, + { + "day": 5, + "flight": "U2779", + "utc": "17:34:00" + }, + { + "day": 6, + "flight": "U2622", + "utc": "14:27:00" + }, + { + "day": 6, + "flight": "U2057", + "utc": "10:56:00" + }, + { + "day": 6, + "flight": "U2378", + "utc": "15:22:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BRS", + "distance": 914.710726420036, + "equipment": "320 319", + "id": 55469, + "schedule": [ + { + "day": 0, + "flight": "U2533", + "utc": "12:23:00" + }, + { + "day": 1, + "flight": "U2509", + "utc": "16:59:00" + }, + { + "day": 1, + "flight": "U2409", + "utc": "19:38:00" + }, + { + "day": 1, + "flight": "U2984", + "utc": "10:37:00" + }, + { + "day": 1, + "flight": "U2366", + "utc": "20:19:00" + }, + { + "day": 1, + "flight": "U2844", + "utc": "17:16:00" + }, + { + "day": 2, + "flight": "U2328", + "utc": "08:32:00" + }, + { + "day": 2, + "flight": "U2240", + "utc": "15:21:00" + }, + { + "day": 3, + "flight": "U2469", + "utc": "09:58:00" + }, + { + "day": 3, + "flight": "U2588", + "utc": "04:30:00" + }, + { + "day": 4, + "flight": "U2688", + "utc": "21:43:00" + }, + { + "day": 4, + "flight": "U2967", + "utc": "20:18:00" + }, + { + "day": 5, + "flight": "U2536", + "utc": "00:42:00" + }, + { + "day": 5, + "flight": "U2097", + "utc": "06:17:00" + }, + { + "day": 5, + "flight": "U2469", + "utc": "05:20:00" + }, + { + "day": 5, + "flight": "U2663", + "utc": "07:19:00" + }, + { + "day": 5, + "flight": "U2954", + "utc": "20:52:00" + }, + { + "day": 6, + "flight": "U2293", + "utc": "02:32:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BRU", + "distance": 842.027454616631, + "equipment": "319", + "id": 55470, + "schedule": [ + { + "day": 0, + "flight": "U2497", + "utc": "16:39:00" + }, + { + "day": 0, + "flight": "U2139", + "utc": "23:18:00" + }, + { + "day": 1, + "flight": "U2736", + "utc": "00:06:00" + }, + { + "day": 1, + "flight": "U2189", + "utc": "13:26:00" + }, + { + "day": 1, + "flight": "U2670", + "utc": "17:56:00" + }, + { + "day": 1, + "flight": "U2645", + "utc": "16:54:00" + }, + { + "day": 2, + "flight": "U2326", + "utc": "19:43:00" + }, + { + "day": 2, + "flight": "U2082", + "utc": "07:34:00" + }, + { + "day": 2, + "flight": "U2799", + "utc": "09:31:00" + }, + { + "day": 3, + "flight": "U2919", + "utc": "21:16:00" + }, + { + "day": 3, + "flight": "U2847", + "utc": "01:15:00" + }, + { + "day": 3, + "flight": "U2163", + "utc": "22:26:00" + }, + { + "day": 4, + "flight": "U2361", + "utc": "07:45:00" + }, + { + "day": 4, + "flight": "U2951", + "utc": "12:59:00" + }, + { + "day": 4, + "flight": "U2869", + "utc": "18:16:00" + }, + { + "day": 5, + "flight": "U2608", + "utc": "09:18:00" + }, + { + "day": 5, + "flight": "U2265", + "utc": "08:22:00" + }, + { + "day": 5, + "flight": "U2787", + "utc": "21:56:00" + }, + { + "day": 5, + "flight": "U2242", + "utc": "10:16:00" + }, + { + "day": 5, + "flight": "U2931", + "utc": "08:12:00" + }, + { + "day": 6, + "flight": "U2732", + "utc": "03:59:00" + }, + { + "day": 6, + "flight": "U2684", + "utc": "05:02:00" + }, + { + "day": 6, + "flight": "U2718", + "utc": "07:42:00" + }, + { + "day": 6, + "flight": "U2789", + "utc": "00:50:00" + }, + { + "day": 6, + "flight": "U2364", + "utc": "16:49:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BSL", + "distance": 650.756926586045, + "equipment": "319", + "id": 55471, + "schedule": [ + { + "day": 0, + "flight": "U2948", + "utc": "00:07:00" + }, + { + "day": 1, + "flight": "U2684", + "utc": "21:58:00" + }, + { + "day": 1, + "flight": "U2478", + "utc": "17:44:00" + }, + { + "day": 1, + "flight": "U2990", + "utc": "08:44:00" + }, + { + "day": 1, + "flight": "U2884", + "utc": "05:21:00" + }, + { + "day": 2, + "flight": "U2804", + "utc": "14:08:00" + }, + { + "day": 2, + "flight": "U2952", + "utc": "01:30:00" + }, + { + "day": 2, + "flight": "U2413", + "utc": "05:49:00" + }, + { + "day": 2, + "flight": "U2586", + "utc": "04:20:00" + }, + { + "day": 2, + "flight": "U2970", + "utc": "09:59:00" + }, + { + "day": 3, + "flight": "U2933", + "utc": "09:20:00" + }, + { + "day": 3, + "flight": "U2225", + "utc": "09:07:00" + }, + { + "day": 4, + "flight": "U2546", + "utc": "20:47:00" + }, + { + "day": 4, + "flight": "U2470", + "utc": "06:33:00" + }, + { + "day": 4, + "flight": "U2669", + "utc": "17:22:00" + }, + { + "day": 4, + "flight": "U2421", + "utc": "20:26:00" + }, + { + "day": 5, + "flight": "U2915", + "utc": "03:46:00" + }, + { + "day": 5, + "flight": "U2178", + "utc": "19:13:00" + }, + { + "day": 6, + "flight": "U2113", + "utc": "06:17:00" + }, + { + "day": 6, + "flight": "U2472", + "utc": "15:17:00" + }, + { + "day": 6, + "flight": "U2572", + "utc": "15:08:00" + }, + { + "day": 6, + "flight": "U2806", + "utc": "09:53:00" + }, + { + "day": 6, + "flight": "U2880", + "utc": "19:51:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "319 320", + "id": 55472, + "schedule": [ + { + "day": 0, + "flight": "U2783", + "utc": "04:04:00" + }, + { + "day": 0, + "flight": "U2306", + "utc": "12:27:00" + }, + { + "day": 0, + "flight": "U2568", + "utc": "22:02:00" + }, + { + "day": 0, + "flight": "U2181", + "utc": "12:06:00" + }, + { + "day": 0, + "flight": "U2994", + "utc": "07:29:00" + }, + { + "day": 1, + "flight": "U2148", + "utc": "05:42:00" + }, + { + "day": 1, + "flight": "U2598", + "utc": "03:59:00" + }, + { + "day": 1, + "flight": "U2486", + "utc": "22:53:00" + }, + { + "day": 2, + "flight": "U2878", + "utc": "07:27:00" + }, + { + "day": 3, + "flight": "U2940", + "utc": "19:09:00" + }, + { + "day": 3, + "flight": "U2472", + "utc": "13:32:00" + }, + { + "day": 3, + "flight": "U2764", + "utc": "22:04:00" + }, + { + "day": 4, + "flight": "U2398", + "utc": "01:20:00" + }, + { + "day": 4, + "flight": "U2640", + "utc": "22:50:00" + }, + { + "day": 4, + "flight": "U2323", + "utc": "04:22:00" + }, + { + "day": 5, + "flight": "U2015", + "utc": "10:27:00" + }, + { + "day": 5, + "flight": "U2339", + "utc": "15:46:00" + }, + { + "day": 5, + "flight": "U2000", + "utc": "14:10:00" + }, + { + "day": 5, + "flight": "U2159", + "utc": "03:50:00" + }, + { + "day": 5, + "flight": "U2509", + "utc": "04:22:00" + }, + { + "day": 6, + "flight": "U2639", + "utc": "17:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "319", + "id": 55473, + "schedule": [ + { + "day": 0, + "flight": "U2207", + "utc": "10:41:00" + }, + { + "day": 1, + "flight": "U2992", + "utc": "23:32:00" + }, + { + "day": 1, + "flight": "U2456", + "utc": "12:15:00" + }, + { + "day": 2, + "flight": "U2130", + "utc": "04:59:00" + }, + { + "day": 2, + "flight": "U2358", + "utc": "22:48:00" + }, + { + "day": 3, + "flight": "U2163", + "utc": "19:05:00" + }, + { + "day": 4, + "flight": "U2643", + "utc": "05:31:00" + }, + { + "day": 4, + "flight": "U2475", + "utc": "14:17:00" + }, + { + "day": 4, + "flight": "U2675", + "utc": "10:16:00" + }, + { + "day": 4, + "flight": "U2260", + "utc": "21:43:00" + }, + { + "day": 5, + "flight": "U2711", + "utc": "05:27:00" + }, + { + "day": 5, + "flight": "U2502", + "utc": "21:27:00" + }, + { + "day": 6, + "flight": "U2754", + "utc": "19:41:00" + }, + { + "day": 6, + "flight": "U2771", + "utc": "21:15:00" + }, + { + "day": 6, + "flight": "U2733", + "utc": "03:49:00" + }, + { + "day": 6, + "flight": "U2326", + "utc": "09:00:00" + }, + { + "day": 6, + "flight": "U2916", + "utc": "08:04:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "GVA", + "distance": 472.80826589600406, + "equipment": "319", + "id": 55474, + "schedule": [ + { + "day": 0, + "flight": "U2283", + "utc": "23:24:00" + }, + { + "day": 0, + "flight": "U2818", + "utc": "06:27:00" + }, + { + "day": 1, + "flight": "U2427", + "utc": "17:05:00" + }, + { + "day": 1, + "flight": "U2152", + "utc": "11:22:00" + }, + { + "day": 1, + "flight": "U2830", + "utc": "08:25:00" + }, + { + "day": 2, + "flight": "U2120", + "utc": "07:48:00" + }, + { + "day": 3, + "flight": "U2044", + "utc": "05:59:00" + }, + { + "day": 3, + "flight": "U2642", + "utc": "07:14:00" + }, + { + "day": 4, + "flight": "U2054", + "utc": "14:28:00" + }, + { + "day": 5, + "flight": "U2279", + "utc": "11:19:00" + }, + { + "day": 5, + "flight": "U2134", + "utc": "18:51:00" + }, + { + "day": 5, + "flight": "U2691", + "utc": "02:31:00" + }, + { + "day": 5, + "flight": "U2655", + "utc": "21:49:00" + }, + { + "day": 6, + "flight": "U2805", + "utc": "14:23:00" + }, + { + "day": 6, + "flight": "U2614", + "utc": "22:06:00" + }, + { + "day": 6, + "flight": "U2370", + "utc": "15:16:00" + }, + { + "day": 6, + "flight": "U2170", + "utc": "11:22:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LGW", + "distance": 844.1654023845344, + "equipment": "319 320", + "id": 55475, + "schedule": [ + { + "day": 0, + "flight": "U2933", + "utc": "04:57:00" + }, + { + "day": 0, + "flight": "U2353", + "utc": "18:26:00" + }, + { + "day": 0, + "flight": "U2005", + "utc": "15:06:00" + }, + { + "day": 1, + "flight": "U2701", + "utc": "09:37:00" + }, + { + "day": 2, + "flight": "U2142", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "U2583", + "utc": "16:29:00" + }, + { + "day": 2, + "flight": "U2424", + "utc": "10:14:00" + }, + { + "day": 3, + "flight": "U2528", + "utc": "21:34:00" + }, + { + "day": 3, + "flight": "U2213", + "utc": "21:34:00" + }, + { + "day": 3, + "flight": "U2664", + "utc": "09:18:00" + }, + { + "day": 4, + "flight": "U2487", + "utc": "00:05:00" + }, + { + "day": 4, + "flight": "U2324", + "utc": "12:30:00" + }, + { + "day": 4, + "flight": "U2244", + "utc": "08:01:00" + }, + { + "day": 4, + "flight": "U2930", + "utc": "23:04:00" + }, + { + "day": 4, + "flight": "U2442", + "utc": "20:48:00" + }, + { + "day": 5, + "flight": "U2885", + "utc": "22:34:00" + }, + { + "day": 5, + "flight": "U2670", + "utc": "17:09:00" + }, + { + "day": 5, + "flight": "U2045", + "utc": "17:23:00" + }, + { + "day": 6, + "flight": "U2785", + "utc": "13:25:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LIL", + "distance": 781.8286754466159, + "equipment": "319", + "id": 55476, + "schedule": [ + { + "day": 0, + "flight": "U2448", + "utc": "11:55:00" + }, + { + "day": 1, + "flight": "U2947", + "utc": "11:22:00" + }, + { + "day": 1, + "flight": "U2978", + "utc": "15:08:00" + }, + { + "day": 2, + "flight": "U2244", + "utc": "02:54:00" + }, + { + "day": 3, + "flight": "U2880", + "utc": "22:25:00" + }, + { + "day": 3, + "flight": "U2966", + "utc": "11:29:00" + }, + { + "day": 3, + "flight": "U2581", + "utc": "01:52:00" + }, + { + "day": 4, + "flight": "U2461", + "utc": "11:43:00" + }, + { + "day": 4, + "flight": "U2882", + "utc": "04:18:00" + }, + { + "day": 4, + "flight": "U2556", + "utc": "01:31:00" + }, + { + "day": 4, + "flight": "U2528", + "utc": "10:56:00" + }, + { + "day": 4, + "flight": "U2060", + "utc": "09:32:00" + }, + { + "day": 5, + "flight": "U2289", + "utc": "06:04:00" + }, + { + "day": 6, + "flight": "U2776", + "utc": "06:37:00" + }, + { + "day": 6, + "flight": "U2510", + "utc": "07:51:00" + }, + { + "day": 6, + "flight": "U2861", + "utc": "22:24:00" + }, + { + "day": 6, + "flight": "U2936", + "utc": "06:57:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319", + "id": 55477, + "schedule": [ + { + "day": 0, + "flight": "U2340", + "utc": "21:08:00" + }, + { + "day": 0, + "flight": "U2501", + "utc": "11:27:00" + }, + { + "day": 0, + "flight": "U2855", + "utc": "20:34:00" + }, + { + "day": 1, + "flight": "U2025", + "utc": "01:40:00" + }, + { + "day": 1, + "flight": "U2320", + "utc": "02:40:00" + }, + { + "day": 1, + "flight": "U2402", + "utc": "05:53:00" + }, + { + "day": 1, + "flight": "U2858", + "utc": "02:47:00" + }, + { + "day": 1, + "flight": "U2828", + "utc": "04:34:00" + }, + { + "day": 2, + "flight": "U2361", + "utc": "07:59:00" + }, + { + "day": 2, + "flight": "U2640", + "utc": "04:01:00" + }, + { + "day": 2, + "flight": "U2777", + "utc": "18:07:00" + }, + { + "day": 3, + "flight": "U2602", + "utc": "19:50:00" + }, + { + "day": 4, + "flight": "U2487", + "utc": "00:56:00" + }, + { + "day": 5, + "flight": "U2702", + "utc": "05:40:00" + }, + { + "day": 6, + "flight": "U2074", + "utc": "14:47:00" + }, + { + "day": 6, + "flight": "U2763", + "utc": "21:12:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "NCE", + "distance": 470.8031011808527, + "equipment": "319", + "id": 55478, + "schedule": [ + { + "day": 0, + "flight": "U2536", + "utc": "00:51:00" + }, + { + "day": 0, + "flight": "U2640", + "utc": "10:51:00" + }, + { + "day": 0, + "flight": "U2734", + "utc": "19:10:00" + }, + { + "day": 0, + "flight": "U2973", + "utc": "19:49:00" + }, + { + "day": 0, + "flight": "U2387", + "utc": "07:11:00" + }, + { + "day": 1, + "flight": "U2852", + "utc": "01:07:00" + }, + { + "day": 1, + "flight": "U2532", + "utc": "10:19:00" + }, + { + "day": 1, + "flight": "U2896", + "utc": "06:50:00" + }, + { + "day": 2, + "flight": "U2510", + "utc": "12:58:00" + }, + { + "day": 2, + "flight": "U2929", + "utc": "22:05:00" + }, + { + "day": 3, + "flight": "U2563", + "utc": "12:44:00" + }, + { + "day": 3, + "flight": "U2947", + "utc": "04:21:00" + }, + { + "day": 3, + "flight": "U2787", + "utc": "05:13:00" + }, + { + "day": 4, + "flight": "U2383", + "utc": "23:41:00" + }, + { + "day": 4, + "flight": "U2485", + "utc": "13:25:00" + }, + { + "day": 5, + "flight": "U2064", + "utc": "20:55:00" + }, + { + "day": 5, + "flight": "U2690", + "utc": "04:31:00" + }, + { + "day": 5, + "flight": "U2713", + "utc": "18:06:00" + }, + { + "day": 6, + "flight": "U2099", + "utc": "09:45:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "NTE", + "distance": 455.4490681425203, + "equipment": "319", + "id": 55479, + "schedule": [ + { + "day": 0, + "flight": "U2117", + "utc": "10:10:00" + }, + { + "day": 1, + "flight": "U2746", + "utc": "08:08:00" + }, + { + "day": 1, + "flight": "U2454", + "utc": "21:03:00" + }, + { + "day": 1, + "flight": "U2860", + "utc": "12:06:00" + }, + { + "day": 2, + "flight": "U2902", + "utc": "18:21:00" + }, + { + "day": 2, + "flight": "U2031", + "utc": "23:38:00" + }, + { + "day": 3, + "flight": "U2255", + "utc": "01:05:00" + }, + { + "day": 4, + "flight": "U2037", + "utc": "06:54:00" + }, + { + "day": 4, + "flight": "U2671", + "utc": "18:55:00" + }, + { + "day": 4, + "flight": "U2793", + "utc": "18:13:00" + }, + { + "day": 4, + "flight": "U2564", + "utc": "03:51:00" + }, + { + "day": 5, + "flight": "U2209", + "utc": "13:21:00" + }, + { + "day": 6, + "flight": "U2139", + "utc": "23:11:00" + }, + { + "day": 6, + "flight": "U2398", + "utc": "15:26:00" + }, + { + "day": 6, + "flight": "U2335", + "utc": "08:44:00" + }, + { + "day": 6, + "flight": "U2591", + "utc": "01:43:00" + }, + { + "day": 6, + "flight": "U2623", + "utc": "06:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "ORY", + "distance": 571.8189591117047, + "equipment": "320 319", + "id": 55480, + "schedule": [ + { + "day": 0, + "flight": "U2687", + "utc": "12:05:00" + }, + { + "day": 1, + "flight": "U2311", + "utc": "03:54:00" + }, + { + "day": 1, + "flight": "U2180", + "utc": "15:47:00" + }, + { + "day": 1, + "flight": "U2937", + "utc": "07:31:00" + }, + { + "day": 1, + "flight": "U2210", + "utc": "20:01:00" + }, + { + "day": 1, + "flight": "U2593", + "utc": "13:47:00" + }, + { + "day": 2, + "flight": "U2747", + "utc": "20:18:00" + }, + { + "day": 2, + "flight": "U2810", + "utc": "22:27:00" + }, + { + "day": 2, + "flight": "U2888", + "utc": "20:35:00" + }, + { + "day": 3, + "flight": "U2363", + "utc": "15:56:00" + }, + { + "day": 3, + "flight": "U2344", + "utc": "01:35:00" + }, + { + "day": 4, + "flight": "U2153", + "utc": "13:29:00" + }, + { + "day": 4, + "flight": "U2256", + "utc": "10:58:00" + }, + { + "day": 5, + "flight": "U2880", + "utc": "15:55:00" + }, + { + "day": 5, + "flight": "U2659", + "utc": "21:57:00" + }, + { + "day": 6, + "flight": "U2797", + "utc": "03:33:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "319 320", + "id": 55481, + "schedule": [ + { + "day": 0, + "flight": "U2751", + "utc": "03:33:00" + }, + { + "day": 0, + "flight": "U2066", + "utc": "00:35:00" + }, + { + "day": 0, + "flight": "U2660", + "utc": "20:57:00" + }, + { + "day": 0, + "flight": "U2700", + "utc": "12:47:00" + }, + { + "day": 0, + "flight": "U2838", + "utc": "03:17:00" + }, + { + "day": 1, + "flight": "U2802", + "utc": "16:53:00" + }, + { + "day": 1, + "flight": "U2203", + "utc": "23:14:00" + }, + { + "day": 1, + "flight": "U2029", + "utc": "06:13:00" + }, + { + "day": 1, + "flight": "U2228", + "utc": "19:13:00" + }, + { + "day": 2, + "flight": "U2671", + "utc": "11:55:00" + }, + { + "day": 2, + "flight": "U2526", + "utc": "11:12:00" + }, + { + "day": 2, + "flight": "U2747", + "utc": "12:18:00" + }, + { + "day": 3, + "flight": "U2417", + "utc": "12:17:00" + }, + { + "day": 3, + "flight": "U2082", + "utc": "14:54:00" + }, + { + "day": 4, + "flight": "U2069", + "utc": "21:57:00" + }, + { + "day": 4, + "flight": "U2708", + "utc": "00:16:00" + }, + { + "day": 4, + "flight": "U2067", + "utc": "23:46:00" + }, + { + "day": 4, + "flight": "U2334", + "utc": "15:46:00" + }, + { + "day": 4, + "flight": "U2084", + "utc": "01:10:00" + }, + { + "day": 5, + "flight": "U2693", + "utc": "04:39:00" + }, + { + "day": 5, + "flight": "U2415", + "utc": "15:54:00" + }, + { + "day": 5, + "flight": "U2378", + "utc": "09:10:00" + }, + { + "day": 5, + "flight": "U2094", + "utc": "01:03:00" + }, + { + "day": 5, + "flight": "U2399", + "utc": "09:25:00" + }, + { + "day": 6, + "flight": "U2534", + "utc": "20:07:00" + }, + { + "day": 6, + "flight": "U2509", + "utc": "10:02:00" + }, + { + "day": 6, + "flight": "U2280", + "utc": "06:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "AGP", + "distance": 919.3439362090616, + "equipment": "320", + "id": 62413, + "schedule": [ + { + "day": 0, + "flight": "VY306", + "utc": "08:50:00" + }, + { + "day": 0, + "flight": "VY637", + "utc": "15:53:00" + }, + { + "day": 0, + "flight": "VY587", + "utc": "21:50:00" + }, + { + "day": 0, + "flight": "VY313", + "utc": "16:54:00" + }, + { + "day": 1, + "flight": "VY228", + "utc": "02:02:00" + }, + { + "day": 2, + "flight": "VY543", + "utc": "17:54:00" + }, + { + "day": 2, + "flight": "VY681", + "utc": "02:51:00" + }, + { + "day": 2, + "flight": "VY649", + "utc": "06:19:00" + }, + { + "day": 3, + "flight": "VY243", + "utc": "22:54:00" + }, + { + "day": 3, + "flight": "VY373", + "utc": "12:15:00" + }, + { + "day": 3, + "flight": "VY408", + "utc": "03:16:00" + }, + { + "day": 3, + "flight": "VY627", + "utc": "19:42:00" + }, + { + "day": 3, + "flight": "VY580", + "utc": "18:49:00" + }, + { + "day": 4, + "flight": "VY607", + "utc": "17:01:00" + }, + { + "day": 4, + "flight": "VY177", + "utc": "16:28:00" + }, + { + "day": 4, + "flight": "VY066", + "utc": "15:52:00" + }, + { + "day": 4, + "flight": "VY185", + "utc": "18:35:00" + }, + { + "day": 4, + "flight": "VY318", + "utc": "14:19:00" + }, + { + "day": 5, + "flight": "VY960", + "utc": "01:26:00" + }, + { + "day": 5, + "flight": "VY217", + "utc": "02:12:00" + }, + { + "day": 6, + "flight": "VY558", + "utc": "01:41:00" + }, + { + "day": 6, + "flight": "VY412", + "utc": "11:25:00" + }, + { + "day": 6, + "flight": "VY596", + "utc": "20:06:00" + }, + { + "day": 6, + "flight": "VY176", + "utc": "22:40:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "BCN", + "distance": 265.8469587104912, + "equipment": "320", + "id": 62414, + "schedule": [ + { + "day": 0, + "flight": "VY864", + "utc": "21:52:00" + }, + { + "day": 1, + "flight": "VY591", + "utc": "22:27:00" + }, + { + "day": 1, + "flight": "VY081", + "utc": "15:06:00" + }, + { + "day": 1, + "flight": "VY143", + "utc": "20:13:00" + }, + { + "day": 1, + "flight": "VY957", + "utc": "20:03:00" + }, + { + "day": 1, + "flight": "VY201", + "utc": "22:01:00" + }, + { + "day": 2, + "flight": "VY953", + "utc": "11:47:00" + }, + { + "day": 2, + "flight": "VY207", + "utc": "03:38:00" + }, + { + "day": 3, + "flight": "VY091", + "utc": "22:34:00" + }, + { + "day": 3, + "flight": "VY910", + "utc": "16:14:00" + }, + { + "day": 3, + "flight": "VY908", + "utc": "13:27:00" + }, + { + "day": 3, + "flight": "VY021", + "utc": "11:41:00" + }, + { + "day": 3, + "flight": "VY150", + "utc": "09:21:00" + }, + { + "day": 4, + "flight": "VY422", + "utc": "17:33:00" + }, + { + "day": 4, + "flight": "VY905", + "utc": "02:40:00" + }, + { + "day": 4, + "flight": "VY779", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "VY656", + "utc": "23:40:00" + }, + { + "day": 5, + "flight": "VY317", + "utc": "21:24:00" + }, + { + "day": 5, + "flight": "VY932", + "utc": "08:49:00" + }, + { + "day": 5, + "flight": "VY422", + "utc": "12:41:00" + }, + { + "day": 6, + "flight": "VY720", + "utc": "01:16:00" + }, + { + "day": 6, + "flight": "VY473", + "utc": "06:02:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "PMI", + "distance": 467.1315518195575, + "equipment": "320", + "id": 62415, + "schedule": [ + { + "day": 0, + "flight": "VY490", + "utc": "05:18:00" + }, + { + "day": 0, + "flight": "VY773", + "utc": "01:14:00" + }, + { + "day": 0, + "flight": "VY500", + "utc": "23:29:00" + }, + { + "day": 0, + "flight": "VY860", + "utc": "18:39:00" + }, + { + "day": 1, + "flight": "VY573", + "utc": "22:20:00" + }, + { + "day": 1, + "flight": "VY004", + "utc": "02:59:00" + }, + { + "day": 1, + "flight": "VY507", + "utc": "03:05:00" + }, + { + "day": 1, + "flight": "VY789", + "utc": "11:25:00" + }, + { + "day": 2, + "flight": "VY600", + "utc": "20:30:00" + }, + { + "day": 2, + "flight": "VY291", + "utc": "09:58:00" + }, + { + "day": 2, + "flight": "VY021", + "utc": "07:38:00" + }, + { + "day": 2, + "flight": "VY667", + "utc": "11:43:00" + }, + { + "day": 3, + "flight": "VY411", + "utc": "06:25:00" + }, + { + "day": 3, + "flight": "VY842", + "utc": "05:41:00" + }, + { + "day": 3, + "flight": "VY287", + "utc": "02:46:00" + }, + { + "day": 3, + "flight": "VY114", + "utc": "00:53:00" + }, + { + "day": 3, + "flight": "VY674", + "utc": "12:24:00" + }, + { + "day": 4, + "flight": "VY228", + "utc": "20:25:00" + }, + { + "day": 5, + "flight": "VY276", + "utc": "21:16:00" + }, + { + "day": 6, + "flight": "VY541", + "utc": "17:57:00" + }, + { + "day": 6, + "flight": "VY913", + "utc": "08:49:00" + }, + { + "day": 6, + "flight": "VY456", + "utc": "01:12:00" + }, + { + "day": 6, + "flight": "VY827", + "utc": "04:05:00" + }, + { + "day": 6, + "flight": "VY880", + "utc": "17:52:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "XK", + "airlineid": "airline_1909", + "destinationairport": "AJA", + "distance": 635.8270740976213, + "equipment": "320", + "id": 65438, + "schedule": [ + { + "day": 0, + "flight": "XK629", + "utc": "06:48:00" + }, + { + "day": 0, + "flight": "XK034", + "utc": "06:05:00" + }, + { + "day": 0, + "flight": "XK235", + "utc": "06:10:00" + }, + { + "day": 0, + "flight": "XK886", + "utc": "18:33:00" + }, + { + "day": 0, + "flight": "XK152", + "utc": "14:22:00" + }, + { + "day": 1, + "flight": "XK175", + "utc": "20:39:00" + }, + { + "day": 1, + "flight": "XK283", + "utc": "18:51:00" + }, + { + "day": 2, + "flight": "XK802", + "utc": "22:14:00" + }, + { + "day": 2, + "flight": "XK065", + "utc": "18:28:00" + }, + { + "day": 2, + "flight": "XK331", + "utc": "06:59:00" + }, + { + "day": 2, + "flight": "XK106", + "utc": "01:42:00" + }, + { + "day": 3, + "flight": "XK962", + "utc": "11:48:00" + }, + { + "day": 3, + "flight": "XK085", + "utc": "17:40:00" + }, + { + "day": 4, + "flight": "XK018", + "utc": "13:12:00" + }, + { + "day": 5, + "flight": "XK484", + "utc": "06:21:00" + }, + { + "day": 5, + "flight": "XK417", + "utc": "20:43:00" + }, + { + "day": 5, + "flight": "XK571", + "utc": "20:21:00" + }, + { + "day": 5, + "flight": "XK576", + "utc": "05:54:00" + }, + { + "day": 6, + "flight": "XK933", + "utc": "10:40:00" + }, + { + "day": 6, + "flight": "XK247", + "utc": "13:50:00" + }, + { + "day": 6, + "flight": "XK542", + "utc": "00:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AA", + "airlineid": "airline_24", + "destinationairport": "LHR", + "distance": 883.3122325423356, + "equipment": "320 319", + "id": 6898, + "schedule": [ + { + "day": 0, + "flight": "AA020", + "utc": "05:46:00" + }, + { + "day": 1, + "flight": "AA288", + "utc": "23:39:00" + }, + { + "day": 1, + "flight": "AA758", + "utc": "13:22:00" + }, + { + "day": 1, + "flight": "AA396", + "utc": "11:01:00" + }, + { + "day": 1, + "flight": "AA133", + "utc": "14:34:00" + }, + { + "day": 1, + "flight": "AA448", + "utc": "19:27:00" + }, + { + "day": 2, + "flight": "AA660", + "utc": "15:24:00" + }, + { + "day": 2, + "flight": "AA529", + "utc": "01:22:00" + }, + { + "day": 2, + "flight": "AA738", + "utc": "12:23:00" + }, + { + "day": 3, + "flight": "AA759", + "utc": "19:33:00" + }, + { + "day": 4, + "flight": "AA739", + "utc": "02:40:00" + }, + { + "day": 4, + "flight": "AA455", + "utc": "04:42:00" + }, + { + "day": 4, + "flight": "AA832", + "utc": "22:45:00" + }, + { + "day": 4, + "flight": "AA932", + "utc": "17:16:00" + }, + { + "day": 4, + "flight": "AA188", + "utc": "15:15:00" + }, + { + "day": 5, + "flight": "AA548", + "utc": "00:09:00" + }, + { + "day": 5, + "flight": "AA452", + "utc": "05:00:00" + }, + { + "day": 5, + "flight": "AA905", + "utc": "03:24:00" + }, + { + "day": 5, + "flight": "AA571", + "utc": "01:04:00" + }, + { + "day": 5, + "flight": "AA168", + "utc": "10:38:00" + }, + { + "day": 6, + "flight": "AA329", + "utc": "20:38:00" + }, + { + "day": 6, + "flight": "AA799", + "utc": "07:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "AJA", + "distance": 635.8270740976213, + "equipment": "320", + "id": 9985, + "schedule": [ + { + "day": 0, + "flight": "AF736", + "utc": "17:30:00" + }, + { + "day": 1, + "flight": "AF398", + "utc": "05:17:00" + }, + { + "day": 1, + "flight": "AF296", + "utc": "21:03:00" + }, + { + "day": 1, + "flight": "AF711", + "utc": "22:47:00" + }, + { + "day": 1, + "flight": "AF189", + "utc": "20:04:00" + }, + { + "day": 2, + "flight": "AF737", + "utc": "09:54:00" + }, + { + "day": 2, + "flight": "AF458", + "utc": "15:20:00" + }, + { + "day": 2, + "flight": "AF328", + "utc": "13:01:00" + }, + { + "day": 2, + "flight": "AF572", + "utc": "10:01:00" + }, + { + "day": 2, + "flight": "AF295", + "utc": "03:30:00" + }, + { + "day": 3, + "flight": "AF272", + "utc": "06:29:00" + }, + { + "day": 3, + "flight": "AF516", + "utc": "07:05:00" + }, + { + "day": 3, + "flight": "AF438", + "utc": "09:20:00" + }, + { + "day": 3, + "flight": "AF584", + "utc": "16:37:00" + }, + { + "day": 3, + "flight": "AF700", + "utc": "09:23:00" + }, + { + "day": 4, + "flight": "AF637", + "utc": "13:27:00" + }, + { + "day": 4, + "flight": "AF081", + "utc": "03:02:00" + }, + { + "day": 4, + "flight": "AF551", + "utc": "03:41:00" + }, + { + "day": 4, + "flight": "AF884", + "utc": "16:28:00" + }, + { + "day": 5, + "flight": "AF966", + "utc": "20:17:00" + }, + { + "day": 5, + "flight": "AF093", + "utc": "18:00:00" + }, + { + "day": 5, + "flight": "AF529", + "utc": "01:21:00" + }, + { + "day": 5, + "flight": "AF958", + "utc": "03:43:00" + }, + { + "day": 5, + "flight": "AF863", + "utc": "01:35:00" + }, + { + "day": 6, + "flight": "AF035", + "utc": "20:01:00" + }, + { + "day": 6, + "flight": "AF650", + "utc": "04:42:00" + }, + { + "day": 6, + "flight": "AF281", + "utc": "21:12:00" + }, + { + "day": 6, + "flight": "AF762", + "utc": "05:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "AMS", + "distance": 997.4702942027754, + "equipment": "E90", + "id": 9986, + "schedule": [ + { + "day": 0, + "flight": "AF828", + "utc": "04:07:00" + }, + { + "day": 0, + "flight": "AF923", + "utc": "02:34:00" + }, + { + "day": 0, + "flight": "AF622", + "utc": "15:56:00" + }, + { + "day": 0, + "flight": "AF409", + "utc": "20:12:00" + }, + { + "day": 0, + "flight": "AF462", + "utc": "04:35:00" + }, + { + "day": 1, + "flight": "AF688", + "utc": "01:30:00" + }, + { + "day": 1, + "flight": "AF444", + "utc": "01:03:00" + }, + { + "day": 1, + "flight": "AF789", + "utc": "20:50:00" + }, + { + "day": 1, + "flight": "AF253", + "utc": "19:01:00" + }, + { + "day": 1, + "flight": "AF731", + "utc": "03:44:00" + }, + { + "day": 2, + "flight": "AF331", + "utc": "19:21:00" + }, + { + "day": 3, + "flight": "AF101", + "utc": "19:35:00" + }, + { + "day": 4, + "flight": "AF928", + "utc": "08:16:00" + }, + { + "day": 4, + "flight": "AF359", + "utc": "16:04:00" + }, + { + "day": 4, + "flight": "AF497", + "utc": "13:02:00" + }, + { + "day": 5, + "flight": "AF326", + "utc": "18:14:00" + }, + { + "day": 5, + "flight": "AF019", + "utc": "11:55:00" + }, + { + "day": 6, + "flight": "AF624", + "utc": "21:46:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ATH", + "distance": 1996.3800921392394, + "equipment": "320", + "id": 9987, + "schedule": [ + { + "day": 0, + "flight": "AF893", + "utc": "23:36:00" + }, + { + "day": 0, + "flight": "AF498", + "utc": "19:37:00" + }, + { + "day": 1, + "flight": "AF266", + "utc": "02:51:00" + }, + { + "day": 1, + "flight": "AF970", + "utc": "06:54:00" + }, + { + "day": 1, + "flight": "AF880", + "utc": "20:08:00" + }, + { + "day": 2, + "flight": "AF758", + "utc": "15:11:00" + }, + { + "day": 2, + "flight": "AF437", + "utc": "08:53:00" + }, + { + "day": 2, + "flight": "AF930", + "utc": "08:47:00" + }, + { + "day": 2, + "flight": "AF671", + "utc": "09:09:00" + }, + { + "day": 2, + "flight": "AF151", + "utc": "05:10:00" + }, + { + "day": 3, + "flight": "AF142", + "utc": "19:27:00" + }, + { + "day": 3, + "flight": "AF805", + "utc": "23:07:00" + }, + { + "day": 4, + "flight": "AF821", + "utc": "11:18:00" + }, + { + "day": 4, + "flight": "AF146", + "utc": "12:32:00" + }, + { + "day": 5, + "flight": "AF591", + "utc": "03:51:00" + }, + { + "day": 5, + "flight": "AF506", + "utc": "06:24:00" + }, + { + "day": 6, + "flight": "AF455", + "utc": "11:23:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "320 319 321", + "id": 9988, + "schedule": [ + { + "day": 0, + "flight": "AF099", + "utc": "20:30:00" + }, + { + "day": 0, + "flight": "AF282", + "utc": "03:57:00" + }, + { + "day": 1, + "flight": "AF890", + "utc": "16:06:00" + }, + { + "day": 1, + "flight": "AF974", + "utc": "06:16:00" + }, + { + "day": 1, + "flight": "AF099", + "utc": "16:08:00" + }, + { + "day": 1, + "flight": "AF998", + "utc": "00:23:00" + }, + { + "day": 1, + "flight": "AF117", + "utc": "03:16:00" + }, + { + "day": 2, + "flight": "AF081", + "utc": "01:22:00" + }, + { + "day": 2, + "flight": "AF550", + "utc": "08:21:00" + }, + { + "day": 3, + "flight": "AF029", + "utc": "21:23:00" + }, + { + "day": 3, + "flight": "AF669", + "utc": "15:11:00" + }, + { + "day": 3, + "flight": "AF897", + "utc": "17:58:00" + }, + { + "day": 4, + "flight": "AF812", + "utc": "19:48:00" + }, + { + "day": 4, + "flight": "AF861", + "utc": "06:15:00" + }, + { + "day": 4, + "flight": "AF767", + "utc": "21:25:00" + }, + { + "day": 4, + "flight": "AF411", + "utc": "01:17:00" + }, + { + "day": 4, + "flight": "AF003", + "utc": "13:03:00" + }, + { + "day": 5, + "flight": "AF362", + "utc": "04:02:00" + }, + { + "day": 5, + "flight": "AF967", + "utc": "02:19:00" + }, + { + "day": 5, + "flight": "AF237", + "utc": "17:45:00" + }, + { + "day": 5, + "flight": "AF618", + "utc": "19:20:00" + }, + { + "day": 5, + "flight": "AF864", + "utc": "21:19:00" + }, + { + "day": 6, + "flight": "AF031", + "utc": "07:08:00" + }, + { + "day": 6, + "flight": "AF213", + "utc": "22:11:00" + }, + { + "day": 6, + "flight": "AF505", + "utc": "21:28:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "CMN", + "distance": 1379.8271930529227, + "equipment": "319 320", + "id": 9989, + "schedule": [ + { + "day": 0, + "flight": "AF336", + "utc": "07:45:00" + }, + { + "day": 0, + "flight": "AF660", + "utc": "15:44:00" + }, + { + "day": 1, + "flight": "AF203", + "utc": "17:34:00" + }, + { + "day": 1, + "flight": "AF513", + "utc": "17:55:00" + }, + { + "day": 2, + "flight": "AF100", + "utc": "13:37:00" + }, + { + "day": 3, + "flight": "AF704", + "utc": "14:15:00" + }, + { + "day": 3, + "flight": "AF562", + "utc": "13:28:00" + }, + { + "day": 3, + "flight": "AF925", + "utc": "19:16:00" + }, + { + "day": 4, + "flight": "AF901", + "utc": "01:26:00" + }, + { + "day": 5, + "flight": "AF685", + "utc": "16:08:00" + }, + { + "day": 5, + "flight": "AF512", + "utc": "18:25:00" + }, + { + "day": 5, + "flight": "AF242", + "utc": "08:31:00" + }, + { + "day": 5, + "flight": "AF993", + "utc": "19:19:00" + }, + { + "day": 5, + "flight": "AF223", + "utc": "03:49:00" + }, + { + "day": 6, + "flight": "AF913", + "utc": "17:19:00" + }, + { + "day": 6, + "flight": "AF443", + "utc": "02:40:00" + }, + { + "day": 6, + "flight": "AF802", + "utc": "21:06:00" + }, + { + "day": 6, + "flight": "AF469", + "utc": "06:57:00" + }, + { + "day": 6, + "flight": "AF383", + "utc": "10:57:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "319 320", + "id": 9990, + "schedule": [ + { + "day": 0, + "flight": "AF023", + "utc": "13:28:00" + }, + { + "day": 0, + "flight": "AF429", + "utc": "11:52:00" + }, + { + "day": 0, + "flight": "AF606", + "utc": "17:25:00" + }, + { + "day": 1, + "flight": "AF132", + "utc": "07:15:00" + }, + { + "day": 1, + "flight": "AF132", + "utc": "00:14:00" + }, + { + "day": 1, + "flight": "AF568", + "utc": "09:49:00" + }, + { + "day": 2, + "flight": "AF489", + "utc": "16:51:00" + }, + { + "day": 3, + "flight": "AF427", + "utc": "06:10:00" + }, + { + "day": 4, + "flight": "AF566", + "utc": "23:15:00" + }, + { + "day": 4, + "flight": "AF238", + "utc": "22:49:00" + }, + { + "day": 4, + "flight": "AF606", + "utc": "16:17:00" + }, + { + "day": 5, + "flight": "AF925", + "utc": "23:53:00" + }, + { + "day": 5, + "flight": "AF888", + "utc": "12:11:00" + }, + { + "day": 5, + "flight": "AF817", + "utc": "13:09:00" + }, + { + "day": 5, + "flight": "AF290", + "utc": "03:13:00" + }, + { + "day": 5, + "flight": "AF213", + "utc": "02:47:00" + }, + { + "day": 6, + "flight": "AF891", + "utc": "14:24:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "HAM", + "distance": 1277.920368466386, + "equipment": "319", + "id": 9991, + "schedule": [ + { + "day": 0, + "flight": "AF447", + "utc": "05:13:00" + }, + { + "day": 1, + "flight": "AF948", + "utc": "22:21:00" + }, + { + "day": 1, + "flight": "AF812", + "utc": "03:32:00" + }, + { + "day": 1, + "flight": "AF473", + "utc": "12:07:00" + }, + { + "day": 2, + "flight": "AF144", + "utc": "21:30:00" + }, + { + "day": 2, + "flight": "AF721", + "utc": "10:42:00" + }, + { + "day": 2, + "flight": "AF117", + "utc": "02:07:00" + }, + { + "day": 2, + "flight": "AF382", + "utc": "10:57:00" + }, + { + "day": 3, + "flight": "AF432", + "utc": "12:33:00" + }, + { + "day": 3, + "flight": "AF936", + "utc": "07:58:00" + }, + { + "day": 4, + "flight": "AF082", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "AF060", + "utc": "23:38:00" + }, + { + "day": 4, + "flight": "AF040", + "utc": "17:39:00" + }, + { + "day": 4, + "flight": "AF072", + "utc": "02:25:00" + }, + { + "day": 5, + "flight": "AF511", + "utc": "18:29:00" + }, + { + "day": 5, + "flight": "AF065", + "utc": "11:52:00" + }, + { + "day": 5, + "flight": "AF461", + "utc": "18:49:00" + }, + { + "day": 5, + "flight": "AF562", + "utc": "10:10:00" + }, + { + "day": 6, + "flight": "AF305", + "utc": "16:07:00" + }, + { + "day": 6, + "flight": "AF762", + "utc": "19:24:00" + }, + { + "day": 6, + "flight": "AF062", + "utc": "20:15:00" + }, + { + "day": 6, + "flight": "AF339", + "utc": "12:15:00" + }, + { + "day": 6, + "flight": "AF982", + "utc": "15:15:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319 320 CRK", + "id": 9992, + "schedule": [ + { + "day": 0, + "flight": "AF823", + "utc": "19:58:00" + }, + { + "day": 0, + "flight": "AF523", + "utc": "05:11:00" + }, + { + "day": 0, + "flight": "AF212", + "utc": "04:29:00" + }, + { + "day": 0, + "flight": "AF928", + "utc": "07:41:00" + }, + { + "day": 0, + "flight": "AF064", + "utc": "20:55:00" + }, + { + "day": 1, + "flight": "AF584", + "utc": "18:14:00" + }, + { + "day": 1, + "flight": "AF903", + "utc": "07:20:00" + }, + { + "day": 1, + "flight": "AF815", + "utc": "16:43:00" + }, + { + "day": 1, + "flight": "AF283", + "utc": "09:31:00" + }, + { + "day": 1, + "flight": "AF682", + "utc": "02:15:00" + }, + { + "day": 2, + "flight": "AF907", + "utc": "06:21:00" + }, + { + "day": 2, + "flight": "AF094", + "utc": "08:33:00" + }, + { + "day": 2, + "flight": "AF449", + "utc": "15:44:00" + }, + { + "day": 2, + "flight": "AF876", + "utc": "22:00:00" + }, + { + "day": 3, + "flight": "AF828", + "utc": "06:35:00" + }, + { + "day": 3, + "flight": "AF125", + "utc": "15:35:00" + }, + { + "day": 4, + "flight": "AF348", + "utc": "08:34:00" + }, + { + "day": 5, + "flight": "AF100", + "utc": "20:01:00" + }, + { + "day": 5, + "flight": "AF530", + "utc": "11:25:00" + }, + { + "day": 6, + "flight": "AF763", + "utc": "19:11:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "MLA", + "distance": 1412.6976574099108, + "equipment": "320 319", + "id": 9993, + "schedule": [ + { + "day": 0, + "flight": "AF590", + "utc": "23:02:00" + }, + { + "day": 1, + "flight": "AF224", + "utc": "18:02:00" + }, + { + "day": 2, + "flight": "AF834", + "utc": "15:09:00" + }, + { + "day": 2, + "flight": "AF748", + "utc": "09:21:00" + }, + { + "day": 2, + "flight": "AF947", + "utc": "15:28:00" + }, + { + "day": 2, + "flight": "AF058", + "utc": "19:08:00" + }, + { + "day": 2, + "flight": "AF914", + "utc": "18:02:00" + }, + { + "day": 3, + "flight": "AF351", + "utc": "04:18:00" + }, + { + "day": 3, + "flight": "AF975", + "utc": "13:49:00" + }, + { + "day": 3, + "flight": "AF361", + "utc": "18:56:00" + }, + { + "day": 4, + "flight": "AF461", + "utc": "01:40:00" + }, + { + "day": 5, + "flight": "AF281", + "utc": "10:31:00" + }, + { + "day": 6, + "flight": "AF337", + "utc": "10:18:00" + }, + { + "day": 6, + "flight": "AF570", + "utc": "07:41:00" + }, + { + "day": 6, + "flight": "AF823", + "utc": "20:37:00" + }, + { + "day": 6, + "flight": "AF109", + "utc": "14:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ORY", + "distance": 571.8189591117047, + "equipment": "320 319 321", + "id": 9994, + "schedule": [ + { + "day": 0, + "flight": "AF986", + "utc": "12:40:00" + }, + { + "day": 0, + "flight": "AF951", + "utc": "06:14:00" + }, + { + "day": 0, + "flight": "AF527", + "utc": "11:45:00" + }, + { + "day": 0, + "flight": "AF801", + "utc": "14:47:00" + }, + { + "day": 1, + "flight": "AF838", + "utc": "05:42:00" + }, + { + "day": 2, + "flight": "AF952", + "utc": "03:24:00" + }, + { + "day": 2, + "flight": "AF920", + "utc": "14:50:00" + }, + { + "day": 2, + "flight": "AF318", + "utc": "03:40:00" + }, + { + "day": 2, + "flight": "AF137", + "utc": "20:21:00" + }, + { + "day": 3, + "flight": "AF135", + "utc": "15:04:00" + }, + { + "day": 4, + "flight": "AF847", + "utc": "22:57:00" + }, + { + "day": 4, + "flight": "AF010", + "utc": "07:51:00" + }, + { + "day": 4, + "flight": "AF973", + "utc": "17:28:00" + }, + { + "day": 5, + "flight": "AF532", + "utc": "22:28:00" + }, + { + "day": 5, + "flight": "AF447", + "utc": "18:35:00" + }, + { + "day": 5, + "flight": "AF017", + "utc": "13:48:00" + }, + { + "day": 5, + "flight": "AF135", + "utc": "10:16:00" + }, + { + "day": 6, + "flight": "AF933", + "utc": "21:03:00" + }, + { + "day": 6, + "flight": "AF024", + "utc": "05:59:00" + }, + { + "day": 6, + "flight": "AF243", + "utc": "06:19:00" + }, + { + "day": 6, + "flight": "AF619", + "utc": "03:41:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "319 320", + "id": 9995, + "schedule": [ + { + "day": 0, + "flight": "AF312", + "utc": "08:58:00" + }, + { + "day": 0, + "flight": "AF099", + "utc": "22:19:00" + }, + { + "day": 0, + "flight": "AF157", + "utc": "05:26:00" + }, + { + "day": 1, + "flight": "AF793", + "utc": "14:45:00" + }, + { + "day": 1, + "flight": "AF638", + "utc": "03:55:00" + }, + { + "day": 1, + "flight": "AF372", + "utc": "20:37:00" + }, + { + "day": 1, + "flight": "AF788", + "utc": "19:15:00" + }, + { + "day": 1, + "flight": "AF889", + "utc": "02:00:00" + }, + { + "day": 2, + "flight": "AF521", + "utc": "21:48:00" + }, + { + "day": 2, + "flight": "AF990", + "utc": "19:41:00" + }, + { + "day": 2, + "flight": "AF047", + "utc": "00:33:00" + }, + { + "day": 2, + "flight": "AF540", + "utc": "08:19:00" + }, + { + "day": 3, + "flight": "AF247", + "utc": "02:30:00" + }, + { + "day": 3, + "flight": "AF197", + "utc": "07:17:00" + }, + { + "day": 3, + "flight": "AF015", + "utc": "07:05:00" + }, + { + "day": 4, + "flight": "AF213", + "utc": "22:43:00" + }, + { + "day": 5, + "flight": "AF732", + "utc": "03:12:00" + }, + { + "day": 5, + "flight": "AF304", + "utc": "08:21:00" + }, + { + "day": 6, + "flight": "AF274", + "utc": "12:07:00" + }, + { + "day": 6, + "flight": "AF177", + "utc": "19:29:00" + }, + { + "day": 6, + "flight": "AF409", + "utc": "23:56:00" + }, + { + "day": 6, + "flight": "AF099", + "utc": "07:45:00" + }, + { + "day": 6, + "flight": "AF848", + "utc": "12:34:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "SVQ", + "distance": 922.9469580316244, + "equipment": "319", + "id": 9996, + "schedule": [ + { + "day": 0, + "flight": "AF720", + "utc": "10:48:00" + }, + { + "day": 0, + "flight": "AF932", + "utc": "22:03:00" + }, + { + "day": 0, + "flight": "AF292", + "utc": "20:49:00" + }, + { + "day": 1, + "flight": "AF080", + "utc": "09:57:00" + }, + { + "day": 1, + "flight": "AF668", + "utc": "23:52:00" + }, + { + "day": 1, + "flight": "AF713", + "utc": "04:58:00" + }, + { + "day": 1, + "flight": "AF490", + "utc": "13:37:00" + }, + { + "day": 1, + "flight": "AF809", + "utc": "01:49:00" + }, + { + "day": 2, + "flight": "AF203", + "utc": "16:09:00" + }, + { + "day": 2, + "flight": "AF329", + "utc": "19:59:00" + }, + { + "day": 2, + "flight": "AF875", + "utc": "15:10:00" + }, + { + "day": 3, + "flight": "AF757", + "utc": "12:26:00" + }, + { + "day": 3, + "flight": "AF350", + "utc": "13:33:00" + }, + { + "day": 3, + "flight": "AF530", + "utc": "21:25:00" + }, + { + "day": 3, + "flight": "AF793", + "utc": "15:05:00" + }, + { + "day": 3, + "flight": "AF124", + "utc": "23:40:00" + }, + { + "day": 4, + "flight": "AF959", + "utc": "07:46:00" + }, + { + "day": 4, + "flight": "AF363", + "utc": "01:02:00" + }, + { + "day": 5, + "flight": "AF816", + "utc": "10:35:00" + }, + { + "day": 6, + "flight": "AF918", + "utc": "23:43:00" + }, + { + "day": 6, + "flight": "AF600", + "utc": "02:43:00" + }, + { + "day": 6, + "flight": "AF072", + "utc": "21:29:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "SXB", + "distance": 728.4867234220715, + "equipment": "319 320", + "id": 9997, + "schedule": [ + { + "day": 0, + "flight": "AF998", + "utc": "19:19:00" + }, + { + "day": 0, + "flight": "AF527", + "utc": "21:15:00" + }, + { + "day": 0, + "flight": "AF043", + "utc": "12:21:00" + }, + { + "day": 0, + "flight": "AF783", + "utc": "03:06:00" + }, + { + "day": 0, + "flight": "AF947", + "utc": "11:16:00" + }, + { + "day": 1, + "flight": "AF339", + "utc": "22:50:00" + }, + { + "day": 1, + "flight": "AF399", + "utc": "23:32:00" + }, + { + "day": 1, + "flight": "AF327", + "utc": "00:17:00" + }, + { + "day": 1, + "flight": "AF658", + "utc": "20:23:00" + }, + { + "day": 1, + "flight": "AF307", + "utc": "04:54:00" + }, + { + "day": 2, + "flight": "AF521", + "utc": "06:47:00" + }, + { + "day": 2, + "flight": "AF687", + "utc": "12:12:00" + }, + { + "day": 3, + "flight": "AF258", + "utc": "23:32:00" + }, + { + "day": 3, + "flight": "AF265", + "utc": "07:55:00" + }, + { + "day": 3, + "flight": "AF284", + "utc": "12:10:00" + }, + { + "day": 3, + "flight": "AF532", + "utc": "14:27:00" + }, + { + "day": 3, + "flight": "AF916", + "utc": "06:00:00" + }, + { + "day": 4, + "flight": "AF399", + "utc": "17:38:00" + }, + { + "day": 4, + "flight": "AF805", + "utc": "05:59:00" + }, + { + "day": 5, + "flight": "AF657", + "utc": "13:08:00" + }, + { + "day": 5, + "flight": "AF361", + "utc": "12:44:00" + }, + { + "day": 6, + "flight": "AF659", + "utc": "07:14:00" + }, + { + "day": 6, + "flight": "AF096", + "utc": "06:33:00" + }, + { + "day": 6, + "flight": "AF289", + "utc": "01:31:00" + }, + { + "day": 6, + "flight": "AF338", + "utc": "19:03:00" + }, + { + "day": 6, + "flight": "AF985", + "utc": "07:42:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "VCE", + "distance": 894.3253403650848, + "equipment": "319 320", + "id": 9998, + "schedule": [ + { + "day": 0, + "flight": "AF396", + "utc": "14:33:00" + }, + { + "day": 0, + "flight": "AF180", + "utc": "02:02:00" + }, + { + "day": 0, + "flight": "AF752", + "utc": "06:07:00" + }, + { + "day": 1, + "flight": "AF686", + "utc": "09:35:00" + }, + { + "day": 1, + "flight": "AF614", + "utc": "00:48:00" + }, + { + "day": 1, + "flight": "AF443", + "utc": "11:54:00" + }, + { + "day": 1, + "flight": "AF125", + "utc": "15:34:00" + }, + { + "day": 2, + "flight": "AF045", + "utc": "20:49:00" + }, + { + "day": 2, + "flight": "AF430", + "utc": "22:18:00" + }, + { + "day": 2, + "flight": "AF068", + "utc": "05:24:00" + }, + { + "day": 2, + "flight": "AF945", + "utc": "08:23:00" + }, + { + "day": 2, + "flight": "AF949", + "utc": "05:19:00" + }, + { + "day": 3, + "flight": "AF249", + "utc": "15:48:00" + }, + { + "day": 3, + "flight": "AF468", + "utc": "09:43:00" + }, + { + "day": 4, + "flight": "AF966", + "utc": "00:15:00" + }, + { + "day": 4, + "flight": "AF461", + "utc": "16:58:00" + }, + { + "day": 5, + "flight": "AF993", + "utc": "12:09:00" + }, + { + "day": 5, + "flight": "AF790", + "utc": "04:27:00" + }, + { + "day": 5, + "flight": "AF370", + "utc": "01:25:00" + }, + { + "day": 5, + "flight": "AF861", + "utc": "21:37:00" + }, + { + "day": 5, + "flight": "AF480", + "utc": "05:17:00" + }, + { + "day": 6, + "flight": "AF733", + "utc": "04:13:00" + }, + { + "day": 6, + "flight": "AF308", + "utc": "01:08:00" + }, + { + "day": 6, + "flight": "AF063", + "utc": "04:55:00" + }, + { + "day": 6, + "flight": "AF257", + "utc": "17:21:00" + }, + { + "day": 6, + "flight": "AF531", + "utc": "13:24:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + } +// tag::extract[] + ] + } +] +// end::extract[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-nest-inner.n1ql b/modules/n1ql/examples/select/ansi-nest-inner.n1ql new file mode 100644 index 000000000..351ccfb88 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest-inner.n1ql @@ -0,0 +1,6 @@ +SELECT * +FROM airport a + INNER NEST route r + ON a.faa = r.sourceairport +WHERE a.city = "Toulouse" +ORDER BY a.airportname; \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-nest-lateral.jsonc b/modules/n1ql/examples/select/ansi-nest-lateral.jsonc new file mode 100644 index 000000000..752357f47 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest-lateral.jsonc @@ -0,0 +1,8607 @@ +// tag::extract[] +[ + { + "a": { + "id": 1273, + "type": "airport", + "airportname": "Blagnac", + "city": "Toulouse", + "country": "France", + "faa": "TLS", + "icao": "LFBO", + "tz": "Europe/Paris", + "geo": { + "lat": 43.629075, + "lon": 1.363819, + "alt": 499 + } + }, + "r": [ + { + "airline": "AH", + "airlineid": "airline_794", + "destinationairport": "ALG", + "distance": 787.299015326995, + "equipment": "736", + "id": 10265, + // end::extract[] + // tag::ellipsis[] + // ... + // end::ellipsis[] + "schedule": [ + { + "day": 0, + "flight": "AH221", + "utc": "17:23:00" + }, + { + "day": 1, + "flight": "AH920", + "utc": "07:44:00" + }, + { + "day": 1, + "flight": "AH593", + "utc": "12:04:00" + }, + { + "day": 1, + "flight": "AH394", + "utc": "00:33:00" + }, + { + "day": 1, + "flight": "AH180", + "utc": "20:18:00" + }, + { + "day": 2, + "flight": "AH974", + "utc": "01:21:00" + }, + { + "day": 3, + "flight": "AH281", + "utc": "09:34:00" + }, + { + "day": 3, + "flight": "AH033", + "utc": "11:02:00" + }, + { + "day": 3, + "flight": "AH385", + "utc": "11:42:00" + }, + { + "day": 3, + "flight": "AH989", + "utc": "09:07:00" + }, + { + "day": 3, + "flight": "AH834", + "utc": "18:46:00" + }, + { + "day": 4, + "flight": "AH417", + "utc": "05:17:00" + }, + { + "day": 4, + "flight": "AH322", + "utc": "11:10:00" + }, + { + "day": 4, + "flight": "AH235", + "utc": "18:43:00" + }, + { + "day": 4, + "flight": "AH995", + "utc": "00:15:00" + }, + { + "day": 4, + "flight": "AH619", + "utc": "08:43:00" + }, + { + "day": 5, + "flight": "AH537", + "utc": "03:48:00" + }, + { + "day": 5, + "flight": "AH181", + "utc": "11:23:00" + }, + { + "day": 5, + "flight": "AH083", + "utc": "12:37:00" + }, + { + "day": 5, + "flight": "AH727", + "utc": "12:08:00" + }, + { + "day": 6, + "flight": "AH377", + "utc": "13:15:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AH", + "airlineid": "airline_794", + "destinationairport": "ORN", + "distance": 906.1483088609814, + "equipment": "736", + "id": 10266, + "schedule": [ + { + "day": 0, + "flight": "AH152", + "utc": "14:02:00" + }, + { + "day": 0, + "flight": "AH864", + "utc": "11:48:00" + }, + { + "day": 0, + "flight": "AH922", + "utc": "11:03:00" + }, + { + "day": 1, + "flight": "AH633", + "utc": "13:22:00" + }, + { + "day": 1, + "flight": "AH450", + "utc": "05:32:00" + }, + { + "day": 1, + "flight": "AH343", + "utc": "05:17:00" + }, + { + "day": 2, + "flight": "AH869", + "utc": "17:26:00" + }, + { + "day": 2, + "flight": "AH175", + "utc": "13:56:00" + }, + { + "day": 3, + "flight": "AH243", + "utc": "22:54:00" + }, + { + "day": 3, + "flight": "AH778", + "utc": "09:53:00" + }, + { + "day": 3, + "flight": "AH049", + "utc": "02:20:00" + }, + { + "day": 3, + "flight": "AH930", + "utc": "05:40:00" + }, + { + "day": 3, + "flight": "AH206", + "utc": "10:03:00" + }, + { + "day": 4, + "flight": "AH125", + "utc": "16:15:00" + }, + { + "day": 4, + "flight": "AH533", + "utc": "10:50:00" + }, + { + "day": 4, + "flight": "AH494", + "utc": "10:36:00" + }, + { + "day": 4, + "flight": "AH759", + "utc": "17:10:00" + }, + { + "day": 5, + "flight": "AH267", + "utc": "22:16:00" + }, + { + "day": 5, + "flight": "AH769", + "utc": "09:13:00" + }, + { + "day": 5, + "flight": "AH116", + "utc": "09:19:00" + }, + { + "day": 5, + "flight": "AH949", + "utc": "02:28:00" + }, + { + "day": 5, + "flight": "AH624", + "utc": "03:51:00" + }, + { + "day": 6, + "flight": "AH597", + "utc": "02:23:00" + }, + { + "day": 6, + "flight": "AH523", + "utc": "05:32:00" + }, + { + "day": 6, + "flight": "AH615", + "utc": "00:19:00" + }, + { + "day": 6, + "flight": "AH453", + "utc": "19:08:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AT", + "airlineid": "airline_4248", + "destinationairport": "CMN", + "distance": 1379.8271930529227, + "equipment": "738 73G", + "id": 12271, + "schedule": [ + { + "day": 0, + "flight": "AT780", + "utc": "17:23:00" + }, + { + "day": 0, + "flight": "AT069", + "utc": "00:25:00" + }, + { + "day": 0, + "flight": "AT970", + "utc": "10:57:00" + }, + { + "day": 1, + "flight": "AT716", + "utc": "05:22:00" + }, + { + "day": 1, + "flight": "AT424", + "utc": "02:09:00" + }, + { + "day": 1, + "flight": "AT498", + "utc": "00:54:00" + }, + { + "day": 1, + "flight": "AT552", + "utc": "19:13:00" + }, + { + "day": 1, + "flight": "AT967", + "utc": "05:05:00" + }, + { + "day": 2, + "flight": "AT640", + "utc": "17:24:00" + }, + { + "day": 2, + "flight": "AT877", + "utc": "04:34:00" + }, + { + "day": 2, + "flight": "AT439", + "utc": "12:48:00" + }, + { + "day": 3, + "flight": "AT447", + "utc": "06:27:00" + }, + { + "day": 3, + "flight": "AT882", + "utc": "10:53:00" + }, + { + "day": 3, + "flight": "AT548", + "utc": "08:29:00" + }, + { + "day": 3, + "flight": "AT489", + "utc": "10:37:00" + }, + { + "day": 3, + "flight": "AT611", + "utc": "14:16:00" + }, + { + "day": 4, + "flight": "AT539", + "utc": "19:59:00" + }, + { + "day": 4, + "flight": "AT570", + "utc": "03:23:00" + }, + { + "day": 4, + "flight": "AT350", + "utc": "15:03:00" + }, + { + "day": 4, + "flight": "AT899", + "utc": "08:00:00" + }, + { + "day": 4, + "flight": "AT909", + "utc": "16:53:00" + }, + { + "day": 5, + "flight": "AT985", + "utc": "21:31:00" + }, + { + "day": 5, + "flight": "AT617", + "utc": "16:28:00" + }, + { + "day": 5, + "flight": "AT745", + "utc": "19:02:00" + }, + { + "day": 6, + "flight": "AT015", + "utc": "10:04:00" + }, + { + "day": 6, + "flight": "AT270", + "utc": "03:19:00" + }, + { + "day": 6, + "flight": "AT975", + "utc": "04:16:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AT", + "airlineid": "airline_4248", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "738", + "id": 12272, + "schedule": [ + { + "day": 0, + "flight": "AT223", + "utc": "10:06:00" + }, + { + "day": 1, + "flight": "AT187", + "utc": "20:12:00" + }, + { + "day": 2, + "flight": "AT379", + "utc": "14:45:00" + }, + { + "day": 2, + "flight": "AT950", + "utc": "08:07:00" + }, + { + "day": 2, + "flight": "AT921", + "utc": "22:15:00" + }, + { + "day": 2, + "flight": "AT122", + "utc": "06:39:00" + }, + { + "day": 3, + "flight": "AT413", + "utc": "21:46:00" + }, + { + "day": 3, + "flight": "AT974", + "utc": "13:14:00" + }, + { + "day": 3, + "flight": "AT805", + "utc": "22:18:00" + }, + { + "day": 3, + "flight": "AT558", + "utc": "15:35:00" + }, + { + "day": 4, + "flight": "AT919", + "utc": "11:11:00" + }, + { + "day": 4, + "flight": "AT380", + "utc": "14:20:00" + }, + { + "day": 4, + "flight": "AT588", + "utc": "12:03:00" + }, + { + "day": 4, + "flight": "AT762", + "utc": "16:07:00" + }, + { + "day": 5, + "flight": "AT423", + "utc": "12:28:00" + }, + { + "day": 6, + "flight": "AT554", + "utc": "15:05:00" + }, + { + "day": 6, + "flight": "AT145", + "utc": "07:36:00" + }, + { + "day": 6, + "flight": "AT179", + "utc": "05:51:00" + }, + { + "day": 6, + "flight": "AT460", + "utc": "02:34:00" + }, + { + "day": 6, + "flight": "AT648", + "utc": "16:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "320 319", + "id": 13715, + "schedule": [ + { + "day": 0, + "flight": "AZ503", + "utc": "10:59:00" + }, + { + "day": 0, + "flight": "AZ608", + "utc": "02:25:00" + }, + { + "day": 1, + "flight": "AZ013", + "utc": "21:09:00" + }, + { + "day": 1, + "flight": "AZ108", + "utc": "22:36:00" + }, + { + "day": 1, + "flight": "AZ730", + "utc": "17:38:00" + }, + { + "day": 2, + "flight": "AZ527", + "utc": "17:39:00" + }, + { + "day": 2, + "flight": "AZ506", + "utc": "21:44:00" + }, + { + "day": 2, + "flight": "AZ072", + "utc": "10:12:00" + }, + { + "day": 2, + "flight": "AZ661", + "utc": "21:42:00" + }, + { + "day": 3, + "flight": "AZ873", + "utc": "16:32:00" + }, + { + "day": 3, + "flight": "AZ005", + "utc": "18:21:00" + }, + { + "day": 3, + "flight": "AZ573", + "utc": "17:58:00" + }, + { + "day": 4, + "flight": "AZ318", + "utc": "10:20:00" + }, + { + "day": 4, + "flight": "AZ537", + "utc": "13:33:00" + }, + { + "day": 4, + "flight": "AZ187", + "utc": "14:18:00" + }, + { + "day": 4, + "flight": "AZ590", + "utc": "12:28:00" + }, + { + "day": 5, + "flight": "AZ997", + "utc": "22:03:00" + }, + { + "day": 6, + "flight": "AZ915", + "utc": "21:20:00" + }, + { + "day": 6, + "flight": "AZ927", + "utc": "17:48:00" + }, + { + "day": 6, + "flight": "AZ073", + "utc": "05:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "E75", + "id": 13716, + "schedule": [ + { + "day": 0, + "flight": "AZ121", + "utc": "02:19:00" + }, + { + "day": 0, + "flight": "AZ997", + "utc": "02:46:00" + }, + { + "day": 1, + "flight": "AZ068", + "utc": "15:00:00" + }, + { + "day": 1, + "flight": "AZ873", + "utc": "01:54:00" + }, + { + "day": 1, + "flight": "AZ441", + "utc": "06:02:00" + }, + { + "day": 1, + "flight": "AZ942", + "utc": "01:37:00" + }, + { + "day": 1, + "flight": "AZ399", + "utc": "20:15:00" + }, + { + "day": 2, + "flight": "AZ471", + "utc": "05:47:00" + }, + { + "day": 3, + "flight": "AZ641", + "utc": "09:17:00" + }, + { + "day": 3, + "flight": "AZ994", + "utc": "21:28:00" + }, + { + "day": 3, + "flight": "AZ237", + "utc": "04:09:00" + }, + { + "day": 3, + "flight": "AZ294", + "utc": "03:44:00" + }, + { + "day": 3, + "flight": "AZ683", + "utc": "20:27:00" + }, + { + "day": 4, + "flight": "AZ925", + "utc": "02:55:00" + }, + { + "day": 4, + "flight": "AZ713", + "utc": "14:45:00" + }, + { + "day": 5, + "flight": "AZ414", + "utc": "10:11:00" + }, + { + "day": 5, + "flight": "AZ163", + "utc": "07:30:00" + }, + { + "day": 5, + "flight": "AZ413", + "utc": "21:23:00" + }, + { + "day": 5, + "flight": "AZ535", + "utc": "04:02:00" + }, + { + "day": 5, + "flight": "AZ119", + "utc": "21:16:00" + }, + { + "day": 6, + "flight": "AZ610", + "utc": "12:40:00" + }, + { + "day": 6, + "flight": "AZ694", + "utc": "03:10:00" + }, + { + "day": 6, + "flight": "AZ190", + "utc": "12:47:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319 320 CRK", + "id": 13717, + "schedule": [ + { + "day": 0, + "flight": "AZ226", + "utc": "06:27:00" + }, + { + "day": 0, + "flight": "AZ102", + "utc": "15:40:00" + }, + { + "day": 0, + "flight": "AZ366", + "utc": "05:31:00" + }, + { + "day": 0, + "flight": "AZ469", + "utc": "23:10:00" + }, + { + "day": 0, + "flight": "AZ910", + "utc": "05:39:00" + }, + { + "day": 1, + "flight": "AZ643", + "utc": "13:50:00" + }, + { + "day": 1, + "flight": "AZ897", + "utc": "15:10:00" + }, + { + "day": 1, + "flight": "AZ167", + "utc": "15:00:00" + }, + { + "day": 1, + "flight": "AZ427", + "utc": "10:23:00" + }, + { + "day": 2, + "flight": "AZ472", + "utc": "07:02:00" + }, + { + "day": 3, + "flight": "AZ887", + "utc": "13:57:00" + }, + { + "day": 3, + "flight": "AZ694", + "utc": "20:32:00" + }, + { + "day": 3, + "flight": "AZ781", + "utc": "00:51:00" + }, + { + "day": 3, + "flight": "AZ633", + "utc": "22:00:00" + }, + { + "day": 4, + "flight": "AZ346", + "utc": "21:27:00" + }, + { + "day": 4, + "flight": "AZ570", + "utc": "15:59:00" + }, + { + "day": 4, + "flight": "AZ395", + "utc": "20:42:00" + }, + { + "day": 4, + "flight": "AZ009", + "utc": "15:01:00" + }, + { + "day": 4, + "flight": "AZ097", + "utc": "19:04:00" + }, + { + "day": 5, + "flight": "AZ363", + "utc": "01:15:00" + }, + { + "day": 5, + "flight": "AZ513", + "utc": "23:55:00" + }, + { + "day": 5, + "flight": "AZ311", + "utc": "10:51:00" + }, + { + "day": 5, + "flight": "AZ374", + "utc": "23:22:00" + }, + { + "day": 6, + "flight": "AZ027", + "utc": "10:27:00" + }, + { + "day": 6, + "flight": "AZ782", + "utc": "23:04:00" + }, + { + "day": 6, + "flight": "AZ869", + "utc": "01:27:00" + }, + { + "day": 6, + "flight": "AZ117", + "utc": "09:01:00" + }, + { + "day": 6, + "flight": "AZ365", + "utc": "11:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "VCE", + "distance": 894.3253403650848, + "equipment": "319 320", + "id": 13718, + "schedule": [ + { + "day": 0, + "flight": "AZ323", + "utc": "21:01:00" + }, + { + "day": 0, + "flight": "AZ639", + "utc": "06:08:00" + }, + { + "day": 0, + "flight": "AZ751", + "utc": "09:17:00" + }, + { + "day": 0, + "flight": "AZ418", + "utc": "10:51:00" + }, + { + "day": 0, + "flight": "AZ293", + "utc": "09:42:00" + }, + { + "day": 1, + "flight": "AZ294", + "utc": "11:55:00" + }, + { + "day": 1, + "flight": "AZ618", + "utc": "04:56:00" + }, + { + "day": 1, + "flight": "AZ919", + "utc": "00:38:00" + }, + { + "day": 2, + "flight": "AZ839", + "utc": "17:52:00" + }, + { + "day": 2, + "flight": "AZ252", + "utc": "23:45:00" + }, + { + "day": 3, + "flight": "AZ477", + "utc": "00:11:00" + }, + { + "day": 4, + "flight": "AZ903", + "utc": "15:47:00" + }, + { + "day": 4, + "flight": "AZ933", + "utc": "23:28:00" + }, + { + "day": 4, + "flight": "AZ320", + "utc": "18:22:00" + }, + { + "day": 4, + "flight": "AZ866", + "utc": "04:11:00" + }, + { + "day": 5, + "flight": "AZ877", + "utc": "21:44:00" + }, + { + "day": 5, + "flight": "AZ810", + "utc": "06:51:00" + }, + { + "day": 6, + "flight": "AZ910", + "utc": "12:05:00" + }, + { + "day": 6, + "flight": "AZ341", + "utc": "10:32:00" + }, + { + "day": 6, + "flight": "AZ544", + "utc": "18:04:00" + }, + { + "day": 6, + "flight": "AZ780", + "utc": "10:21:00" + }, + { + "day": 6, + "flight": "AZ392", + "utc": "07:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "BA", + "airlineid": "airline_1355", + "destinationairport": "LHR", + "distance": 883.3122325423356, + "equipment": "320 319 321", + "id": 14913, + "schedule": [ + { + "day": 0, + "flight": "BA098", + "utc": "11:01:00" + }, + { + "day": 0, + "flight": "BA391", + "utc": "05:10:00" + }, + { + "day": 0, + "flight": "BA960", + "utc": "22:58:00" + }, + { + "day": 1, + "flight": "BA681", + "utc": "10:42:00" + }, + { + "day": 1, + "flight": "BA255", + "utc": "14:13:00" + }, + { + "day": 1, + "flight": "BA715", + "utc": "02:32:00" + }, + { + "day": 1, + "flight": "BA860", + "utc": "13:23:00" + }, + { + "day": 1, + "flight": "BA241", + "utc": "12:27:00" + }, + { + "day": 2, + "flight": "BA737", + "utc": "18:30:00" + }, + { + "day": 2, + "flight": "BA602", + "utc": "15:35:00" + }, + { + "day": 2, + "flight": "BA709", + "utc": "12:21:00" + }, + { + "day": 2, + "flight": "BA796", + "utc": "11:08:00" + }, + { + "day": 2, + "flight": "BA067", + "utc": "00:28:00" + }, + { + "day": 3, + "flight": "BA111", + "utc": "00:08:00" + }, + { + "day": 3, + "flight": "BA920", + "utc": "14:33:00" + }, + { + "day": 3, + "flight": "BA469", + "utc": "18:09:00" + }, + { + "day": 3, + "flight": "BA122", + "utc": "05:40:00" + }, + { + "day": 3, + "flight": "BA194", + "utc": "11:45:00" + }, + { + "day": 4, + "flight": "BA481", + "utc": "19:41:00" + }, + { + "day": 4, + "flight": "BA430", + "utc": "01:39:00" + }, + { + "day": 4, + "flight": "BA439", + "utc": "07:02:00" + }, + { + "day": 5, + "flight": "BA287", + "utc": "08:08:00" + }, + { + "day": 5, + "flight": "BA097", + "utc": "04:45:00" + }, + { + "day": 6, + "flight": "BA177", + "utc": "00:26:00" + }, + { + "day": 6, + "flight": "BA703", + "utc": "23:45:00" + }, + { + "day": 6, + "flight": "BA326", + "utc": "15:49:00" + }, + { + "day": 6, + "flight": "BA238", + "utc": "23:31:00" + }, + { + "day": 6, + "flight": "BA717", + "utc": "07:18:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "4U", + "airlineid": "airline_2548", + "destinationairport": "HAM", + "distance": 1277.920368466386, + "equipment": "CRJ", + "id": 1638, + "schedule": [ + { + "day": 0, + "flight": "4U997", + "utc": "03:46:00" + }, + { + "day": 1, + "flight": "4U464", + "utc": "15:51:00" + }, + { + "day": 1, + "flight": "4U823", + "utc": "01:54:00" + }, + { + "day": 2, + "flight": "4U060", + "utc": "01:28:00" + }, + { + "day": 2, + "flight": "4U489", + "utc": "08:26:00" + }, + { + "day": 2, + "flight": "4U835", + "utc": "15:04:00" + }, + { + "day": 2, + "flight": "4U267", + "utc": "23:16:00" + }, + { + "day": 3, + "flight": "4U085", + "utc": "22:10:00" + }, + { + "day": 3, + "flight": "4U835", + "utc": "11:52:00" + }, + { + "day": 3, + "flight": "4U688", + "utc": "09:26:00" + }, + { + "day": 4, + "flight": "4U808", + "utc": "20:34:00" + }, + { + "day": 4, + "flight": "4U408", + "utc": "10:31:00" + }, + { + "day": 4, + "flight": "4U614", + "utc": "11:22:00" + }, + { + "day": 4, + "flight": "4U093", + "utc": "17:56:00" + }, + { + "day": 4, + "flight": "4U664", + "utc": "03:06:00" + }, + { + "day": 5, + "flight": "4U030", + "utc": "13:04:00" + }, + { + "day": 6, + "flight": "4U771", + "utc": "08:13:00" + }, + { + "day": 6, + "flight": "4U198", + "utc": "20:11:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "EI", + "airlineid": "airline_837", + "destinationairport": "DUB", + "distance": 1223.7865232537742, + "equipment": "320", + "id": 23056, + "schedule": [ + { + "day": 0, + "flight": "EI370", + "utc": "11:48:00" + }, + { + "day": 1, + "flight": "EI137", + "utc": "16:37:00" + }, + { + "day": 1, + "flight": "EI052", + "utc": "11:06:00" + }, + { + "day": 1, + "flight": "EI383", + "utc": "14:12:00" + }, + { + "day": 2, + "flight": "EI657", + "utc": "11:49:00" + }, + { + "day": 2, + "flight": "EI394", + "utc": "04:10:00" + }, + { + "day": 2, + "flight": "EI000", + "utc": "01:50:00" + }, + { + "day": 2, + "flight": "EI475", + "utc": "06:36:00" + }, + { + "day": 2, + "flight": "EI292", + "utc": "12:49:00" + }, + { + "day": 3, + "flight": "EI262", + "utc": "05:57:00" + }, + { + "day": 3, + "flight": "EI355", + "utc": "08:00:00" + }, + { + "day": 3, + "flight": "EI831", + "utc": "13:22:00" + }, + { + "day": 3, + "flight": "EI812", + "utc": "12:43:00" + }, + { + "day": 3, + "flight": "EI228", + "utc": "08:51:00" + }, + { + "day": 4, + "flight": "EI446", + "utc": "04:33:00" + }, + { + "day": 4, + "flight": "EI823", + "utc": "11:38:00" + }, + { + "day": 4, + "flight": "EI880", + "utc": "07:11:00" + }, + { + "day": 4, + "flight": "EI483", + "utc": "18:05:00" + }, + { + "day": 5, + "flight": "EI989", + "utc": "05:58:00" + }, + { + "day": 5, + "flight": "EI395", + "utc": "07:41:00" + }, + { + "day": 5, + "flight": "EI362", + "utc": "04:45:00" + }, + { + "day": 5, + "flight": "EI749", + "utc": "16:24:00" + }, + { + "day": 5, + "flight": "EI146", + "utc": "07:57:00" + }, + { + "day": 6, + "flight": "EI249", + "utc": "06:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ET", + "airlineid": "airline_2220", + "destinationairport": "FRA", + "distance": 895.9770471097812, + "equipment": "735", + "id": 23940, + "schedule": [ + { + "day": 0, + "flight": "ET478", + "utc": "13:07:00" + }, + { + "day": 0, + "flight": "ET739", + "utc": "11:40:00" + }, + { + "day": 0, + "flight": "ET520", + "utc": "10:18:00" + }, + { + "day": 1, + "flight": "ET223", + "utc": "07:18:00" + }, + { + "day": 2, + "flight": "ET473", + "utc": "02:16:00" + }, + { + "day": 3, + "flight": "ET341", + "utc": "11:18:00" + }, + { + "day": 3, + "flight": "ET928", + "utc": "05:33:00" + }, + { + "day": 3, + "flight": "ET563", + "utc": "06:17:00" + }, + { + "day": 3, + "flight": "ET107", + "utc": "23:11:00" + }, + { + "day": 4, + "flight": "ET204", + "utc": "22:10:00" + }, + { + "day": 4, + "flight": "ET428", + "utc": "12:06:00" + }, + { + "day": 4, + "flight": "ET246", + "utc": "18:11:00" + }, + { + "day": 5, + "flight": "ET964", + "utc": "02:06:00" + }, + { + "day": 5, + "flight": "ET452", + "utc": "02:36:00" + }, + { + "day": 5, + "flight": "ET362", + "utc": "00:43:00" + }, + { + "day": 5, + "flight": "ET098", + "utc": "02:52:00" + }, + { + "day": 6, + "flight": "ET378", + "utc": "11:31:00" + }, + { + "day": 6, + "flight": "ET541", + "utc": "03:24:00" + }, + { + "day": 6, + "flight": "ET010", + "utc": "05:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "F7", + "airlineid": "airline_2420", + "destinationairport": "GVA", + "distance": 472.80826589600406, + "equipment": "AT7", + "id": 24308, + "schedule": [ + { + "day": 0, + "flight": "F7903", + "utc": "21:43:00" + }, + { + "day": 0, + "flight": "F7859", + "utc": "02:36:00" + }, + { + "day": 1, + "flight": "F7360", + "utc": "18:52:00" + }, + { + "day": 1, + "flight": "F7401", + "utc": "04:33:00" + }, + { + "day": 2, + "flight": "F7127", + "utc": "02:17:00" + }, + { + "day": 2, + "flight": "F7772", + "utc": "06:20:00" + }, + { + "day": 2, + "flight": "F7056", + "utc": "04:56:00" + }, + { + "day": 2, + "flight": "F7884", + "utc": "10:25:00" + }, + { + "day": 2, + "flight": "F7191", + "utc": "03:20:00" + }, + { + "day": 3, + "flight": "F7235", + "utc": "16:22:00" + }, + { + "day": 4, + "flight": "F7619", + "utc": "03:09:00" + }, + { + "day": 4, + "flight": "F7421", + "utc": "15:49:00" + }, + { + "day": 4, + "flight": "F7915", + "utc": "18:59:00" + }, + { + "day": 5, + "flight": "F7759", + "utc": "09:56:00" + }, + { + "day": 6, + "flight": "F7515", + "utc": "09:50:00" + }, + { + "day": 6, + "flight": "F7400", + "utc": "00:10:00" + }, + { + "day": 6, + "flight": "F7362", + "utc": "08:47:00" + }, + { + "day": 6, + "flight": "F7098", + "utc": "21:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "AGP", + "distance": 919.3439362090616, + "equipment": "320", + "id": 32956, + "schedule": [ + { + "day": 0, + "flight": "IB587", + "utc": "19:18:00" + }, + { + "day": 1, + "flight": "IB830", + "utc": "07:20:00" + }, + { + "day": 1, + "flight": "IB966", + "utc": "00:13:00" + }, + { + "day": 1, + "flight": "IB923", + "utc": "20:53:00" + }, + { + "day": 1, + "flight": "IB151", + "utc": "01:03:00" + }, + { + "day": 1, + "flight": "IB479", + "utc": "21:56:00" + }, + { + "day": 2, + "flight": "IB950", + "utc": "20:52:00" + }, + { + "day": 3, + "flight": "IB517", + "utc": "01:57:00" + }, + { + "day": 3, + "flight": "IB242", + "utc": "01:46:00" + }, + { + "day": 3, + "flight": "IB875", + "utc": "08:31:00" + }, + { + "day": 4, + "flight": "IB828", + "utc": "09:25:00" + }, + { + "day": 4, + "flight": "IB676", + "utc": "01:32:00" + }, + { + "day": 5, + "flight": "IB943", + "utc": "15:51:00" + }, + { + "day": 6, + "flight": "IB384", + "utc": "22:30:00" + }, + { + "day": 6, + "flight": "IB278", + "utc": "18:51:00" + }, + { + "day": 6, + "flight": "IB511", + "utc": "23:39:00" + }, + { + "day": 6, + "flight": "IB429", + "utc": "18:51:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "BCN", + "distance": 265.8469587104912, + "equipment": "320", + "id": 32957, + "schedule": [ + { + "day": 0, + "flight": "IB518", + "utc": "10:08:00" + }, + { + "day": 1, + "flight": "IB011", + "utc": "18:40:00" + }, + { + "day": 1, + "flight": "IB839", + "utc": "09:11:00" + }, + { + "day": 1, + "flight": "IB767", + "utc": "14:32:00" + }, + { + "day": 2, + "flight": "IB958", + "utc": "17:49:00" + }, + { + "day": 2, + "flight": "IB055", + "utc": "02:06:00" + }, + { + "day": 2, + "flight": "IB718", + "utc": "12:09:00" + }, + { + "day": 2, + "flight": "IB544", + "utc": "19:50:00" + }, + { + "day": 2, + "flight": "IB221", + "utc": "02:53:00" + }, + { + "day": 3, + "flight": "IB596", + "utc": "01:30:00" + }, + { + "day": 3, + "flight": "IB433", + "utc": "21:32:00" + }, + { + "day": 3, + "flight": "IB996", + "utc": "04:23:00" + }, + { + "day": 4, + "flight": "IB575", + "utc": "04:54:00" + }, + { + "day": 4, + "flight": "IB743", + "utc": "16:36:00" + }, + { + "day": 4, + "flight": "IB335", + "utc": "18:23:00" + }, + { + "day": 5, + "flight": "IB775", + "utc": "12:25:00" + }, + { + "day": 5, + "flight": "IB949", + "utc": "19:00:00" + }, + { + "day": 5, + "flight": "IB955", + "utc": "07:08:00" + }, + { + "day": 5, + "flight": "IB309", + "utc": "19:11:00" + }, + { + "day": 6, + "flight": "IB228", + "utc": "18:42:00" + }, + { + "day": 6, + "flight": "IB195", + "utc": "06:02:00" + }, + { + "day": 6, + "flight": "IB721", + "utc": "01:06:00" + }, + { + "day": 6, + "flight": "IB313", + "utc": "05:19:00" + }, + { + "day": 6, + "flight": "IB797", + "utc": "19:35:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "MAD", + "distance": 535.7735390346035, + "equipment": "CRK CR9 CR2", + "id": 32958, + "schedule": [ + { + "day": 0, + "flight": "IB321", + "utc": "19:44:00" + }, + { + "day": 0, + "flight": "IB262", + "utc": "04:50:00" + }, + { + "day": 0, + "flight": "IB266", + "utc": "03:12:00" + }, + { + "day": 1, + "flight": "IB365", + "utc": "00:15:00" + }, + { + "day": 1, + "flight": "IB159", + "utc": "07:14:00" + }, + { + "day": 1, + "flight": "IB507", + "utc": "07:30:00" + }, + { + "day": 1, + "flight": "IB760", + "utc": "21:03:00" + }, + { + "day": 2, + "flight": "IB072", + "utc": "05:28:00" + }, + { + "day": 2, + "flight": "IB707", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "IB101", + "utc": "17:49:00" + }, + { + "day": 3, + "flight": "IB949", + "utc": "06:14:00" + }, + { + "day": 3, + "flight": "IB780", + "utc": "13:13:00" + }, + { + "day": 3, + "flight": "IB675", + "utc": "01:43:00" + }, + { + "day": 3, + "flight": "IB942", + "utc": "11:46:00" + }, + { + "day": 3, + "flight": "IB669", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "IB290", + "utc": "01:53:00" + }, + { + "day": 4, + "flight": "IB587", + "utc": "04:52:00" + }, + { + "day": 4, + "flight": "IB553", + "utc": "23:37:00" + }, + { + "day": 4, + "flight": "IB623", + "utc": "03:23:00" + }, + { + "day": 5, + "flight": "IB667", + "utc": "20:42:00" + }, + { + "day": 6, + "flight": "IB763", + "utc": "11:56:00" + }, + { + "day": 6, + "flight": "IB004", + "utc": "12:38:00" + }, + { + "day": 6, + "flight": "IB606", + "utc": "11:07:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "PMI", + "distance": 467.1315518195575, + "equipment": "320", + "id": 32959, + "schedule": [ + { + "day": 0, + "flight": "IB718", + "utc": "00:29:00" + }, + { + "day": 1, + "flight": "IB529", + "utc": "21:51:00" + }, + { + "day": 1, + "flight": "IB262", + "utc": "18:34:00" + }, + { + "day": 1, + "flight": "IB202", + "utc": "05:59:00" + }, + { + "day": 1, + "flight": "IB428", + "utc": "00:21:00" + }, + { + "day": 1, + "flight": "IB433", + "utc": "13:14:00" + }, + { + "day": 2, + "flight": "IB873", + "utc": "03:44:00" + }, + { + "day": 2, + "flight": "IB588", + "utc": "06:43:00" + }, + { + "day": 2, + "flight": "IB848", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "IB656", + "utc": "08:28:00" + }, + { + "day": 3, + "flight": "IB865", + "utc": "03:25:00" + }, + { + "day": 4, + "flight": "IB322", + "utc": "06:53:00" + }, + { + "day": 5, + "flight": "IB208", + "utc": "16:30:00" + }, + { + "day": 5, + "flight": "IB316", + "utc": "23:39:00" + }, + { + "day": 6, + "flight": "IB038", + "utc": "14:32:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "SVQ", + "distance": 922.9469580316244, + "equipment": "CR2 CR9", + "id": 32960, + "schedule": [ + { + "day": 0, + "flight": "IB226", + "utc": "15:38:00" + }, + { + "day": 1, + "flight": "IB907", + "utc": "20:45:00" + }, + { + "day": 1, + "flight": "IB223", + "utc": "13:32:00" + }, + { + "day": 2, + "flight": "IB285", + "utc": "21:42:00" + }, + { + "day": 2, + "flight": "IB825", + "utc": "11:24:00" + }, + { + "day": 2, + "flight": "IB376", + "utc": "21:47:00" + }, + { + "day": 2, + "flight": "IB239", + "utc": "04:40:00" + }, + { + "day": 2, + "flight": "IB103", + "utc": "19:33:00" + }, + { + "day": 3, + "flight": "IB475", + "utc": "20:31:00" + }, + { + "day": 3, + "flight": "IB732", + "utc": "03:24:00" + }, + { + "day": 3, + "flight": "IB618", + "utc": "02:15:00" + }, + { + "day": 3, + "flight": "IB718", + "utc": "01:24:00" + }, + { + "day": 3, + "flight": "IB258", + "utc": "16:40:00" + }, + { + "day": 4, + "flight": "IB007", + "utc": "06:47:00" + }, + { + "day": 4, + "flight": "IB963", + "utc": "08:06:00" + }, + { + "day": 4, + "flight": "IB695", + "utc": "23:29:00" + }, + { + "day": 4, + "flight": "IB756", + "utc": "22:37:00" + }, + { + "day": 4, + "flight": "IB555", + "utc": "04:34:00" + }, + { + "day": 5, + "flight": "IB480", + "utc": "19:14:00" + }, + { + "day": 5, + "flight": "IB436", + "utc": "15:11:00" + }, + { + "day": 5, + "flight": "IB561", + "utc": "19:43:00" + }, + { + "day": 6, + "flight": "IB324", + "utc": "15:17:00" + }, + { + "day": 6, + "flight": "IB656", + "utc": "17:44:00" + }, + { + "day": 6, + "flight": "IB649", + "utc": "01:49:00" + }, + { + "day": 6, + "flight": "IB616", + "utc": "04:28:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "KL", + "airlineid": "airline_3090", + "destinationairport": "AMS", + "distance": 997.4702942027754, + "equipment": "EMJ", + "id": 36938, + "schedule": [ + { + "day": 0, + "flight": "KL119", + "utc": "23:23:00" + }, + { + "day": 0, + "flight": "KL028", + "utc": "16:25:00" + }, + { + "day": 0, + "flight": "KL388", + "utc": "21:51:00" + }, + { + "day": 1, + "flight": "KL644", + "utc": "14:15:00" + }, + { + "day": 1, + "flight": "KL816", + "utc": "02:49:00" + }, + { + "day": 2, + "flight": "KL713", + "utc": "21:18:00" + }, + { + "day": 2, + "flight": "KL045", + "utc": "03:30:00" + }, + { + "day": 2, + "flight": "KL755", + "utc": "04:12:00" + }, + { + "day": 2, + "flight": "KL554", + "utc": "21:21:00" + }, + { + "day": 2, + "flight": "KL684", + "utc": "17:06:00" + }, + { + "day": 3, + "flight": "KL045", + "utc": "13:12:00" + }, + { + "day": 3, + "flight": "KL002", + "utc": "01:39:00" + }, + { + "day": 4, + "flight": "KL398", + "utc": "07:13:00" + }, + { + "day": 4, + "flight": "KL169", + "utc": "12:16:00" + }, + { + "day": 5, + "flight": "KL548", + "utc": "06:29:00" + }, + { + "day": 5, + "flight": "KL168", + "utc": "13:10:00" + }, + { + "day": 5, + "flight": "KL417", + "utc": "16:25:00" + }, + { + "day": 5, + "flight": "KL656", + "utc": "07:19:00" + }, + { + "day": 5, + "flight": "KL570", + "utc": "04:28:00" + }, + { + "day": 6, + "flight": "KL710", + "utc": "18:57:00" + }, + { + "day": 6, + "flight": "KL453", + "utc": "14:01:00" + }, + { + "day": 6, + "flight": "KL139", + "utc": "09:26:00" + }, + { + "day": 6, + "flight": "KL055", + "utc": "17:53:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LH", + "airlineid": "airline_3320", + "destinationairport": "FRA", + "distance": 895.9770471097812, + "equipment": "321 319 735 733", + "id": 38788, + "schedule": [ + { + "day": 0, + "flight": "LH182", + "utc": "17:57:00" + }, + { + "day": 0, + "flight": "LH378", + "utc": "23:48:00" + }, + { + "day": 0, + "flight": "LH719", + "utc": "04:51:00" + }, + { + "day": 0, + "flight": "LH093", + "utc": "07:33:00" + }, + { + "day": 1, + "flight": "LH478", + "utc": "09:22:00" + }, + { + "day": 1, + "flight": "LH690", + "utc": "17:45:00" + }, + { + "day": 1, + "flight": "LH047", + "utc": "09:16:00" + }, + { + "day": 2, + "flight": "LH452", + "utc": "03:47:00" + }, + { + "day": 3, + "flight": "LH567", + "utc": "11:45:00" + }, + { + "day": 3, + "flight": "LH798", + "utc": "16:08:00" + }, + { + "day": 3, + "flight": "LH960", + "utc": "03:04:00" + }, + { + "day": 4, + "flight": "LH025", + "utc": "08:49:00" + }, + { + "day": 4, + "flight": "LH057", + "utc": "21:14:00" + }, + { + "day": 4, + "flight": "LH531", + "utc": "14:33:00" + }, + { + "day": 4, + "flight": "LH326", + "utc": "03:01:00" + }, + { + "day": 5, + "flight": "LH896", + "utc": "13:43:00" + }, + { + "day": 5, + "flight": "LH430", + "utc": "05:54:00" + }, + { + "day": 5, + "flight": "LH970", + "utc": "04:56:00" + }, + { + "day": 5, + "flight": "LH631", + "utc": "09:26:00" + }, + { + "day": 6, + "flight": "LH333", + "utc": "14:35:00" + }, + { + "day": 6, + "flight": "LH238", + "utc": "16:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LH", + "airlineid": "airline_3320", + "destinationairport": "MUC", + "distance": 960.1175459963162, + "equipment": "E95 319 CR9", + "id": 38789, + "schedule": [ + { + "day": 0, + "flight": "LH106", + "utc": "12:56:00" + }, + { + "day": 0, + "flight": "LH636", + "utc": "05:06:00" + }, + { + "day": 0, + "flight": "LH300", + "utc": "09:20:00" + }, + { + "day": 1, + "flight": "LH996", + "utc": "19:29:00" + }, + { + "day": 1, + "flight": "LH746", + "utc": "10:57:00" + }, + { + "day": 2, + "flight": "LH391", + "utc": "16:36:00" + }, + { + "day": 2, + "flight": "LH079", + "utc": "23:31:00" + }, + { + "day": 2, + "flight": "LH340", + "utc": "10:39:00" + }, + { + "day": 2, + "flight": "LH192", + "utc": "07:48:00" + }, + { + "day": 3, + "flight": "LH563", + "utc": "18:53:00" + }, + { + "day": 3, + "flight": "LH371", + "utc": "08:50:00" + }, + { + "day": 4, + "flight": "LH679", + "utc": "08:56:00" + }, + { + "day": 4, + "flight": "LH078", + "utc": "09:08:00" + }, + { + "day": 4, + "flight": "LH655", + "utc": "14:38:00" + }, + { + "day": 4, + "flight": "LH223", + "utc": "21:54:00" + }, + { + "day": 5, + "flight": "LH253", + "utc": "19:19:00" + }, + { + "day": 5, + "flight": "LH525", + "utc": "15:57:00" + }, + { + "day": 5, + "flight": "LH597", + "utc": "17:13:00" + }, + { + "day": 5, + "flight": "LH315", + "utc": "11:20:00" + }, + { + "day": 6, + "flight": "LH220", + "utc": "03:43:00" + }, + { + "day": 6, + "flight": "LH436", + "utc": "07:44:00" + }, + { + "day": 6, + "flight": "LH405", + "utc": "02:54:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LS", + "airlineid": "airline_3026", + "destinationairport": "MAN", + "distance": 1113.7047637485857, + "equipment": "733", + "id": 39505, + "schedule": [ + { + "day": 0, + "flight": "LS423", + "utc": "10:40:00" + }, + { + "day": 0, + "flight": "LS623", + "utc": "17:06:00" + }, + { + "day": 0, + "flight": "LS249", + "utc": "04:44:00" + }, + { + "day": 1, + "flight": "LS652", + "utc": "21:17:00" + }, + { + "day": 1, + "flight": "LS967", + "utc": "07:51:00" + }, + { + "day": 1, + "flight": "LS903", + "utc": "00:46:00" + }, + { + "day": 1, + "flight": "LS677", + "utc": "05:11:00" + }, + { + "day": 1, + "flight": "LS052", + "utc": "12:41:00" + }, + { + "day": 2, + "flight": "LS007", + "utc": "21:49:00" + }, + { + "day": 2, + "flight": "LS939", + "utc": "23:49:00" + }, + { + "day": 2, + "flight": "LS302", + "utc": "07:34:00" + }, + { + "day": 3, + "flight": "LS621", + "utc": "05:51:00" + }, + { + "day": 4, + "flight": "LS175", + "utc": "02:50:00" + }, + { + "day": 4, + "flight": "LS573", + "utc": "03:49:00" + }, + { + "day": 4, + "flight": "LS528", + "utc": "04:27:00" + }, + { + "day": 4, + "flight": "LS210", + "utc": "19:08:00" + }, + { + "day": 5, + "flight": "LS706", + "utc": "05:35:00" + }, + { + "day": 5, + "flight": "LS663", + "utc": "23:00:00" + }, + { + "day": 5, + "flight": "LS217", + "utc": "04:32:00" + }, + { + "day": 5, + "flight": "LS585", + "utc": "02:15:00" + }, + { + "day": 5, + "flight": "LS163", + "utc": "05:21:00" + }, + { + "day": 6, + "flight": "LS299", + "utc": "05:12:00" + }, + { + "day": 6, + "flight": "LS259", + "utc": "20:44:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "LIL", + "distance": 781.8286754466159, + "equipment": "E70", + "id": 4627, + "schedule": [ + { + "day": 0, + "flight": "A5460", + "utc": "17:28:00" + }, + { + "day": 0, + "flight": "A5895", + "utc": "22:47:00" + }, + { + "day": 0, + "flight": "A5181", + "utc": "18:35:00" + }, + { + "day": 0, + "flight": "A5682", + "utc": "09:47:00" + }, + { + "day": 1, + "flight": "A5875", + "utc": "02:04:00" + }, + { + "day": 1, + "flight": "A5659", + "utc": "20:46:00" + }, + { + "day": 1, + "flight": "A5468", + "utc": "15:49:00" + }, + { + "day": 2, + "flight": "A5922", + "utc": "19:01:00" + }, + { + "day": 2, + "flight": "A5805", + "utc": "00:36:00" + }, + { + "day": 2, + "flight": "A5845", + "utc": "06:28:00" + }, + { + "day": 2, + "flight": "A5150", + "utc": "06:07:00" + }, + { + "day": 2, + "flight": "A5724", + "utc": "03:42:00" + }, + { + "day": 3, + "flight": "A5678", + "utc": "04:33:00" + }, + { + "day": 3, + "flight": "A5535", + "utc": "00:11:00" + }, + { + "day": 3, + "flight": "A5085", + "utc": "14:15:00" + }, + { + "day": 4, + "flight": "A5977", + "utc": "16:46:00" + }, + { + "day": 4, + "flight": "A5994", + "utc": "11:15:00" + }, + { + "day": 4, + "flight": "A5404", + "utc": "21:01:00" + }, + { + "day": 5, + "flight": "A5450", + "utc": "06:41:00" + }, + { + "day": 5, + "flight": "A5761", + "utc": "22:09:00" + }, + { + "day": 5, + "flight": "A5598", + "utc": "00:47:00" + }, + { + "day": 5, + "flight": "A5994", + "utc": "14:58:00" + }, + { + "day": 6, + "flight": "A5828", + "utc": "18:06:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "MRS", + "distance": 311.0670134047465, + "equipment": "AT5", + "id": 4628, + "schedule": [ + { + "day": 0, + "flight": "A5338", + "utc": "05:02:00" + }, + { + "day": 0, + "flight": "A5882", + "utc": "12:46:00" + }, + { + "day": 0, + "flight": "A5406", + "utc": "10:08:00" + }, + { + "day": 0, + "flight": "A5631", + "utc": "18:02:00" + }, + { + "day": 0, + "flight": "A5670", + "utc": "03:24:00" + }, + { + "day": 1, + "flight": "A5689", + "utc": "16:59:00" + }, + { + "day": 2, + "flight": "A5073", + "utc": "13:10:00" + }, + { + "day": 2, + "flight": "A5790", + "utc": "07:41:00" + }, + { + "day": 3, + "flight": "A5862", + "utc": "22:10:00" + }, + { + "day": 3, + "flight": "A5650", + "utc": "07:40:00" + }, + { + "day": 3, + "flight": "A5874", + "utc": "20:54:00" + }, + { + "day": 3, + "flight": "A5502", + "utc": "17:52:00" + }, + { + "day": 3, + "flight": "A5294", + "utc": "19:33:00" + }, + { + "day": 4, + "flight": "A5376", + "utc": "09:42:00" + }, + { + "day": 4, + "flight": "A5302", + "utc": "21:26:00" + }, + { + "day": 4, + "flight": "A5348", + "utc": "10:57:00" + }, + { + "day": 4, + "flight": "A5003", + "utc": "08:01:00" + }, + { + "day": 4, + "flight": "A5018", + "utc": "20:03:00" + }, + { + "day": 5, + "flight": "A5983", + "utc": "03:02:00" + }, + { + "day": 5, + "flight": "A5026", + "utc": "08:27:00" + }, + { + "day": 5, + "flight": "A5481", + "utc": "15:09:00" + }, + { + "day": 5, + "flight": "A5479", + "utc": "22:40:00" + }, + { + "day": 5, + "flight": "A5264", + "utc": "16:22:00" + }, + { + "day": 6, + "flight": "A5308", + "utc": "23:02:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "NCE", + "distance": 470.8031011808527, + "equipment": "AT7", + "id": 4629, + "schedule": [ + { + "day": 0, + "flight": "A5283", + "utc": "02:13:00" + }, + { + "day": 0, + "flight": "A5869", + "utc": "12:53:00" + }, + { + "day": 1, + "flight": "A5559", + "utc": "15:22:00" + }, + { + "day": 1, + "flight": "A5213", + "utc": "13:43:00" + }, + { + "day": 1, + "flight": "A5935", + "utc": "19:54:00" + }, + { + "day": 1, + "flight": "A5622", + "utc": "16:18:00" + }, + { + "day": 2, + "flight": "A5016", + "utc": "17:15:00" + }, + { + "day": 2, + "flight": "A5523", + "utc": "21:14:00" + }, + { + "day": 2, + "flight": "A5896", + "utc": "08:11:00" + }, + { + "day": 3, + "flight": "A5287", + "utc": "00:53:00" + }, + { + "day": 3, + "flight": "A5772", + "utc": "09:58:00" + }, + { + "day": 4, + "flight": "A5470", + "utc": "06:37:00" + }, + { + "day": 4, + "flight": "A5047", + "utc": "03:32:00" + }, + { + "day": 4, + "flight": "A5006", + "utc": "07:08:00" + }, + { + "day": 4, + "flight": "A5631", + "utc": "09:29:00" + }, + { + "day": 4, + "flight": "A5434", + "utc": "02:39:00" + }, + { + "day": 5, + "flight": "A5437", + "utc": "08:39:00" + }, + { + "day": 5, + "flight": "A5606", + "utc": "22:00:00" + }, + { + "day": 5, + "flight": "A5895", + "utc": "20:21:00" + }, + { + "day": 5, + "flight": "A5504", + "utc": "20:04:00" + }, + { + "day": 6, + "flight": "A5579", + "utc": "02:55:00" + }, + { + "day": 6, + "flight": "A5099", + "utc": "22:02:00" + }, + { + "day": 6, + "flight": "A5703", + "utc": "02:31:00" + }, + { + "day": 6, + "flight": "A5253", + "utc": "14:34:00" + }, + { + "day": 6, + "flight": "A5615", + "utc": "11:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "NTE", + "distance": 455.4490681425203, + "equipment": "CR7", + "id": 4630, + "schedule": [ + { + "day": 0, + "flight": "A5134", + "utc": "20:08:00" + }, + { + "day": 0, + "flight": "A5131", + "utc": "02:01:00" + }, + { + "day": 0, + "flight": "A5431", + "utc": "17:28:00" + }, + { + "day": 0, + "flight": "A5382", + "utc": "12:25:00" + }, + { + "day": 1, + "flight": "A5065", + "utc": "16:44:00" + }, + { + "day": 1, + "flight": "A5091", + "utc": "03:41:00" + }, + { + "day": 1, + "flight": "A5242", + "utc": "04:14:00" + }, + { + "day": 1, + "flight": "A5781", + "utc": "12:57:00" + }, + { + "day": 2, + "flight": "A5552", + "utc": "15:45:00" + }, + { + "day": 2, + "flight": "A5610", + "utc": "17:04:00" + }, + { + "day": 2, + "flight": "A5252", + "utc": "03:20:00" + }, + { + "day": 2, + "flight": "A5112", + "utc": "02:20:00" + }, + { + "day": 2, + "flight": "A5684", + "utc": "06:52:00" + }, + { + "day": 3, + "flight": "A5601", + "utc": "02:23:00" + }, + { + "day": 3, + "flight": "A5066", + "utc": "19:34:00" + }, + { + "day": 3, + "flight": "A5226", + "utc": "09:59:00" + }, + { + "day": 3, + "flight": "A5216", + "utc": "13:05:00" + }, + { + "day": 4, + "flight": "A5793", + "utc": "03:37:00" + }, + { + "day": 4, + "flight": "A5506", + "utc": "00:37:00" + }, + { + "day": 4, + "flight": "A5053", + "utc": "03:43:00" + }, + { + "day": 4, + "flight": "A5006", + "utc": "08:21:00" + }, + { + "day": 5, + "flight": "A5463", + "utc": "10:00:00" + }, + { + "day": 5, + "flight": "A5609", + "utc": "05:23:00" + }, + { + "day": 6, + "flight": "A5040", + "utc": "20:12:00" + }, + { + "day": 6, + "flight": "A5449", + "utc": "02:33:00" + }, + { + "day": 6, + "flight": "A5870", + "utc": "17:40:00" + }, + { + "day": 6, + "flight": "A5577", + "utc": "09:57:00" + }, + { + "day": 6, + "flight": "A5516", + "utc": "03:49:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "RNS", + "distance": 548.8740198503464, + "equipment": "CRJ CR7", + "id": 4631, + "schedule": [ + { + "day": 0, + "flight": "A5172", + "utc": "16:26:00" + }, + { + "day": 0, + "flight": "A5610", + "utc": "01:09:00" + }, + { + "day": 0, + "flight": "A5338", + "utc": "05:14:00" + }, + { + "day": 1, + "flight": "A5456", + "utc": "17:30:00" + }, + { + "day": 2, + "flight": "A5316", + "utc": "14:50:00" + }, + { + "day": 2, + "flight": "A5137", + "utc": "19:39:00" + }, + { + "day": 2, + "flight": "A5478", + "utc": "02:26:00" + }, + { + "day": 3, + "flight": "A5007", + "utc": "21:23:00" + }, + { + "day": 3, + "flight": "A5614", + "utc": "00:19:00" + }, + { + "day": 3, + "flight": "A5025", + "utc": "07:24:00" + }, + { + "day": 4, + "flight": "A5295", + "utc": "22:57:00" + }, + { + "day": 4, + "flight": "A5250", + "utc": "09:02:00" + }, + { + "day": 5, + "flight": "A5548", + "utc": "11:17:00" + }, + { + "day": 5, + "flight": "A5666", + "utc": "21:29:00" + }, + { + "day": 5, + "flight": "A5572", + "utc": "22:04:00" + }, + { + "day": 6, + "flight": "A5953", + "utc": "06:52:00" + }, + { + "day": 6, + "flight": "A5438", + "utc": "01:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "SE", + "airlineid": "airline_5479", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "332", + "id": 49359, + "schedule": [ + { + "day": 0, + "flight": "SE239", + "utc": "02:38:00" + }, + { + "day": 1, + "flight": "SE278", + "utc": "13:05:00" + }, + { + "day": 2, + "flight": "SE859", + "utc": "03:00:00" + }, + { + "day": 3, + "flight": "SE316", + "utc": "06:46:00" + }, + { + "day": 3, + "flight": "SE570", + "utc": "22:46:00" + }, + { + "day": 3, + "flight": "SE236", + "utc": "06:03:00" + }, + { + "day": 3, + "flight": "SE140", + "utc": "07:28:00" + }, + { + "day": 4, + "flight": "SE907", + "utc": "22:00:00" + }, + { + "day": 4, + "flight": "SE943", + "utc": "04:02:00" + }, + { + "day": 4, + "flight": "SE337", + "utc": "16:25:00" + }, + { + "day": 4, + "flight": "SE342", + "utc": "21:03:00" + }, + { + "day": 5, + "flight": "SE200", + "utc": "02:43:00" + }, + { + "day": 5, + "flight": "SE777", + "utc": "04:12:00" + }, + { + "day": 6, + "flight": "SE566", + "utc": "13:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "SN", + "airlineid": "airline_1531", + "destinationairport": "BRU", + "distance": 842.027454616631, + "equipment": "AR1", + "id": 50376, + "schedule": [ + { + "day": 0, + "flight": "SN526", + "utc": "17:16:00" + }, + { + "day": 0, + "flight": "SN650", + "utc": "05:15:00" + }, + { + "day": 1, + "flight": "SN990", + "utc": "22:21:00" + }, + { + "day": 2, + "flight": "SN199", + "utc": "12:46:00" + }, + { + "day": 2, + "flight": "SN329", + "utc": "14:46:00" + }, + { + "day": 3, + "flight": "SN504", + "utc": "19:57:00" + }, + { + "day": 3, + "flight": "SN802", + "utc": "13:25:00" + }, + { + "day": 3, + "flight": "SN769", + "utc": "10:36:00" + }, + { + "day": 3, + "flight": "SN806", + "utc": "06:33:00" + }, + { + "day": 4, + "flight": "SN332", + "utc": "07:50:00" + }, + { + "day": 4, + "flight": "SN147", + "utc": "05:19:00" + }, + { + "day": 4, + "flight": "SN036", + "utc": "19:01:00" + }, + { + "day": 4, + "flight": "SN184", + "utc": "19:45:00" + }, + { + "day": 4, + "flight": "SN395", + "utc": "00:58:00" + }, + { + "day": 5, + "flight": "SN532", + "utc": "15:37:00" + }, + { + "day": 6, + "flight": "SN973", + "utc": "16:37:00" + }, + { + "day": 6, + "flight": "SN605", + "utc": "05:06:00" + }, + { + "day": 6, + "flight": "SN450", + "utc": "20:54:00" + }, + { + "day": 6, + "flight": "SN822", + "utc": "23:11:00" + }, + { + "day": 6, + "flight": "SN149", + "utc": "01:59:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "BRS", + "distance": 914.710726420036, + "equipment": "ER4", + "id": 50746, + "schedule": [ + { + "day": 0, + "flight": "ST010", + "utc": "01:55:00" + }, + { + "day": 0, + "flight": "ST465", + "utc": "22:46:00" + }, + { + "day": 0, + "flight": "ST492", + "utc": "14:29:00" + }, + { + "day": 1, + "flight": "ST648", + "utc": "04:09:00" + }, + { + "day": 2, + "flight": "ST986", + "utc": "18:13:00" + }, + { + "day": 2, + "flight": "ST818", + "utc": "00:36:00" + }, + { + "day": 2, + "flight": "ST484", + "utc": "12:12:00" + }, + { + "day": 2, + "flight": "ST401", + "utc": "05:03:00" + }, + { + "day": 2, + "flight": "ST075", + "utc": "01:11:00" + }, + { + "day": 3, + "flight": "ST467", + "utc": "13:35:00" + }, + { + "day": 3, + "flight": "ST556", + "utc": "07:23:00" + }, + { + "day": 3, + "flight": "ST035", + "utc": "17:14:00" + }, + { + "day": 3, + "flight": "ST786", + "utc": "06:31:00" + }, + { + "day": 3, + "flight": "ST544", + "utc": "02:47:00" + }, + { + "day": 4, + "flight": "ST689", + "utc": "10:42:00" + }, + { + "day": 4, + "flight": "ST643", + "utc": "01:58:00" + }, + { + "day": 4, + "flight": "ST022", + "utc": "03:46:00" + }, + { + "day": 4, + "flight": "ST805", + "utc": "00:34:00" + }, + { + "day": 5, + "flight": "ST581", + "utc": "21:11:00" + }, + { + "day": 6, + "flight": "ST175", + "utc": "23:56:00" + }, + { + "day": 6, + "flight": "ST166", + "utc": "09:23:00" + }, + { + "day": 6, + "flight": "ST101", + "utc": "14:57:00" + }, + { + "day": 6, + "flight": "ST983", + "utc": "08:31:00" + }, + { + "day": 6, + "flight": "ST822", + "utc": "17:34:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "CEG", + "distance": 1108.5852832314715, + "equipment": "ER4", + "id": 50747, + "schedule": [ + { + "day": 0, + "flight": "ST127", + "utc": "21:02:00" + }, + { + "day": 0, + "flight": "ST839", + "utc": "22:35:00" + }, + { + "day": 0, + "flight": "ST267", + "utc": "14:02:00" + }, + { + "day": 0, + "flight": "ST016", + "utc": "10:17:00" + }, + { + "day": 1, + "flight": "ST623", + "utc": "07:52:00" + }, + { + "day": 1, + "flight": "ST105", + "utc": "00:34:00" + }, + { + "day": 1, + "flight": "ST459", + "utc": "02:07:00" + }, + { + "day": 1, + "flight": "ST170", + "utc": "18:29:00" + }, + { + "day": 1, + "flight": "ST830", + "utc": "21:49:00" + }, + { + "day": 2, + "flight": "ST884", + "utc": "21:53:00" + }, + { + "day": 3, + "flight": "ST924", + "utc": "04:55:00" + }, + { + "day": 3, + "flight": "ST261", + "utc": "01:16:00" + }, + { + "day": 3, + "flight": "ST016", + "utc": "04:50:00" + }, + { + "day": 3, + "flight": "ST260", + "utc": "04:46:00" + }, + { + "day": 4, + "flight": "ST863", + "utc": "10:59:00" + }, + { + "day": 4, + "flight": "ST200", + "utc": "03:30:00" + }, + { + "day": 4, + "flight": "ST152", + "utc": "07:31:00" + }, + { + "day": 5, + "flight": "ST738", + "utc": "05:45:00" + }, + { + "day": 5, + "flight": "ST453", + "utc": "00:23:00" + }, + { + "day": 5, + "flight": "ST503", + "utc": "02:00:00" + }, + { + "day": 6, + "flight": "ST286", + "utc": "16:11:00" + }, + { + "day": 6, + "flight": "ST878", + "utc": "19:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "XFW", + "distance": 1263.676446061964, + "equipment": "319", + "id": 50748, + "schedule": [ + { + "day": 0, + "flight": "ST732", + "utc": "23:31:00" + }, + { + "day": 1, + "flight": "ST711", + "utc": "12:54:00" + }, + { + "day": 1, + "flight": "ST553", + "utc": "08:51:00" + }, + { + "day": 2, + "flight": "ST603", + "utc": "02:06:00" + }, + { + "day": 3, + "flight": "ST345", + "utc": "05:04:00" + }, + { + "day": 3, + "flight": "ST401", + "utc": "20:24:00" + }, + { + "day": 4, + "flight": "ST317", + "utc": "00:48:00" + }, + { + "day": 4, + "flight": "ST133", + "utc": "14:45:00" + }, + { + "day": 4, + "flight": "ST217", + "utc": "08:52:00" + }, + { + "day": 4, + "flight": "ST471", + "utc": "01:06:00" + }, + { + "day": 4, + "flight": "ST213", + "utc": "06:59:00" + }, + { + "day": 5, + "flight": "ST277", + "utc": "00:10:00" + }, + { + "day": 5, + "flight": "ST056", + "utc": "10:50:00" + }, + { + "day": 5, + "flight": "ST553", + "utc": "07:18:00" + }, + { + "day": 5, + "flight": "ST673", + "utc": "06:34:00" + }, + { + "day": 5, + "flight": "ST729", + "utc": "20:03:00" + }, + { + "day": 6, + "flight": "ST737", + "utc": "20:09:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T3", + "airlineid": "airline_2117", + "destinationairport": "DIJ", + "distance": 498.1611053856414, + "equipment": "J41", + "id": 51783, + "schedule": [ + { + "day": 0, + "flight": "T3325", + "utc": "05:11:00" + }, + { + "day": 0, + "flight": "T3160", + "utc": "07:27:00" + }, + { + "day": 1, + "flight": "T3803", + "utc": "11:18:00" + }, + { + "day": 1, + "flight": "T3946", + "utc": "16:35:00" + }, + { + "day": 2, + "flight": "T3548", + "utc": "07:03:00" + }, + { + "day": 2, + "flight": "T3516", + "utc": "05:09:00" + }, + { + "day": 2, + "flight": "T3849", + "utc": "01:43:00" + }, + { + "day": 2, + "flight": "T3096", + "utc": "05:54:00" + }, + { + "day": 2, + "flight": "T3020", + "utc": "23:04:00" + }, + { + "day": 3, + "flight": "T3523", + "utc": "02:22:00" + }, + { + "day": 3, + "flight": "T3724", + "utc": "17:07:00" + }, + { + "day": 4, + "flight": "T3751", + "utc": "05:04:00" + }, + { + "day": 4, + "flight": "T3360", + "utc": "19:01:00" + }, + { + "day": 4, + "flight": "T3945", + "utc": "05:38:00" + }, + { + "day": 4, + "flight": "T3861", + "utc": "17:35:00" + }, + { + "day": 4, + "flight": "T3362", + "utc": "18:29:00" + }, + { + "day": 5, + "flight": "T3884", + "utc": "16:36:00" + }, + { + "day": 6, + "flight": "T3032", + "utc": "22:22:00" + }, + { + "day": 6, + "flight": "T3719", + "utc": "11:59:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T7", + "airlineid": "airline_4965", + "destinationairport": "ETZ", + "distance": 703.3976464387359, + "equipment": "BEH", + "id": 51823, + "schedule": [ + { + "day": 0, + "flight": "T7417", + "utc": "04:52:00" + }, + { + "day": 1, + "flight": "T7281", + "utc": "14:33:00" + }, + { + "day": 2, + "flight": "T7500", + "utc": "02:16:00" + }, + { + "day": 3, + "flight": "T7552", + "utc": "23:16:00" + }, + { + "day": 4, + "flight": "T7538", + "utc": "16:00:00" + }, + { + "day": 4, + "flight": "T7925", + "utc": "20:07:00" + }, + { + "day": 4, + "flight": "T7339", + "utc": "21:34:00" + }, + { + "day": 4, + "flight": "T7667", + "utc": "02:53:00" + }, + { + "day": 4, + "flight": "T7282", + "utc": "09:14:00" + }, + { + "day": 5, + "flight": "T7073", + "utc": "23:57:00" + }, + { + "day": 5, + "flight": "T7243", + "utc": "16:41:00" + }, + { + "day": 5, + "flight": "T7665", + "utc": "09:52:00" + }, + { + "day": 6, + "flight": "T7246", + "utc": "17:16:00" + }, + { + "day": 6, + "flight": "T7106", + "utc": "04:20:00" + }, + { + "day": 6, + "flight": "T7978", + "utc": "03:41:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T7", + "airlineid": "airline_4965", + "destinationairport": "MXP", + "distance": 623.5176024539427, + "equipment": "BEH", + "id": 51824, + "schedule": [ + { + "day": 0, + "flight": "T7538", + "utc": "03:44:00" + }, + { + "day": 0, + "flight": "T7420", + "utc": "11:59:00" + }, + { + "day": 1, + "flight": "T7941", + "utc": "21:37:00" + }, + { + "day": 1, + "flight": "T7079", + "utc": "21:14:00" + }, + { + "day": 1, + "flight": "T7359", + "utc": "04:57:00" + }, + { + "day": 1, + "flight": "T7298", + "utc": "06:52:00" + }, + { + "day": 2, + "flight": "T7045", + "utc": "19:21:00" + }, + { + "day": 2, + "flight": "T7446", + "utc": "12:35:00" + }, + { + "day": 2, + "flight": "T7316", + "utc": "21:56:00" + }, + { + "day": 2, + "flight": "T7357", + "utc": "01:13:00" + }, + { + "day": 3, + "flight": "T7759", + "utc": "22:58:00" + }, + { + "day": 3, + "flight": "T7030", + "utc": "14:17:00" + }, + { + "day": 3, + "flight": "T7422", + "utc": "16:16:00" + }, + { + "day": 4, + "flight": "T7772", + "utc": "03:34:00" + }, + { + "day": 4, + "flight": "T7581", + "utc": "06:16:00" + }, + { + "day": 4, + "flight": "T7321", + "utc": "02:39:00" + }, + { + "day": 4, + "flight": "T7634", + "utc": "19:07:00" + }, + { + "day": 5, + "flight": "T7988", + "utc": "16:22:00" + }, + { + "day": 5, + "flight": "T7714", + "utc": "03:48:00" + }, + { + "day": 6, + "flight": "T7317", + "utc": "14:36:00" + }, + { + "day": 6, + "flight": "T7616", + "utc": "08:05:00" + }, + { + "day": 6, + "flight": "T7528", + "utc": "19:38:00" + }, + { + "day": 6, + "flight": "T7837", + "utc": "19:16:00" + }, + { + "day": 6, + "flight": "T7113", + "utc": "18:40:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TK", + "airlineid": "airline_4951", + "destinationairport": "IST", + "distance": 2266.207133048303, + "equipment": "320 321", + "id": 52846, + "schedule": [ + { + "day": 0, + "flight": "TK981", + "utc": "05:00:00" + }, + { + "day": 0, + "flight": "TK948", + "utc": "06:35:00" + }, + { + "day": 0, + "flight": "TK175", + "utc": "18:26:00" + }, + { + "day": 0, + "flight": "TK266", + "utc": "23:13:00" + }, + { + "day": 1, + "flight": "TK518", + "utc": "23:14:00" + }, + { + "day": 1, + "flight": "TK527", + "utc": "15:43:00" + }, + { + "day": 2, + "flight": "TK409", + "utc": "00:18:00" + }, + { + "day": 3, + "flight": "TK211", + "utc": "05:35:00" + }, + { + "day": 4, + "flight": "TK068", + "utc": "02:47:00" + }, + { + "day": 5, + "flight": "TK348", + "utc": "14:15:00" + }, + { + "day": 6, + "flight": "TK439", + "utc": "03:54:00" + }, + { + "day": 6, + "flight": "TK927", + "utc": "11:17:00" + }, + { + "day": 6, + "flight": "TK779", + "utc": "20:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TP", + "airlineid": "airline_4869", + "destinationairport": "LIS", + "distance": 1029.4070254527778, + "equipment": "100 ER4", + "id": 53824, + "schedule": [ + { + "day": 0, + "flight": "TP104", + "utc": "22:19:00" + }, + { + "day": 1, + "flight": "TP439", + "utc": "20:47:00" + }, + { + "day": 1, + "flight": "TP157", + "utc": "11:59:00" + }, + { + "day": 1, + "flight": "TP990", + "utc": "22:45:00" + }, + { + "day": 1, + "flight": "TP931", + "utc": "16:42:00" + }, + { + "day": 1, + "flight": "TP064", + "utc": "01:01:00" + }, + { + "day": 2, + "flight": "TP512", + "utc": "12:47:00" + }, + { + "day": 3, + "flight": "TP779", + "utc": "06:59:00" + }, + { + "day": 3, + "flight": "TP439", + "utc": "01:48:00" + }, + { + "day": 3, + "flight": "TP368", + "utc": "06:34:00" + }, + { + "day": 3, + "flight": "TP374", + "utc": "05:51:00" + }, + { + "day": 3, + "flight": "TP960", + "utc": "12:04:00" + }, + { + "day": 4, + "flight": "TP587", + "utc": "05:51:00" + }, + { + "day": 4, + "flight": "TP963", + "utc": "05:26:00" + }, + { + "day": 4, + "flight": "TP701", + "utc": "14:33:00" + }, + { + "day": 4, + "flight": "TP505", + "utc": "02:35:00" + }, + { + "day": 5, + "flight": "TP466", + "utc": "16:41:00" + }, + { + "day": 5, + "flight": "TP691", + "utc": "07:18:00" + }, + { + "day": 5, + "flight": "TP147", + "utc": "11:43:00" + }, + { + "day": 6, + "flight": "TP192", + "utc": "21:25:00" + }, + { + "day": 6, + "flight": "TP555", + "utc": "14:32:00" + }, + { + "day": 6, + "flight": "TP159", + "utc": "01:18:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TS", + "airlineid": "airline_1317", + "destinationairport": "YUL", + "distance": 5727.754070420711, + "equipment": "310", + "id": 53980, + "schedule": [ + { + "day": 0, + "flight": "TS022", + "utc": "17:05:00" + }, + { + "day": 0, + "flight": "TS378", + "utc": "07:58:00" + }, + { + "day": 0, + "flight": "TS288", + "utc": "18:01:00" + }, + { + "day": 0, + "flight": "TS447", + "utc": "14:50:00" + }, + { + "day": 1, + "flight": "TS820", + "utc": "02:32:00" + }, + { + "day": 1, + "flight": "TS349", + "utc": "07:31:00" + }, + { + "day": 1, + "flight": "TS522", + "utc": "02:22:00" + }, + { + "day": 1, + "flight": "TS271", + "utc": "21:31:00" + }, + { + "day": 2, + "flight": "TS018", + "utc": "09:50:00" + }, + { + "day": 2, + "flight": "TS375", + "utc": "17:20:00" + }, + { + "day": 2, + "flight": "TS841", + "utc": "10:09:00" + }, + { + "day": 2, + "flight": "TS710", + "utc": "02:23:00" + }, + { + "day": 2, + "flight": "TS541", + "utc": "21:38:00" + }, + { + "day": 3, + "flight": "TS458", + "utc": "08:17:00" + }, + { + "day": 3, + "flight": "TS682", + "utc": "15:57:00" + }, + { + "day": 3, + "flight": "TS988", + "utc": "16:06:00" + }, + { + "day": 3, + "flight": "TS508", + "utc": "20:13:00" + }, + { + "day": 3, + "flight": "TS461", + "utc": "20:23:00" + }, + { + "day": 4, + "flight": "TS703", + "utc": "22:23:00" + }, + { + "day": 4, + "flight": "TS693", + "utc": "17:31:00" + }, + { + "day": 4, + "flight": "TS167", + "utc": "00:21:00" + }, + { + "day": 4, + "flight": "TS123", + "utc": "20:23:00" + }, + { + "day": 5, + "flight": "TS465", + "utc": "03:23:00" + }, + { + "day": 5, + "flight": "TS675", + "utc": "04:50:00" + }, + { + "day": 6, + "flight": "TS529", + "utc": "00:48:00" + }, + { + "day": 6, + "flight": "TS394", + "utc": "17:07:00" + }, + { + "day": 6, + "flight": "TS003", + "utc": "20:48:00" + }, + { + "day": 6, + "flight": "TS961", + "utc": "13:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TU", + "airlineid": "airline_4870", + "destinationairport": "TUN", + "distance": 1063.7112627835468, + "equipment": "736", + "id": 54192, + "schedule": [ + { + "day": 0, + "flight": "TU408", + "utc": "03:17:00" + }, + { + "day": 1, + "flight": "TU112", + "utc": "22:41:00" + }, + { + "day": 2, + "flight": "TU006", + "utc": "12:25:00" + }, + { + "day": 2, + "flight": "TU923", + "utc": "21:40:00" + }, + { + "day": 2, + "flight": "TU869", + "utc": "14:04:00" + }, + { + "day": 3, + "flight": "TU072", + "utc": "14:32:00" + }, + { + "day": 3, + "flight": "TU362", + "utc": "20:43:00" + }, + { + "day": 4, + "flight": "TU876", + "utc": "11:57:00" + }, + { + "day": 4, + "flight": "TU486", + "utc": "15:28:00" + }, + { + "day": 4, + "flight": "TU161", + "utc": "08:26:00" + }, + { + "day": 4, + "flight": "TU312", + "utc": "06:41:00" + }, + { + "day": 4, + "flight": "TU887", + "utc": "06:35:00" + }, + { + "day": 5, + "flight": "TU507", + "utc": "20:03:00" + }, + { + "day": 5, + "flight": "TU893", + "utc": "01:33:00" + }, + { + "day": 6, + "flight": "TU871", + "utc": "12:34:00" + }, + { + "day": 6, + "flight": "TU610", + "utc": "04:01:00" + }, + { + "day": 6, + "flight": "TU896", + "utc": "17:25:00" + }, + { + "day": 6, + "flight": "TU158", + "utc": "15:20:00" + }, + { + "day": 6, + "flight": "TU008", + "utc": "00:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BIA", + "distance": 669.8441063067557, + "equipment": "319", + "id": 55468, + "schedule": [ + { + "day": 0, + "flight": "U2494", + "utc": "14:35:00" + }, + { + "day": 0, + "flight": "U2177", + "utc": "19:05:00" + }, + { + "day": 1, + "flight": "U2900", + "utc": "03:08:00" + }, + { + "day": 1, + "flight": "U2439", + "utc": "02:58:00" + }, + { + "day": 1, + "flight": "U2722", + "utc": "00:10:00" + }, + { + "day": 1, + "flight": "U2651", + "utc": "06:08:00" + }, + { + "day": 1, + "flight": "U2905", + "utc": "17:10:00" + }, + { + "day": 2, + "flight": "U2882", + "utc": "12:51:00" + }, + { + "day": 2, + "flight": "U2455", + "utc": "20:21:00" + }, + { + "day": 2, + "flight": "U2814", + "utc": "22:11:00" + }, + { + "day": 3, + "flight": "U2437", + "utc": "04:39:00" + }, + { + "day": 3, + "flight": "U2356", + "utc": "14:44:00" + }, + { + "day": 3, + "flight": "U2823", + "utc": "17:08:00" + }, + { + "day": 3, + "flight": "U2605", + "utc": "09:37:00" + }, + { + "day": 3, + "flight": "U2285", + "utc": "20:14:00" + }, + { + "day": 4, + "flight": "U2088", + "utc": "13:05:00" + }, + { + "day": 4, + "flight": "U2248", + "utc": "07:03:00" + }, + { + "day": 4, + "flight": "U2031", + "utc": "08:47:00" + }, + { + "day": 5, + "flight": "U2779", + "utc": "17:34:00" + }, + { + "day": 6, + "flight": "U2622", + "utc": "14:27:00" + }, + { + "day": 6, + "flight": "U2057", + "utc": "10:56:00" + }, + { + "day": 6, + "flight": "U2378", + "utc": "15:22:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BRS", + "distance": 914.710726420036, + "equipment": "320 319", + "id": 55469, + "schedule": [ + { + "day": 0, + "flight": "U2533", + "utc": "12:23:00" + }, + { + "day": 1, + "flight": "U2509", + "utc": "16:59:00" + }, + { + "day": 1, + "flight": "U2409", + "utc": "19:38:00" + }, + { + "day": 1, + "flight": "U2984", + "utc": "10:37:00" + }, + { + "day": 1, + "flight": "U2366", + "utc": "20:19:00" + }, + { + "day": 1, + "flight": "U2844", + "utc": "17:16:00" + }, + { + "day": 2, + "flight": "U2328", + "utc": "08:32:00" + }, + { + "day": 2, + "flight": "U2240", + "utc": "15:21:00" + }, + { + "day": 3, + "flight": "U2469", + "utc": "09:58:00" + }, + { + "day": 3, + "flight": "U2588", + "utc": "04:30:00" + }, + { + "day": 4, + "flight": "U2688", + "utc": "21:43:00" + }, + { + "day": 4, + "flight": "U2967", + "utc": "20:18:00" + }, + { + "day": 5, + "flight": "U2536", + "utc": "00:42:00" + }, + { + "day": 5, + "flight": "U2097", + "utc": "06:17:00" + }, + { + "day": 5, + "flight": "U2469", + "utc": "05:20:00" + }, + { + "day": 5, + "flight": "U2663", + "utc": "07:19:00" + }, + { + "day": 5, + "flight": "U2954", + "utc": "20:52:00" + }, + { + "day": 6, + "flight": "U2293", + "utc": "02:32:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BRU", + "distance": 842.027454616631, + "equipment": "319", + "id": 55470, + "schedule": [ + { + "day": 0, + "flight": "U2497", + "utc": "16:39:00" + }, + { + "day": 0, + "flight": "U2139", + "utc": "23:18:00" + }, + { + "day": 1, + "flight": "U2736", + "utc": "00:06:00" + }, + { + "day": 1, + "flight": "U2189", + "utc": "13:26:00" + }, + { + "day": 1, + "flight": "U2670", + "utc": "17:56:00" + }, + { + "day": 1, + "flight": "U2645", + "utc": "16:54:00" + }, + { + "day": 2, + "flight": "U2326", + "utc": "19:43:00" + }, + { + "day": 2, + "flight": "U2082", + "utc": "07:34:00" + }, + { + "day": 2, + "flight": "U2799", + "utc": "09:31:00" + }, + { + "day": 3, + "flight": "U2919", + "utc": "21:16:00" + }, + { + "day": 3, + "flight": "U2847", + "utc": "01:15:00" + }, + { + "day": 3, + "flight": "U2163", + "utc": "22:26:00" + }, + { + "day": 4, + "flight": "U2361", + "utc": "07:45:00" + }, + { + "day": 4, + "flight": "U2951", + "utc": "12:59:00" + }, + { + "day": 4, + "flight": "U2869", + "utc": "18:16:00" + }, + { + "day": 5, + "flight": "U2608", + "utc": "09:18:00" + }, + { + "day": 5, + "flight": "U2265", + "utc": "08:22:00" + }, + { + "day": 5, + "flight": "U2787", + "utc": "21:56:00" + }, + { + "day": 5, + "flight": "U2242", + "utc": "10:16:00" + }, + { + "day": 5, + "flight": "U2931", + "utc": "08:12:00" + }, + { + "day": 6, + "flight": "U2732", + "utc": "03:59:00" + }, + { + "day": 6, + "flight": "U2684", + "utc": "05:02:00" + }, + { + "day": 6, + "flight": "U2718", + "utc": "07:42:00" + }, + { + "day": 6, + "flight": "U2789", + "utc": "00:50:00" + }, + { + "day": 6, + "flight": "U2364", + "utc": "16:49:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BSL", + "distance": 650.756926586045, + "equipment": "319", + "id": 55471, + "schedule": [ + { + "day": 0, + "flight": "U2948", + "utc": "00:07:00" + }, + { + "day": 1, + "flight": "U2684", + "utc": "21:58:00" + }, + { + "day": 1, + "flight": "U2478", + "utc": "17:44:00" + }, + { + "day": 1, + "flight": "U2990", + "utc": "08:44:00" + }, + { + "day": 1, + "flight": "U2884", + "utc": "05:21:00" + }, + { + "day": 2, + "flight": "U2804", + "utc": "14:08:00" + }, + { + "day": 2, + "flight": "U2952", + "utc": "01:30:00" + }, + { + "day": 2, + "flight": "U2413", + "utc": "05:49:00" + }, + { + "day": 2, + "flight": "U2586", + "utc": "04:20:00" + }, + { + "day": 2, + "flight": "U2970", + "utc": "09:59:00" + }, + { + "day": 3, + "flight": "U2933", + "utc": "09:20:00" + }, + { + "day": 3, + "flight": "U2225", + "utc": "09:07:00" + }, + { + "day": 4, + "flight": "U2546", + "utc": "20:47:00" + }, + { + "day": 4, + "flight": "U2470", + "utc": "06:33:00" + }, + { + "day": 4, + "flight": "U2669", + "utc": "17:22:00" + }, + { + "day": 4, + "flight": "U2421", + "utc": "20:26:00" + }, + { + "day": 5, + "flight": "U2915", + "utc": "03:46:00" + }, + { + "day": 5, + "flight": "U2178", + "utc": "19:13:00" + }, + { + "day": 6, + "flight": "U2113", + "utc": "06:17:00" + }, + { + "day": 6, + "flight": "U2472", + "utc": "15:17:00" + }, + { + "day": 6, + "flight": "U2572", + "utc": "15:08:00" + }, + { + "day": 6, + "flight": "U2806", + "utc": "09:53:00" + }, + { + "day": 6, + "flight": "U2880", + "utc": "19:51:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "319 320", + "id": 55472, + "schedule": [ + { + "day": 0, + "flight": "U2783", + "utc": "04:04:00" + }, + { + "day": 0, + "flight": "U2306", + "utc": "12:27:00" + }, + { + "day": 0, + "flight": "U2568", + "utc": "22:02:00" + }, + { + "day": 0, + "flight": "U2181", + "utc": "12:06:00" + }, + { + "day": 0, + "flight": "U2994", + "utc": "07:29:00" + }, + { + "day": 1, + "flight": "U2148", + "utc": "05:42:00" + }, + { + "day": 1, + "flight": "U2598", + "utc": "03:59:00" + }, + { + "day": 1, + "flight": "U2486", + "utc": "22:53:00" + }, + { + "day": 2, + "flight": "U2878", + "utc": "07:27:00" + }, + { + "day": 3, + "flight": "U2940", + "utc": "19:09:00" + }, + { + "day": 3, + "flight": "U2472", + "utc": "13:32:00" + }, + { + "day": 3, + "flight": "U2764", + "utc": "22:04:00" + }, + { + "day": 4, + "flight": "U2398", + "utc": "01:20:00" + }, + { + "day": 4, + "flight": "U2640", + "utc": "22:50:00" + }, + { + "day": 4, + "flight": "U2323", + "utc": "04:22:00" + }, + { + "day": 5, + "flight": "U2015", + "utc": "10:27:00" + }, + { + "day": 5, + "flight": "U2339", + "utc": "15:46:00" + }, + { + "day": 5, + "flight": "U2000", + "utc": "14:10:00" + }, + { + "day": 5, + "flight": "U2159", + "utc": "03:50:00" + }, + { + "day": 5, + "flight": "U2509", + "utc": "04:22:00" + }, + { + "day": 6, + "flight": "U2639", + "utc": "17:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "319", + "id": 55473, + "schedule": [ + { + "day": 0, + "flight": "U2207", + "utc": "10:41:00" + }, + { + "day": 1, + "flight": "U2992", + "utc": "23:32:00" + }, + { + "day": 1, + "flight": "U2456", + "utc": "12:15:00" + }, + { + "day": 2, + "flight": "U2130", + "utc": "04:59:00" + }, + { + "day": 2, + "flight": "U2358", + "utc": "22:48:00" + }, + { + "day": 3, + "flight": "U2163", + "utc": "19:05:00" + }, + { + "day": 4, + "flight": "U2643", + "utc": "05:31:00" + }, + { + "day": 4, + "flight": "U2475", + "utc": "14:17:00" + }, + { + "day": 4, + "flight": "U2675", + "utc": "10:16:00" + }, + { + "day": 4, + "flight": "U2260", + "utc": "21:43:00" + }, + { + "day": 5, + "flight": "U2711", + "utc": "05:27:00" + }, + { + "day": 5, + "flight": "U2502", + "utc": "21:27:00" + }, + { + "day": 6, + "flight": "U2754", + "utc": "19:41:00" + }, + { + "day": 6, + "flight": "U2771", + "utc": "21:15:00" + }, + { + "day": 6, + "flight": "U2733", + "utc": "03:49:00" + }, + { + "day": 6, + "flight": "U2326", + "utc": "09:00:00" + }, + { + "day": 6, + "flight": "U2916", + "utc": "08:04:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "GVA", + "distance": 472.80826589600406, + "equipment": "319", + "id": 55474, + "schedule": [ + { + "day": 0, + "flight": "U2283", + "utc": "23:24:00" + }, + { + "day": 0, + "flight": "U2818", + "utc": "06:27:00" + }, + { + "day": 1, + "flight": "U2427", + "utc": "17:05:00" + }, + { + "day": 1, + "flight": "U2152", + "utc": "11:22:00" + }, + { + "day": 1, + "flight": "U2830", + "utc": "08:25:00" + }, + { + "day": 2, + "flight": "U2120", + "utc": "07:48:00" + }, + { + "day": 3, + "flight": "U2044", + "utc": "05:59:00" + }, + { + "day": 3, + "flight": "U2642", + "utc": "07:14:00" + }, + { + "day": 4, + "flight": "U2054", + "utc": "14:28:00" + }, + { + "day": 5, + "flight": "U2279", + "utc": "11:19:00" + }, + { + "day": 5, + "flight": "U2134", + "utc": "18:51:00" + }, + { + "day": 5, + "flight": "U2691", + "utc": "02:31:00" + }, + { + "day": 5, + "flight": "U2655", + "utc": "21:49:00" + }, + { + "day": 6, + "flight": "U2805", + "utc": "14:23:00" + }, + { + "day": 6, + "flight": "U2614", + "utc": "22:06:00" + }, + { + "day": 6, + "flight": "U2370", + "utc": "15:16:00" + }, + { + "day": 6, + "flight": "U2170", + "utc": "11:22:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LGW", + "distance": 844.1654023845344, + "equipment": "319 320", + "id": 55475, + "schedule": [ + { + "day": 0, + "flight": "U2933", + "utc": "04:57:00" + }, + { + "day": 0, + "flight": "U2353", + "utc": "18:26:00" + }, + { + "day": 0, + "flight": "U2005", + "utc": "15:06:00" + }, + { + "day": 1, + "flight": "U2701", + "utc": "09:37:00" + }, + { + "day": 2, + "flight": "U2142", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "U2583", + "utc": "16:29:00" + }, + { + "day": 2, + "flight": "U2424", + "utc": "10:14:00" + }, + { + "day": 3, + "flight": "U2528", + "utc": "21:34:00" + }, + { + "day": 3, + "flight": "U2213", + "utc": "21:34:00" + }, + { + "day": 3, + "flight": "U2664", + "utc": "09:18:00" + }, + { + "day": 4, + "flight": "U2487", + "utc": "00:05:00" + }, + { + "day": 4, + "flight": "U2324", + "utc": "12:30:00" + }, + { + "day": 4, + "flight": "U2244", + "utc": "08:01:00" + }, + { + "day": 4, + "flight": "U2930", + "utc": "23:04:00" + }, + { + "day": 4, + "flight": "U2442", + "utc": "20:48:00" + }, + { + "day": 5, + "flight": "U2885", + "utc": "22:34:00" + }, + { + "day": 5, + "flight": "U2670", + "utc": "17:09:00" + }, + { + "day": 5, + "flight": "U2045", + "utc": "17:23:00" + }, + { + "day": 6, + "flight": "U2785", + "utc": "13:25:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LIL", + "distance": 781.8286754466159, + "equipment": "319", + "id": 55476, + "schedule": [ + { + "day": 0, + "flight": "U2448", + "utc": "11:55:00" + }, + { + "day": 1, + "flight": "U2947", + "utc": "11:22:00" + }, + { + "day": 1, + "flight": "U2978", + "utc": "15:08:00" + }, + { + "day": 2, + "flight": "U2244", + "utc": "02:54:00" + }, + { + "day": 3, + "flight": "U2880", + "utc": "22:25:00" + }, + { + "day": 3, + "flight": "U2966", + "utc": "11:29:00" + }, + { + "day": 3, + "flight": "U2581", + "utc": "01:52:00" + }, + { + "day": 4, + "flight": "U2461", + "utc": "11:43:00" + }, + { + "day": 4, + "flight": "U2882", + "utc": "04:18:00" + }, + { + "day": 4, + "flight": "U2556", + "utc": "01:31:00" + }, + { + "day": 4, + "flight": "U2528", + "utc": "10:56:00" + }, + { + "day": 4, + "flight": "U2060", + "utc": "09:32:00" + }, + { + "day": 5, + "flight": "U2289", + "utc": "06:04:00" + }, + { + "day": 6, + "flight": "U2776", + "utc": "06:37:00" + }, + { + "day": 6, + "flight": "U2510", + "utc": "07:51:00" + }, + { + "day": 6, + "flight": "U2861", + "utc": "22:24:00" + }, + { + "day": 6, + "flight": "U2936", + "utc": "06:57:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319", + "id": 55477, + "schedule": [ + { + "day": 0, + "flight": "U2340", + "utc": "21:08:00" + }, + { + "day": 0, + "flight": "U2501", + "utc": "11:27:00" + }, + { + "day": 0, + "flight": "U2855", + "utc": "20:34:00" + }, + { + "day": 1, + "flight": "U2025", + "utc": "01:40:00" + }, + { + "day": 1, + "flight": "U2320", + "utc": "02:40:00" + }, + { + "day": 1, + "flight": "U2402", + "utc": "05:53:00" + }, + { + "day": 1, + "flight": "U2858", + "utc": "02:47:00" + }, + { + "day": 1, + "flight": "U2828", + "utc": "04:34:00" + }, + { + "day": 2, + "flight": "U2361", + "utc": "07:59:00" + }, + { + "day": 2, + "flight": "U2640", + "utc": "04:01:00" + }, + { + "day": 2, + "flight": "U2777", + "utc": "18:07:00" + }, + { + "day": 3, + "flight": "U2602", + "utc": "19:50:00" + }, + { + "day": 4, + "flight": "U2487", + "utc": "00:56:00" + }, + { + "day": 5, + "flight": "U2702", + "utc": "05:40:00" + }, + { + "day": 6, + "flight": "U2074", + "utc": "14:47:00" + }, + { + "day": 6, + "flight": "U2763", + "utc": "21:12:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "NCE", + "distance": 470.8031011808527, + "equipment": "319", + "id": 55478, + "schedule": [ + { + "day": 0, + "flight": "U2536", + "utc": "00:51:00" + }, + { + "day": 0, + "flight": "U2640", + "utc": "10:51:00" + }, + { + "day": 0, + "flight": "U2734", + "utc": "19:10:00" + }, + { + "day": 0, + "flight": "U2973", + "utc": "19:49:00" + }, + { + "day": 0, + "flight": "U2387", + "utc": "07:11:00" + }, + { + "day": 1, + "flight": "U2852", + "utc": "01:07:00" + }, + { + "day": 1, + "flight": "U2532", + "utc": "10:19:00" + }, + { + "day": 1, + "flight": "U2896", + "utc": "06:50:00" + }, + { + "day": 2, + "flight": "U2510", + "utc": "12:58:00" + }, + { + "day": 2, + "flight": "U2929", + "utc": "22:05:00" + }, + { + "day": 3, + "flight": "U2563", + "utc": "12:44:00" + }, + { + "day": 3, + "flight": "U2947", + "utc": "04:21:00" + }, + { + "day": 3, + "flight": "U2787", + "utc": "05:13:00" + }, + { + "day": 4, + "flight": "U2383", + "utc": "23:41:00" + }, + { + "day": 4, + "flight": "U2485", + "utc": "13:25:00" + }, + { + "day": 5, + "flight": "U2064", + "utc": "20:55:00" + }, + { + "day": 5, + "flight": "U2690", + "utc": "04:31:00" + }, + { + "day": 5, + "flight": "U2713", + "utc": "18:06:00" + }, + { + "day": 6, + "flight": "U2099", + "utc": "09:45:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "NTE", + "distance": 455.4490681425203, + "equipment": "319", + "id": 55479, + "schedule": [ + { + "day": 0, + "flight": "U2117", + "utc": "10:10:00" + }, + { + "day": 1, + "flight": "U2746", + "utc": "08:08:00" + }, + { + "day": 1, + "flight": "U2454", + "utc": "21:03:00" + }, + { + "day": 1, + "flight": "U2860", + "utc": "12:06:00" + }, + { + "day": 2, + "flight": "U2902", + "utc": "18:21:00" + }, + { + "day": 2, + "flight": "U2031", + "utc": "23:38:00" + }, + { + "day": 3, + "flight": "U2255", + "utc": "01:05:00" + }, + { + "day": 4, + "flight": "U2037", + "utc": "06:54:00" + }, + { + "day": 4, + "flight": "U2671", + "utc": "18:55:00" + }, + { + "day": 4, + "flight": "U2793", + "utc": "18:13:00" + }, + { + "day": 4, + "flight": "U2564", + "utc": "03:51:00" + }, + { + "day": 5, + "flight": "U2209", + "utc": "13:21:00" + }, + { + "day": 6, + "flight": "U2139", + "utc": "23:11:00" + }, + { + "day": 6, + "flight": "U2398", + "utc": "15:26:00" + }, + { + "day": 6, + "flight": "U2335", + "utc": "08:44:00" + }, + { + "day": 6, + "flight": "U2591", + "utc": "01:43:00" + }, + { + "day": 6, + "flight": "U2623", + "utc": "06:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "ORY", + "distance": 571.8189591117047, + "equipment": "320 319", + "id": 55480, + "schedule": [ + { + "day": 0, + "flight": "U2687", + "utc": "12:05:00" + }, + { + "day": 1, + "flight": "U2311", + "utc": "03:54:00" + }, + { + "day": 1, + "flight": "U2180", + "utc": "15:47:00" + }, + { + "day": 1, + "flight": "U2937", + "utc": "07:31:00" + }, + { + "day": 1, + "flight": "U2210", + "utc": "20:01:00" + }, + { + "day": 1, + "flight": "U2593", + "utc": "13:47:00" + }, + { + "day": 2, + "flight": "U2747", + "utc": "20:18:00" + }, + { + "day": 2, + "flight": "U2810", + "utc": "22:27:00" + }, + { + "day": 2, + "flight": "U2888", + "utc": "20:35:00" + }, + { + "day": 3, + "flight": "U2363", + "utc": "15:56:00" + }, + { + "day": 3, + "flight": "U2344", + "utc": "01:35:00" + }, + { + "day": 4, + "flight": "U2153", + "utc": "13:29:00" + }, + { + "day": 4, + "flight": "U2256", + "utc": "10:58:00" + }, + { + "day": 5, + "flight": "U2880", + "utc": "15:55:00" + }, + { + "day": 5, + "flight": "U2659", + "utc": "21:57:00" + }, + { + "day": 6, + "flight": "U2797", + "utc": "03:33:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "319 320", + "id": 55481, + "schedule": [ + { + "day": 0, + "flight": "U2751", + "utc": "03:33:00" + }, + { + "day": 0, + "flight": "U2066", + "utc": "00:35:00" + }, + { + "day": 0, + "flight": "U2660", + "utc": "20:57:00" + }, + { + "day": 0, + "flight": "U2700", + "utc": "12:47:00" + }, + { + "day": 0, + "flight": "U2838", + "utc": "03:17:00" + }, + { + "day": 1, + "flight": "U2802", + "utc": "16:53:00" + }, + { + "day": 1, + "flight": "U2203", + "utc": "23:14:00" + }, + { + "day": 1, + "flight": "U2029", + "utc": "06:13:00" + }, + { + "day": 1, + "flight": "U2228", + "utc": "19:13:00" + }, + { + "day": 2, + "flight": "U2671", + "utc": "11:55:00" + }, + { + "day": 2, + "flight": "U2526", + "utc": "11:12:00" + }, + { + "day": 2, + "flight": "U2747", + "utc": "12:18:00" + }, + { + "day": 3, + "flight": "U2417", + "utc": "12:17:00" + }, + { + "day": 3, + "flight": "U2082", + "utc": "14:54:00" + }, + { + "day": 4, + "flight": "U2069", + "utc": "21:57:00" + }, + { + "day": 4, + "flight": "U2708", + "utc": "00:16:00" + }, + { + "day": 4, + "flight": "U2067", + "utc": "23:46:00" + }, + { + "day": 4, + "flight": "U2334", + "utc": "15:46:00" + }, + { + "day": 4, + "flight": "U2084", + "utc": "01:10:00" + }, + { + "day": 5, + "flight": "U2693", + "utc": "04:39:00" + }, + { + "day": 5, + "flight": "U2415", + "utc": "15:54:00" + }, + { + "day": 5, + "flight": "U2378", + "utc": "09:10:00" + }, + { + "day": 5, + "flight": "U2094", + "utc": "01:03:00" + }, + { + "day": 5, + "flight": "U2399", + "utc": "09:25:00" + }, + { + "day": 6, + "flight": "U2534", + "utc": "20:07:00" + }, + { + "day": 6, + "flight": "U2509", + "utc": "10:02:00" + }, + { + "day": 6, + "flight": "U2280", + "utc": "06:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "AGP", + "distance": 919.3439362090616, + "equipment": "320", + "id": 62413, + "schedule": [ + { + "day": 0, + "flight": "VY306", + "utc": "08:50:00" + }, + { + "day": 0, + "flight": "VY637", + "utc": "15:53:00" + }, + { + "day": 0, + "flight": "VY587", + "utc": "21:50:00" + }, + { + "day": 0, + "flight": "VY313", + "utc": "16:54:00" + }, + { + "day": 1, + "flight": "VY228", + "utc": "02:02:00" + }, + { + "day": 2, + "flight": "VY543", + "utc": "17:54:00" + }, + { + "day": 2, + "flight": "VY681", + "utc": "02:51:00" + }, + { + "day": 2, + "flight": "VY649", + "utc": "06:19:00" + }, + { + "day": 3, + "flight": "VY243", + "utc": "22:54:00" + }, + { + "day": 3, + "flight": "VY373", + "utc": "12:15:00" + }, + { + "day": 3, + "flight": "VY408", + "utc": "03:16:00" + }, + { + "day": 3, + "flight": "VY627", + "utc": "19:42:00" + }, + { + "day": 3, + "flight": "VY580", + "utc": "18:49:00" + }, + { + "day": 4, + "flight": "VY607", + "utc": "17:01:00" + }, + { + "day": 4, + "flight": "VY177", + "utc": "16:28:00" + }, + { + "day": 4, + "flight": "VY066", + "utc": "15:52:00" + }, + { + "day": 4, + "flight": "VY185", + "utc": "18:35:00" + }, + { + "day": 4, + "flight": "VY318", + "utc": "14:19:00" + }, + { + "day": 5, + "flight": "VY960", + "utc": "01:26:00" + }, + { + "day": 5, + "flight": "VY217", + "utc": "02:12:00" + }, + { + "day": 6, + "flight": "VY558", + "utc": "01:41:00" + }, + { + "day": 6, + "flight": "VY412", + "utc": "11:25:00" + }, + { + "day": 6, + "flight": "VY596", + "utc": "20:06:00" + }, + { + "day": 6, + "flight": "VY176", + "utc": "22:40:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "BCN", + "distance": 265.8469587104912, + "equipment": "320", + "id": 62414, + "schedule": [ + { + "day": 0, + "flight": "VY864", + "utc": "21:52:00" + }, + { + "day": 1, + "flight": "VY591", + "utc": "22:27:00" + }, + { + "day": 1, + "flight": "VY081", + "utc": "15:06:00" + }, + { + "day": 1, + "flight": "VY143", + "utc": "20:13:00" + }, + { + "day": 1, + "flight": "VY957", + "utc": "20:03:00" + }, + { + "day": 1, + "flight": "VY201", + "utc": "22:01:00" + }, + { + "day": 2, + "flight": "VY953", + "utc": "11:47:00" + }, + { + "day": 2, + "flight": "VY207", + "utc": "03:38:00" + }, + { + "day": 3, + "flight": "VY091", + "utc": "22:34:00" + }, + { + "day": 3, + "flight": "VY910", + "utc": "16:14:00" + }, + { + "day": 3, + "flight": "VY908", + "utc": "13:27:00" + }, + { + "day": 3, + "flight": "VY021", + "utc": "11:41:00" + }, + { + "day": 3, + "flight": "VY150", + "utc": "09:21:00" + }, + { + "day": 4, + "flight": "VY422", + "utc": "17:33:00" + }, + { + "day": 4, + "flight": "VY905", + "utc": "02:40:00" + }, + { + "day": 4, + "flight": "VY779", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "VY656", + "utc": "23:40:00" + }, + { + "day": 5, + "flight": "VY317", + "utc": "21:24:00" + }, + { + "day": 5, + "flight": "VY932", + "utc": "08:49:00" + }, + { + "day": 5, + "flight": "VY422", + "utc": "12:41:00" + }, + { + "day": 6, + "flight": "VY720", + "utc": "01:16:00" + }, + { + "day": 6, + "flight": "VY473", + "utc": "06:02:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "PMI", + "distance": 467.1315518195575, + "equipment": "320", + "id": 62415, + "schedule": [ + { + "day": 0, + "flight": "VY490", + "utc": "05:18:00" + }, + { + "day": 0, + "flight": "VY773", + "utc": "01:14:00" + }, + { + "day": 0, + "flight": "VY500", + "utc": "23:29:00" + }, + { + "day": 0, + "flight": "VY860", + "utc": "18:39:00" + }, + { + "day": 1, + "flight": "VY573", + "utc": "22:20:00" + }, + { + "day": 1, + "flight": "VY004", + "utc": "02:59:00" + }, + { + "day": 1, + "flight": "VY507", + "utc": "03:05:00" + }, + { + "day": 1, + "flight": "VY789", + "utc": "11:25:00" + }, + { + "day": 2, + "flight": "VY600", + "utc": "20:30:00" + }, + { + "day": 2, + "flight": "VY291", + "utc": "09:58:00" + }, + { + "day": 2, + "flight": "VY021", + "utc": "07:38:00" + }, + { + "day": 2, + "flight": "VY667", + "utc": "11:43:00" + }, + { + "day": 3, + "flight": "VY411", + "utc": "06:25:00" + }, + { + "day": 3, + "flight": "VY842", + "utc": "05:41:00" + }, + { + "day": 3, + "flight": "VY287", + "utc": "02:46:00" + }, + { + "day": 3, + "flight": "VY114", + "utc": "00:53:00" + }, + { + "day": 3, + "flight": "VY674", + "utc": "12:24:00" + }, + { + "day": 4, + "flight": "VY228", + "utc": "20:25:00" + }, + { + "day": 5, + "flight": "VY276", + "utc": "21:16:00" + }, + { + "day": 6, + "flight": "VY541", + "utc": "17:57:00" + }, + { + "day": 6, + "flight": "VY913", + "utc": "08:49:00" + }, + { + "day": 6, + "flight": "VY456", + "utc": "01:12:00" + }, + { + "day": 6, + "flight": "VY827", + "utc": "04:05:00" + }, + { + "day": 6, + "flight": "VY880", + "utc": "17:52:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "XK", + "airlineid": "airline_1909", + "destinationairport": "AJA", + "distance": 635.8270740976213, + "equipment": "320", + "id": 65438, + "schedule": [ + { + "day": 0, + "flight": "XK629", + "utc": "06:48:00" + }, + { + "day": 0, + "flight": "XK034", + "utc": "06:05:00" + }, + { + "day": 0, + "flight": "XK235", + "utc": "06:10:00" + }, + { + "day": 0, + "flight": "XK886", + "utc": "18:33:00" + }, + { + "day": 0, + "flight": "XK152", + "utc": "14:22:00" + }, + { + "day": 1, + "flight": "XK175", + "utc": "20:39:00" + }, + { + "day": 1, + "flight": "XK283", + "utc": "18:51:00" + }, + { + "day": 2, + "flight": "XK802", + "utc": "22:14:00" + }, + { + "day": 2, + "flight": "XK065", + "utc": "18:28:00" + }, + { + "day": 2, + "flight": "XK331", + "utc": "06:59:00" + }, + { + "day": 2, + "flight": "XK106", + "utc": "01:42:00" + }, + { + "day": 3, + "flight": "XK962", + "utc": "11:48:00" + }, + { + "day": 3, + "flight": "XK085", + "utc": "17:40:00" + }, + { + "day": 4, + "flight": "XK018", + "utc": "13:12:00" + }, + { + "day": 5, + "flight": "XK484", + "utc": "06:21:00" + }, + { + "day": 5, + "flight": "XK417", + "utc": "20:43:00" + }, + { + "day": 5, + "flight": "XK571", + "utc": "20:21:00" + }, + { + "day": 5, + "flight": "XK576", + "utc": "05:54:00" + }, + { + "day": 6, + "flight": "XK933", + "utc": "10:40:00" + }, + { + "day": 6, + "flight": "XK247", + "utc": "13:50:00" + }, + { + "day": 6, + "flight": "XK542", + "utc": "00:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AA", + "airlineid": "airline_24", + "destinationairport": "LHR", + "distance": 883.3122325423356, + "equipment": "320 319", + "id": 6898, + "schedule": [ + { + "day": 0, + "flight": "AA020", + "utc": "05:46:00" + }, + { + "day": 1, + "flight": "AA288", + "utc": "23:39:00" + }, + { + "day": 1, + "flight": "AA758", + "utc": "13:22:00" + }, + { + "day": 1, + "flight": "AA396", + "utc": "11:01:00" + }, + { + "day": 1, + "flight": "AA133", + "utc": "14:34:00" + }, + { + "day": 1, + "flight": "AA448", + "utc": "19:27:00" + }, + { + "day": 2, + "flight": "AA660", + "utc": "15:24:00" + }, + { + "day": 2, + "flight": "AA529", + "utc": "01:22:00" + }, + { + "day": 2, + "flight": "AA738", + "utc": "12:23:00" + }, + { + "day": 3, + "flight": "AA759", + "utc": "19:33:00" + }, + { + "day": 4, + "flight": "AA739", + "utc": "02:40:00" + }, + { + "day": 4, + "flight": "AA455", + "utc": "04:42:00" + }, + { + "day": 4, + "flight": "AA832", + "utc": "22:45:00" + }, + { + "day": 4, + "flight": "AA932", + "utc": "17:16:00" + }, + { + "day": 4, + "flight": "AA188", + "utc": "15:15:00" + }, + { + "day": 5, + "flight": "AA548", + "utc": "00:09:00" + }, + { + "day": 5, + "flight": "AA452", + "utc": "05:00:00" + }, + { + "day": 5, + "flight": "AA905", + "utc": "03:24:00" + }, + { + "day": 5, + "flight": "AA571", + "utc": "01:04:00" + }, + { + "day": 5, + "flight": "AA168", + "utc": "10:38:00" + }, + { + "day": 6, + "flight": "AA329", + "utc": "20:38:00" + }, + { + "day": 6, + "flight": "AA799", + "utc": "07:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "AJA", + "distance": 635.8270740976213, + "equipment": "320", + "id": 9985, + "schedule": [ + { + "day": 0, + "flight": "AF736", + "utc": "17:30:00" + }, + { + "day": 1, + "flight": "AF398", + "utc": "05:17:00" + }, + { + "day": 1, + "flight": "AF296", + "utc": "21:03:00" + }, + { + "day": 1, + "flight": "AF711", + "utc": "22:47:00" + }, + { + "day": 1, + "flight": "AF189", + "utc": "20:04:00" + }, + { + "day": 2, + "flight": "AF737", + "utc": "09:54:00" + }, + { + "day": 2, + "flight": "AF458", + "utc": "15:20:00" + }, + { + "day": 2, + "flight": "AF328", + "utc": "13:01:00" + }, + { + "day": 2, + "flight": "AF572", + "utc": "10:01:00" + }, + { + "day": 2, + "flight": "AF295", + "utc": "03:30:00" + }, + { + "day": 3, + "flight": "AF272", + "utc": "06:29:00" + }, + { + "day": 3, + "flight": "AF516", + "utc": "07:05:00" + }, + { + "day": 3, + "flight": "AF438", + "utc": "09:20:00" + }, + { + "day": 3, + "flight": "AF584", + "utc": "16:37:00" + }, + { + "day": 3, + "flight": "AF700", + "utc": "09:23:00" + }, + { + "day": 4, + "flight": "AF637", + "utc": "13:27:00" + }, + { + "day": 4, + "flight": "AF081", + "utc": "03:02:00" + }, + { + "day": 4, + "flight": "AF551", + "utc": "03:41:00" + }, + { + "day": 4, + "flight": "AF884", + "utc": "16:28:00" + }, + { + "day": 5, + "flight": "AF966", + "utc": "20:17:00" + }, + { + "day": 5, + "flight": "AF093", + "utc": "18:00:00" + }, + { + "day": 5, + "flight": "AF529", + "utc": "01:21:00" + }, + { + "day": 5, + "flight": "AF958", + "utc": "03:43:00" + }, + { + "day": 5, + "flight": "AF863", + "utc": "01:35:00" + }, + { + "day": 6, + "flight": "AF035", + "utc": "20:01:00" + }, + { + "day": 6, + "flight": "AF650", + "utc": "04:42:00" + }, + { + "day": 6, + "flight": "AF281", + "utc": "21:12:00" + }, + { + "day": 6, + "flight": "AF762", + "utc": "05:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "AMS", + "distance": 997.4702942027754, + "equipment": "E90", + "id": 9986, + "schedule": [ + { + "day": 0, + "flight": "AF828", + "utc": "04:07:00" + }, + { + "day": 0, + "flight": "AF923", + "utc": "02:34:00" + }, + { + "day": 0, + "flight": "AF622", + "utc": "15:56:00" + }, + { + "day": 0, + "flight": "AF409", + "utc": "20:12:00" + }, + { + "day": 0, + "flight": "AF462", + "utc": "04:35:00" + }, + { + "day": 1, + "flight": "AF688", + "utc": "01:30:00" + }, + { + "day": 1, + "flight": "AF444", + "utc": "01:03:00" + }, + { + "day": 1, + "flight": "AF789", + "utc": "20:50:00" + }, + { + "day": 1, + "flight": "AF253", + "utc": "19:01:00" + }, + { + "day": 1, + "flight": "AF731", + "utc": "03:44:00" + }, + { + "day": 2, + "flight": "AF331", + "utc": "19:21:00" + }, + { + "day": 3, + "flight": "AF101", + "utc": "19:35:00" + }, + { + "day": 4, + "flight": "AF928", + "utc": "08:16:00" + }, + { + "day": 4, + "flight": "AF359", + "utc": "16:04:00" + }, + { + "day": 4, + "flight": "AF497", + "utc": "13:02:00" + }, + { + "day": 5, + "flight": "AF326", + "utc": "18:14:00" + }, + { + "day": 5, + "flight": "AF019", + "utc": "11:55:00" + }, + { + "day": 6, + "flight": "AF624", + "utc": "21:46:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ATH", + "distance": 1996.3800921392394, + "equipment": "320", + "id": 9987, + "schedule": [ + { + "day": 0, + "flight": "AF893", + "utc": "23:36:00" + }, + { + "day": 0, + "flight": "AF498", + "utc": "19:37:00" + }, + { + "day": 1, + "flight": "AF266", + "utc": "02:51:00" + }, + { + "day": 1, + "flight": "AF970", + "utc": "06:54:00" + }, + { + "day": 1, + "flight": "AF880", + "utc": "20:08:00" + }, + { + "day": 2, + "flight": "AF758", + "utc": "15:11:00" + }, + { + "day": 2, + "flight": "AF437", + "utc": "08:53:00" + }, + { + "day": 2, + "flight": "AF930", + "utc": "08:47:00" + }, + { + "day": 2, + "flight": "AF671", + "utc": "09:09:00" + }, + { + "day": 2, + "flight": "AF151", + "utc": "05:10:00" + }, + { + "day": 3, + "flight": "AF142", + "utc": "19:27:00" + }, + { + "day": 3, + "flight": "AF805", + "utc": "23:07:00" + }, + { + "day": 4, + "flight": "AF821", + "utc": "11:18:00" + }, + { + "day": 4, + "flight": "AF146", + "utc": "12:32:00" + }, + { + "day": 5, + "flight": "AF591", + "utc": "03:51:00" + }, + { + "day": 5, + "flight": "AF506", + "utc": "06:24:00" + }, + { + "day": 6, + "flight": "AF455", + "utc": "11:23:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "320 319 321", + "id": 9988, + "schedule": [ + { + "day": 0, + "flight": "AF099", + "utc": "20:30:00" + }, + { + "day": 0, + "flight": "AF282", + "utc": "03:57:00" + }, + { + "day": 1, + "flight": "AF890", + "utc": "16:06:00" + }, + { + "day": 1, + "flight": "AF974", + "utc": "06:16:00" + }, + { + "day": 1, + "flight": "AF099", + "utc": "16:08:00" + }, + { + "day": 1, + "flight": "AF998", + "utc": "00:23:00" + }, + { + "day": 1, + "flight": "AF117", + "utc": "03:16:00" + }, + { + "day": 2, + "flight": "AF081", + "utc": "01:22:00" + }, + { + "day": 2, + "flight": "AF550", + "utc": "08:21:00" + }, + { + "day": 3, + "flight": "AF029", + "utc": "21:23:00" + }, + { + "day": 3, + "flight": "AF669", + "utc": "15:11:00" + }, + { + "day": 3, + "flight": "AF897", + "utc": "17:58:00" + }, + { + "day": 4, + "flight": "AF812", + "utc": "19:48:00" + }, + { + "day": 4, + "flight": "AF861", + "utc": "06:15:00" + }, + { + "day": 4, + "flight": "AF767", + "utc": "21:25:00" + }, + { + "day": 4, + "flight": "AF411", + "utc": "01:17:00" + }, + { + "day": 4, + "flight": "AF003", + "utc": "13:03:00" + }, + { + "day": 5, + "flight": "AF362", + "utc": "04:02:00" + }, + { + "day": 5, + "flight": "AF967", + "utc": "02:19:00" + }, + { + "day": 5, + "flight": "AF237", + "utc": "17:45:00" + }, + { + "day": 5, + "flight": "AF618", + "utc": "19:20:00" + }, + { + "day": 5, + "flight": "AF864", + "utc": "21:19:00" + }, + { + "day": 6, + "flight": "AF031", + "utc": "07:08:00" + }, + { + "day": 6, + "flight": "AF213", + "utc": "22:11:00" + }, + { + "day": 6, + "flight": "AF505", + "utc": "21:28:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "CMN", + "distance": 1379.8271930529227, + "equipment": "319 320", + "id": 9989, + "schedule": [ + { + "day": 0, + "flight": "AF336", + "utc": "07:45:00" + }, + { + "day": 0, + "flight": "AF660", + "utc": "15:44:00" + }, + { + "day": 1, + "flight": "AF203", + "utc": "17:34:00" + }, + { + "day": 1, + "flight": "AF513", + "utc": "17:55:00" + }, + { + "day": 2, + "flight": "AF100", + "utc": "13:37:00" + }, + { + "day": 3, + "flight": "AF704", + "utc": "14:15:00" + }, + { + "day": 3, + "flight": "AF562", + "utc": "13:28:00" + }, + { + "day": 3, + "flight": "AF925", + "utc": "19:16:00" + }, + { + "day": 4, + "flight": "AF901", + "utc": "01:26:00" + }, + { + "day": 5, + "flight": "AF685", + "utc": "16:08:00" + }, + { + "day": 5, + "flight": "AF512", + "utc": "18:25:00" + }, + { + "day": 5, + "flight": "AF242", + "utc": "08:31:00" + }, + { + "day": 5, + "flight": "AF993", + "utc": "19:19:00" + }, + { + "day": 5, + "flight": "AF223", + "utc": "03:49:00" + }, + { + "day": 6, + "flight": "AF913", + "utc": "17:19:00" + }, + { + "day": 6, + "flight": "AF443", + "utc": "02:40:00" + }, + { + "day": 6, + "flight": "AF802", + "utc": "21:06:00" + }, + { + "day": 6, + "flight": "AF469", + "utc": "06:57:00" + }, + { + "day": 6, + "flight": "AF383", + "utc": "10:57:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "319 320", + "id": 9990, + "schedule": [ + { + "day": 0, + "flight": "AF023", + "utc": "13:28:00" + }, + { + "day": 0, + "flight": "AF429", + "utc": "11:52:00" + }, + { + "day": 0, + "flight": "AF606", + "utc": "17:25:00" + }, + { + "day": 1, + "flight": "AF132", + "utc": "07:15:00" + }, + { + "day": 1, + "flight": "AF132", + "utc": "00:14:00" + }, + { + "day": 1, + "flight": "AF568", + "utc": "09:49:00" + }, + { + "day": 2, + "flight": "AF489", + "utc": "16:51:00" + }, + { + "day": 3, + "flight": "AF427", + "utc": "06:10:00" + }, + { + "day": 4, + "flight": "AF566", + "utc": "23:15:00" + }, + { + "day": 4, + "flight": "AF238", + "utc": "22:49:00" + }, + { + "day": 4, + "flight": "AF606", + "utc": "16:17:00" + }, + { + "day": 5, + "flight": "AF925", + "utc": "23:53:00" + }, + { + "day": 5, + "flight": "AF888", + "utc": "12:11:00" + }, + { + "day": 5, + "flight": "AF817", + "utc": "13:09:00" + }, + { + "day": 5, + "flight": "AF290", + "utc": "03:13:00" + }, + { + "day": 5, + "flight": "AF213", + "utc": "02:47:00" + }, + { + "day": 6, + "flight": "AF891", + "utc": "14:24:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "HAM", + "distance": 1277.920368466386, + "equipment": "319", + "id": 9991, + "schedule": [ + { + "day": 0, + "flight": "AF447", + "utc": "05:13:00" + }, + { + "day": 1, + "flight": "AF948", + "utc": "22:21:00" + }, + { + "day": 1, + "flight": "AF812", + "utc": "03:32:00" + }, + { + "day": 1, + "flight": "AF473", + "utc": "12:07:00" + }, + { + "day": 2, + "flight": "AF144", + "utc": "21:30:00" + }, + { + "day": 2, + "flight": "AF721", + "utc": "10:42:00" + }, + { + "day": 2, + "flight": "AF117", + "utc": "02:07:00" + }, + { + "day": 2, + "flight": "AF382", + "utc": "10:57:00" + }, + { + "day": 3, + "flight": "AF432", + "utc": "12:33:00" + }, + { + "day": 3, + "flight": "AF936", + "utc": "07:58:00" + }, + { + "day": 4, + "flight": "AF082", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "AF060", + "utc": "23:38:00" + }, + { + "day": 4, + "flight": "AF040", + "utc": "17:39:00" + }, + { + "day": 4, + "flight": "AF072", + "utc": "02:25:00" + }, + { + "day": 5, + "flight": "AF511", + "utc": "18:29:00" + }, + { + "day": 5, + "flight": "AF065", + "utc": "11:52:00" + }, + { + "day": 5, + "flight": "AF461", + "utc": "18:49:00" + }, + { + "day": 5, + "flight": "AF562", + "utc": "10:10:00" + }, + { + "day": 6, + "flight": "AF305", + "utc": "16:07:00" + }, + { + "day": 6, + "flight": "AF762", + "utc": "19:24:00" + }, + { + "day": 6, + "flight": "AF062", + "utc": "20:15:00" + }, + { + "day": 6, + "flight": "AF339", + "utc": "12:15:00" + }, + { + "day": 6, + "flight": "AF982", + "utc": "15:15:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319 320 CRK", + "id": 9992, + "schedule": [ + { + "day": 0, + "flight": "AF823", + "utc": "19:58:00" + }, + { + "day": 0, + "flight": "AF523", + "utc": "05:11:00" + }, + { + "day": 0, + "flight": "AF212", + "utc": "04:29:00" + }, + { + "day": 0, + "flight": "AF928", + "utc": "07:41:00" + }, + { + "day": 0, + "flight": "AF064", + "utc": "20:55:00" + }, + { + "day": 1, + "flight": "AF584", + "utc": "18:14:00" + }, + { + "day": 1, + "flight": "AF903", + "utc": "07:20:00" + }, + { + "day": 1, + "flight": "AF815", + "utc": "16:43:00" + }, + { + "day": 1, + "flight": "AF283", + "utc": "09:31:00" + }, + { + "day": 1, + "flight": "AF682", + "utc": "02:15:00" + }, + { + "day": 2, + "flight": "AF907", + "utc": "06:21:00" + }, + { + "day": 2, + "flight": "AF094", + "utc": "08:33:00" + }, + { + "day": 2, + "flight": "AF449", + "utc": "15:44:00" + }, + { + "day": 2, + "flight": "AF876", + "utc": "22:00:00" + }, + { + "day": 3, + "flight": "AF828", + "utc": "06:35:00" + }, + { + "day": 3, + "flight": "AF125", + "utc": "15:35:00" + }, + { + "day": 4, + "flight": "AF348", + "utc": "08:34:00" + }, + { + "day": 5, + "flight": "AF100", + "utc": "20:01:00" + }, + { + "day": 5, + "flight": "AF530", + "utc": "11:25:00" + }, + { + "day": 6, + "flight": "AF763", + "utc": "19:11:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "MLA", + "distance": 1412.6976574099108, + "equipment": "320 319", + "id": 9993, + "schedule": [ + { + "day": 0, + "flight": "AF590", + "utc": "23:02:00" + }, + { + "day": 1, + "flight": "AF224", + "utc": "18:02:00" + }, + { + "day": 2, + "flight": "AF834", + "utc": "15:09:00" + }, + { + "day": 2, + "flight": "AF748", + "utc": "09:21:00" + }, + { + "day": 2, + "flight": "AF947", + "utc": "15:28:00" + }, + { + "day": 2, + "flight": "AF058", + "utc": "19:08:00" + }, + { + "day": 2, + "flight": "AF914", + "utc": "18:02:00" + }, + { + "day": 3, + "flight": "AF351", + "utc": "04:18:00" + }, + { + "day": 3, + "flight": "AF975", + "utc": "13:49:00" + }, + { + "day": 3, + "flight": "AF361", + "utc": "18:56:00" + }, + { + "day": 4, + "flight": "AF461", + "utc": "01:40:00" + }, + { + "day": 5, + "flight": "AF281", + "utc": "10:31:00" + }, + { + "day": 6, + "flight": "AF337", + "utc": "10:18:00" + }, + { + "day": 6, + "flight": "AF570", + "utc": "07:41:00" + }, + { + "day": 6, + "flight": "AF823", + "utc": "20:37:00" + }, + { + "day": 6, + "flight": "AF109", + "utc": "14:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ORY", + "distance": 571.8189591117047, + "equipment": "320 319 321", + "id": 9994, + "schedule": [ + { + "day": 0, + "flight": "AF986", + "utc": "12:40:00" + }, + { + "day": 0, + "flight": "AF951", + "utc": "06:14:00" + }, + { + "day": 0, + "flight": "AF527", + "utc": "11:45:00" + }, + { + "day": 0, + "flight": "AF801", + "utc": "14:47:00" + }, + { + "day": 1, + "flight": "AF838", + "utc": "05:42:00" + }, + { + "day": 2, + "flight": "AF952", + "utc": "03:24:00" + }, + { + "day": 2, + "flight": "AF920", + "utc": "14:50:00" + }, + { + "day": 2, + "flight": "AF318", + "utc": "03:40:00" + }, + { + "day": 2, + "flight": "AF137", + "utc": "20:21:00" + }, + { + "day": 3, + "flight": "AF135", + "utc": "15:04:00" + }, + { + "day": 4, + "flight": "AF847", + "utc": "22:57:00" + }, + { + "day": 4, + "flight": "AF010", + "utc": "07:51:00" + }, + { + "day": 4, + "flight": "AF973", + "utc": "17:28:00" + }, + { + "day": 5, + "flight": "AF532", + "utc": "22:28:00" + }, + { + "day": 5, + "flight": "AF447", + "utc": "18:35:00" + }, + { + "day": 5, + "flight": "AF017", + "utc": "13:48:00" + }, + { + "day": 5, + "flight": "AF135", + "utc": "10:16:00" + }, + { + "day": 6, + "flight": "AF933", + "utc": "21:03:00" + }, + { + "day": 6, + "flight": "AF024", + "utc": "05:59:00" + }, + { + "day": 6, + "flight": "AF243", + "utc": "06:19:00" + }, + { + "day": 6, + "flight": "AF619", + "utc": "03:41:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "319 320", + "id": 9995, + "schedule": [ + { + "day": 0, + "flight": "AF312", + "utc": "08:58:00" + }, + { + "day": 0, + "flight": "AF099", + "utc": "22:19:00" + }, + { + "day": 0, + "flight": "AF157", + "utc": "05:26:00" + }, + { + "day": 1, + "flight": "AF793", + "utc": "14:45:00" + }, + { + "day": 1, + "flight": "AF638", + "utc": "03:55:00" + }, + { + "day": 1, + "flight": "AF372", + "utc": "20:37:00" + }, + { + "day": 1, + "flight": "AF788", + "utc": "19:15:00" + }, + { + "day": 1, + "flight": "AF889", + "utc": "02:00:00" + }, + { + "day": 2, + "flight": "AF521", + "utc": "21:48:00" + }, + { + "day": 2, + "flight": "AF990", + "utc": "19:41:00" + }, + { + "day": 2, + "flight": "AF047", + "utc": "00:33:00" + }, + { + "day": 2, + "flight": "AF540", + "utc": "08:19:00" + }, + { + "day": 3, + "flight": "AF247", + "utc": "02:30:00" + }, + { + "day": 3, + "flight": "AF197", + "utc": "07:17:00" + }, + { + "day": 3, + "flight": "AF015", + "utc": "07:05:00" + }, + { + "day": 4, + "flight": "AF213", + "utc": "22:43:00" + }, + { + "day": 5, + "flight": "AF732", + "utc": "03:12:00" + }, + { + "day": 5, + "flight": "AF304", + "utc": "08:21:00" + }, + { + "day": 6, + "flight": "AF274", + "utc": "12:07:00" + }, + { + "day": 6, + "flight": "AF177", + "utc": "19:29:00" + }, + { + "day": 6, + "flight": "AF409", + "utc": "23:56:00" + }, + { + "day": 6, + "flight": "AF099", + "utc": "07:45:00" + }, + { + "day": 6, + "flight": "AF848", + "utc": "12:34:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "SVQ", + "distance": 922.9469580316244, + "equipment": "319", + "id": 9996, + "schedule": [ + { + "day": 0, + "flight": "AF720", + "utc": "10:48:00" + }, + { + "day": 0, + "flight": "AF932", + "utc": "22:03:00" + }, + { + "day": 0, + "flight": "AF292", + "utc": "20:49:00" + }, + { + "day": 1, + "flight": "AF080", + "utc": "09:57:00" + }, + { + "day": 1, + "flight": "AF668", + "utc": "23:52:00" + }, + { + "day": 1, + "flight": "AF713", + "utc": "04:58:00" + }, + { + "day": 1, + "flight": "AF490", + "utc": "13:37:00" + }, + { + "day": 1, + "flight": "AF809", + "utc": "01:49:00" + }, + { + "day": 2, + "flight": "AF203", + "utc": "16:09:00" + }, + { + "day": 2, + "flight": "AF329", + "utc": "19:59:00" + }, + { + "day": 2, + "flight": "AF875", + "utc": "15:10:00" + }, + { + "day": 3, + "flight": "AF757", + "utc": "12:26:00" + }, + { + "day": 3, + "flight": "AF350", + "utc": "13:33:00" + }, + { + "day": 3, + "flight": "AF530", + "utc": "21:25:00" + }, + { + "day": 3, + "flight": "AF793", + "utc": "15:05:00" + }, + { + "day": 3, + "flight": "AF124", + "utc": "23:40:00" + }, + { + "day": 4, + "flight": "AF959", + "utc": "07:46:00" + }, + { + "day": 4, + "flight": "AF363", + "utc": "01:02:00" + }, + { + "day": 5, + "flight": "AF816", + "utc": "10:35:00" + }, + { + "day": 6, + "flight": "AF918", + "utc": "23:43:00" + }, + { + "day": 6, + "flight": "AF600", + "utc": "02:43:00" + }, + { + "day": 6, + "flight": "AF072", + "utc": "21:29:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "SXB", + "distance": 728.4867234220715, + "equipment": "319 320", + "id": 9997, + "schedule": [ + { + "day": 0, + "flight": "AF998", + "utc": "19:19:00" + }, + { + "day": 0, + "flight": "AF527", + "utc": "21:15:00" + }, + { + "day": 0, + "flight": "AF043", + "utc": "12:21:00" + }, + { + "day": 0, + "flight": "AF783", + "utc": "03:06:00" + }, + { + "day": 0, + "flight": "AF947", + "utc": "11:16:00" + }, + { + "day": 1, + "flight": "AF339", + "utc": "22:50:00" + }, + { + "day": 1, + "flight": "AF399", + "utc": "23:32:00" + }, + { + "day": 1, + "flight": "AF327", + "utc": "00:17:00" + }, + { + "day": 1, + "flight": "AF658", + "utc": "20:23:00" + }, + { + "day": 1, + "flight": "AF307", + "utc": "04:54:00" + }, + { + "day": 2, + "flight": "AF521", + "utc": "06:47:00" + }, + { + "day": 2, + "flight": "AF687", + "utc": "12:12:00" + }, + { + "day": 3, + "flight": "AF258", + "utc": "23:32:00" + }, + { + "day": 3, + "flight": "AF265", + "utc": "07:55:00" + }, + { + "day": 3, + "flight": "AF284", + "utc": "12:10:00" + }, + { + "day": 3, + "flight": "AF532", + "utc": "14:27:00" + }, + { + "day": 3, + "flight": "AF916", + "utc": "06:00:00" + }, + { + "day": 4, + "flight": "AF399", + "utc": "17:38:00" + }, + { + "day": 4, + "flight": "AF805", + "utc": "05:59:00" + }, + { + "day": 5, + "flight": "AF657", + "utc": "13:08:00" + }, + { + "day": 5, + "flight": "AF361", + "utc": "12:44:00" + }, + { + "day": 6, + "flight": "AF659", + "utc": "07:14:00" + }, + { + "day": 6, + "flight": "AF096", + "utc": "06:33:00" + }, + { + "day": 6, + "flight": "AF289", + "utc": "01:31:00" + }, + { + "day": 6, + "flight": "AF338", + "utc": "19:03:00" + }, + { + "day": 6, + "flight": "AF985", + "utc": "07:42:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "VCE", + "distance": 894.3253403650848, + "equipment": "319 320", + "id": 9998, + "schedule": [ + { + "day": 0, + "flight": "AF396", + "utc": "14:33:00" + }, + { + "day": 0, + "flight": "AF180", + "utc": "02:02:00" + }, + { + "day": 0, + "flight": "AF752", + "utc": "06:07:00" + }, + { + "day": 1, + "flight": "AF686", + "utc": "09:35:00" + }, + { + "day": 1, + "flight": "AF614", + "utc": "00:48:00" + }, + { + "day": 1, + "flight": "AF443", + "utc": "11:54:00" + }, + { + "day": 1, + "flight": "AF125", + "utc": "15:34:00" + }, + { + "day": 2, + "flight": "AF045", + "utc": "20:49:00" + }, + { + "day": 2, + "flight": "AF430", + "utc": "22:18:00" + }, + { + "day": 2, + "flight": "AF068", + "utc": "05:24:00" + }, + { + "day": 2, + "flight": "AF945", + "utc": "08:23:00" + }, + { + "day": 2, + "flight": "AF949", + "utc": "05:19:00" + }, + { + "day": 3, + "flight": "AF249", + "utc": "15:48:00" + }, + { + "day": 3, + "flight": "AF468", + "utc": "09:43:00" + }, + { + "day": 4, + "flight": "AF966", + "utc": "00:15:00" + }, + { + "day": 4, + "flight": "AF461", + "utc": "16:58:00" + }, + { + "day": 5, + "flight": "AF993", + "utc": "12:09:00" + }, + { + "day": 5, + "flight": "AF790", + "utc": "04:27:00" + }, + { + "day": 5, + "flight": "AF370", + "utc": "01:25:00" + }, + { + "day": 5, + "flight": "AF861", + "utc": "21:37:00" + }, + { + "day": 5, + "flight": "AF480", + "utc": "05:17:00" + }, + { + "day": 6, + "flight": "AF733", + "utc": "04:13:00" + }, + { + "day": 6, + "flight": "AF308", + "utc": "01:08:00" + }, + { + "day": 6, + "flight": "AF063", + "utc": "04:55:00" + }, + { + "day": 6, + "flight": "AF257", + "utc": "17:21:00" + }, + { + "day": 6, + "flight": "AF531", + "utc": "13:24:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + } + ] + } +] diff --git a/modules/n1ql/examples/select/ansi-nest-lateral.n1ql b/modules/n1ql/examples/select/ansi-nest-lateral.n1ql new file mode 100644 index 000000000..ea5ff0f31 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest-lateral.n1ql @@ -0,0 +1,9 @@ +SELECT * +FROM airport a + NEST LATERAL ( + SELECT r1.* FROM route r1 + WHERE a.faa = r1.sourceairport + ) AS r + ON true +WHERE a.city = "Toulouse" +ORDER BY a.airportname; diff --git a/modules/n1ql/examples/select/ansi-nest-left.jsonc b/modules/n1ql/examples/select/ansi-nest-left.jsonc new file mode 100644 index 000000000..a6fa8c2c8 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest-left.jsonc @@ -0,0 +1,8645 @@ +// tag::extract[] +[ + { + "a": { + "airportname": "Blagnac", + "city": "Toulouse", + "country": "France", + "faa": "TLS", + "geo": { + "alt": 499, + "lat": 43.629075, + "lon": 1.363819 + }, + "icao": "LFBO", + "id": 1273, + "type": "airport", + "tz": "Europe/Paris" + }, + "r": [ + { + "airline": "AH", + "airlineid": "airline_794", + "destinationairport": "ALG", + "distance": 787.299015326995, + "equipment": "736", + "id": 10265, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + "schedule": [ + { + "day": 0, + "flight": "AH221", + "utc": "17:23:00" + }, + { + "day": 1, + "flight": "AH920", + "utc": "07:44:00" + }, + { + "day": 1, + "flight": "AH593", + "utc": "12:04:00" + }, + { + "day": 1, + "flight": "AH394", + "utc": "00:33:00" + }, + { + "day": 1, + "flight": "AH180", + "utc": "20:18:00" + }, + { + "day": 2, + "flight": "AH974", + "utc": "01:21:00" + }, + { + "day": 3, + "flight": "AH281", + "utc": "09:34:00" + }, + { + "day": 3, + "flight": "AH033", + "utc": "11:02:00" + }, + { + "day": 3, + "flight": "AH385", + "utc": "11:42:00" + }, + { + "day": 3, + "flight": "AH989", + "utc": "09:07:00" + }, + { + "day": 3, + "flight": "AH834", + "utc": "18:46:00" + }, + { + "day": 4, + "flight": "AH417", + "utc": "05:17:00" + }, + { + "day": 4, + "flight": "AH322", + "utc": "11:10:00" + }, + { + "day": 4, + "flight": "AH235", + "utc": "18:43:00" + }, + { + "day": 4, + "flight": "AH995", + "utc": "00:15:00" + }, + { + "day": 4, + "flight": "AH619", + "utc": "08:43:00" + }, + { + "day": 5, + "flight": "AH537", + "utc": "03:48:00" + }, + { + "day": 5, + "flight": "AH181", + "utc": "11:23:00" + }, + { + "day": 5, + "flight": "AH083", + "utc": "12:37:00" + }, + { + "day": 5, + "flight": "AH727", + "utc": "12:08:00" + }, + { + "day": 6, + "flight": "AH377", + "utc": "13:15:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AH", + "airlineid": "airline_794", + "destinationairport": "ORN", + "distance": 906.1483088609814, + "equipment": "736", + "id": 10266, + "schedule": [ + { + "day": 0, + "flight": "AH152", + "utc": "14:02:00" + }, + { + "day": 0, + "flight": "AH864", + "utc": "11:48:00" + }, + { + "day": 0, + "flight": "AH922", + "utc": "11:03:00" + }, + { + "day": 1, + "flight": "AH633", + "utc": "13:22:00" + }, + { + "day": 1, + "flight": "AH450", + "utc": "05:32:00" + }, + { + "day": 1, + "flight": "AH343", + "utc": "05:17:00" + }, + { + "day": 2, + "flight": "AH869", + "utc": "17:26:00" + }, + { + "day": 2, + "flight": "AH175", + "utc": "13:56:00" + }, + { + "day": 3, + "flight": "AH243", + "utc": "22:54:00" + }, + { + "day": 3, + "flight": "AH778", + "utc": "09:53:00" + }, + { + "day": 3, + "flight": "AH049", + "utc": "02:20:00" + }, + { + "day": 3, + "flight": "AH930", + "utc": "05:40:00" + }, + { + "day": 3, + "flight": "AH206", + "utc": "10:03:00" + }, + { + "day": 4, + "flight": "AH125", + "utc": "16:15:00" + }, + { + "day": 4, + "flight": "AH533", + "utc": "10:50:00" + }, + { + "day": 4, + "flight": "AH494", + "utc": "10:36:00" + }, + { + "day": 4, + "flight": "AH759", + "utc": "17:10:00" + }, + { + "day": 5, + "flight": "AH267", + "utc": "22:16:00" + }, + { + "day": 5, + "flight": "AH769", + "utc": "09:13:00" + }, + { + "day": 5, + "flight": "AH116", + "utc": "09:19:00" + }, + { + "day": 5, + "flight": "AH949", + "utc": "02:28:00" + }, + { + "day": 5, + "flight": "AH624", + "utc": "03:51:00" + }, + { + "day": 6, + "flight": "AH597", + "utc": "02:23:00" + }, + { + "day": 6, + "flight": "AH523", + "utc": "05:32:00" + }, + { + "day": 6, + "flight": "AH615", + "utc": "00:19:00" + }, + { + "day": 6, + "flight": "AH453", + "utc": "19:08:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AT", + "airlineid": "airline_4248", + "destinationairport": "CMN", + "distance": 1379.8271930529227, + "equipment": "738 73G", + "id": 12271, + "schedule": [ + { + "day": 0, + "flight": "AT780", + "utc": "17:23:00" + }, + { + "day": 0, + "flight": "AT069", + "utc": "00:25:00" + }, + { + "day": 0, + "flight": "AT970", + "utc": "10:57:00" + }, + { + "day": 1, + "flight": "AT716", + "utc": "05:22:00" + }, + { + "day": 1, + "flight": "AT424", + "utc": "02:09:00" + }, + { + "day": 1, + "flight": "AT498", + "utc": "00:54:00" + }, + { + "day": 1, + "flight": "AT552", + "utc": "19:13:00" + }, + { + "day": 1, + "flight": "AT967", + "utc": "05:05:00" + }, + { + "day": 2, + "flight": "AT640", + "utc": "17:24:00" + }, + { + "day": 2, + "flight": "AT877", + "utc": "04:34:00" + }, + { + "day": 2, + "flight": "AT439", + "utc": "12:48:00" + }, + { + "day": 3, + "flight": "AT447", + "utc": "06:27:00" + }, + { + "day": 3, + "flight": "AT882", + "utc": "10:53:00" + }, + { + "day": 3, + "flight": "AT548", + "utc": "08:29:00" + }, + { + "day": 3, + "flight": "AT489", + "utc": "10:37:00" + }, + { + "day": 3, + "flight": "AT611", + "utc": "14:16:00" + }, + { + "day": 4, + "flight": "AT539", + "utc": "19:59:00" + }, + { + "day": 4, + "flight": "AT570", + "utc": "03:23:00" + }, + { + "day": 4, + "flight": "AT350", + "utc": "15:03:00" + }, + { + "day": 4, + "flight": "AT899", + "utc": "08:00:00" + }, + { + "day": 4, + "flight": "AT909", + "utc": "16:53:00" + }, + { + "day": 5, + "flight": "AT985", + "utc": "21:31:00" + }, + { + "day": 5, + "flight": "AT617", + "utc": "16:28:00" + }, + { + "day": 5, + "flight": "AT745", + "utc": "19:02:00" + }, + { + "day": 6, + "flight": "AT015", + "utc": "10:04:00" + }, + { + "day": 6, + "flight": "AT270", + "utc": "03:19:00" + }, + { + "day": 6, + "flight": "AT975", + "utc": "04:16:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AT", + "airlineid": "airline_4248", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "738", + "id": 12272, + "schedule": [ + { + "day": 0, + "flight": "AT223", + "utc": "10:06:00" + }, + { + "day": 1, + "flight": "AT187", + "utc": "20:12:00" + }, + { + "day": 2, + "flight": "AT379", + "utc": "14:45:00" + }, + { + "day": 2, + "flight": "AT950", + "utc": "08:07:00" + }, + { + "day": 2, + "flight": "AT921", + "utc": "22:15:00" + }, + { + "day": 2, + "flight": "AT122", + "utc": "06:39:00" + }, + { + "day": 3, + "flight": "AT413", + "utc": "21:46:00" + }, + { + "day": 3, + "flight": "AT974", + "utc": "13:14:00" + }, + { + "day": 3, + "flight": "AT805", + "utc": "22:18:00" + }, + { + "day": 3, + "flight": "AT558", + "utc": "15:35:00" + }, + { + "day": 4, + "flight": "AT919", + "utc": "11:11:00" + }, + { + "day": 4, + "flight": "AT380", + "utc": "14:20:00" + }, + { + "day": 4, + "flight": "AT588", + "utc": "12:03:00" + }, + { + "day": 4, + "flight": "AT762", + "utc": "16:07:00" + }, + { + "day": 5, + "flight": "AT423", + "utc": "12:28:00" + }, + { + "day": 6, + "flight": "AT554", + "utc": "15:05:00" + }, + { + "day": 6, + "flight": "AT145", + "utc": "07:36:00" + }, + { + "day": 6, + "flight": "AT179", + "utc": "05:51:00" + }, + { + "day": 6, + "flight": "AT460", + "utc": "02:34:00" + }, + { + "day": 6, + "flight": "AT648", + "utc": "16:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "320 319", + "id": 13715, + "schedule": [ + { + "day": 0, + "flight": "AZ503", + "utc": "10:59:00" + }, + { + "day": 0, + "flight": "AZ608", + "utc": "02:25:00" + }, + { + "day": 1, + "flight": "AZ013", + "utc": "21:09:00" + }, + { + "day": 1, + "flight": "AZ108", + "utc": "22:36:00" + }, + { + "day": 1, + "flight": "AZ730", + "utc": "17:38:00" + }, + { + "day": 2, + "flight": "AZ527", + "utc": "17:39:00" + }, + { + "day": 2, + "flight": "AZ506", + "utc": "21:44:00" + }, + { + "day": 2, + "flight": "AZ072", + "utc": "10:12:00" + }, + { + "day": 2, + "flight": "AZ661", + "utc": "21:42:00" + }, + { + "day": 3, + "flight": "AZ873", + "utc": "16:32:00" + }, + { + "day": 3, + "flight": "AZ005", + "utc": "18:21:00" + }, + { + "day": 3, + "flight": "AZ573", + "utc": "17:58:00" + }, + { + "day": 4, + "flight": "AZ318", + "utc": "10:20:00" + }, + { + "day": 4, + "flight": "AZ537", + "utc": "13:33:00" + }, + { + "day": 4, + "flight": "AZ187", + "utc": "14:18:00" + }, + { + "day": 4, + "flight": "AZ590", + "utc": "12:28:00" + }, + { + "day": 5, + "flight": "AZ997", + "utc": "22:03:00" + }, + { + "day": 6, + "flight": "AZ915", + "utc": "21:20:00" + }, + { + "day": 6, + "flight": "AZ927", + "utc": "17:48:00" + }, + { + "day": 6, + "flight": "AZ073", + "utc": "05:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "E75", + "id": 13716, + "schedule": [ + { + "day": 0, + "flight": "AZ121", + "utc": "02:19:00" + }, + { + "day": 0, + "flight": "AZ997", + "utc": "02:46:00" + }, + { + "day": 1, + "flight": "AZ068", + "utc": "15:00:00" + }, + { + "day": 1, + "flight": "AZ873", + "utc": "01:54:00" + }, + { + "day": 1, + "flight": "AZ441", + "utc": "06:02:00" + }, + { + "day": 1, + "flight": "AZ942", + "utc": "01:37:00" + }, + { + "day": 1, + "flight": "AZ399", + "utc": "20:15:00" + }, + { + "day": 2, + "flight": "AZ471", + "utc": "05:47:00" + }, + { + "day": 3, + "flight": "AZ641", + "utc": "09:17:00" + }, + { + "day": 3, + "flight": "AZ994", + "utc": "21:28:00" + }, + { + "day": 3, + "flight": "AZ237", + "utc": "04:09:00" + }, + { + "day": 3, + "flight": "AZ294", + "utc": "03:44:00" + }, + { + "day": 3, + "flight": "AZ683", + "utc": "20:27:00" + }, + { + "day": 4, + "flight": "AZ925", + "utc": "02:55:00" + }, + { + "day": 4, + "flight": "AZ713", + "utc": "14:45:00" + }, + { + "day": 5, + "flight": "AZ414", + "utc": "10:11:00" + }, + { + "day": 5, + "flight": "AZ163", + "utc": "07:30:00" + }, + { + "day": 5, + "flight": "AZ413", + "utc": "21:23:00" + }, + { + "day": 5, + "flight": "AZ535", + "utc": "04:02:00" + }, + { + "day": 5, + "flight": "AZ119", + "utc": "21:16:00" + }, + { + "day": 6, + "flight": "AZ610", + "utc": "12:40:00" + }, + { + "day": 6, + "flight": "AZ694", + "utc": "03:10:00" + }, + { + "day": 6, + "flight": "AZ190", + "utc": "12:47:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319 320 CRK", + "id": 13717, + "schedule": [ + { + "day": 0, + "flight": "AZ226", + "utc": "06:27:00" + }, + { + "day": 0, + "flight": "AZ102", + "utc": "15:40:00" + }, + { + "day": 0, + "flight": "AZ366", + "utc": "05:31:00" + }, + { + "day": 0, + "flight": "AZ469", + "utc": "23:10:00" + }, + { + "day": 0, + "flight": "AZ910", + "utc": "05:39:00" + }, + { + "day": 1, + "flight": "AZ643", + "utc": "13:50:00" + }, + { + "day": 1, + "flight": "AZ897", + "utc": "15:10:00" + }, + { + "day": 1, + "flight": "AZ167", + "utc": "15:00:00" + }, + { + "day": 1, + "flight": "AZ427", + "utc": "10:23:00" + }, + { + "day": 2, + "flight": "AZ472", + "utc": "07:02:00" + }, + { + "day": 3, + "flight": "AZ887", + "utc": "13:57:00" + }, + { + "day": 3, + "flight": "AZ694", + "utc": "20:32:00" + }, + { + "day": 3, + "flight": "AZ781", + "utc": "00:51:00" + }, + { + "day": 3, + "flight": "AZ633", + "utc": "22:00:00" + }, + { + "day": 4, + "flight": "AZ346", + "utc": "21:27:00" + }, + { + "day": 4, + "flight": "AZ570", + "utc": "15:59:00" + }, + { + "day": 4, + "flight": "AZ395", + "utc": "20:42:00" + }, + { + "day": 4, + "flight": "AZ009", + "utc": "15:01:00" + }, + { + "day": 4, + "flight": "AZ097", + "utc": "19:04:00" + }, + { + "day": 5, + "flight": "AZ363", + "utc": "01:15:00" + }, + { + "day": 5, + "flight": "AZ513", + "utc": "23:55:00" + }, + { + "day": 5, + "flight": "AZ311", + "utc": "10:51:00" + }, + { + "day": 5, + "flight": "AZ374", + "utc": "23:22:00" + }, + { + "day": 6, + "flight": "AZ027", + "utc": "10:27:00" + }, + { + "day": 6, + "flight": "AZ782", + "utc": "23:04:00" + }, + { + "day": 6, + "flight": "AZ869", + "utc": "01:27:00" + }, + { + "day": 6, + "flight": "AZ117", + "utc": "09:01:00" + }, + { + "day": 6, + "flight": "AZ365", + "utc": "11:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AZ", + "airlineid": "airline_596", + "destinationairport": "VCE", + "distance": 894.3253403650848, + "equipment": "319 320", + "id": 13718, + "schedule": [ + { + "day": 0, + "flight": "AZ323", + "utc": "21:01:00" + }, + { + "day": 0, + "flight": "AZ639", + "utc": "06:08:00" + }, + { + "day": 0, + "flight": "AZ751", + "utc": "09:17:00" + }, + { + "day": 0, + "flight": "AZ418", + "utc": "10:51:00" + }, + { + "day": 0, + "flight": "AZ293", + "utc": "09:42:00" + }, + { + "day": 1, + "flight": "AZ294", + "utc": "11:55:00" + }, + { + "day": 1, + "flight": "AZ618", + "utc": "04:56:00" + }, + { + "day": 1, + "flight": "AZ919", + "utc": "00:38:00" + }, + { + "day": 2, + "flight": "AZ839", + "utc": "17:52:00" + }, + { + "day": 2, + "flight": "AZ252", + "utc": "23:45:00" + }, + { + "day": 3, + "flight": "AZ477", + "utc": "00:11:00" + }, + { + "day": 4, + "flight": "AZ903", + "utc": "15:47:00" + }, + { + "day": 4, + "flight": "AZ933", + "utc": "23:28:00" + }, + { + "day": 4, + "flight": "AZ320", + "utc": "18:22:00" + }, + { + "day": 4, + "flight": "AZ866", + "utc": "04:11:00" + }, + { + "day": 5, + "flight": "AZ877", + "utc": "21:44:00" + }, + { + "day": 5, + "flight": "AZ810", + "utc": "06:51:00" + }, + { + "day": 6, + "flight": "AZ910", + "utc": "12:05:00" + }, + { + "day": 6, + "flight": "AZ341", + "utc": "10:32:00" + }, + { + "day": 6, + "flight": "AZ544", + "utc": "18:04:00" + }, + { + "day": 6, + "flight": "AZ780", + "utc": "10:21:00" + }, + { + "day": 6, + "flight": "AZ392", + "utc": "07:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "BA", + "airlineid": "airline_1355", + "destinationairport": "LHR", + "distance": 883.3122325423356, + "equipment": "320 319 321", + "id": 14913, + "schedule": [ + { + "day": 0, + "flight": "BA098", + "utc": "11:01:00" + }, + { + "day": 0, + "flight": "BA391", + "utc": "05:10:00" + }, + { + "day": 0, + "flight": "BA960", + "utc": "22:58:00" + }, + { + "day": 1, + "flight": "BA681", + "utc": "10:42:00" + }, + { + "day": 1, + "flight": "BA255", + "utc": "14:13:00" + }, + { + "day": 1, + "flight": "BA715", + "utc": "02:32:00" + }, + { + "day": 1, + "flight": "BA860", + "utc": "13:23:00" + }, + { + "day": 1, + "flight": "BA241", + "utc": "12:27:00" + }, + { + "day": 2, + "flight": "BA737", + "utc": "18:30:00" + }, + { + "day": 2, + "flight": "BA602", + "utc": "15:35:00" + }, + { + "day": 2, + "flight": "BA709", + "utc": "12:21:00" + }, + { + "day": 2, + "flight": "BA796", + "utc": "11:08:00" + }, + { + "day": 2, + "flight": "BA067", + "utc": "00:28:00" + }, + { + "day": 3, + "flight": "BA111", + "utc": "00:08:00" + }, + { + "day": 3, + "flight": "BA920", + "utc": "14:33:00" + }, + { + "day": 3, + "flight": "BA469", + "utc": "18:09:00" + }, + { + "day": 3, + "flight": "BA122", + "utc": "05:40:00" + }, + { + "day": 3, + "flight": "BA194", + "utc": "11:45:00" + }, + { + "day": 4, + "flight": "BA481", + "utc": "19:41:00" + }, + { + "day": 4, + "flight": "BA430", + "utc": "01:39:00" + }, + { + "day": 4, + "flight": "BA439", + "utc": "07:02:00" + }, + { + "day": 5, + "flight": "BA287", + "utc": "08:08:00" + }, + { + "day": 5, + "flight": "BA097", + "utc": "04:45:00" + }, + { + "day": 6, + "flight": "BA177", + "utc": "00:26:00" + }, + { + "day": 6, + "flight": "BA703", + "utc": "23:45:00" + }, + { + "day": 6, + "flight": "BA326", + "utc": "15:49:00" + }, + { + "day": 6, + "flight": "BA238", + "utc": "23:31:00" + }, + { + "day": 6, + "flight": "BA717", + "utc": "07:18:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "4U", + "airlineid": "airline_2548", + "destinationairport": "HAM", + "distance": 1277.920368466386, + "equipment": "CRJ", + "id": 1638, + "schedule": [ + { + "day": 0, + "flight": "4U997", + "utc": "03:46:00" + }, + { + "day": 1, + "flight": "4U464", + "utc": "15:51:00" + }, + { + "day": 1, + "flight": "4U823", + "utc": "01:54:00" + }, + { + "day": 2, + "flight": "4U060", + "utc": "01:28:00" + }, + { + "day": 2, + "flight": "4U489", + "utc": "08:26:00" + }, + { + "day": 2, + "flight": "4U835", + "utc": "15:04:00" + }, + { + "day": 2, + "flight": "4U267", + "utc": "23:16:00" + }, + { + "day": 3, + "flight": "4U085", + "utc": "22:10:00" + }, + { + "day": 3, + "flight": "4U835", + "utc": "11:52:00" + }, + { + "day": 3, + "flight": "4U688", + "utc": "09:26:00" + }, + { + "day": 4, + "flight": "4U808", + "utc": "20:34:00" + }, + { + "day": 4, + "flight": "4U408", + "utc": "10:31:00" + }, + { + "day": 4, + "flight": "4U614", + "utc": "11:22:00" + }, + { + "day": 4, + "flight": "4U093", + "utc": "17:56:00" + }, + { + "day": 4, + "flight": "4U664", + "utc": "03:06:00" + }, + { + "day": 5, + "flight": "4U030", + "utc": "13:04:00" + }, + { + "day": 6, + "flight": "4U771", + "utc": "08:13:00" + }, + { + "day": 6, + "flight": "4U198", + "utc": "20:11:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "EI", + "airlineid": "airline_837", + "destinationairport": "DUB", + "distance": 1223.7865232537742, + "equipment": "320", + "id": 23056, + "schedule": [ + { + "day": 0, + "flight": "EI370", + "utc": "11:48:00" + }, + { + "day": 1, + "flight": "EI137", + "utc": "16:37:00" + }, + { + "day": 1, + "flight": "EI052", + "utc": "11:06:00" + }, + { + "day": 1, + "flight": "EI383", + "utc": "14:12:00" + }, + { + "day": 2, + "flight": "EI657", + "utc": "11:49:00" + }, + { + "day": 2, + "flight": "EI394", + "utc": "04:10:00" + }, + { + "day": 2, + "flight": "EI000", + "utc": "01:50:00" + }, + { + "day": 2, + "flight": "EI475", + "utc": "06:36:00" + }, + { + "day": 2, + "flight": "EI292", + "utc": "12:49:00" + }, + { + "day": 3, + "flight": "EI262", + "utc": "05:57:00" + }, + { + "day": 3, + "flight": "EI355", + "utc": "08:00:00" + }, + { + "day": 3, + "flight": "EI831", + "utc": "13:22:00" + }, + { + "day": 3, + "flight": "EI812", + "utc": "12:43:00" + }, + { + "day": 3, + "flight": "EI228", + "utc": "08:51:00" + }, + { + "day": 4, + "flight": "EI446", + "utc": "04:33:00" + }, + { + "day": 4, + "flight": "EI823", + "utc": "11:38:00" + }, + { + "day": 4, + "flight": "EI880", + "utc": "07:11:00" + }, + { + "day": 4, + "flight": "EI483", + "utc": "18:05:00" + }, + { + "day": 5, + "flight": "EI989", + "utc": "05:58:00" + }, + { + "day": 5, + "flight": "EI395", + "utc": "07:41:00" + }, + { + "day": 5, + "flight": "EI362", + "utc": "04:45:00" + }, + { + "day": 5, + "flight": "EI749", + "utc": "16:24:00" + }, + { + "day": 5, + "flight": "EI146", + "utc": "07:57:00" + }, + { + "day": 6, + "flight": "EI249", + "utc": "06:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ET", + "airlineid": "airline_2220", + "destinationairport": "FRA", + "distance": 895.9770471097812, + "equipment": "735", + "id": 23940, + "schedule": [ + { + "day": 0, + "flight": "ET478", + "utc": "13:07:00" + }, + { + "day": 0, + "flight": "ET739", + "utc": "11:40:00" + }, + { + "day": 0, + "flight": "ET520", + "utc": "10:18:00" + }, + { + "day": 1, + "flight": "ET223", + "utc": "07:18:00" + }, + { + "day": 2, + "flight": "ET473", + "utc": "02:16:00" + }, + { + "day": 3, + "flight": "ET341", + "utc": "11:18:00" + }, + { + "day": 3, + "flight": "ET928", + "utc": "05:33:00" + }, + { + "day": 3, + "flight": "ET563", + "utc": "06:17:00" + }, + { + "day": 3, + "flight": "ET107", + "utc": "23:11:00" + }, + { + "day": 4, + "flight": "ET204", + "utc": "22:10:00" + }, + { + "day": 4, + "flight": "ET428", + "utc": "12:06:00" + }, + { + "day": 4, + "flight": "ET246", + "utc": "18:11:00" + }, + { + "day": 5, + "flight": "ET964", + "utc": "02:06:00" + }, + { + "day": 5, + "flight": "ET452", + "utc": "02:36:00" + }, + { + "day": 5, + "flight": "ET362", + "utc": "00:43:00" + }, + { + "day": 5, + "flight": "ET098", + "utc": "02:52:00" + }, + { + "day": 6, + "flight": "ET378", + "utc": "11:31:00" + }, + { + "day": 6, + "flight": "ET541", + "utc": "03:24:00" + }, + { + "day": 6, + "flight": "ET010", + "utc": "05:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "F7", + "airlineid": "airline_2420", + "destinationairport": "GVA", + "distance": 472.80826589600406, + "equipment": "AT7", + "id": 24308, + "schedule": [ + { + "day": 0, + "flight": "F7903", + "utc": "21:43:00" + }, + { + "day": 0, + "flight": "F7859", + "utc": "02:36:00" + }, + { + "day": 1, + "flight": "F7360", + "utc": "18:52:00" + }, + { + "day": 1, + "flight": "F7401", + "utc": "04:33:00" + }, + { + "day": 2, + "flight": "F7127", + "utc": "02:17:00" + }, + { + "day": 2, + "flight": "F7772", + "utc": "06:20:00" + }, + { + "day": 2, + "flight": "F7056", + "utc": "04:56:00" + }, + { + "day": 2, + "flight": "F7884", + "utc": "10:25:00" + }, + { + "day": 2, + "flight": "F7191", + "utc": "03:20:00" + }, + { + "day": 3, + "flight": "F7235", + "utc": "16:22:00" + }, + { + "day": 4, + "flight": "F7619", + "utc": "03:09:00" + }, + { + "day": 4, + "flight": "F7421", + "utc": "15:49:00" + }, + { + "day": 4, + "flight": "F7915", + "utc": "18:59:00" + }, + { + "day": 5, + "flight": "F7759", + "utc": "09:56:00" + }, + { + "day": 6, + "flight": "F7515", + "utc": "09:50:00" + }, + { + "day": 6, + "flight": "F7400", + "utc": "00:10:00" + }, + { + "day": 6, + "flight": "F7362", + "utc": "08:47:00" + }, + { + "day": 6, + "flight": "F7098", + "utc": "21:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "AGP", + "distance": 919.3439362090616, + "equipment": "320", + "id": 32956, + "schedule": [ + { + "day": 0, + "flight": "IB587", + "utc": "19:18:00" + }, + { + "day": 1, + "flight": "IB830", + "utc": "07:20:00" + }, + { + "day": 1, + "flight": "IB966", + "utc": "00:13:00" + }, + { + "day": 1, + "flight": "IB923", + "utc": "20:53:00" + }, + { + "day": 1, + "flight": "IB151", + "utc": "01:03:00" + }, + { + "day": 1, + "flight": "IB479", + "utc": "21:56:00" + }, + { + "day": 2, + "flight": "IB950", + "utc": "20:52:00" + }, + { + "day": 3, + "flight": "IB517", + "utc": "01:57:00" + }, + { + "day": 3, + "flight": "IB242", + "utc": "01:46:00" + }, + { + "day": 3, + "flight": "IB875", + "utc": "08:31:00" + }, + { + "day": 4, + "flight": "IB828", + "utc": "09:25:00" + }, + { + "day": 4, + "flight": "IB676", + "utc": "01:32:00" + }, + { + "day": 5, + "flight": "IB943", + "utc": "15:51:00" + }, + { + "day": 6, + "flight": "IB384", + "utc": "22:30:00" + }, + { + "day": 6, + "flight": "IB278", + "utc": "18:51:00" + }, + { + "day": 6, + "flight": "IB511", + "utc": "23:39:00" + }, + { + "day": 6, + "flight": "IB429", + "utc": "18:51:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "BCN", + "distance": 265.8469587104912, + "equipment": "320", + "id": 32957, + "schedule": [ + { + "day": 0, + "flight": "IB518", + "utc": "10:08:00" + }, + { + "day": 1, + "flight": "IB011", + "utc": "18:40:00" + }, + { + "day": 1, + "flight": "IB839", + "utc": "09:11:00" + }, + { + "day": 1, + "flight": "IB767", + "utc": "14:32:00" + }, + { + "day": 2, + "flight": "IB958", + "utc": "17:49:00" + }, + { + "day": 2, + "flight": "IB055", + "utc": "02:06:00" + }, + { + "day": 2, + "flight": "IB718", + "utc": "12:09:00" + }, + { + "day": 2, + "flight": "IB544", + "utc": "19:50:00" + }, + { + "day": 2, + "flight": "IB221", + "utc": "02:53:00" + }, + { + "day": 3, + "flight": "IB596", + "utc": "01:30:00" + }, + { + "day": 3, + "flight": "IB433", + "utc": "21:32:00" + }, + { + "day": 3, + "flight": "IB996", + "utc": "04:23:00" + }, + { + "day": 4, + "flight": "IB575", + "utc": "04:54:00" + }, + { + "day": 4, + "flight": "IB743", + "utc": "16:36:00" + }, + { + "day": 4, + "flight": "IB335", + "utc": "18:23:00" + }, + { + "day": 5, + "flight": "IB775", + "utc": "12:25:00" + }, + { + "day": 5, + "flight": "IB949", + "utc": "19:00:00" + }, + { + "day": 5, + "flight": "IB955", + "utc": "07:08:00" + }, + { + "day": 5, + "flight": "IB309", + "utc": "19:11:00" + }, + { + "day": 6, + "flight": "IB228", + "utc": "18:42:00" + }, + { + "day": 6, + "flight": "IB195", + "utc": "06:02:00" + }, + { + "day": 6, + "flight": "IB721", + "utc": "01:06:00" + }, + { + "day": 6, + "flight": "IB313", + "utc": "05:19:00" + }, + { + "day": 6, + "flight": "IB797", + "utc": "19:35:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "MAD", + "distance": 535.7735390346035, + "equipment": "CRK CR9 CR2", + "id": 32958, + "schedule": [ + { + "day": 0, + "flight": "IB321", + "utc": "19:44:00" + }, + { + "day": 0, + "flight": "IB262", + "utc": "04:50:00" + }, + { + "day": 0, + "flight": "IB266", + "utc": "03:12:00" + }, + { + "day": 1, + "flight": "IB365", + "utc": "00:15:00" + }, + { + "day": 1, + "flight": "IB159", + "utc": "07:14:00" + }, + { + "day": 1, + "flight": "IB507", + "utc": "07:30:00" + }, + { + "day": 1, + "flight": "IB760", + "utc": "21:03:00" + }, + { + "day": 2, + "flight": "IB072", + "utc": "05:28:00" + }, + { + "day": 2, + "flight": "IB707", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "IB101", + "utc": "17:49:00" + }, + { + "day": 3, + "flight": "IB949", + "utc": "06:14:00" + }, + { + "day": 3, + "flight": "IB780", + "utc": "13:13:00" + }, + { + "day": 3, + "flight": "IB675", + "utc": "01:43:00" + }, + { + "day": 3, + "flight": "IB942", + "utc": "11:46:00" + }, + { + "day": 3, + "flight": "IB669", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "IB290", + "utc": "01:53:00" + }, + { + "day": 4, + "flight": "IB587", + "utc": "04:52:00" + }, + { + "day": 4, + "flight": "IB553", + "utc": "23:37:00" + }, + { + "day": 4, + "flight": "IB623", + "utc": "03:23:00" + }, + { + "day": 5, + "flight": "IB667", + "utc": "20:42:00" + }, + { + "day": 6, + "flight": "IB763", + "utc": "11:56:00" + }, + { + "day": 6, + "flight": "IB004", + "utc": "12:38:00" + }, + { + "day": 6, + "flight": "IB606", + "utc": "11:07:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "PMI", + "distance": 467.1315518195575, + "equipment": "320", + "id": 32959, + "schedule": [ + { + "day": 0, + "flight": "IB718", + "utc": "00:29:00" + }, + { + "day": 1, + "flight": "IB529", + "utc": "21:51:00" + }, + { + "day": 1, + "flight": "IB262", + "utc": "18:34:00" + }, + { + "day": 1, + "flight": "IB202", + "utc": "05:59:00" + }, + { + "day": 1, + "flight": "IB428", + "utc": "00:21:00" + }, + { + "day": 1, + "flight": "IB433", + "utc": "13:14:00" + }, + { + "day": 2, + "flight": "IB873", + "utc": "03:44:00" + }, + { + "day": 2, + "flight": "IB588", + "utc": "06:43:00" + }, + { + "day": 2, + "flight": "IB848", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "IB656", + "utc": "08:28:00" + }, + { + "day": 3, + "flight": "IB865", + "utc": "03:25:00" + }, + { + "day": 4, + "flight": "IB322", + "utc": "06:53:00" + }, + { + "day": 5, + "flight": "IB208", + "utc": "16:30:00" + }, + { + "day": 5, + "flight": "IB316", + "utc": "23:39:00" + }, + { + "day": 6, + "flight": "IB038", + "utc": "14:32:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "IB", + "airlineid": "airline_2822", + "destinationairport": "SVQ", + "distance": 922.9469580316244, + "equipment": "CR2 CR9", + "id": 32960, + "schedule": [ + { + "day": 0, + "flight": "IB226", + "utc": "15:38:00" + }, + { + "day": 1, + "flight": "IB907", + "utc": "20:45:00" + }, + { + "day": 1, + "flight": "IB223", + "utc": "13:32:00" + }, + { + "day": 2, + "flight": "IB285", + "utc": "21:42:00" + }, + { + "day": 2, + "flight": "IB825", + "utc": "11:24:00" + }, + { + "day": 2, + "flight": "IB376", + "utc": "21:47:00" + }, + { + "day": 2, + "flight": "IB239", + "utc": "04:40:00" + }, + { + "day": 2, + "flight": "IB103", + "utc": "19:33:00" + }, + { + "day": 3, + "flight": "IB475", + "utc": "20:31:00" + }, + { + "day": 3, + "flight": "IB732", + "utc": "03:24:00" + }, + { + "day": 3, + "flight": "IB618", + "utc": "02:15:00" + }, + { + "day": 3, + "flight": "IB718", + "utc": "01:24:00" + }, + { + "day": 3, + "flight": "IB258", + "utc": "16:40:00" + }, + { + "day": 4, + "flight": "IB007", + "utc": "06:47:00" + }, + { + "day": 4, + "flight": "IB963", + "utc": "08:06:00" + }, + { + "day": 4, + "flight": "IB695", + "utc": "23:29:00" + }, + { + "day": 4, + "flight": "IB756", + "utc": "22:37:00" + }, + { + "day": 4, + "flight": "IB555", + "utc": "04:34:00" + }, + { + "day": 5, + "flight": "IB480", + "utc": "19:14:00" + }, + { + "day": 5, + "flight": "IB436", + "utc": "15:11:00" + }, + { + "day": 5, + "flight": "IB561", + "utc": "19:43:00" + }, + { + "day": 6, + "flight": "IB324", + "utc": "15:17:00" + }, + { + "day": 6, + "flight": "IB656", + "utc": "17:44:00" + }, + { + "day": 6, + "flight": "IB649", + "utc": "01:49:00" + }, + { + "day": 6, + "flight": "IB616", + "utc": "04:28:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "KL", + "airlineid": "airline_3090", + "destinationairport": "AMS", + "distance": 997.4702942027754, + "equipment": "EMJ", + "id": 36938, + "schedule": [ + { + "day": 0, + "flight": "KL119", + "utc": "23:23:00" + }, + { + "day": 0, + "flight": "KL028", + "utc": "16:25:00" + }, + { + "day": 0, + "flight": "KL388", + "utc": "21:51:00" + }, + { + "day": 1, + "flight": "KL644", + "utc": "14:15:00" + }, + { + "day": 1, + "flight": "KL816", + "utc": "02:49:00" + }, + { + "day": 2, + "flight": "KL713", + "utc": "21:18:00" + }, + { + "day": 2, + "flight": "KL045", + "utc": "03:30:00" + }, + { + "day": 2, + "flight": "KL755", + "utc": "04:12:00" + }, + { + "day": 2, + "flight": "KL554", + "utc": "21:21:00" + }, + { + "day": 2, + "flight": "KL684", + "utc": "17:06:00" + }, + { + "day": 3, + "flight": "KL045", + "utc": "13:12:00" + }, + { + "day": 3, + "flight": "KL002", + "utc": "01:39:00" + }, + { + "day": 4, + "flight": "KL398", + "utc": "07:13:00" + }, + { + "day": 4, + "flight": "KL169", + "utc": "12:16:00" + }, + { + "day": 5, + "flight": "KL548", + "utc": "06:29:00" + }, + { + "day": 5, + "flight": "KL168", + "utc": "13:10:00" + }, + { + "day": 5, + "flight": "KL417", + "utc": "16:25:00" + }, + { + "day": 5, + "flight": "KL656", + "utc": "07:19:00" + }, + { + "day": 5, + "flight": "KL570", + "utc": "04:28:00" + }, + { + "day": 6, + "flight": "KL710", + "utc": "18:57:00" + }, + { + "day": 6, + "flight": "KL453", + "utc": "14:01:00" + }, + { + "day": 6, + "flight": "KL139", + "utc": "09:26:00" + }, + { + "day": 6, + "flight": "KL055", + "utc": "17:53:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LH", + "airlineid": "airline_3320", + "destinationairport": "FRA", + "distance": 895.9770471097812, + "equipment": "321 319 735 733", + "id": 38788, + "schedule": [ + { + "day": 0, + "flight": "LH182", + "utc": "17:57:00" + }, + { + "day": 0, + "flight": "LH378", + "utc": "23:48:00" + }, + { + "day": 0, + "flight": "LH719", + "utc": "04:51:00" + }, + { + "day": 0, + "flight": "LH093", + "utc": "07:33:00" + }, + { + "day": 1, + "flight": "LH478", + "utc": "09:22:00" + }, + { + "day": 1, + "flight": "LH690", + "utc": "17:45:00" + }, + { + "day": 1, + "flight": "LH047", + "utc": "09:16:00" + }, + { + "day": 2, + "flight": "LH452", + "utc": "03:47:00" + }, + { + "day": 3, + "flight": "LH567", + "utc": "11:45:00" + }, + { + "day": 3, + "flight": "LH798", + "utc": "16:08:00" + }, + { + "day": 3, + "flight": "LH960", + "utc": "03:04:00" + }, + { + "day": 4, + "flight": "LH025", + "utc": "08:49:00" + }, + { + "day": 4, + "flight": "LH057", + "utc": "21:14:00" + }, + { + "day": 4, + "flight": "LH531", + "utc": "14:33:00" + }, + { + "day": 4, + "flight": "LH326", + "utc": "03:01:00" + }, + { + "day": 5, + "flight": "LH896", + "utc": "13:43:00" + }, + { + "day": 5, + "flight": "LH430", + "utc": "05:54:00" + }, + { + "day": 5, + "flight": "LH970", + "utc": "04:56:00" + }, + { + "day": 5, + "flight": "LH631", + "utc": "09:26:00" + }, + { + "day": 6, + "flight": "LH333", + "utc": "14:35:00" + }, + { + "day": 6, + "flight": "LH238", + "utc": "16:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LH", + "airlineid": "airline_3320", + "destinationairport": "MUC", + "distance": 960.1175459963162, + "equipment": "E95 319 CR9", + "id": 38789, + "schedule": [ + { + "day": 0, + "flight": "LH106", + "utc": "12:56:00" + }, + { + "day": 0, + "flight": "LH636", + "utc": "05:06:00" + }, + { + "day": 0, + "flight": "LH300", + "utc": "09:20:00" + }, + { + "day": 1, + "flight": "LH996", + "utc": "19:29:00" + }, + { + "day": 1, + "flight": "LH746", + "utc": "10:57:00" + }, + { + "day": 2, + "flight": "LH391", + "utc": "16:36:00" + }, + { + "day": 2, + "flight": "LH079", + "utc": "23:31:00" + }, + { + "day": 2, + "flight": "LH340", + "utc": "10:39:00" + }, + { + "day": 2, + "flight": "LH192", + "utc": "07:48:00" + }, + { + "day": 3, + "flight": "LH563", + "utc": "18:53:00" + }, + { + "day": 3, + "flight": "LH371", + "utc": "08:50:00" + }, + { + "day": 4, + "flight": "LH679", + "utc": "08:56:00" + }, + { + "day": 4, + "flight": "LH078", + "utc": "09:08:00" + }, + { + "day": 4, + "flight": "LH655", + "utc": "14:38:00" + }, + { + "day": 4, + "flight": "LH223", + "utc": "21:54:00" + }, + { + "day": 5, + "flight": "LH253", + "utc": "19:19:00" + }, + { + "day": 5, + "flight": "LH525", + "utc": "15:57:00" + }, + { + "day": 5, + "flight": "LH597", + "utc": "17:13:00" + }, + { + "day": 5, + "flight": "LH315", + "utc": "11:20:00" + }, + { + "day": 6, + "flight": "LH220", + "utc": "03:43:00" + }, + { + "day": 6, + "flight": "LH436", + "utc": "07:44:00" + }, + { + "day": 6, + "flight": "LH405", + "utc": "02:54:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "LS", + "airlineid": "airline_3026", + "destinationairport": "MAN", + "distance": 1113.7047637485857, + "equipment": "733", + "id": 39505, + "schedule": [ + { + "day": 0, + "flight": "LS423", + "utc": "10:40:00" + }, + { + "day": 0, + "flight": "LS623", + "utc": "17:06:00" + }, + { + "day": 0, + "flight": "LS249", + "utc": "04:44:00" + }, + { + "day": 1, + "flight": "LS652", + "utc": "21:17:00" + }, + { + "day": 1, + "flight": "LS967", + "utc": "07:51:00" + }, + { + "day": 1, + "flight": "LS903", + "utc": "00:46:00" + }, + { + "day": 1, + "flight": "LS677", + "utc": "05:11:00" + }, + { + "day": 1, + "flight": "LS052", + "utc": "12:41:00" + }, + { + "day": 2, + "flight": "LS007", + "utc": "21:49:00" + }, + { + "day": 2, + "flight": "LS939", + "utc": "23:49:00" + }, + { + "day": 2, + "flight": "LS302", + "utc": "07:34:00" + }, + { + "day": 3, + "flight": "LS621", + "utc": "05:51:00" + }, + { + "day": 4, + "flight": "LS175", + "utc": "02:50:00" + }, + { + "day": 4, + "flight": "LS573", + "utc": "03:49:00" + }, + { + "day": 4, + "flight": "LS528", + "utc": "04:27:00" + }, + { + "day": 4, + "flight": "LS210", + "utc": "19:08:00" + }, + { + "day": 5, + "flight": "LS706", + "utc": "05:35:00" + }, + { + "day": 5, + "flight": "LS663", + "utc": "23:00:00" + }, + { + "day": 5, + "flight": "LS217", + "utc": "04:32:00" + }, + { + "day": 5, + "flight": "LS585", + "utc": "02:15:00" + }, + { + "day": 5, + "flight": "LS163", + "utc": "05:21:00" + }, + { + "day": 6, + "flight": "LS299", + "utc": "05:12:00" + }, + { + "day": 6, + "flight": "LS259", + "utc": "20:44:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "LIL", + "distance": 781.8286754466159, + "equipment": "E70", + "id": 4627, + "schedule": [ + { + "day": 0, + "flight": "A5460", + "utc": "17:28:00" + }, + { + "day": 0, + "flight": "A5895", + "utc": "22:47:00" + }, + { + "day": 0, + "flight": "A5181", + "utc": "18:35:00" + }, + { + "day": 0, + "flight": "A5682", + "utc": "09:47:00" + }, + { + "day": 1, + "flight": "A5875", + "utc": "02:04:00" + }, + { + "day": 1, + "flight": "A5659", + "utc": "20:46:00" + }, + { + "day": 1, + "flight": "A5468", + "utc": "15:49:00" + }, + { + "day": 2, + "flight": "A5922", + "utc": "19:01:00" + }, + { + "day": 2, + "flight": "A5805", + "utc": "00:36:00" + }, + { + "day": 2, + "flight": "A5845", + "utc": "06:28:00" + }, + { + "day": 2, + "flight": "A5150", + "utc": "06:07:00" + }, + { + "day": 2, + "flight": "A5724", + "utc": "03:42:00" + }, + { + "day": 3, + "flight": "A5678", + "utc": "04:33:00" + }, + { + "day": 3, + "flight": "A5535", + "utc": "00:11:00" + }, + { + "day": 3, + "flight": "A5085", + "utc": "14:15:00" + }, + { + "day": 4, + "flight": "A5977", + "utc": "16:46:00" + }, + { + "day": 4, + "flight": "A5994", + "utc": "11:15:00" + }, + { + "day": 4, + "flight": "A5404", + "utc": "21:01:00" + }, + { + "day": 5, + "flight": "A5450", + "utc": "06:41:00" + }, + { + "day": 5, + "flight": "A5761", + "utc": "22:09:00" + }, + { + "day": 5, + "flight": "A5598", + "utc": "00:47:00" + }, + { + "day": 5, + "flight": "A5994", + "utc": "14:58:00" + }, + { + "day": 6, + "flight": "A5828", + "utc": "18:06:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "MRS", + "distance": 311.0670134047465, + "equipment": "AT5", + "id": 4628, + "schedule": [ + { + "day": 0, + "flight": "A5338", + "utc": "05:02:00" + }, + { + "day": 0, + "flight": "A5882", + "utc": "12:46:00" + }, + { + "day": 0, + "flight": "A5406", + "utc": "10:08:00" + }, + { + "day": 0, + "flight": "A5631", + "utc": "18:02:00" + }, + { + "day": 0, + "flight": "A5670", + "utc": "03:24:00" + }, + { + "day": 1, + "flight": "A5689", + "utc": "16:59:00" + }, + { + "day": 2, + "flight": "A5073", + "utc": "13:10:00" + }, + { + "day": 2, + "flight": "A5790", + "utc": "07:41:00" + }, + { + "day": 3, + "flight": "A5862", + "utc": "22:10:00" + }, + { + "day": 3, + "flight": "A5650", + "utc": "07:40:00" + }, + { + "day": 3, + "flight": "A5874", + "utc": "20:54:00" + }, + { + "day": 3, + "flight": "A5502", + "utc": "17:52:00" + }, + { + "day": 3, + "flight": "A5294", + "utc": "19:33:00" + }, + { + "day": 4, + "flight": "A5376", + "utc": "09:42:00" + }, + { + "day": 4, + "flight": "A5302", + "utc": "21:26:00" + }, + { + "day": 4, + "flight": "A5348", + "utc": "10:57:00" + }, + { + "day": 4, + "flight": "A5003", + "utc": "08:01:00" + }, + { + "day": 4, + "flight": "A5018", + "utc": "20:03:00" + }, + { + "day": 5, + "flight": "A5983", + "utc": "03:02:00" + }, + { + "day": 5, + "flight": "A5026", + "utc": "08:27:00" + }, + { + "day": 5, + "flight": "A5481", + "utc": "15:09:00" + }, + { + "day": 5, + "flight": "A5479", + "utc": "22:40:00" + }, + { + "day": 5, + "flight": "A5264", + "utc": "16:22:00" + }, + { + "day": 6, + "flight": "A5308", + "utc": "23:02:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "NCE", + "distance": 470.8031011808527, + "equipment": "AT7", + "id": 4629, + "schedule": [ + { + "day": 0, + "flight": "A5283", + "utc": "02:13:00" + }, + { + "day": 0, + "flight": "A5869", + "utc": "12:53:00" + }, + { + "day": 1, + "flight": "A5559", + "utc": "15:22:00" + }, + { + "day": 1, + "flight": "A5213", + "utc": "13:43:00" + }, + { + "day": 1, + "flight": "A5935", + "utc": "19:54:00" + }, + { + "day": 1, + "flight": "A5622", + "utc": "16:18:00" + }, + { + "day": 2, + "flight": "A5016", + "utc": "17:15:00" + }, + { + "day": 2, + "flight": "A5523", + "utc": "21:14:00" + }, + { + "day": 2, + "flight": "A5896", + "utc": "08:11:00" + }, + { + "day": 3, + "flight": "A5287", + "utc": "00:53:00" + }, + { + "day": 3, + "flight": "A5772", + "utc": "09:58:00" + }, + { + "day": 4, + "flight": "A5470", + "utc": "06:37:00" + }, + { + "day": 4, + "flight": "A5047", + "utc": "03:32:00" + }, + { + "day": 4, + "flight": "A5006", + "utc": "07:08:00" + }, + { + "day": 4, + "flight": "A5631", + "utc": "09:29:00" + }, + { + "day": 4, + "flight": "A5434", + "utc": "02:39:00" + }, + { + "day": 5, + "flight": "A5437", + "utc": "08:39:00" + }, + { + "day": 5, + "flight": "A5606", + "utc": "22:00:00" + }, + { + "day": 5, + "flight": "A5895", + "utc": "20:21:00" + }, + { + "day": 5, + "flight": "A5504", + "utc": "20:04:00" + }, + { + "day": 6, + "flight": "A5579", + "utc": "02:55:00" + }, + { + "day": 6, + "flight": "A5099", + "utc": "22:02:00" + }, + { + "day": 6, + "flight": "A5703", + "utc": "02:31:00" + }, + { + "day": 6, + "flight": "A5253", + "utc": "14:34:00" + }, + { + "day": 6, + "flight": "A5615", + "utc": "11:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "NTE", + "distance": 455.4490681425203, + "equipment": "CR7", + "id": 4630, + "schedule": [ + { + "day": 0, + "flight": "A5134", + "utc": "20:08:00" + }, + { + "day": 0, + "flight": "A5131", + "utc": "02:01:00" + }, + { + "day": 0, + "flight": "A5431", + "utc": "17:28:00" + }, + { + "day": 0, + "flight": "A5382", + "utc": "12:25:00" + }, + { + "day": 1, + "flight": "A5065", + "utc": "16:44:00" + }, + { + "day": 1, + "flight": "A5091", + "utc": "03:41:00" + }, + { + "day": 1, + "flight": "A5242", + "utc": "04:14:00" + }, + { + "day": 1, + "flight": "A5781", + "utc": "12:57:00" + }, + { + "day": 2, + "flight": "A5552", + "utc": "15:45:00" + }, + { + "day": 2, + "flight": "A5610", + "utc": "17:04:00" + }, + { + "day": 2, + "flight": "A5252", + "utc": "03:20:00" + }, + { + "day": 2, + "flight": "A5112", + "utc": "02:20:00" + }, + { + "day": 2, + "flight": "A5684", + "utc": "06:52:00" + }, + { + "day": 3, + "flight": "A5601", + "utc": "02:23:00" + }, + { + "day": 3, + "flight": "A5066", + "utc": "19:34:00" + }, + { + "day": 3, + "flight": "A5226", + "utc": "09:59:00" + }, + { + "day": 3, + "flight": "A5216", + "utc": "13:05:00" + }, + { + "day": 4, + "flight": "A5793", + "utc": "03:37:00" + }, + { + "day": 4, + "flight": "A5506", + "utc": "00:37:00" + }, + { + "day": 4, + "flight": "A5053", + "utc": "03:43:00" + }, + { + "day": 4, + "flight": "A5006", + "utc": "08:21:00" + }, + { + "day": 5, + "flight": "A5463", + "utc": "10:00:00" + }, + { + "day": 5, + "flight": "A5609", + "utc": "05:23:00" + }, + { + "day": 6, + "flight": "A5040", + "utc": "20:12:00" + }, + { + "day": 6, + "flight": "A5449", + "utc": "02:33:00" + }, + { + "day": 6, + "flight": "A5870", + "utc": "17:40:00" + }, + { + "day": 6, + "flight": "A5577", + "utc": "09:57:00" + }, + { + "day": 6, + "flight": "A5516", + "utc": "03:49:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "A5", + "airlineid": "airline_1203", + "destinationairport": "RNS", + "distance": 548.8740198503464, + "equipment": "CRJ CR7", + "id": 4631, + "schedule": [ + { + "day": 0, + "flight": "A5172", + "utc": "16:26:00" + }, + { + "day": 0, + "flight": "A5610", + "utc": "01:09:00" + }, + { + "day": 0, + "flight": "A5338", + "utc": "05:14:00" + }, + { + "day": 1, + "flight": "A5456", + "utc": "17:30:00" + }, + { + "day": 2, + "flight": "A5316", + "utc": "14:50:00" + }, + { + "day": 2, + "flight": "A5137", + "utc": "19:39:00" + }, + { + "day": 2, + "flight": "A5478", + "utc": "02:26:00" + }, + { + "day": 3, + "flight": "A5007", + "utc": "21:23:00" + }, + { + "day": 3, + "flight": "A5614", + "utc": "00:19:00" + }, + { + "day": 3, + "flight": "A5025", + "utc": "07:24:00" + }, + { + "day": 4, + "flight": "A5295", + "utc": "22:57:00" + }, + { + "day": 4, + "flight": "A5250", + "utc": "09:02:00" + }, + { + "day": 5, + "flight": "A5548", + "utc": "11:17:00" + }, + { + "day": 5, + "flight": "A5666", + "utc": "21:29:00" + }, + { + "day": 5, + "flight": "A5572", + "utc": "22:04:00" + }, + { + "day": 6, + "flight": "A5953", + "utc": "06:52:00" + }, + { + "day": 6, + "flight": "A5438", + "utc": "01:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "SE", + "airlineid": "airline_5479", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "332", + "id": 49359, + "schedule": [ + { + "day": 0, + "flight": "SE239", + "utc": "02:38:00" + }, + { + "day": 1, + "flight": "SE278", + "utc": "13:05:00" + }, + { + "day": 2, + "flight": "SE859", + "utc": "03:00:00" + }, + { + "day": 3, + "flight": "SE316", + "utc": "06:46:00" + }, + { + "day": 3, + "flight": "SE570", + "utc": "22:46:00" + }, + { + "day": 3, + "flight": "SE236", + "utc": "06:03:00" + }, + { + "day": 3, + "flight": "SE140", + "utc": "07:28:00" + }, + { + "day": 4, + "flight": "SE907", + "utc": "22:00:00" + }, + { + "day": 4, + "flight": "SE943", + "utc": "04:02:00" + }, + { + "day": 4, + "flight": "SE337", + "utc": "16:25:00" + }, + { + "day": 4, + "flight": "SE342", + "utc": "21:03:00" + }, + { + "day": 5, + "flight": "SE200", + "utc": "02:43:00" + }, + { + "day": 5, + "flight": "SE777", + "utc": "04:12:00" + }, + { + "day": 6, + "flight": "SE566", + "utc": "13:38:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "SN", + "airlineid": "airline_1531", + "destinationairport": "BRU", + "distance": 842.027454616631, + "equipment": "AR1", + "id": 50376, + "schedule": [ + { + "day": 0, + "flight": "SN526", + "utc": "17:16:00" + }, + { + "day": 0, + "flight": "SN650", + "utc": "05:15:00" + }, + { + "day": 1, + "flight": "SN990", + "utc": "22:21:00" + }, + { + "day": 2, + "flight": "SN199", + "utc": "12:46:00" + }, + { + "day": 2, + "flight": "SN329", + "utc": "14:46:00" + }, + { + "day": 3, + "flight": "SN504", + "utc": "19:57:00" + }, + { + "day": 3, + "flight": "SN802", + "utc": "13:25:00" + }, + { + "day": 3, + "flight": "SN769", + "utc": "10:36:00" + }, + { + "day": 3, + "flight": "SN806", + "utc": "06:33:00" + }, + { + "day": 4, + "flight": "SN332", + "utc": "07:50:00" + }, + { + "day": 4, + "flight": "SN147", + "utc": "05:19:00" + }, + { + "day": 4, + "flight": "SN036", + "utc": "19:01:00" + }, + { + "day": 4, + "flight": "SN184", + "utc": "19:45:00" + }, + { + "day": 4, + "flight": "SN395", + "utc": "00:58:00" + }, + { + "day": 5, + "flight": "SN532", + "utc": "15:37:00" + }, + { + "day": 6, + "flight": "SN973", + "utc": "16:37:00" + }, + { + "day": 6, + "flight": "SN605", + "utc": "05:06:00" + }, + { + "day": 6, + "flight": "SN450", + "utc": "20:54:00" + }, + { + "day": 6, + "flight": "SN822", + "utc": "23:11:00" + }, + { + "day": 6, + "flight": "SN149", + "utc": "01:59:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "BRS", + "distance": 914.710726420036, + "equipment": "ER4", + "id": 50746, + "schedule": [ + { + "day": 0, + "flight": "ST010", + "utc": "01:55:00" + }, + { + "day": 0, + "flight": "ST465", + "utc": "22:46:00" + }, + { + "day": 0, + "flight": "ST492", + "utc": "14:29:00" + }, + { + "day": 1, + "flight": "ST648", + "utc": "04:09:00" + }, + { + "day": 2, + "flight": "ST986", + "utc": "18:13:00" + }, + { + "day": 2, + "flight": "ST818", + "utc": "00:36:00" + }, + { + "day": 2, + "flight": "ST484", + "utc": "12:12:00" + }, + { + "day": 2, + "flight": "ST401", + "utc": "05:03:00" + }, + { + "day": 2, + "flight": "ST075", + "utc": "01:11:00" + }, + { + "day": 3, + "flight": "ST467", + "utc": "13:35:00" + }, + { + "day": 3, + "flight": "ST556", + "utc": "07:23:00" + }, + { + "day": 3, + "flight": "ST035", + "utc": "17:14:00" + }, + { + "day": 3, + "flight": "ST786", + "utc": "06:31:00" + }, + { + "day": 3, + "flight": "ST544", + "utc": "02:47:00" + }, + { + "day": 4, + "flight": "ST689", + "utc": "10:42:00" + }, + { + "day": 4, + "flight": "ST643", + "utc": "01:58:00" + }, + { + "day": 4, + "flight": "ST022", + "utc": "03:46:00" + }, + { + "day": 4, + "flight": "ST805", + "utc": "00:34:00" + }, + { + "day": 5, + "flight": "ST581", + "utc": "21:11:00" + }, + { + "day": 6, + "flight": "ST175", + "utc": "23:56:00" + }, + { + "day": 6, + "flight": "ST166", + "utc": "09:23:00" + }, + { + "day": 6, + "flight": "ST101", + "utc": "14:57:00" + }, + { + "day": 6, + "flight": "ST983", + "utc": "08:31:00" + }, + { + "day": 6, + "flight": "ST822", + "utc": "17:34:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "CEG", + "distance": 1108.5852832314715, + "equipment": "ER4", + "id": 50747, + "schedule": [ + { + "day": 0, + "flight": "ST127", + "utc": "21:02:00" + }, + { + "day": 0, + "flight": "ST839", + "utc": "22:35:00" + }, + { + "day": 0, + "flight": "ST267", + "utc": "14:02:00" + }, + { + "day": 0, + "flight": "ST016", + "utc": "10:17:00" + }, + { + "day": 1, + "flight": "ST623", + "utc": "07:52:00" + }, + { + "day": 1, + "flight": "ST105", + "utc": "00:34:00" + }, + { + "day": 1, + "flight": "ST459", + "utc": "02:07:00" + }, + { + "day": 1, + "flight": "ST170", + "utc": "18:29:00" + }, + { + "day": 1, + "flight": "ST830", + "utc": "21:49:00" + }, + { + "day": 2, + "flight": "ST884", + "utc": "21:53:00" + }, + { + "day": 3, + "flight": "ST924", + "utc": "04:55:00" + }, + { + "day": 3, + "flight": "ST261", + "utc": "01:16:00" + }, + { + "day": 3, + "flight": "ST016", + "utc": "04:50:00" + }, + { + "day": 3, + "flight": "ST260", + "utc": "04:46:00" + }, + { + "day": 4, + "flight": "ST863", + "utc": "10:59:00" + }, + { + "day": 4, + "flight": "ST200", + "utc": "03:30:00" + }, + { + "day": 4, + "flight": "ST152", + "utc": "07:31:00" + }, + { + "day": 5, + "flight": "ST738", + "utc": "05:45:00" + }, + { + "day": 5, + "flight": "ST453", + "utc": "00:23:00" + }, + { + "day": 5, + "flight": "ST503", + "utc": "02:00:00" + }, + { + "day": 6, + "flight": "ST286", + "utc": "16:11:00" + }, + { + "day": 6, + "flight": "ST878", + "utc": "19:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "ST", + "airlineid": "airline_2547", + "destinationairport": "XFW", + "distance": 1263.676446061964, + "equipment": "319", + "id": 50748, + "schedule": [ + { + "day": 0, + "flight": "ST732", + "utc": "23:31:00" + }, + { + "day": 1, + "flight": "ST711", + "utc": "12:54:00" + }, + { + "day": 1, + "flight": "ST553", + "utc": "08:51:00" + }, + { + "day": 2, + "flight": "ST603", + "utc": "02:06:00" + }, + { + "day": 3, + "flight": "ST345", + "utc": "05:04:00" + }, + { + "day": 3, + "flight": "ST401", + "utc": "20:24:00" + }, + { + "day": 4, + "flight": "ST317", + "utc": "00:48:00" + }, + { + "day": 4, + "flight": "ST133", + "utc": "14:45:00" + }, + { + "day": 4, + "flight": "ST217", + "utc": "08:52:00" + }, + { + "day": 4, + "flight": "ST471", + "utc": "01:06:00" + }, + { + "day": 4, + "flight": "ST213", + "utc": "06:59:00" + }, + { + "day": 5, + "flight": "ST277", + "utc": "00:10:00" + }, + { + "day": 5, + "flight": "ST056", + "utc": "10:50:00" + }, + { + "day": 5, + "flight": "ST553", + "utc": "07:18:00" + }, + { + "day": 5, + "flight": "ST673", + "utc": "06:34:00" + }, + { + "day": 5, + "flight": "ST729", + "utc": "20:03:00" + }, + { + "day": 6, + "flight": "ST737", + "utc": "20:09:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T3", + "airlineid": "airline_2117", + "destinationairport": "DIJ", + "distance": 498.1611053856414, + "equipment": "J41", + "id": 51783, + "schedule": [ + { + "day": 0, + "flight": "T3325", + "utc": "05:11:00" + }, + { + "day": 0, + "flight": "T3160", + "utc": "07:27:00" + }, + { + "day": 1, + "flight": "T3803", + "utc": "11:18:00" + }, + { + "day": 1, + "flight": "T3946", + "utc": "16:35:00" + }, + { + "day": 2, + "flight": "T3548", + "utc": "07:03:00" + }, + { + "day": 2, + "flight": "T3516", + "utc": "05:09:00" + }, + { + "day": 2, + "flight": "T3849", + "utc": "01:43:00" + }, + { + "day": 2, + "flight": "T3096", + "utc": "05:54:00" + }, + { + "day": 2, + "flight": "T3020", + "utc": "23:04:00" + }, + { + "day": 3, + "flight": "T3523", + "utc": "02:22:00" + }, + { + "day": 3, + "flight": "T3724", + "utc": "17:07:00" + }, + { + "day": 4, + "flight": "T3751", + "utc": "05:04:00" + }, + { + "day": 4, + "flight": "T3360", + "utc": "19:01:00" + }, + { + "day": 4, + "flight": "T3945", + "utc": "05:38:00" + }, + { + "day": 4, + "flight": "T3861", + "utc": "17:35:00" + }, + { + "day": 4, + "flight": "T3362", + "utc": "18:29:00" + }, + { + "day": 5, + "flight": "T3884", + "utc": "16:36:00" + }, + { + "day": 6, + "flight": "T3032", + "utc": "22:22:00" + }, + { + "day": 6, + "flight": "T3719", + "utc": "11:59:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T7", + "airlineid": "airline_4965", + "destinationairport": "ETZ", + "distance": 703.3976464387359, + "equipment": "BEH", + "id": 51823, + "schedule": [ + { + "day": 0, + "flight": "T7417", + "utc": "04:52:00" + }, + { + "day": 1, + "flight": "T7281", + "utc": "14:33:00" + }, + { + "day": 2, + "flight": "T7500", + "utc": "02:16:00" + }, + { + "day": 3, + "flight": "T7552", + "utc": "23:16:00" + }, + { + "day": 4, + "flight": "T7538", + "utc": "16:00:00" + }, + { + "day": 4, + "flight": "T7925", + "utc": "20:07:00" + }, + { + "day": 4, + "flight": "T7339", + "utc": "21:34:00" + }, + { + "day": 4, + "flight": "T7667", + "utc": "02:53:00" + }, + { + "day": 4, + "flight": "T7282", + "utc": "09:14:00" + }, + { + "day": 5, + "flight": "T7073", + "utc": "23:57:00" + }, + { + "day": 5, + "flight": "T7243", + "utc": "16:41:00" + }, + { + "day": 5, + "flight": "T7665", + "utc": "09:52:00" + }, + { + "day": 6, + "flight": "T7246", + "utc": "17:16:00" + }, + { + "day": 6, + "flight": "T7106", + "utc": "04:20:00" + }, + { + "day": 6, + "flight": "T7978", + "utc": "03:41:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "T7", + "airlineid": "airline_4965", + "destinationairport": "MXP", + "distance": 623.5176024539427, + "equipment": "BEH", + "id": 51824, + "schedule": [ + { + "day": 0, + "flight": "T7538", + "utc": "03:44:00" + }, + { + "day": 0, + "flight": "T7420", + "utc": "11:59:00" + }, + { + "day": 1, + "flight": "T7941", + "utc": "21:37:00" + }, + { + "day": 1, + "flight": "T7079", + "utc": "21:14:00" + }, + { + "day": 1, + "flight": "T7359", + "utc": "04:57:00" + }, + { + "day": 1, + "flight": "T7298", + "utc": "06:52:00" + }, + { + "day": 2, + "flight": "T7045", + "utc": "19:21:00" + }, + { + "day": 2, + "flight": "T7446", + "utc": "12:35:00" + }, + { + "day": 2, + "flight": "T7316", + "utc": "21:56:00" + }, + { + "day": 2, + "flight": "T7357", + "utc": "01:13:00" + }, + { + "day": 3, + "flight": "T7759", + "utc": "22:58:00" + }, + { + "day": 3, + "flight": "T7030", + "utc": "14:17:00" + }, + { + "day": 3, + "flight": "T7422", + "utc": "16:16:00" + }, + { + "day": 4, + "flight": "T7772", + "utc": "03:34:00" + }, + { + "day": 4, + "flight": "T7581", + "utc": "06:16:00" + }, + { + "day": 4, + "flight": "T7321", + "utc": "02:39:00" + }, + { + "day": 4, + "flight": "T7634", + "utc": "19:07:00" + }, + { + "day": 5, + "flight": "T7988", + "utc": "16:22:00" + }, + { + "day": 5, + "flight": "T7714", + "utc": "03:48:00" + }, + { + "day": 6, + "flight": "T7317", + "utc": "14:36:00" + }, + { + "day": 6, + "flight": "T7616", + "utc": "08:05:00" + }, + { + "day": 6, + "flight": "T7528", + "utc": "19:38:00" + }, + { + "day": 6, + "flight": "T7837", + "utc": "19:16:00" + }, + { + "day": 6, + "flight": "T7113", + "utc": "18:40:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TK", + "airlineid": "airline_4951", + "destinationairport": "IST", + "distance": 2266.207133048303, + "equipment": "320 321", + "id": 52846, + "schedule": [ + { + "day": 0, + "flight": "TK981", + "utc": "05:00:00" + }, + { + "day": 0, + "flight": "TK948", + "utc": "06:35:00" + }, + { + "day": 0, + "flight": "TK175", + "utc": "18:26:00" + }, + { + "day": 0, + "flight": "TK266", + "utc": "23:13:00" + }, + { + "day": 1, + "flight": "TK518", + "utc": "23:14:00" + }, + { + "day": 1, + "flight": "TK527", + "utc": "15:43:00" + }, + { + "day": 2, + "flight": "TK409", + "utc": "00:18:00" + }, + { + "day": 3, + "flight": "TK211", + "utc": "05:35:00" + }, + { + "day": 4, + "flight": "TK068", + "utc": "02:47:00" + }, + { + "day": 5, + "flight": "TK348", + "utc": "14:15:00" + }, + { + "day": 6, + "flight": "TK439", + "utc": "03:54:00" + }, + { + "day": 6, + "flight": "TK927", + "utc": "11:17:00" + }, + { + "day": 6, + "flight": "TK779", + "utc": "20:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TP", + "airlineid": "airline_4869", + "destinationairport": "LIS", + "distance": 1029.4070254527778, + "equipment": "100 ER4", + "id": 53824, + "schedule": [ + { + "day": 0, + "flight": "TP104", + "utc": "22:19:00" + }, + { + "day": 1, + "flight": "TP439", + "utc": "20:47:00" + }, + { + "day": 1, + "flight": "TP157", + "utc": "11:59:00" + }, + { + "day": 1, + "flight": "TP990", + "utc": "22:45:00" + }, + { + "day": 1, + "flight": "TP931", + "utc": "16:42:00" + }, + { + "day": 1, + "flight": "TP064", + "utc": "01:01:00" + }, + { + "day": 2, + "flight": "TP512", + "utc": "12:47:00" + }, + { + "day": 3, + "flight": "TP779", + "utc": "06:59:00" + }, + { + "day": 3, + "flight": "TP439", + "utc": "01:48:00" + }, + { + "day": 3, + "flight": "TP368", + "utc": "06:34:00" + }, + { + "day": 3, + "flight": "TP374", + "utc": "05:51:00" + }, + { + "day": 3, + "flight": "TP960", + "utc": "12:04:00" + }, + { + "day": 4, + "flight": "TP587", + "utc": "05:51:00" + }, + { + "day": 4, + "flight": "TP963", + "utc": "05:26:00" + }, + { + "day": 4, + "flight": "TP701", + "utc": "14:33:00" + }, + { + "day": 4, + "flight": "TP505", + "utc": "02:35:00" + }, + { + "day": 5, + "flight": "TP466", + "utc": "16:41:00" + }, + { + "day": 5, + "flight": "TP691", + "utc": "07:18:00" + }, + { + "day": 5, + "flight": "TP147", + "utc": "11:43:00" + }, + { + "day": 6, + "flight": "TP192", + "utc": "21:25:00" + }, + { + "day": 6, + "flight": "TP555", + "utc": "14:32:00" + }, + { + "day": 6, + "flight": "TP159", + "utc": "01:18:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TS", + "airlineid": "airline_1317", + "destinationairport": "YUL", + "distance": 5727.754070420711, + "equipment": "310", + "id": 53980, + "schedule": [ + { + "day": 0, + "flight": "TS022", + "utc": "17:05:00" + }, + { + "day": 0, + "flight": "TS378", + "utc": "07:58:00" + }, + { + "day": 0, + "flight": "TS288", + "utc": "18:01:00" + }, + { + "day": 0, + "flight": "TS447", + "utc": "14:50:00" + }, + { + "day": 1, + "flight": "TS820", + "utc": "02:32:00" + }, + { + "day": 1, + "flight": "TS349", + "utc": "07:31:00" + }, + { + "day": 1, + "flight": "TS522", + "utc": "02:22:00" + }, + { + "day": 1, + "flight": "TS271", + "utc": "21:31:00" + }, + { + "day": 2, + "flight": "TS018", + "utc": "09:50:00" + }, + { + "day": 2, + "flight": "TS375", + "utc": "17:20:00" + }, + { + "day": 2, + "flight": "TS841", + "utc": "10:09:00" + }, + { + "day": 2, + "flight": "TS710", + "utc": "02:23:00" + }, + { + "day": 2, + "flight": "TS541", + "utc": "21:38:00" + }, + { + "day": 3, + "flight": "TS458", + "utc": "08:17:00" + }, + { + "day": 3, + "flight": "TS682", + "utc": "15:57:00" + }, + { + "day": 3, + "flight": "TS988", + "utc": "16:06:00" + }, + { + "day": 3, + "flight": "TS508", + "utc": "20:13:00" + }, + { + "day": 3, + "flight": "TS461", + "utc": "20:23:00" + }, + { + "day": 4, + "flight": "TS703", + "utc": "22:23:00" + }, + { + "day": 4, + "flight": "TS693", + "utc": "17:31:00" + }, + { + "day": 4, + "flight": "TS167", + "utc": "00:21:00" + }, + { + "day": 4, + "flight": "TS123", + "utc": "20:23:00" + }, + { + "day": 5, + "flight": "TS465", + "utc": "03:23:00" + }, + { + "day": 5, + "flight": "TS675", + "utc": "04:50:00" + }, + { + "day": 6, + "flight": "TS529", + "utc": "00:48:00" + }, + { + "day": 6, + "flight": "TS394", + "utc": "17:07:00" + }, + { + "day": 6, + "flight": "TS003", + "utc": "20:48:00" + }, + { + "day": 6, + "flight": "TS961", + "utc": "13:05:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "TU", + "airlineid": "airline_4870", + "destinationairport": "TUN", + "distance": 1063.7112627835468, + "equipment": "736", + "id": 54192, + "schedule": [ + { + "day": 0, + "flight": "TU408", + "utc": "03:17:00" + }, + { + "day": 1, + "flight": "TU112", + "utc": "22:41:00" + }, + { + "day": 2, + "flight": "TU006", + "utc": "12:25:00" + }, + { + "day": 2, + "flight": "TU923", + "utc": "21:40:00" + }, + { + "day": 2, + "flight": "TU869", + "utc": "14:04:00" + }, + { + "day": 3, + "flight": "TU072", + "utc": "14:32:00" + }, + { + "day": 3, + "flight": "TU362", + "utc": "20:43:00" + }, + { + "day": 4, + "flight": "TU876", + "utc": "11:57:00" + }, + { + "day": 4, + "flight": "TU486", + "utc": "15:28:00" + }, + { + "day": 4, + "flight": "TU161", + "utc": "08:26:00" + }, + { + "day": 4, + "flight": "TU312", + "utc": "06:41:00" + }, + { + "day": 4, + "flight": "TU887", + "utc": "06:35:00" + }, + { + "day": 5, + "flight": "TU507", + "utc": "20:03:00" + }, + { + "day": 5, + "flight": "TU893", + "utc": "01:33:00" + }, + { + "day": 6, + "flight": "TU871", + "utc": "12:34:00" + }, + { + "day": 6, + "flight": "TU610", + "utc": "04:01:00" + }, + { + "day": 6, + "flight": "TU896", + "utc": "17:25:00" + }, + { + "day": 6, + "flight": "TU158", + "utc": "15:20:00" + }, + { + "day": 6, + "flight": "TU008", + "utc": "00:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BIA", + "distance": 669.8441063067557, + "equipment": "319", + "id": 55468, + "schedule": [ + { + "day": 0, + "flight": "U2494", + "utc": "14:35:00" + }, + { + "day": 0, + "flight": "U2177", + "utc": "19:05:00" + }, + { + "day": 1, + "flight": "U2900", + "utc": "03:08:00" + }, + { + "day": 1, + "flight": "U2439", + "utc": "02:58:00" + }, + { + "day": 1, + "flight": "U2722", + "utc": "00:10:00" + }, + { + "day": 1, + "flight": "U2651", + "utc": "06:08:00" + }, + { + "day": 1, + "flight": "U2905", + "utc": "17:10:00" + }, + { + "day": 2, + "flight": "U2882", + "utc": "12:51:00" + }, + { + "day": 2, + "flight": "U2455", + "utc": "20:21:00" + }, + { + "day": 2, + "flight": "U2814", + "utc": "22:11:00" + }, + { + "day": 3, + "flight": "U2437", + "utc": "04:39:00" + }, + { + "day": 3, + "flight": "U2356", + "utc": "14:44:00" + }, + { + "day": 3, + "flight": "U2823", + "utc": "17:08:00" + }, + { + "day": 3, + "flight": "U2605", + "utc": "09:37:00" + }, + { + "day": 3, + "flight": "U2285", + "utc": "20:14:00" + }, + { + "day": 4, + "flight": "U2088", + "utc": "13:05:00" + }, + { + "day": 4, + "flight": "U2248", + "utc": "07:03:00" + }, + { + "day": 4, + "flight": "U2031", + "utc": "08:47:00" + }, + { + "day": 5, + "flight": "U2779", + "utc": "17:34:00" + }, + { + "day": 6, + "flight": "U2622", + "utc": "14:27:00" + }, + { + "day": 6, + "flight": "U2057", + "utc": "10:56:00" + }, + { + "day": 6, + "flight": "U2378", + "utc": "15:22:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BRS", + "distance": 914.710726420036, + "equipment": "320 319", + "id": 55469, + "schedule": [ + { + "day": 0, + "flight": "U2533", + "utc": "12:23:00" + }, + { + "day": 1, + "flight": "U2509", + "utc": "16:59:00" + }, + { + "day": 1, + "flight": "U2409", + "utc": "19:38:00" + }, + { + "day": 1, + "flight": "U2984", + "utc": "10:37:00" + }, + { + "day": 1, + "flight": "U2366", + "utc": "20:19:00" + }, + { + "day": 1, + "flight": "U2844", + "utc": "17:16:00" + }, + { + "day": 2, + "flight": "U2328", + "utc": "08:32:00" + }, + { + "day": 2, + "flight": "U2240", + "utc": "15:21:00" + }, + { + "day": 3, + "flight": "U2469", + "utc": "09:58:00" + }, + { + "day": 3, + "flight": "U2588", + "utc": "04:30:00" + }, + { + "day": 4, + "flight": "U2688", + "utc": "21:43:00" + }, + { + "day": 4, + "flight": "U2967", + "utc": "20:18:00" + }, + { + "day": 5, + "flight": "U2536", + "utc": "00:42:00" + }, + { + "day": 5, + "flight": "U2097", + "utc": "06:17:00" + }, + { + "day": 5, + "flight": "U2469", + "utc": "05:20:00" + }, + { + "day": 5, + "flight": "U2663", + "utc": "07:19:00" + }, + { + "day": 5, + "flight": "U2954", + "utc": "20:52:00" + }, + { + "day": 6, + "flight": "U2293", + "utc": "02:32:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BRU", + "distance": 842.027454616631, + "equipment": "319", + "id": 55470, + "schedule": [ + { + "day": 0, + "flight": "U2497", + "utc": "16:39:00" + }, + { + "day": 0, + "flight": "U2139", + "utc": "23:18:00" + }, + { + "day": 1, + "flight": "U2736", + "utc": "00:06:00" + }, + { + "day": 1, + "flight": "U2189", + "utc": "13:26:00" + }, + { + "day": 1, + "flight": "U2670", + "utc": "17:56:00" + }, + { + "day": 1, + "flight": "U2645", + "utc": "16:54:00" + }, + { + "day": 2, + "flight": "U2326", + "utc": "19:43:00" + }, + { + "day": 2, + "flight": "U2082", + "utc": "07:34:00" + }, + { + "day": 2, + "flight": "U2799", + "utc": "09:31:00" + }, + { + "day": 3, + "flight": "U2919", + "utc": "21:16:00" + }, + { + "day": 3, + "flight": "U2847", + "utc": "01:15:00" + }, + { + "day": 3, + "flight": "U2163", + "utc": "22:26:00" + }, + { + "day": 4, + "flight": "U2361", + "utc": "07:45:00" + }, + { + "day": 4, + "flight": "U2951", + "utc": "12:59:00" + }, + { + "day": 4, + "flight": "U2869", + "utc": "18:16:00" + }, + { + "day": 5, + "flight": "U2608", + "utc": "09:18:00" + }, + { + "day": 5, + "flight": "U2265", + "utc": "08:22:00" + }, + { + "day": 5, + "flight": "U2787", + "utc": "21:56:00" + }, + { + "day": 5, + "flight": "U2242", + "utc": "10:16:00" + }, + { + "day": 5, + "flight": "U2931", + "utc": "08:12:00" + }, + { + "day": 6, + "flight": "U2732", + "utc": "03:59:00" + }, + { + "day": 6, + "flight": "U2684", + "utc": "05:02:00" + }, + { + "day": 6, + "flight": "U2718", + "utc": "07:42:00" + }, + { + "day": 6, + "flight": "U2789", + "utc": "00:50:00" + }, + { + "day": 6, + "flight": "U2364", + "utc": "16:49:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "BSL", + "distance": 650.756926586045, + "equipment": "319", + "id": 55471, + "schedule": [ + { + "day": 0, + "flight": "U2948", + "utc": "00:07:00" + }, + { + "day": 1, + "flight": "U2684", + "utc": "21:58:00" + }, + { + "day": 1, + "flight": "U2478", + "utc": "17:44:00" + }, + { + "day": 1, + "flight": "U2990", + "utc": "08:44:00" + }, + { + "day": 1, + "flight": "U2884", + "utc": "05:21:00" + }, + { + "day": 2, + "flight": "U2804", + "utc": "14:08:00" + }, + { + "day": 2, + "flight": "U2952", + "utc": "01:30:00" + }, + { + "day": 2, + "flight": "U2413", + "utc": "05:49:00" + }, + { + "day": 2, + "flight": "U2586", + "utc": "04:20:00" + }, + { + "day": 2, + "flight": "U2970", + "utc": "09:59:00" + }, + { + "day": 3, + "flight": "U2933", + "utc": "09:20:00" + }, + { + "day": 3, + "flight": "U2225", + "utc": "09:07:00" + }, + { + "day": 4, + "flight": "U2546", + "utc": "20:47:00" + }, + { + "day": 4, + "flight": "U2470", + "utc": "06:33:00" + }, + { + "day": 4, + "flight": "U2669", + "utc": "17:22:00" + }, + { + "day": 4, + "flight": "U2421", + "utc": "20:26:00" + }, + { + "day": 5, + "flight": "U2915", + "utc": "03:46:00" + }, + { + "day": 5, + "flight": "U2178", + "utc": "19:13:00" + }, + { + "day": 6, + "flight": "U2113", + "utc": "06:17:00" + }, + { + "day": 6, + "flight": "U2472", + "utc": "15:17:00" + }, + { + "day": 6, + "flight": "U2572", + "utc": "15:08:00" + }, + { + "day": 6, + "flight": "U2806", + "utc": "09:53:00" + }, + { + "day": 6, + "flight": "U2880", + "utc": "19:51:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "319 320", + "id": 55472, + "schedule": [ + { + "day": 0, + "flight": "U2783", + "utc": "04:04:00" + }, + { + "day": 0, + "flight": "U2306", + "utc": "12:27:00" + }, + { + "day": 0, + "flight": "U2568", + "utc": "22:02:00" + }, + { + "day": 0, + "flight": "U2181", + "utc": "12:06:00" + }, + { + "day": 0, + "flight": "U2994", + "utc": "07:29:00" + }, + { + "day": 1, + "flight": "U2148", + "utc": "05:42:00" + }, + { + "day": 1, + "flight": "U2598", + "utc": "03:59:00" + }, + { + "day": 1, + "flight": "U2486", + "utc": "22:53:00" + }, + { + "day": 2, + "flight": "U2878", + "utc": "07:27:00" + }, + { + "day": 3, + "flight": "U2940", + "utc": "19:09:00" + }, + { + "day": 3, + "flight": "U2472", + "utc": "13:32:00" + }, + { + "day": 3, + "flight": "U2764", + "utc": "22:04:00" + }, + { + "day": 4, + "flight": "U2398", + "utc": "01:20:00" + }, + { + "day": 4, + "flight": "U2640", + "utc": "22:50:00" + }, + { + "day": 4, + "flight": "U2323", + "utc": "04:22:00" + }, + { + "day": 5, + "flight": "U2015", + "utc": "10:27:00" + }, + { + "day": 5, + "flight": "U2339", + "utc": "15:46:00" + }, + { + "day": 5, + "flight": "U2000", + "utc": "14:10:00" + }, + { + "day": 5, + "flight": "U2159", + "utc": "03:50:00" + }, + { + "day": 5, + "flight": "U2509", + "utc": "04:22:00" + }, + { + "day": 6, + "flight": "U2639", + "utc": "17:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "319", + "id": 55473, + "schedule": [ + { + "day": 0, + "flight": "U2207", + "utc": "10:41:00" + }, + { + "day": 1, + "flight": "U2992", + "utc": "23:32:00" + }, + { + "day": 1, + "flight": "U2456", + "utc": "12:15:00" + }, + { + "day": 2, + "flight": "U2130", + "utc": "04:59:00" + }, + { + "day": 2, + "flight": "U2358", + "utc": "22:48:00" + }, + { + "day": 3, + "flight": "U2163", + "utc": "19:05:00" + }, + { + "day": 4, + "flight": "U2643", + "utc": "05:31:00" + }, + { + "day": 4, + "flight": "U2475", + "utc": "14:17:00" + }, + { + "day": 4, + "flight": "U2675", + "utc": "10:16:00" + }, + { + "day": 4, + "flight": "U2260", + "utc": "21:43:00" + }, + { + "day": 5, + "flight": "U2711", + "utc": "05:27:00" + }, + { + "day": 5, + "flight": "U2502", + "utc": "21:27:00" + }, + { + "day": 6, + "flight": "U2754", + "utc": "19:41:00" + }, + { + "day": 6, + "flight": "U2771", + "utc": "21:15:00" + }, + { + "day": 6, + "flight": "U2733", + "utc": "03:49:00" + }, + { + "day": 6, + "flight": "U2326", + "utc": "09:00:00" + }, + { + "day": 6, + "flight": "U2916", + "utc": "08:04:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "GVA", + "distance": 472.80826589600406, + "equipment": "319", + "id": 55474, + "schedule": [ + { + "day": 0, + "flight": "U2283", + "utc": "23:24:00" + }, + { + "day": 0, + "flight": "U2818", + "utc": "06:27:00" + }, + { + "day": 1, + "flight": "U2427", + "utc": "17:05:00" + }, + { + "day": 1, + "flight": "U2152", + "utc": "11:22:00" + }, + { + "day": 1, + "flight": "U2830", + "utc": "08:25:00" + }, + { + "day": 2, + "flight": "U2120", + "utc": "07:48:00" + }, + { + "day": 3, + "flight": "U2044", + "utc": "05:59:00" + }, + { + "day": 3, + "flight": "U2642", + "utc": "07:14:00" + }, + { + "day": 4, + "flight": "U2054", + "utc": "14:28:00" + }, + { + "day": 5, + "flight": "U2279", + "utc": "11:19:00" + }, + { + "day": 5, + "flight": "U2134", + "utc": "18:51:00" + }, + { + "day": 5, + "flight": "U2691", + "utc": "02:31:00" + }, + { + "day": 5, + "flight": "U2655", + "utc": "21:49:00" + }, + { + "day": 6, + "flight": "U2805", + "utc": "14:23:00" + }, + { + "day": 6, + "flight": "U2614", + "utc": "22:06:00" + }, + { + "day": 6, + "flight": "U2370", + "utc": "15:16:00" + }, + { + "day": 6, + "flight": "U2170", + "utc": "11:22:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LGW", + "distance": 844.1654023845344, + "equipment": "319 320", + "id": 55475, + "schedule": [ + { + "day": 0, + "flight": "U2933", + "utc": "04:57:00" + }, + { + "day": 0, + "flight": "U2353", + "utc": "18:26:00" + }, + { + "day": 0, + "flight": "U2005", + "utc": "15:06:00" + }, + { + "day": 1, + "flight": "U2701", + "utc": "09:37:00" + }, + { + "day": 2, + "flight": "U2142", + "utc": "22:02:00" + }, + { + "day": 2, + "flight": "U2583", + "utc": "16:29:00" + }, + { + "day": 2, + "flight": "U2424", + "utc": "10:14:00" + }, + { + "day": 3, + "flight": "U2528", + "utc": "21:34:00" + }, + { + "day": 3, + "flight": "U2213", + "utc": "21:34:00" + }, + { + "day": 3, + "flight": "U2664", + "utc": "09:18:00" + }, + { + "day": 4, + "flight": "U2487", + "utc": "00:05:00" + }, + { + "day": 4, + "flight": "U2324", + "utc": "12:30:00" + }, + { + "day": 4, + "flight": "U2244", + "utc": "08:01:00" + }, + { + "day": 4, + "flight": "U2930", + "utc": "23:04:00" + }, + { + "day": 4, + "flight": "U2442", + "utc": "20:48:00" + }, + { + "day": 5, + "flight": "U2885", + "utc": "22:34:00" + }, + { + "day": 5, + "flight": "U2670", + "utc": "17:09:00" + }, + { + "day": 5, + "flight": "U2045", + "utc": "17:23:00" + }, + { + "day": 6, + "flight": "U2785", + "utc": "13:25:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LIL", + "distance": 781.8286754466159, + "equipment": "319", + "id": 55476, + "schedule": [ + { + "day": 0, + "flight": "U2448", + "utc": "11:55:00" + }, + { + "day": 1, + "flight": "U2947", + "utc": "11:22:00" + }, + { + "day": 1, + "flight": "U2978", + "utc": "15:08:00" + }, + { + "day": 2, + "flight": "U2244", + "utc": "02:54:00" + }, + { + "day": 3, + "flight": "U2880", + "utc": "22:25:00" + }, + { + "day": 3, + "flight": "U2966", + "utc": "11:29:00" + }, + { + "day": 3, + "flight": "U2581", + "utc": "01:52:00" + }, + { + "day": 4, + "flight": "U2461", + "utc": "11:43:00" + }, + { + "day": 4, + "flight": "U2882", + "utc": "04:18:00" + }, + { + "day": 4, + "flight": "U2556", + "utc": "01:31:00" + }, + { + "day": 4, + "flight": "U2528", + "utc": "10:56:00" + }, + { + "day": 4, + "flight": "U2060", + "utc": "09:32:00" + }, + { + "day": 5, + "flight": "U2289", + "utc": "06:04:00" + }, + { + "day": 6, + "flight": "U2776", + "utc": "06:37:00" + }, + { + "day": 6, + "flight": "U2510", + "utc": "07:51:00" + }, + { + "day": 6, + "flight": "U2861", + "utc": "22:24:00" + }, + { + "day": 6, + "flight": "U2936", + "utc": "06:57:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319", + "id": 55477, + "schedule": [ + { + "day": 0, + "flight": "U2340", + "utc": "21:08:00" + }, + { + "day": 0, + "flight": "U2501", + "utc": "11:27:00" + }, + { + "day": 0, + "flight": "U2855", + "utc": "20:34:00" + }, + { + "day": 1, + "flight": "U2025", + "utc": "01:40:00" + }, + { + "day": 1, + "flight": "U2320", + "utc": "02:40:00" + }, + { + "day": 1, + "flight": "U2402", + "utc": "05:53:00" + }, + { + "day": 1, + "flight": "U2858", + "utc": "02:47:00" + }, + { + "day": 1, + "flight": "U2828", + "utc": "04:34:00" + }, + { + "day": 2, + "flight": "U2361", + "utc": "07:59:00" + }, + { + "day": 2, + "flight": "U2640", + "utc": "04:01:00" + }, + { + "day": 2, + "flight": "U2777", + "utc": "18:07:00" + }, + { + "day": 3, + "flight": "U2602", + "utc": "19:50:00" + }, + { + "day": 4, + "flight": "U2487", + "utc": "00:56:00" + }, + { + "day": 5, + "flight": "U2702", + "utc": "05:40:00" + }, + { + "day": 6, + "flight": "U2074", + "utc": "14:47:00" + }, + { + "day": 6, + "flight": "U2763", + "utc": "21:12:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "NCE", + "distance": 470.8031011808527, + "equipment": "319", + "id": 55478, + "schedule": [ + { + "day": 0, + "flight": "U2536", + "utc": "00:51:00" + }, + { + "day": 0, + "flight": "U2640", + "utc": "10:51:00" + }, + { + "day": 0, + "flight": "U2734", + "utc": "19:10:00" + }, + { + "day": 0, + "flight": "U2973", + "utc": "19:49:00" + }, + { + "day": 0, + "flight": "U2387", + "utc": "07:11:00" + }, + { + "day": 1, + "flight": "U2852", + "utc": "01:07:00" + }, + { + "day": 1, + "flight": "U2532", + "utc": "10:19:00" + }, + { + "day": 1, + "flight": "U2896", + "utc": "06:50:00" + }, + { + "day": 2, + "flight": "U2510", + "utc": "12:58:00" + }, + { + "day": 2, + "flight": "U2929", + "utc": "22:05:00" + }, + { + "day": 3, + "flight": "U2563", + "utc": "12:44:00" + }, + { + "day": 3, + "flight": "U2947", + "utc": "04:21:00" + }, + { + "day": 3, + "flight": "U2787", + "utc": "05:13:00" + }, + { + "day": 4, + "flight": "U2383", + "utc": "23:41:00" + }, + { + "day": 4, + "flight": "U2485", + "utc": "13:25:00" + }, + { + "day": 5, + "flight": "U2064", + "utc": "20:55:00" + }, + { + "day": 5, + "flight": "U2690", + "utc": "04:31:00" + }, + { + "day": 5, + "flight": "U2713", + "utc": "18:06:00" + }, + { + "day": 6, + "flight": "U2099", + "utc": "09:45:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "NTE", + "distance": 455.4490681425203, + "equipment": "319", + "id": 55479, + "schedule": [ + { + "day": 0, + "flight": "U2117", + "utc": "10:10:00" + }, + { + "day": 1, + "flight": "U2746", + "utc": "08:08:00" + }, + { + "day": 1, + "flight": "U2454", + "utc": "21:03:00" + }, + { + "day": 1, + "flight": "U2860", + "utc": "12:06:00" + }, + { + "day": 2, + "flight": "U2902", + "utc": "18:21:00" + }, + { + "day": 2, + "flight": "U2031", + "utc": "23:38:00" + }, + { + "day": 3, + "flight": "U2255", + "utc": "01:05:00" + }, + { + "day": 4, + "flight": "U2037", + "utc": "06:54:00" + }, + { + "day": 4, + "flight": "U2671", + "utc": "18:55:00" + }, + { + "day": 4, + "flight": "U2793", + "utc": "18:13:00" + }, + { + "day": 4, + "flight": "U2564", + "utc": "03:51:00" + }, + { + "day": 5, + "flight": "U2209", + "utc": "13:21:00" + }, + { + "day": 6, + "flight": "U2139", + "utc": "23:11:00" + }, + { + "day": 6, + "flight": "U2398", + "utc": "15:26:00" + }, + { + "day": 6, + "flight": "U2335", + "utc": "08:44:00" + }, + { + "day": 6, + "flight": "U2591", + "utc": "01:43:00" + }, + { + "day": 6, + "flight": "U2623", + "utc": "06:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "ORY", + "distance": 571.8189591117047, + "equipment": "320 319", + "id": 55480, + "schedule": [ + { + "day": 0, + "flight": "U2687", + "utc": "12:05:00" + }, + { + "day": 1, + "flight": "U2311", + "utc": "03:54:00" + }, + { + "day": 1, + "flight": "U2180", + "utc": "15:47:00" + }, + { + "day": 1, + "flight": "U2937", + "utc": "07:31:00" + }, + { + "day": 1, + "flight": "U2210", + "utc": "20:01:00" + }, + { + "day": 1, + "flight": "U2593", + "utc": "13:47:00" + }, + { + "day": 2, + "flight": "U2747", + "utc": "20:18:00" + }, + { + "day": 2, + "flight": "U2810", + "utc": "22:27:00" + }, + { + "day": 2, + "flight": "U2888", + "utc": "20:35:00" + }, + { + "day": 3, + "flight": "U2363", + "utc": "15:56:00" + }, + { + "day": 3, + "flight": "U2344", + "utc": "01:35:00" + }, + { + "day": 4, + "flight": "U2153", + "utc": "13:29:00" + }, + { + "day": 4, + "flight": "U2256", + "utc": "10:58:00" + }, + { + "day": 5, + "flight": "U2880", + "utc": "15:55:00" + }, + { + "day": 5, + "flight": "U2659", + "utc": "21:57:00" + }, + { + "day": 6, + "flight": "U2797", + "utc": "03:33:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "U2", + "airlineid": "airline_2297", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "319 320", + "id": 55481, + "schedule": [ + { + "day": 0, + "flight": "U2751", + "utc": "03:33:00" + }, + { + "day": 0, + "flight": "U2066", + "utc": "00:35:00" + }, + { + "day": 0, + "flight": "U2660", + "utc": "20:57:00" + }, + { + "day": 0, + "flight": "U2700", + "utc": "12:47:00" + }, + { + "day": 0, + "flight": "U2838", + "utc": "03:17:00" + }, + { + "day": 1, + "flight": "U2802", + "utc": "16:53:00" + }, + { + "day": 1, + "flight": "U2203", + "utc": "23:14:00" + }, + { + "day": 1, + "flight": "U2029", + "utc": "06:13:00" + }, + { + "day": 1, + "flight": "U2228", + "utc": "19:13:00" + }, + { + "day": 2, + "flight": "U2671", + "utc": "11:55:00" + }, + { + "day": 2, + "flight": "U2526", + "utc": "11:12:00" + }, + { + "day": 2, + "flight": "U2747", + "utc": "12:18:00" + }, + { + "day": 3, + "flight": "U2417", + "utc": "12:17:00" + }, + { + "day": 3, + "flight": "U2082", + "utc": "14:54:00" + }, + { + "day": 4, + "flight": "U2069", + "utc": "21:57:00" + }, + { + "day": 4, + "flight": "U2708", + "utc": "00:16:00" + }, + { + "day": 4, + "flight": "U2067", + "utc": "23:46:00" + }, + { + "day": 4, + "flight": "U2334", + "utc": "15:46:00" + }, + { + "day": 4, + "flight": "U2084", + "utc": "01:10:00" + }, + { + "day": 5, + "flight": "U2693", + "utc": "04:39:00" + }, + { + "day": 5, + "flight": "U2415", + "utc": "15:54:00" + }, + { + "day": 5, + "flight": "U2378", + "utc": "09:10:00" + }, + { + "day": 5, + "flight": "U2094", + "utc": "01:03:00" + }, + { + "day": 5, + "flight": "U2399", + "utc": "09:25:00" + }, + { + "day": 6, + "flight": "U2534", + "utc": "20:07:00" + }, + { + "day": 6, + "flight": "U2509", + "utc": "10:02:00" + }, + { + "day": 6, + "flight": "U2280", + "utc": "06:27:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "AGP", + "distance": 919.3439362090616, + "equipment": "320", + "id": 62413, + "schedule": [ + { + "day": 0, + "flight": "VY306", + "utc": "08:50:00" + }, + { + "day": 0, + "flight": "VY637", + "utc": "15:53:00" + }, + { + "day": 0, + "flight": "VY587", + "utc": "21:50:00" + }, + { + "day": 0, + "flight": "VY313", + "utc": "16:54:00" + }, + { + "day": 1, + "flight": "VY228", + "utc": "02:02:00" + }, + { + "day": 2, + "flight": "VY543", + "utc": "17:54:00" + }, + { + "day": 2, + "flight": "VY681", + "utc": "02:51:00" + }, + { + "day": 2, + "flight": "VY649", + "utc": "06:19:00" + }, + { + "day": 3, + "flight": "VY243", + "utc": "22:54:00" + }, + { + "day": 3, + "flight": "VY373", + "utc": "12:15:00" + }, + { + "day": 3, + "flight": "VY408", + "utc": "03:16:00" + }, + { + "day": 3, + "flight": "VY627", + "utc": "19:42:00" + }, + { + "day": 3, + "flight": "VY580", + "utc": "18:49:00" + }, + { + "day": 4, + "flight": "VY607", + "utc": "17:01:00" + }, + { + "day": 4, + "flight": "VY177", + "utc": "16:28:00" + }, + { + "day": 4, + "flight": "VY066", + "utc": "15:52:00" + }, + { + "day": 4, + "flight": "VY185", + "utc": "18:35:00" + }, + { + "day": 4, + "flight": "VY318", + "utc": "14:19:00" + }, + { + "day": 5, + "flight": "VY960", + "utc": "01:26:00" + }, + { + "day": 5, + "flight": "VY217", + "utc": "02:12:00" + }, + { + "day": 6, + "flight": "VY558", + "utc": "01:41:00" + }, + { + "day": 6, + "flight": "VY412", + "utc": "11:25:00" + }, + { + "day": 6, + "flight": "VY596", + "utc": "20:06:00" + }, + { + "day": 6, + "flight": "VY176", + "utc": "22:40:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "BCN", + "distance": 265.8469587104912, + "equipment": "320", + "id": 62414, + "schedule": [ + { + "day": 0, + "flight": "VY864", + "utc": "21:52:00" + }, + { + "day": 1, + "flight": "VY591", + "utc": "22:27:00" + }, + { + "day": 1, + "flight": "VY081", + "utc": "15:06:00" + }, + { + "day": 1, + "flight": "VY143", + "utc": "20:13:00" + }, + { + "day": 1, + "flight": "VY957", + "utc": "20:03:00" + }, + { + "day": 1, + "flight": "VY201", + "utc": "22:01:00" + }, + { + "day": 2, + "flight": "VY953", + "utc": "11:47:00" + }, + { + "day": 2, + "flight": "VY207", + "utc": "03:38:00" + }, + { + "day": 3, + "flight": "VY091", + "utc": "22:34:00" + }, + { + "day": 3, + "flight": "VY910", + "utc": "16:14:00" + }, + { + "day": 3, + "flight": "VY908", + "utc": "13:27:00" + }, + { + "day": 3, + "flight": "VY021", + "utc": "11:41:00" + }, + { + "day": 3, + "flight": "VY150", + "utc": "09:21:00" + }, + { + "day": 4, + "flight": "VY422", + "utc": "17:33:00" + }, + { + "day": 4, + "flight": "VY905", + "utc": "02:40:00" + }, + { + "day": 4, + "flight": "VY779", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "VY656", + "utc": "23:40:00" + }, + { + "day": 5, + "flight": "VY317", + "utc": "21:24:00" + }, + { + "day": 5, + "flight": "VY932", + "utc": "08:49:00" + }, + { + "day": 5, + "flight": "VY422", + "utc": "12:41:00" + }, + { + "day": 6, + "flight": "VY720", + "utc": "01:16:00" + }, + { + "day": 6, + "flight": "VY473", + "utc": "06:02:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "VY", + "airlineid": "airline_2439", + "destinationairport": "PMI", + "distance": 467.1315518195575, + "equipment": "320", + "id": 62415, + "schedule": [ + { + "day": 0, + "flight": "VY490", + "utc": "05:18:00" + }, + { + "day": 0, + "flight": "VY773", + "utc": "01:14:00" + }, + { + "day": 0, + "flight": "VY500", + "utc": "23:29:00" + }, + { + "day": 0, + "flight": "VY860", + "utc": "18:39:00" + }, + { + "day": 1, + "flight": "VY573", + "utc": "22:20:00" + }, + { + "day": 1, + "flight": "VY004", + "utc": "02:59:00" + }, + { + "day": 1, + "flight": "VY507", + "utc": "03:05:00" + }, + { + "day": 1, + "flight": "VY789", + "utc": "11:25:00" + }, + { + "day": 2, + "flight": "VY600", + "utc": "20:30:00" + }, + { + "day": 2, + "flight": "VY291", + "utc": "09:58:00" + }, + { + "day": 2, + "flight": "VY021", + "utc": "07:38:00" + }, + { + "day": 2, + "flight": "VY667", + "utc": "11:43:00" + }, + { + "day": 3, + "flight": "VY411", + "utc": "06:25:00" + }, + { + "day": 3, + "flight": "VY842", + "utc": "05:41:00" + }, + { + "day": 3, + "flight": "VY287", + "utc": "02:46:00" + }, + { + "day": 3, + "flight": "VY114", + "utc": "00:53:00" + }, + { + "day": 3, + "flight": "VY674", + "utc": "12:24:00" + }, + { + "day": 4, + "flight": "VY228", + "utc": "20:25:00" + }, + { + "day": 5, + "flight": "VY276", + "utc": "21:16:00" + }, + { + "day": 6, + "flight": "VY541", + "utc": "17:57:00" + }, + { + "day": 6, + "flight": "VY913", + "utc": "08:49:00" + }, + { + "day": 6, + "flight": "VY456", + "utc": "01:12:00" + }, + { + "day": 6, + "flight": "VY827", + "utc": "04:05:00" + }, + { + "day": 6, + "flight": "VY880", + "utc": "17:52:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "XK", + "airlineid": "airline_1909", + "destinationairport": "AJA", + "distance": 635.8270740976213, + "equipment": "320", + "id": 65438, + "schedule": [ + { + "day": 0, + "flight": "XK629", + "utc": "06:48:00" + }, + { + "day": 0, + "flight": "XK034", + "utc": "06:05:00" + }, + { + "day": 0, + "flight": "XK235", + "utc": "06:10:00" + }, + { + "day": 0, + "flight": "XK886", + "utc": "18:33:00" + }, + { + "day": 0, + "flight": "XK152", + "utc": "14:22:00" + }, + { + "day": 1, + "flight": "XK175", + "utc": "20:39:00" + }, + { + "day": 1, + "flight": "XK283", + "utc": "18:51:00" + }, + { + "day": 2, + "flight": "XK802", + "utc": "22:14:00" + }, + { + "day": 2, + "flight": "XK065", + "utc": "18:28:00" + }, + { + "day": 2, + "flight": "XK331", + "utc": "06:59:00" + }, + { + "day": 2, + "flight": "XK106", + "utc": "01:42:00" + }, + { + "day": 3, + "flight": "XK962", + "utc": "11:48:00" + }, + { + "day": 3, + "flight": "XK085", + "utc": "17:40:00" + }, + { + "day": 4, + "flight": "XK018", + "utc": "13:12:00" + }, + { + "day": 5, + "flight": "XK484", + "utc": "06:21:00" + }, + { + "day": 5, + "flight": "XK417", + "utc": "20:43:00" + }, + { + "day": 5, + "flight": "XK571", + "utc": "20:21:00" + }, + { + "day": 5, + "flight": "XK576", + "utc": "05:54:00" + }, + { + "day": 6, + "flight": "XK933", + "utc": "10:40:00" + }, + { + "day": 6, + "flight": "XK247", + "utc": "13:50:00" + }, + { + "day": 6, + "flight": "XK542", + "utc": "00:17:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AA", + "airlineid": "airline_24", + "destinationairport": "LHR", + "distance": 883.3122325423356, + "equipment": "320 319", + "id": 6898, + "schedule": [ + { + "day": 0, + "flight": "AA020", + "utc": "05:46:00" + }, + { + "day": 1, + "flight": "AA288", + "utc": "23:39:00" + }, + { + "day": 1, + "flight": "AA758", + "utc": "13:22:00" + }, + { + "day": 1, + "flight": "AA396", + "utc": "11:01:00" + }, + { + "day": 1, + "flight": "AA133", + "utc": "14:34:00" + }, + { + "day": 1, + "flight": "AA448", + "utc": "19:27:00" + }, + { + "day": 2, + "flight": "AA660", + "utc": "15:24:00" + }, + { + "day": 2, + "flight": "AA529", + "utc": "01:22:00" + }, + { + "day": 2, + "flight": "AA738", + "utc": "12:23:00" + }, + { + "day": 3, + "flight": "AA759", + "utc": "19:33:00" + }, + { + "day": 4, + "flight": "AA739", + "utc": "02:40:00" + }, + { + "day": 4, + "flight": "AA455", + "utc": "04:42:00" + }, + { + "day": 4, + "flight": "AA832", + "utc": "22:45:00" + }, + { + "day": 4, + "flight": "AA932", + "utc": "17:16:00" + }, + { + "day": 4, + "flight": "AA188", + "utc": "15:15:00" + }, + { + "day": 5, + "flight": "AA548", + "utc": "00:09:00" + }, + { + "day": 5, + "flight": "AA452", + "utc": "05:00:00" + }, + { + "day": 5, + "flight": "AA905", + "utc": "03:24:00" + }, + { + "day": 5, + "flight": "AA571", + "utc": "01:04:00" + }, + { + "day": 5, + "flight": "AA168", + "utc": "10:38:00" + }, + { + "day": 6, + "flight": "AA329", + "utc": "20:38:00" + }, + { + "day": 6, + "flight": "AA799", + "utc": "07:55:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "AJA", + "distance": 635.8270740976213, + "equipment": "320", + "id": 9985, + "schedule": [ + { + "day": 0, + "flight": "AF736", + "utc": "17:30:00" + }, + { + "day": 1, + "flight": "AF398", + "utc": "05:17:00" + }, + { + "day": 1, + "flight": "AF296", + "utc": "21:03:00" + }, + { + "day": 1, + "flight": "AF711", + "utc": "22:47:00" + }, + { + "day": 1, + "flight": "AF189", + "utc": "20:04:00" + }, + { + "day": 2, + "flight": "AF737", + "utc": "09:54:00" + }, + { + "day": 2, + "flight": "AF458", + "utc": "15:20:00" + }, + { + "day": 2, + "flight": "AF328", + "utc": "13:01:00" + }, + { + "day": 2, + "flight": "AF572", + "utc": "10:01:00" + }, + { + "day": 2, + "flight": "AF295", + "utc": "03:30:00" + }, + { + "day": 3, + "flight": "AF272", + "utc": "06:29:00" + }, + { + "day": 3, + "flight": "AF516", + "utc": "07:05:00" + }, + { + "day": 3, + "flight": "AF438", + "utc": "09:20:00" + }, + { + "day": 3, + "flight": "AF584", + "utc": "16:37:00" + }, + { + "day": 3, + "flight": "AF700", + "utc": "09:23:00" + }, + { + "day": 4, + "flight": "AF637", + "utc": "13:27:00" + }, + { + "day": 4, + "flight": "AF081", + "utc": "03:02:00" + }, + { + "day": 4, + "flight": "AF551", + "utc": "03:41:00" + }, + { + "day": 4, + "flight": "AF884", + "utc": "16:28:00" + }, + { + "day": 5, + "flight": "AF966", + "utc": "20:17:00" + }, + { + "day": 5, + "flight": "AF093", + "utc": "18:00:00" + }, + { + "day": 5, + "flight": "AF529", + "utc": "01:21:00" + }, + { + "day": 5, + "flight": "AF958", + "utc": "03:43:00" + }, + { + "day": 5, + "flight": "AF863", + "utc": "01:35:00" + }, + { + "day": 6, + "flight": "AF035", + "utc": "20:01:00" + }, + { + "day": 6, + "flight": "AF650", + "utc": "04:42:00" + }, + { + "day": 6, + "flight": "AF281", + "utc": "21:12:00" + }, + { + "day": 6, + "flight": "AF762", + "utc": "05:58:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "AMS", + "distance": 997.4702942027754, + "equipment": "E90", + "id": 9986, + "schedule": [ + { + "day": 0, + "flight": "AF828", + "utc": "04:07:00" + }, + { + "day": 0, + "flight": "AF923", + "utc": "02:34:00" + }, + { + "day": 0, + "flight": "AF622", + "utc": "15:56:00" + }, + { + "day": 0, + "flight": "AF409", + "utc": "20:12:00" + }, + { + "day": 0, + "flight": "AF462", + "utc": "04:35:00" + }, + { + "day": 1, + "flight": "AF688", + "utc": "01:30:00" + }, + { + "day": 1, + "flight": "AF444", + "utc": "01:03:00" + }, + { + "day": 1, + "flight": "AF789", + "utc": "20:50:00" + }, + { + "day": 1, + "flight": "AF253", + "utc": "19:01:00" + }, + { + "day": 1, + "flight": "AF731", + "utc": "03:44:00" + }, + { + "day": 2, + "flight": "AF331", + "utc": "19:21:00" + }, + { + "day": 3, + "flight": "AF101", + "utc": "19:35:00" + }, + { + "day": 4, + "flight": "AF928", + "utc": "08:16:00" + }, + { + "day": 4, + "flight": "AF359", + "utc": "16:04:00" + }, + { + "day": 4, + "flight": "AF497", + "utc": "13:02:00" + }, + { + "day": 5, + "flight": "AF326", + "utc": "18:14:00" + }, + { + "day": 5, + "flight": "AF019", + "utc": "11:55:00" + }, + { + "day": 6, + "flight": "AF624", + "utc": "21:46:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ATH", + "distance": 1996.3800921392394, + "equipment": "320", + "id": 9987, + "schedule": [ + { + "day": 0, + "flight": "AF893", + "utc": "23:36:00" + }, + { + "day": 0, + "flight": "AF498", + "utc": "19:37:00" + }, + { + "day": 1, + "flight": "AF266", + "utc": "02:51:00" + }, + { + "day": 1, + "flight": "AF970", + "utc": "06:54:00" + }, + { + "day": 1, + "flight": "AF880", + "utc": "20:08:00" + }, + { + "day": 2, + "flight": "AF758", + "utc": "15:11:00" + }, + { + "day": 2, + "flight": "AF437", + "utc": "08:53:00" + }, + { + "day": 2, + "flight": "AF930", + "utc": "08:47:00" + }, + { + "day": 2, + "flight": "AF671", + "utc": "09:09:00" + }, + { + "day": 2, + "flight": "AF151", + "utc": "05:10:00" + }, + { + "day": 3, + "flight": "AF142", + "utc": "19:27:00" + }, + { + "day": 3, + "flight": "AF805", + "utc": "23:07:00" + }, + { + "day": 4, + "flight": "AF821", + "utc": "11:18:00" + }, + { + "day": 4, + "flight": "AF146", + "utc": "12:32:00" + }, + { + "day": 5, + "flight": "AF591", + "utc": "03:51:00" + }, + { + "day": 5, + "flight": "AF506", + "utc": "06:24:00" + }, + { + "day": 6, + "flight": "AF455", + "utc": "11:23:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "CDG", + "distance": 605.5094451553542, + "equipment": "320 319 321", + "id": 9988, + "schedule": [ + { + "day": 0, + "flight": "AF099", + "utc": "20:30:00" + }, + { + "day": 0, + "flight": "AF282", + "utc": "03:57:00" + }, + { + "day": 1, + "flight": "AF890", + "utc": "16:06:00" + }, + { + "day": 1, + "flight": "AF974", + "utc": "06:16:00" + }, + { + "day": 1, + "flight": "AF099", + "utc": "16:08:00" + }, + { + "day": 1, + "flight": "AF998", + "utc": "00:23:00" + }, + { + "day": 1, + "flight": "AF117", + "utc": "03:16:00" + }, + { + "day": 2, + "flight": "AF081", + "utc": "01:22:00" + }, + { + "day": 2, + "flight": "AF550", + "utc": "08:21:00" + }, + { + "day": 3, + "flight": "AF029", + "utc": "21:23:00" + }, + { + "day": 3, + "flight": "AF669", + "utc": "15:11:00" + }, + { + "day": 3, + "flight": "AF897", + "utc": "17:58:00" + }, + { + "day": 4, + "flight": "AF812", + "utc": "19:48:00" + }, + { + "day": 4, + "flight": "AF861", + "utc": "06:15:00" + }, + { + "day": 4, + "flight": "AF767", + "utc": "21:25:00" + }, + { + "day": 4, + "flight": "AF411", + "utc": "01:17:00" + }, + { + "day": 4, + "flight": "AF003", + "utc": "13:03:00" + }, + { + "day": 5, + "flight": "AF362", + "utc": "04:02:00" + }, + { + "day": 5, + "flight": "AF967", + "utc": "02:19:00" + }, + { + "day": 5, + "flight": "AF237", + "utc": "17:45:00" + }, + { + "day": 5, + "flight": "AF618", + "utc": "19:20:00" + }, + { + "day": 5, + "flight": "AF864", + "utc": "21:19:00" + }, + { + "day": 6, + "flight": "AF031", + "utc": "07:08:00" + }, + { + "day": 6, + "flight": "AF213", + "utc": "22:11:00" + }, + { + "day": 6, + "flight": "AF505", + "utc": "21:28:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "CMN", + "distance": 1379.8271930529227, + "equipment": "319 320", + "id": 9989, + "schedule": [ + { + "day": 0, + "flight": "AF336", + "utc": "07:45:00" + }, + { + "day": 0, + "flight": "AF660", + "utc": "15:44:00" + }, + { + "day": 1, + "flight": "AF203", + "utc": "17:34:00" + }, + { + "day": 1, + "flight": "AF513", + "utc": "17:55:00" + }, + { + "day": 2, + "flight": "AF100", + "utc": "13:37:00" + }, + { + "day": 3, + "flight": "AF704", + "utc": "14:15:00" + }, + { + "day": 3, + "flight": "AF562", + "utc": "13:28:00" + }, + { + "day": 3, + "flight": "AF925", + "utc": "19:16:00" + }, + { + "day": 4, + "flight": "AF901", + "utc": "01:26:00" + }, + { + "day": 5, + "flight": "AF685", + "utc": "16:08:00" + }, + { + "day": 5, + "flight": "AF512", + "utc": "18:25:00" + }, + { + "day": 5, + "flight": "AF242", + "utc": "08:31:00" + }, + { + "day": 5, + "flight": "AF993", + "utc": "19:19:00" + }, + { + "day": 5, + "flight": "AF223", + "utc": "03:49:00" + }, + { + "day": 6, + "flight": "AF913", + "utc": "17:19:00" + }, + { + "day": 6, + "flight": "AF443", + "utc": "02:40:00" + }, + { + "day": 6, + "flight": "AF802", + "utc": "21:06:00" + }, + { + "day": 6, + "flight": "AF469", + "utc": "06:57:00" + }, + { + "day": 6, + "flight": "AF383", + "utc": "10:57:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "FCO", + "distance": 911.5448658786228, + "equipment": "319 320", + "id": 9990, + "schedule": [ + { + "day": 0, + "flight": "AF023", + "utc": "13:28:00" + }, + { + "day": 0, + "flight": "AF429", + "utc": "11:52:00" + }, + { + "day": 0, + "flight": "AF606", + "utc": "17:25:00" + }, + { + "day": 1, + "flight": "AF132", + "utc": "07:15:00" + }, + { + "day": 1, + "flight": "AF132", + "utc": "00:14:00" + }, + { + "day": 1, + "flight": "AF568", + "utc": "09:49:00" + }, + { + "day": 2, + "flight": "AF489", + "utc": "16:51:00" + }, + { + "day": 3, + "flight": "AF427", + "utc": "06:10:00" + }, + { + "day": 4, + "flight": "AF566", + "utc": "23:15:00" + }, + { + "day": 4, + "flight": "AF238", + "utc": "22:49:00" + }, + { + "day": 4, + "flight": "AF606", + "utc": "16:17:00" + }, + { + "day": 5, + "flight": "AF925", + "utc": "23:53:00" + }, + { + "day": 5, + "flight": "AF888", + "utc": "12:11:00" + }, + { + "day": 5, + "flight": "AF817", + "utc": "13:09:00" + }, + { + "day": 5, + "flight": "AF290", + "utc": "03:13:00" + }, + { + "day": 5, + "flight": "AF213", + "utc": "02:47:00" + }, + { + "day": 6, + "flight": "AF891", + "utc": "14:24:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "HAM", + "distance": 1277.920368466386, + "equipment": "319", + "id": 9991, + "schedule": [ + { + "day": 0, + "flight": "AF447", + "utc": "05:13:00" + }, + { + "day": 1, + "flight": "AF948", + "utc": "22:21:00" + }, + { + "day": 1, + "flight": "AF812", + "utc": "03:32:00" + }, + { + "day": 1, + "flight": "AF473", + "utc": "12:07:00" + }, + { + "day": 2, + "flight": "AF144", + "utc": "21:30:00" + }, + { + "day": 2, + "flight": "AF721", + "utc": "10:42:00" + }, + { + "day": 2, + "flight": "AF117", + "utc": "02:07:00" + }, + { + "day": 2, + "flight": "AF382", + "utc": "10:57:00" + }, + { + "day": 3, + "flight": "AF432", + "utc": "12:33:00" + }, + { + "day": 3, + "flight": "AF936", + "utc": "07:58:00" + }, + { + "day": 4, + "flight": "AF082", + "utc": "20:19:00" + }, + { + "day": 4, + "flight": "AF060", + "utc": "23:38:00" + }, + { + "day": 4, + "flight": "AF040", + "utc": "17:39:00" + }, + { + "day": 4, + "flight": "AF072", + "utc": "02:25:00" + }, + { + "day": 5, + "flight": "AF511", + "utc": "18:29:00" + }, + { + "day": 5, + "flight": "AF065", + "utc": "11:52:00" + }, + { + "day": 5, + "flight": "AF461", + "utc": "18:49:00" + }, + { + "day": 5, + "flight": "AF562", + "utc": "10:10:00" + }, + { + "day": 6, + "flight": "AF305", + "utc": "16:07:00" + }, + { + "day": 6, + "flight": "AF762", + "utc": "19:24:00" + }, + { + "day": 6, + "flight": "AF062", + "utc": "20:15:00" + }, + { + "day": 6, + "flight": "AF339", + "utc": "12:15:00" + }, + { + "day": 6, + "flight": "AF982", + "utc": "15:15:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "LYS", + "distance": 375.7311512908275, + "equipment": "319 320 CRK", + "id": 9992, + "schedule": [ + { + "day": 0, + "flight": "AF823", + "utc": "19:58:00" + }, + { + "day": 0, + "flight": "AF523", + "utc": "05:11:00" + }, + { + "day": 0, + "flight": "AF212", + "utc": "04:29:00" + }, + { + "day": 0, + "flight": "AF928", + "utc": "07:41:00" + }, + { + "day": 0, + "flight": "AF064", + "utc": "20:55:00" + }, + { + "day": 1, + "flight": "AF584", + "utc": "18:14:00" + }, + { + "day": 1, + "flight": "AF903", + "utc": "07:20:00" + }, + { + "day": 1, + "flight": "AF815", + "utc": "16:43:00" + }, + { + "day": 1, + "flight": "AF283", + "utc": "09:31:00" + }, + { + "day": 1, + "flight": "AF682", + "utc": "02:15:00" + }, + { + "day": 2, + "flight": "AF907", + "utc": "06:21:00" + }, + { + "day": 2, + "flight": "AF094", + "utc": "08:33:00" + }, + { + "day": 2, + "flight": "AF449", + "utc": "15:44:00" + }, + { + "day": 2, + "flight": "AF876", + "utc": "22:00:00" + }, + { + "day": 3, + "flight": "AF828", + "utc": "06:35:00" + }, + { + "day": 3, + "flight": "AF125", + "utc": "15:35:00" + }, + { + "day": 4, + "flight": "AF348", + "utc": "08:34:00" + }, + { + "day": 5, + "flight": "AF100", + "utc": "20:01:00" + }, + { + "day": 5, + "flight": "AF530", + "utc": "11:25:00" + }, + { + "day": 6, + "flight": "AF763", + "utc": "19:11:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "MLA", + "distance": 1412.6976574099108, + "equipment": "320 319", + "id": 9993, + "schedule": [ + { + "day": 0, + "flight": "AF590", + "utc": "23:02:00" + }, + { + "day": 1, + "flight": "AF224", + "utc": "18:02:00" + }, + { + "day": 2, + "flight": "AF834", + "utc": "15:09:00" + }, + { + "day": 2, + "flight": "AF748", + "utc": "09:21:00" + }, + { + "day": 2, + "flight": "AF947", + "utc": "15:28:00" + }, + { + "day": 2, + "flight": "AF058", + "utc": "19:08:00" + }, + { + "day": 2, + "flight": "AF914", + "utc": "18:02:00" + }, + { + "day": 3, + "flight": "AF351", + "utc": "04:18:00" + }, + { + "day": 3, + "flight": "AF975", + "utc": "13:49:00" + }, + { + "day": 3, + "flight": "AF361", + "utc": "18:56:00" + }, + { + "day": 4, + "flight": "AF461", + "utc": "01:40:00" + }, + { + "day": 5, + "flight": "AF281", + "utc": "10:31:00" + }, + { + "day": 6, + "flight": "AF337", + "utc": "10:18:00" + }, + { + "day": 6, + "flight": "AF570", + "utc": "07:41:00" + }, + { + "day": 6, + "flight": "AF823", + "utc": "20:37:00" + }, + { + "day": 6, + "flight": "AF109", + "utc": "14:01:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "ORY", + "distance": 571.8189591117047, + "equipment": "320 319 321", + "id": 9994, + "schedule": [ + { + "day": 0, + "flight": "AF986", + "utc": "12:40:00" + }, + { + "day": 0, + "flight": "AF951", + "utc": "06:14:00" + }, + { + "day": 0, + "flight": "AF527", + "utc": "11:45:00" + }, + { + "day": 0, + "flight": "AF801", + "utc": "14:47:00" + }, + { + "day": 1, + "flight": "AF838", + "utc": "05:42:00" + }, + { + "day": 2, + "flight": "AF952", + "utc": "03:24:00" + }, + { + "day": 2, + "flight": "AF920", + "utc": "14:50:00" + }, + { + "day": 2, + "flight": "AF318", + "utc": "03:40:00" + }, + { + "day": 2, + "flight": "AF137", + "utc": "20:21:00" + }, + { + "day": 3, + "flight": "AF135", + "utc": "15:04:00" + }, + { + "day": 4, + "flight": "AF847", + "utc": "22:57:00" + }, + { + "day": 4, + "flight": "AF010", + "utc": "07:51:00" + }, + { + "day": 4, + "flight": "AF973", + "utc": "17:28:00" + }, + { + "day": 5, + "flight": "AF532", + "utc": "22:28:00" + }, + { + "day": 5, + "flight": "AF447", + "utc": "18:35:00" + }, + { + "day": 5, + "flight": "AF017", + "utc": "13:48:00" + }, + { + "day": 5, + "flight": "AF135", + "utc": "10:16:00" + }, + { + "day": 6, + "flight": "AF933", + "utc": "21:03:00" + }, + { + "day": 6, + "flight": "AF024", + "utc": "05:59:00" + }, + { + "day": 6, + "flight": "AF243", + "utc": "06:19:00" + }, + { + "day": 6, + "flight": "AF619", + "utc": "03:41:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "RAK", + "distance": 1570.0135778787558, + "equipment": "319 320", + "id": 9995, + "schedule": [ + { + "day": 0, + "flight": "AF312", + "utc": "08:58:00" + }, + { + "day": 0, + "flight": "AF099", + "utc": "22:19:00" + }, + { + "day": 0, + "flight": "AF157", + "utc": "05:26:00" + }, + { + "day": 1, + "flight": "AF793", + "utc": "14:45:00" + }, + { + "day": 1, + "flight": "AF638", + "utc": "03:55:00" + }, + { + "day": 1, + "flight": "AF372", + "utc": "20:37:00" + }, + { + "day": 1, + "flight": "AF788", + "utc": "19:15:00" + }, + { + "day": 1, + "flight": "AF889", + "utc": "02:00:00" + }, + { + "day": 2, + "flight": "AF521", + "utc": "21:48:00" + }, + { + "day": 2, + "flight": "AF990", + "utc": "19:41:00" + }, + { + "day": 2, + "flight": "AF047", + "utc": "00:33:00" + }, + { + "day": 2, + "flight": "AF540", + "utc": "08:19:00" + }, + { + "day": 3, + "flight": "AF247", + "utc": "02:30:00" + }, + { + "day": 3, + "flight": "AF197", + "utc": "07:17:00" + }, + { + "day": 3, + "flight": "AF015", + "utc": "07:05:00" + }, + { + "day": 4, + "flight": "AF213", + "utc": "22:43:00" + }, + { + "day": 5, + "flight": "AF732", + "utc": "03:12:00" + }, + { + "day": 5, + "flight": "AF304", + "utc": "08:21:00" + }, + { + "day": 6, + "flight": "AF274", + "utc": "12:07:00" + }, + { + "day": 6, + "flight": "AF177", + "utc": "19:29:00" + }, + { + "day": 6, + "flight": "AF409", + "utc": "23:56:00" + }, + { + "day": 6, + "flight": "AF099", + "utc": "07:45:00" + }, + { + "day": 6, + "flight": "AF848", + "utc": "12:34:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "SVQ", + "distance": 922.9469580316244, + "equipment": "319", + "id": 9996, + "schedule": [ + { + "day": 0, + "flight": "AF720", + "utc": "10:48:00" + }, + { + "day": 0, + "flight": "AF932", + "utc": "22:03:00" + }, + { + "day": 0, + "flight": "AF292", + "utc": "20:49:00" + }, + { + "day": 1, + "flight": "AF080", + "utc": "09:57:00" + }, + { + "day": 1, + "flight": "AF668", + "utc": "23:52:00" + }, + { + "day": 1, + "flight": "AF713", + "utc": "04:58:00" + }, + { + "day": 1, + "flight": "AF490", + "utc": "13:37:00" + }, + { + "day": 1, + "flight": "AF809", + "utc": "01:49:00" + }, + { + "day": 2, + "flight": "AF203", + "utc": "16:09:00" + }, + { + "day": 2, + "flight": "AF329", + "utc": "19:59:00" + }, + { + "day": 2, + "flight": "AF875", + "utc": "15:10:00" + }, + { + "day": 3, + "flight": "AF757", + "utc": "12:26:00" + }, + { + "day": 3, + "flight": "AF350", + "utc": "13:33:00" + }, + { + "day": 3, + "flight": "AF530", + "utc": "21:25:00" + }, + { + "day": 3, + "flight": "AF793", + "utc": "15:05:00" + }, + { + "day": 3, + "flight": "AF124", + "utc": "23:40:00" + }, + { + "day": 4, + "flight": "AF959", + "utc": "07:46:00" + }, + { + "day": 4, + "flight": "AF363", + "utc": "01:02:00" + }, + { + "day": 5, + "flight": "AF816", + "utc": "10:35:00" + }, + { + "day": 6, + "flight": "AF918", + "utc": "23:43:00" + }, + { + "day": 6, + "flight": "AF600", + "utc": "02:43:00" + }, + { + "day": 6, + "flight": "AF072", + "utc": "21:29:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "SXB", + "distance": 728.4867234220715, + "equipment": "319 320", + "id": 9997, + "schedule": [ + { + "day": 0, + "flight": "AF998", + "utc": "19:19:00" + }, + { + "day": 0, + "flight": "AF527", + "utc": "21:15:00" + }, + { + "day": 0, + "flight": "AF043", + "utc": "12:21:00" + }, + { + "day": 0, + "flight": "AF783", + "utc": "03:06:00" + }, + { + "day": 0, + "flight": "AF947", + "utc": "11:16:00" + }, + { + "day": 1, + "flight": "AF339", + "utc": "22:50:00" + }, + { + "day": 1, + "flight": "AF399", + "utc": "23:32:00" + }, + { + "day": 1, + "flight": "AF327", + "utc": "00:17:00" + }, + { + "day": 1, + "flight": "AF658", + "utc": "20:23:00" + }, + { + "day": 1, + "flight": "AF307", + "utc": "04:54:00" + }, + { + "day": 2, + "flight": "AF521", + "utc": "06:47:00" + }, + { + "day": 2, + "flight": "AF687", + "utc": "12:12:00" + }, + { + "day": 3, + "flight": "AF258", + "utc": "23:32:00" + }, + { + "day": 3, + "flight": "AF265", + "utc": "07:55:00" + }, + { + "day": 3, + "flight": "AF284", + "utc": "12:10:00" + }, + { + "day": 3, + "flight": "AF532", + "utc": "14:27:00" + }, + { + "day": 3, + "flight": "AF916", + "utc": "06:00:00" + }, + { + "day": 4, + "flight": "AF399", + "utc": "17:38:00" + }, + { + "day": 4, + "flight": "AF805", + "utc": "05:59:00" + }, + { + "day": 5, + "flight": "AF657", + "utc": "13:08:00" + }, + { + "day": 5, + "flight": "AF361", + "utc": "12:44:00" + }, + { + "day": 6, + "flight": "AF659", + "utc": "07:14:00" + }, + { + "day": 6, + "flight": "AF096", + "utc": "06:33:00" + }, + { + "day": 6, + "flight": "AF289", + "utc": "01:31:00" + }, + { + "day": 6, + "flight": "AF338", + "utc": "19:03:00" + }, + { + "day": 6, + "flight": "AF985", + "utc": "07:42:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" + }, + { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "VCE", + "distance": 894.3253403650848, + "equipment": "319 320", + "id": 9998, + "schedule": [ + { + "day": 0, + "flight": "AF396", + "utc": "14:33:00" + }, + { + "day": 0, + "flight": "AF180", + "utc": "02:02:00" + }, + { + "day": 0, + "flight": "AF752", + "utc": "06:07:00" + }, + { + "day": 1, + "flight": "AF686", + "utc": "09:35:00" + }, + { + "day": 1, + "flight": "AF614", + "utc": "00:48:00" + }, + { + "day": 1, + "flight": "AF443", + "utc": "11:54:00" + }, + { + "day": 1, + "flight": "AF125", + "utc": "15:34:00" + }, + { + "day": 2, + "flight": "AF045", + "utc": "20:49:00" + }, + { + "day": 2, + "flight": "AF430", + "utc": "22:18:00" + }, + { + "day": 2, + "flight": "AF068", + "utc": "05:24:00" + }, + { + "day": 2, + "flight": "AF945", + "utc": "08:23:00" + }, + { + "day": 2, + "flight": "AF949", + "utc": "05:19:00" + }, + { + "day": 3, + "flight": "AF249", + "utc": "15:48:00" + }, + { + "day": 3, + "flight": "AF468", + "utc": "09:43:00" + }, + { + "day": 4, + "flight": "AF966", + "utc": "00:15:00" + }, + { + "day": 4, + "flight": "AF461", + "utc": "16:58:00" + }, + { + "day": 5, + "flight": "AF993", + "utc": "12:09:00" + }, + { + "day": 5, + "flight": "AF790", + "utc": "04:27:00" + }, + { + "day": 5, + "flight": "AF370", + "utc": "01:25:00" + }, + { + "day": 5, + "flight": "AF861", + "utc": "21:37:00" + }, + { + "day": 5, + "flight": "AF480", + "utc": "05:17:00" + }, + { + "day": 6, + "flight": "AF733", + "utc": "04:13:00" + }, + { + "day": 6, + "flight": "AF308", + "utc": "01:08:00" + }, + { + "day": 6, + "flight": "AF063", + "utc": "04:55:00" + }, + { + "day": 6, + "flight": "AF257", + "utc": "17:21:00" + }, + { + "day": 6, + "flight": "AF531", + "utc": "13:24:00" + } + ], + "sourceairport": "TLS", + "stops": 0, + "type": "route" +// tag::extract[] + } + ] + }, + { + "a": { + "airportname": "Francazal", + "city": "Toulouse", + "country": "France", + "faa": null, + "geo": { + "alt": 535, + "lat": 43.545555, + "lon": 1.3675 + }, + "icao": "LFBF", + "id": 1266, + "type": "airport", + "tz": "Europe/Paris" + }, + "r": [] // <.> + }, + { + "a": { + "airportname": "Lasbordes", + "city": "Toulouse", + "country": "France", + "faa": null, + "geo": { + "alt": 459, + "lat": 43.586113, + "lon": 1.499167 + }, + "icao": "LFCL", + "id": 1286, + "type": "airport", + "tz": "Europe/Paris" + }, + "r": [] + } +] +// end::extract[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-nest-left.n1ql b/modules/n1ql/examples/select/ansi-nest-left.n1ql new file mode 100644 index 000000000..8ebe20a16 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest-left.n1ql @@ -0,0 +1,6 @@ +SELECT * +FROM airport a + LEFT NEST route r + ON a.faa = r.sourceairport +WHERE a.city = "Toulouse" +ORDER BY a.airportname; \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-nest.jsonc b/modules/n1ql/examples/select/ansi-nest.jsonc new file mode 100644 index 000000000..894875a61 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest.jsonc @@ -0,0 +1,17 @@ +[ + { + "airline": "B6", + "equipment": "320", + "stops": 0 + }, + { + "airline": "UA", + "equipment": "752 753 738 739 319 320", + "stops": 0 + }, + { + "airline": "VX", + "equipment": "320", + "stops": 0 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ansi-nest.n1ql b/modules/n1ql/examples/select/ansi-nest.n1ql new file mode 100644 index 000000000..b433e1163 --- /dev/null +++ b/modules/n1ql/examples/select/ansi-nest.n1ql @@ -0,0 +1,6 @@ +SELECT r.airline, r.equipment, r.stops +FROM `travel-sample`.inventory.route r + NEST `travel-sample`.inventory.airline a + ON r.airlineid = META(a).id +WHERE r.sourceairport = "SFO" +AND r.destinationairport = "BOS"; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-as-subclause.jsonc b/modules/n1ql/examples/select/group-as-subclause.jsonc new file mode 100644 index 000000000..eeab3d0b9 --- /dev/null +++ b/modules/n1ql/examples/select/group-as-subclause.jsonc @@ -0,0 +1,44 @@ +[ + { + "country": "United States", + "count": 127, + "airlines": [ + { + "id": 10, + "name": "40-Mile Air" + }, + { + "id": 10123, + "name": "Texas Wings" + } + ] + }, + { + "country": "France", + "count": 21, + "airlines": [ + { + "id": 1191, + "name": "Air Austral" + }, + { + "id": 1203, + "name": "Airlinair" + } + ] + }, + { + "country": "United Kingdom", + "count": 39, + "airlines": [ + { + "id": 10642, + "name": "Jc royal.britannica" + }, + { + "id": 112, + "name": "Astraeus" + } + ] + } + ] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-as-subclause.n1ql b/modules/n1ql/examples/select/group-as-subclause.n1ql new file mode 100644 index 000000000..bc6151a2c --- /dev/null +++ b/modules/n1ql/examples/select/group-as-subclause.n1ql @@ -0,0 +1,8 @@ +SELECT country, COUNT(*) as count, + (SELECT g1.airline.name, g1.airline.id + FROM g g1 + LIMIT 2) +AS airlines +FROM airline +GROUP BY country +GROUP AS g; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-as.jsonc b/modules/n1ql/examples/select/group-as.jsonc new file mode 100644 index 000000000..2b7ddae81 --- /dev/null +++ b/modules/n1ql/examples/select/group-as.jsonc @@ -0,0 +1,89 @@ +[ + { + "country": "United Kingdom", + "count": 39, + "group_docs": [ + { + "a": { + "id": 10642, + "type": "airline", + "name": "Jc royal.britannica", + "iata": null, + "icao": "JRB", + "callsign": null, + "country": "United Kingdom" + } + }, + { + "a": { + "id": 112, + "type": "airline", + "name": "Astraeus", + "iata": "5W", + "icao": "AEU", + "callsign": "FLYSTAR", + "country": "United Kingdom" + } + }, + ... + ] + }, + { + "country": "United States", + "count": 127, + "group_docs": [ + { + "a": { + "id": 10, + "type": "airline", + "name": "40-Mile Air", + "iata": "Q5", + "icao": "MLA", + "callsign": "MILE-AIR", + "country": "United States" + } + }, + { + "a": { + "id": 10123, + "type": "airline", + "name": "Texas Wings", + "iata": "TQ", + "icao": "TXW", + "callsign": "TXW", + "country": "United States" + } + }, + ... + ] + }, + { + "country": "France", + "count": 17, + "group_docs": [ + { + "a": { + "id": 1191, + "type": "airline", + "name": "Air Austral", + "iata": "UU", + "icao": "REU", + "callsign": "REUNION", + "country": "France" + } + }, + { + "a": { + "id": 1203, + "type": "airline", + "name": "Airlinair", + "iata": "A5", + "icao": "RLA", + "callsign": "AIRLINAIR", + "country": "France" + } + }, + ... + ] + } + ] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-as.n1ql b/modules/n1ql/examples/select/group-as.n1ql new file mode 100644 index 000000000..47b4f9bee --- /dev/null +++ b/modules/n1ql/examples/select/group-as.n1ql @@ -0,0 +1,4 @@ +SELECT country, COUNT(*) as count, g as group_docs +FROM airline a +GROUP BY country +GROUP AS g; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-alias.jsonc b/modules/n1ql/examples/select/group-by-alias.jsonc new file mode 100644 index 000000000..c5eea90b3 --- /dev/null +++ b/modules/n1ql/examples/select/group-by-alias.jsonc @@ -0,0 +1,10 @@ +[ + { + "Hemisphere": "East", + "LandmarkCount": 459 + }, + { + "Hemisphere": "West", + "LandmarkCount": 3885 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-alias.n1ql b/modules/n1ql/examples/select/group-by-alias.n1ql new file mode 100644 index 000000000..721433ab8 --- /dev/null +++ b/modules/n1ql/examples/select/group-by-alias.n1ql @@ -0,0 +1,6 @@ +SELECT Hemisphere, COUNT(DISTINCT name) AS LandmarkCount +FROM landmark AS l +GROUP BY CASE + WHEN l.geo.lon <0 THEN "West" + ELSE "East" +END AS Hemisphere; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-compare-having.n1ql b/modules/n1ql/examples/select/group-by-compare-having.n1ql new file mode 100644 index 000000000..364ce715b --- /dev/null +++ b/modules/n1ql/examples/select/group-by-compare-having.n1ql @@ -0,0 +1,5 @@ +SELECT city City, COUNT(DISTINCT name) LandmarkCount +FROM landmark +GROUP BY city +HAVING city > "S" +ORDER BY city; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-compare-where.n1ql b/modules/n1ql/examples/select/group-by-compare-where.n1ql new file mode 100644 index 000000000..c4f352e9a --- /dev/null +++ b/modules/n1ql/examples/select/group-by-compare-where.n1ql @@ -0,0 +1,5 @@ +SELECT city City, COUNT(DISTINCT name) LandmarkCount +FROM landmark +WHERE city > "S" +GROUP BY city +ORDER BY city; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-compare.jsonc b/modules/n1ql/examples/select/group-by-compare.jsonc new file mode 100644 index 000000000..cf77ade5c --- /dev/null +++ b/modules/n1ql/examples/select/group-by-compare.jsonc @@ -0,0 +1,559 @@ +// tag::excerpt[] +[ + { + "City": "Sacramento", + "LandmarkCount": 2 + }, + { + "City": "Saint Albans", + "LandmarkCount": 5 + }, + { + "City": "Saint Andrews", + "LandmarkCount": 13 + }, + { + "City": "Saint Annes Head", + "LandmarkCount": 1 + }, +// end::excerpt[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "City": "Saint David's", + "LandmarkCount": 1 + }, + { + "City": "Saint Helena", + "LandmarkCount": 1 + }, + { + "City": "Saint Marys Island", + "LandmarkCount": 1 + }, + { + "City": "Saint-Claude", + "LandmarkCount": 1 + }, + { + "City": "Saint-Denis", + "LandmarkCount": 1 + }, + { + "City": "Saint-Florent", + "LandmarkCount": 4 + }, + { + "City": "Saint-Marcel-sur-Aude", + "LandmarkCount": 1 + }, + { + "City": "Saint-Raphaël", + "LandmarkCount": 1 + }, + { + "City": "Saint-Waast-la-Vallée", + "LandmarkCount": 1 + }, + { + "City": "Sale", + "LandmarkCount": 5 + }, + { + "City": "Salisbury", + "LandmarkCount": 3 + }, + { + "City": "San Diego", + "LandmarkCount": 197 + }, + { + "City": "San Francisco", + "LandmarkCount": 797 + }, + { + "City": "San Gabriel", + "LandmarkCount": 2 + }, + { + "City": "San Jose", + "LandmarkCount": 1 + }, + { + "City": "San Juan Bautista", + "LandmarkCount": 1 + }, + { + "City": "San Juan Capistrano", + "LandmarkCount": 2 + }, + { + "City": "San Luis Obispo", + "LandmarkCount": 1 + }, + { + "City": "San Marcos", + "LandmarkCount": 1 + }, + { + "City": "San Marino", + "LandmarkCount": 1 + }, + { + "City": "San Miguel", + "LandmarkCount": 2 + }, + { + "City": "San Rafael", + "LandmarkCount": 1 + }, + { + "City": "Sannerville", + "LandmarkCount": 1 + }, + { + "City": "Santa Barbara", + "LandmarkCount": 53 + }, + { + "City": "Santa Clara", + "LandmarkCount": 1 + }, + { + "City": "Santa Cruz", + "LandmarkCount": 1 + }, + { + "City": "Santa Margarita", + "LandmarkCount": 3 + }, + { + "City": "Santa Monica", + "LandmarkCount": 38 + }, + { + "City": "Santa Rosa", + "LandmarkCount": 5 + }, + { + "City": "Sarratt", + "LandmarkCount": 1 + }, + { + "City": "Saundersfoot", + "LandmarkCount": 2 + }, + { + "City": "Scarinish", + "LandmarkCount": 1 + }, + { + "City": "Scottish Borders", + "LandmarkCount": 1 + }, + { + "City": "Sebastopol", + "LandmarkCount": 3 + }, + { + "City": "Sedbury", + "LandmarkCount": 1 + }, + { + "City": "Semur-en-Auxois", + "LandmarkCount": 2 + }, + { + "City": "Septmoncel", + "LandmarkCount": 1 + }, + { + "City": "Shardlow", + "LandmarkCount": 2 + }, + { + "City": "Shurdington", + "LandmarkCount": 2 + }, + { + "City": "Sibsey", + "LandmarkCount": 1 + }, + { + "City": "Simi Valley", + "LandmarkCount": 1 + }, + { + "City": "Smiddy Closs", + "LandmarkCount": 1 + }, + { + "City": "Soledad", + "LandmarkCount": 2 + }, + { + "City": "Solvang", + "LandmarkCount": 1 + }, + { + "City": "Somerset", + "LandmarkCount": 3 + }, + { + "City": "Sonoma", + "LandmarkCount": 80 + }, + { + "City": "South Lanarkshire", + "LandmarkCount": 4 + }, + { + "City": "South Shields", + "LandmarkCount": 3 + }, + { + "City": "Southampton", + "LandmarkCount": 2 + }, + { + "City": "Southend-on-Sea", + "LandmarkCount": 1 + }, + { + "City": "Speke", + "LandmarkCount": 1 + }, + { + "City": "Stable Yd", + "LandmarkCount": 1 + }, + { + "City": "Stanmore", + "LandmarkCount": 1 + }, + { + "City": "Station Precinct", + "LandmarkCount": 1 + }, + { + "City": "Stirling", + "LandmarkCount": 7 + }, + { + "City": "Stockport", + "LandmarkCount": 15 + }, + { + "City": "Stornoway", + "LandmarkCount": 4 + }, + { + "City": "Strathpeffer", + "LandmarkCount": 7 + }, + { + "City": "Suffolk", + "LandmarkCount": 1 + }, + { + "City": "Suisun City", + "LandmarkCount": 1 + }, + { + "City": "Sunderland", + "LandmarkCount": 3 + }, + { + "City": "Surrey", + "LandmarkCount": 1 + }, + { + "City": "Sutton Coldfield", + "LandmarkCount": 1 + }, + { + "City": "Swansea", + "LandmarkCount": 1 + }, + { + "City": "Swindon", + "LandmarkCount": 5 + }, + { + "City": "Tadcaster", + "LandmarkCount": 1 + }, + { + "City": "Tamworth", + "LandmarkCount": 1 + }, + { + "City": "Tattershall", + "LandmarkCount": 2 + }, + { + "City": "Tenby", + "LandmarkCount": 5 + }, + { + "City": "The Castle", + "LandmarkCount": 1 + }, + { + "City": "The Mumbles", + "LandmarkCount": 2 + }, + { + "City": "Thousand Oaks", + "LandmarkCount": 10 + }, + { + "City": "Thurstaston", + "LandmarkCount": 1 + }, + { + "City": "Timperley", + "LandmarkCount": 7 + }, + { + "City": "Tintagel", + "LandmarkCount": 1 + }, + { + "City": "Tintern", + "LandmarkCount": 1 + }, + { + "City": "Tobermory", + "LandmarkCount": 2 + }, + { + "City": "Topanga", + "LandmarkCount": 5 + }, + { + "City": "Totnes", + "LandmarkCount": 2 + }, + { + "City": "Tresaith", + "LandmarkCount": 1 + }, + { + "City": "Tuolumne County", + "LandmarkCount": 5 + }, + { + "City": "Twentynine Palms", + "LandmarkCount": 1 + }, + { + "City": "Twickenham", + "LandmarkCount": 1 + }, + { + "City": "Ty'n Y Cei", + "LandmarkCount": 1 + }, + { + "City": "Tyne and Wear", + "LandmarkCount": 4 + }, + { + "City": "Tynemouth", + "LandmarkCount": 1 + }, + { + "City": "Tywyn", + "LandmarkCount": 1 + }, + { + "City": "Ulbster", + "LandmarkCount": 1 + }, + { + "City": "Upminster", + "LandmarkCount": 4 + }, + { + "City": "Urville", + "LandmarkCount": 1 + }, + { + "City": "Vaison-la-Romaine", + "LandmarkCount": 9 + }, + { + "City": "Vale of Glamorgan", + "LandmarkCount": 2 + }, + { + "City": "Vallejo", + "LandmarkCount": 2 + }, + { + "City": "Ventura", + "LandmarkCount": 6 + }, + { + "City": "Ventura County", + "LandmarkCount": 1 + }, + { + "City": "Verdun", + "LandmarkCount": 2 + }, + { + "City": "Verzeille", + "LandmarkCount": 1 + }, + { + "City": "Vire", + "LandmarkCount": 1 + }, + { + "City": "Visalia", + "LandmarkCount": 1 + }, + { + "City": "Vittel", + "LandmarkCount": 1 + }, + { + "City": "Walmer", + "LandmarkCount": 2 + }, + { + "City": "Walnut Creek", + "LandmarkCount": 1 + }, + { + "City": "Waltham Cross", + "LandmarkCount": 1 + }, + { + "City": "Warrington", + "LandmarkCount": 2 + }, + { + "City": "Washington", + "LandmarkCount": 2 + }, + { + "City": "Watford", + "LandmarkCount": 3 + }, + { + "City": "Watsonville", + "LandmarkCount": 1 + }, + { + "City": "Welshpool", + "LandmarkCount": 1 + }, + { + "City": "Wembley", + "LandmarkCount": 1 + }, + { + "City": "West Berkshire", + "LandmarkCount": 1 + }, + { + "City": "West Bromwich", + "LandmarkCount": 1 + }, + { + "City": "West High Down", + "LandmarkCount": 2 + }, + { + "City": "West Hollywood", + "LandmarkCount": 20 + }, + { + "City": "West Yorkshire", + "LandmarkCount": 2 + }, + { + "City": "Westlake Village", + "LandmarkCount": 1 + }, + { + "City": "Weston-super-Mare", + "LandmarkCount": 18 + }, + { + "City": "Whatstandwell", + "LandmarkCount": 1 + }, + { + "City": "Whins of Milton", + "LandmarkCount": 1 + }, + { + "City": "Whitley Bay", + "LandmarkCount": 1 + }, + { + "City": "Whittier", + "LandmarkCount": 23 + }, + { + "City": "Wick", + "LandmarkCount": 1 + }, + { + "City": "Wigan", + "LandmarkCount": 1 + }, + { + "City": "Wiltshire", + "LandmarkCount": 1 + }, + { + "City": "Winchester", + "LandmarkCount": 2 + }, + { + "City": "Windsor", + "LandmarkCount": 2 + }, + { + "City": "Wirksworth", + "LandmarkCount": 3 + }, + { + "City": "Wishaw", + "LandmarkCount": 1 + }, + { + "City": "Wolverhampton", + "LandmarkCount": 1 + }, + { + "City": "Worcester", + "LandmarkCount": 1 + }, + { + "City": "Wrexham", + "LandmarkCount": 2 + }, + { + "City": "York", + "LandmarkCount": 4 + }, + { + "City": "Yosemite Valley", + "LandmarkCount": 2 + }, + { + "City": "Épinal", + "LandmarkCount": 2 + }, + { + "City": "Évreux", + "LandmarkCount": 1 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-having.jsonc b/modules/n1ql/examples/select/group-by-having.jsonc new file mode 100644 index 000000000..282f99799 --- /dev/null +++ b/modules/n1ql/examples/select/group-by-having.jsonc @@ -0,0 +1,18 @@ +[ + { + "City": "London", + "LandmarkCount": 443 + }, + { + "City": "Los Angeles", + "LandmarkCount": 284 + }, + { + "City": "San Francisco", + "LandmarkCount": 797 + }, + { + "City": "San Diego", + "LandmarkCount": 197 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-having.n1ql b/modules/n1ql/examples/select/group-by-having.n1ql new file mode 100644 index 000000000..faecee7a1 --- /dev/null +++ b/modules/n1ql/examples/select/group-by-having.n1ql @@ -0,0 +1,4 @@ +SELECT city City, COUNT(DISTINCT name) LandmarkCount +FROM landmark +GROUP BY city +HAVING COUNT(DISTINCT name) > 180; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-letting.jsonc b/modules/n1ql/examples/select/group-by-letting.jsonc new file mode 100644 index 000000000..29ee4b4b1 --- /dev/null +++ b/modules/n1ql/examples/select/group-by-letting.jsonc @@ -0,0 +1,10 @@ +[ + { + "City": "London", + "LandmarkCount": 443 + }, + { + "City": "San Francisco", + "LandmarkCount": 797 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by-letting.n1ql b/modules/n1ql/examples/select/group-by-letting.n1ql new file mode 100644 index 000000000..8750790a7 --- /dev/null +++ b/modules/n1ql/examples/select/group-by-letting.n1ql @@ -0,0 +1,5 @@ +SELECT city City, COUNT(DISTINCT name) LandmarkCount +FROM landmark +GROUP BY city +LETTING MinimumThingsToSee = 400 +HAVING COUNT(DISTINCT name) > MinimumThingsToSee; \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by.jsonc b/modules/n1ql/examples/select/group-by.jsonc new file mode 100644 index 000000000..c203d5b9e --- /dev/null +++ b/modules/n1ql/examples/select/group-by.jsonc @@ -0,0 +1,18 @@ +[ + { + "City": "San Francisco", + "LandmarkCount": 797 + }, + { + "City": "London", + "LandmarkCount": 443 + }, + { + "City": "Los Angeles", + "LandmarkCount": 284 + }, + { + "City": "San Diego", + "LandmarkCount": 197 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/group-by.n1ql b/modules/n1ql/examples/select/group-by.n1ql new file mode 100644 index 000000000..788e6ca81 --- /dev/null +++ b/modules/n1ql/examples/select/group-by.n1ql @@ -0,0 +1,5 @@ +SELECT city City, COUNT(DISTINCT name) LandmarkCount +FROM landmark +GROUP BY city +ORDER BY LandmarkCount DESC +LIMIT 4; \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-hint.jsonc b/modules/n1ql/examples/select/index-hint.jsonc new file mode 100644 index 000000000..717489cc1 --- /dev/null +++ b/modules/n1ql/examples/select/index-hint.jsonc @@ -0,0 +1,119 @@ +{ + "cardinality": 1, + "cost": 25.48328348473815, + "optimizer_hints": { + "hints_followed": [ + "INDEX(route def_inventory_route_route_src_dst_day)" + ] + }, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "limit": "1", + "optimizer_estimates": { + "cardinality": 1681.2723543436066, + "cost": 395.71744847285015, + "fr_cost": 12.220147704229976, + "size": 11 + }, +// tag::index[] + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "def_inventory_route_route_src_dst_day", +// end::index[] + "index_id": "e0105bdd794dda39", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1743, + "cost": 354.17696421953406, + "fr_cost": 12.196314953654351, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "index_key": "`sourceairport`", + "low": "\"SFO\"" + } + ] + } + ], + "using": "gsi" + } + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1681.2723543436066, + "cost": 2411.1846820111814, + "fr_cost": 25.411785233011273, + "size": 568 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`route`.`sourceairport`) = \"SFO\")", + "optimizer_estimates": { + "cardinality": 1681.2723543436066, + "cost": 2451.254026681948, + "fr_cost": 25.435617983586898, + "size": 568 + } + }, + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 1681.2723543436066, + "cost": 2491.3233713527143, + "fr_cost": 25.459450734162523, + "size": 568 + }, + "result_terms": [ + { + "expr": "(`route`.`id`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "1", + "optimizer_estimates": { + "cardinality": 1, + "cost": 25.48328348473815, + "fr_cost": 25.48328348473815, + "size": 568 + } + } + ] + }, + "text": "\nSELECT /*+ INDEX (route def_inventory_route_route_src_dst_day) */ id -- <.>\nFROM `travel-sample`.inventory.route -- <.>\nWHERE sourceairport = \"SFO\"\nLIMIT 1;" +} \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-hint.n1ql b/modules/n1ql/examples/select/index-hint.n1ql new file mode 100644 index 000000000..48724cd02 --- /dev/null +++ b/modules/n1ql/examples/select/index-hint.n1ql @@ -0,0 +1,10 @@ +UPDATE STATISTICS FOR route +INDEX (def_inventory_route_route_src_dst_day, def_inventory_route_sourceairport); + +EXPLAIN +/* tag::query[] */ +SELECT /*+ INDEX (route def_inventory_route_route_src_dst_day) */ id -- <.> +FROM route -- <.> +WHERE sourceairport = "SFO" +LIMIT 1; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-join.jsonc b/modules/n1ql/examples/select/index-join.jsonc new file mode 100644 index 000000000..f39013121 --- /dev/null +++ b/modules/n1ql/examples/select/index-join.jsonc @@ -0,0 +1,139 @@ +// tag::extract[] +[ + { + "name": "JetBlue Airways", + "schedule": [ + { + "day": 0, + "flight": "B6076", + "utc": "10:15:00" + }, + { + "day": 0, + "flight": "B6321", + "utc": "00:06:00" + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "day": 1, + "flight": "B6536", + "utc": "22:45:00" + }, + { + "day": 1, + "flight": "B6194", + "utc": "00:51:00" + }, + { + "day": 2, + "flight": "B6918", + "utc": "23:45:00" + }, + { + "day": 2, + "flight": "B6451", + "utc": "18:09:00" + }, + { + "day": 2, + "flight": "B6868", + "utc": "22:04:00" + }, + { + "day": 2, + "flight": "B6621", + "utc": "11:04:00" + }, + { + "day": 3, + "flight": "B6015", + "utc": "16:59:00" + }, + { + "day": 3, + "flight": "B6668", + "utc": "07:22:00" + }, + { + "day": 3, + "flight": "B6188", + "utc": "01:41:00" + }, + { + "day": 3, + "flight": "B6215", + "utc": "19:35:00" + }, + { + "day": 4, + "flight": "B6371", + "utc": "21:37:00" + }, + { + "day": 4, + "flight": "B6024", + "utc": "10:24:00" + }, + { + "day": 4, + "flight": "B6749", + "utc": "01:12:00" + }, + { + "day": 4, + "flight": "B6170", + "utc": "01:14:00" + }, + { + "day": 5, + "flight": "B6613", + "utc": "08:59:00" + }, + { + "day": 5, + "flight": "B6761", + "utc": "15:24:00" + }, + { + "day": 5, + "flight": "B6162", + "utc": "02:42:00" + }, + { + "day": 5, + "flight": "B6341", + "utc": "21:26:00" + }, + { + "day": 5, + "flight": "B6347", + "utc": "08:43:00" + }, + { + "day": 6, + "flight": "B6481", + "utc": "22:08:00" + }, + { + "day": 6, + "flight": "B6549", + "utc": "21:48:00" + }, + { + "day": 6, + "flight": "B6994", + "utc": "11:30:00" + }, + { + "day": 6, + "flight": "B6892", + "utc": "13:27:00" + } +// tag::extract[] + ] + } +] +// end::extract[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-join.n1ql b/modules/n1ql/examples/select/index-join.n1ql new file mode 100644 index 000000000..241a06752 --- /dev/null +++ b/modules/n1ql/examples/select/index-join.n1ql @@ -0,0 +1,24 @@ +-- tag::lookup[] +SELECT DISTINCT route.destinationairport, route.stops, route.airline, + airline.name, airline.callsign +FROM route + JOIN airline + ON KEYS route.airlineid +WHERE airline.icao = "SWA" +LIMIT 4; +-- end::lookup[] + +-- tag::index-req[] +CREATE INDEX route_airlineid ON route(airlineid); +-- end::index-req[] + +-- tag::index-opt[] +CREATE INDEX airline_icao ON airline(icao); +-- end::index-opt[] + +-- tag::query[] +SELECT * FROM airline + JOIN route + ON KEY route.airlineid FOR airline +WHERE airline.icao = "SWA"; +-- end::query[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-legacy.n1ql b/modules/n1ql/examples/select/index-legacy.n1ql new file mode 100644 index 000000000..bb783a216 --- /dev/null +++ b/modules/n1ql/examples/select/index-legacy.n1ql @@ -0,0 +1,9 @@ +UPDATE STATISTICS FOR route +INDEX (def_inventory_route_route_src_dst_day, def_inventory_route_sourceairport); + +/* tag::query[] */ +SELECT id FROM route +USE INDEX (def_inventory_route_route_src_dst_day USING GSI) +WHERE sourceairport = "SFO" +LIMIT 1; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-nest.jsonc b/modules/n1ql/examples/select/index-nest.jsonc new file mode 100644 index 000000000..c3924ca12 --- /dev/null +++ b/modules/n1ql/examples/select/index-nest.jsonc @@ -0,0 +1,253 @@ +// tag::extract[] +[ + { + "aline": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + }, + "rte": [ + { + "airline": "Q5", + "airlineid": "airline_10", + "destinationairport": "FAI", + "distance": 118.20183585107631, + "equipment": "CNA", + "id": 46587, + "schedule": [ +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "day": 0, + "flight": "Q5492", + "utc": "17:00:00" + }, + { + "day": 0, + "flight": "Q5357", + "utc": "09:44:00" + }, + { + "day": 0, + "flight": "Q5873", + "utc": "00:01:00" + }, + { + "day": 1, + "flight": "Q5171", + "utc": "00:59:00" + }, + { + "day": 1, + "flight": "Q5047", + "utc": "10:57:00" + }, + { + "day": 1, + "flight": "Q5889", + "utc": "14:51:00" + }, + { + "day": 1, + "flight": "Q5272", + "utc": "18:36:00" + }, + { + "day": 2, + "flight": "Q5673", + "utc": "21:30:00" + }, + { + "day": 3, + "flight": "Q5381", + "utc": "20:01:00" + }, + { + "day": 4, + "flight": "Q5261", + "utc": "18:37:00" + }, + { + "day": 5, + "flight": "Q5755", + "utc": "23:43:00" + }, + { + "day": 5, + "flight": "Q5544", + "utc": "16:04:00" + }, + { + "day": 6, + "flight": "Q5400", + "utc": "10:46:00" + }, + { + "day": 6, + "flight": "Q5963", + "utc": "13:53:00" + }, + { + "day": 6, + "flight": "Q5195", + "utc": "03:03:00" + }, + { + "day": 6, + "flight": "Q5653", + "utc": "22:58:00" + } +// tag::extract[] + ], + "sourceairport": "HKB", + "stops": 0, + "type": "route" + }, + { + "airline": "Q5", + "airlineid": "airline_10", + "destinationairport": "HKB", + "distance": 118.20183585107631, + "equipment": "CNA", + "id": 46586, + "schedule": [ +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "day": 0, + "flight": "Q5188", + "utc": "12:40:00" + }, + { + "day": 0, + "flight": "Q5630", + "utc": "21:53:00" + }, + { + "day": 0, + "flight": "Q5530", + "utc": "07:47:00" + }, + { + "day": 0, + "flight": "Q5132", + "utc": "01:10:00" + }, + { + "day": 0, + "flight": "Q5746", + "utc": "20:11:00" + }, + { + "day": 1, + "flight": "Q5413", + "utc": "08:07:00" + }, + { + "day": 2, + "flight": "Q5263", + "utc": "17:39:00" + }, + { + "day": 2, + "flight": "Q5564", + "utc": "01:55:00" + }, + { + "day": 2, + "flight": "Q5970", + "utc": "00:09:00" + }, + { + "day": 2, + "flight": "Q5295", + "utc": "21:24:00" + }, + { + "day": 2, + "flight": "Q5051", + "utc": "04:41:00" + }, + { + "day": 3, + "flight": "Q5023", + "utc": "00:16:00" + }, + { + "day": 3, + "flight": "Q5554", + "utc": "11:45:00" + }, + { + "day": 3, + "flight": "Q5619", + "utc": "22:22:00" + }, + { + "day": 4, + "flight": "Q5279", + "utc": "23:19:00" + }, + { + "day": 4, + "flight": "Q5652", + "utc": "13:35:00" + }, + { + "day": 4, + "flight": "Q5631", + "utc": "17:53:00" + }, + { + "day": 4, + "flight": "Q5105", + "utc": "21:54:00" + }, + { + "day": 5, + "flight": "Q5559", + "utc": "01:19:00" + }, + { + "day": 5, + "flight": "Q5600", + "utc": "17:36:00" + }, + { + "day": 6, + "flight": "Q5854", + "utc": "22:59:00" + }, + { + "day": 6, + "flight": "Q5217", + "utc": "11:58:00" + }, + { + "day": 6, + "flight": "Q5756", + "utc": "06:32:00" + }, + { + "day": 6, + "flight": "Q5151", + "utc": "15:14:00" + } +// tag::extract[] + ], + "sourceairport": "FAI", + "stops": 0, + "type": "route" + } + ] + } +] +// end::extract[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-nest.n1ql b/modules/n1ql/examples/select/index-nest.n1ql new file mode 100644 index 000000000..86e26b325 --- /dev/null +++ b/modules/n1ql/examples/select/index-nest.n1ql @@ -0,0 +1,11 @@ +-- tag::index[] +CREATE INDEX route_airlineid ON route(airlineid); +-- end::index[] + +-- tag::query[] +SELECT * +FROM airline aline + INNER NEST route rte + ON KEY rte.airlineid FOR aline +LIMIT 1; +-- end::query[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-opt.jsonc b/modules/n1ql/examples/select/index-opt.jsonc new file mode 100644 index 000000000..b01754405 --- /dev/null +++ b/modules/n1ql/examples/select/index-opt.jsonc @@ -0,0 +1,105 @@ +{ + "cardinality": 1, + "cost": 25.484123541275103, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ +// tag::index[] + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "def_inventory_route_sourceairport", +// end::index[] + "index_id": "10962bf412f58e32", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "limit": "1", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 249, + "cost": 67.02595243096545, + "fr_cost": 12.22098776076693, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "index_key": "`sourceairport`", + "low": "\"SFO\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 249, + "cost": 375.7436970975088, + "fr_cost": 25.412625289548227, + "size": 568 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`route`.`sourceairport`) = \"SFO\")", + "optimizer_estimates": { + "cardinality": 249, + "cost": 381.67805199083966, + "fr_cost": 25.436458040123853, + "size": 568 + } + }, + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 249, + "cost": 387.6124068841705, + "fr_cost": 25.460290790699478, + "size": 568 + }, + "result_terms": [ + { + "expr": "(`route`.`id`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "1", + "optimizer_estimates": { + "cardinality": 1, + "cost": 25.484123541275103, + "fr_cost": 25.484123541275103, + "size": 568 + } + } + ] + }, + "text": "\nSELECT id -- <.>\nFROM `travel-sample`.inventory.route -- <.>\nWHERE sourceairport = \"SFO\"\nLIMIT 1;" +} \ No newline at end of file diff --git a/modules/n1ql/examples/select/index-opt.n1ql b/modules/n1ql/examples/select/index-opt.n1ql new file mode 100644 index 000000000..593e6e25d --- /dev/null +++ b/modules/n1ql/examples/select/index-opt.n1ql @@ -0,0 +1,10 @@ +UPDATE STATISTICS FOR route +INDEX (def_inventory_route_route_src_dst_day, def_inventory_route_sourceairport); + +EXPLAIN +/* tag::query[] */ +SELECT id +FROM route +WHERE sourceairport = "SFO" +LIMIT 1; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/limit-expr.n1ql b/modules/n1ql/examples/select/limit-expr.n1ql new file mode 100644 index 000000000..04d3517bc --- /dev/null +++ b/modules/n1ql/examples/select/limit-expr.n1ql @@ -0,0 +1,10 @@ +\SET -$page 0; +\SET -$results 2; + +/* tag::query[] */ +SELECT name, address, city, country, url +FROM hotel +WHERE vacancy = true +OFFSET $page * $results +LIMIT $results; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/limit-number.n1ql b/modules/n1ql/examples/select/limit-number.n1ql new file mode 100644 index 000000000..b51fb5715 --- /dev/null +++ b/modules/n1ql/examples/select/limit-number.n1ql @@ -0,0 +1,4 @@ +SELECT name, address, city, country, url +FROM hotel +WHERE vacancy = true +LIMIT 2; \ No newline at end of file diff --git a/modules/n1ql/examples/select/limit-result.jsonc b/modules/n1ql/examples/select/limit-result.jsonc new file mode 100644 index 000000000..40a26c893 --- /dev/null +++ b/modules/n1ql/examples/select/limit-result.jsonc @@ -0,0 +1,16 @@ +[ + { + "address": "Capstone Road, ME7 3JE", + "city": "Medway", + "country": "United Kingdom", + "name": "Medway Youth Hostel", + "url": "http://www.yha.org.uk" + }, + { + "address": "6 rue aux Juifs", + "city": "Giverny", + "country": "France", + "name": "The Robins", + "url": "http://givernyguesthouse.com/robin.htm" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/lookup-join-inner.jsonc b/modules/n1ql/examples/select/lookup-join-inner.jsonc new file mode 100644 index 000000000..a630d0ba4 --- /dev/null +++ b/modules/n1ql/examples/select/lookup-join-inner.jsonc @@ -0,0 +1,30 @@ +[ + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "AUS", + "name": "JetBlue Airways", + "stops": 0 + }, + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "BOS", + "name": "JetBlue Airways", + "stops": 0 + }, + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "DXB", + "name": "JetBlue Airways", + "stops": 0 + }, + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "FLL", + "name": "JetBlue Airways", + "stops": 0 + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/lookup-join-inner.n1ql b/modules/n1ql/examples/select/lookup-join-inner.n1ql new file mode 100644 index 000000000..4139449a4 --- /dev/null +++ b/modules/n1ql/examples/select/lookup-join-inner.n1ql @@ -0,0 +1,8 @@ +SELECT DISTINCT route.destinationairport, route.stops, route.airline, + airline.name, airline.callsign +FROM route + JOIN airline + ON KEYS route.airlineid +WHERE route.sourceairport = "SFO" +AND route.stops = 0 +LIMIT 4; \ No newline at end of file diff --git a/modules/n1ql/examples/select/lookup-join-left.jsonc b/modules/n1ql/examples/select/lookup-join-left.jsonc new file mode 100644 index 000000000..1c032e0ad --- /dev/null +++ b/modules/n1ql/examples/select/lookup-join-left.jsonc @@ -0,0 +1,34 @@ +[ + { + "airline": "AF", + "callsign": "AIRFRANS", + "destinationairport": "ATL", + "sourceairport": "SEA" + }, + { + "airline": "AM", + "destinationairport": "ATL", + "sourceairport": "SEA" + }, + { + "airline": "AS", + "destinationairport": "ATL", + "sourceairport": "SEA" + }, + { + "airline": "AZ", + "destinationairport": "ATL", + "sourceairport": "SEA" + }, + { + "airline": "DL", + "callsign": "DELTA", + "destinationairport": "ATL", + "sourceairport": "SEA" + }, + { + "airline": "KL", + "destinationairport": "ATL", + "sourceairport": "SEA" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/lookup-join-left.n1ql b/modules/n1ql/examples/select/lookup-join-left.n1ql new file mode 100644 index 000000000..d155b482c --- /dev/null +++ b/modules/n1ql/examples/select/lookup-join-left.n1ql @@ -0,0 +1,7 @@ +SELECT route.airline, route.sourceairport, route.destinationairport, + airline.callsign +FROM route + LEFT JOIN airline + ON KEYS route.airlineid +WHERE route.destinationairport = "ATL" + AND route.sourceairport = "SEA"; \ No newline at end of file diff --git a/modules/n1ql/examples/select/lookup-nest.jsonc b/modules/n1ql/examples/select/lookup-nest.jsonc new file mode 100644 index 000000000..83503a3d6 --- /dev/null +++ b/modules/n1ql/examples/select/lookup-nest.jsonc @@ -0,0 +1,150 @@ +// tag::extract[] +[ + { + "airline": [ + { + "callsign": "AIRFRANS", + "country": "France", + "iata": "AF", + "icao": "AFR", + "id": 137, + "name": "Air France", + "type": "airline" + } + ], + "route": { + "airline": "AF", + "airlineid": "airline_137", + "destinationairport": "MRS", + "distance": 2881.617376098415, + "equipment": "320", + "id": 10000, + "schedule": [ +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "day": 0, + "flight": "AF198", + "utc": "10:13:00" + }, + { + "day": 0, + "flight": "AF547", + "utc": "19:14:00" + }, + { + "day": 0, + "flight": "AF943", + "utc": "01:31:00" + }, + { + "day": 1, + "flight": "AF356", + "utc": "12:40:00" + }, + { + "day": 1, + "flight": "AF480", + "utc": "08:58:00" + }, + { + "day": 1, + "flight": "AF250", + "utc": "12:59:00" + }, + { + "day": 1, + "flight": "AF130", + "utc": "04:45:00" + }, + { + "day": 2, + "flight": "AF997", + "utc": "00:31:00" + }, + { + "day": 2, + "flight": "AF223", + "utc": "19:41:00" + }, + { + "day": 2, + "flight": "AF890", + "utc": "15:14:00" + }, + { + "day": 2, + "flight": "AF399", + "utc": "00:30:00" + }, + { + "day": 2, + "flight": "AF328", + "utc": "16:18:00" + }, + { + "day": 3, + "flight": "AF074", + "utc": "23:50:00" + }, + { + "day": 3, + "flight": "AF556", + "utc": "11:33:00" + }, + { + "day": 4, + "flight": "AF064", + "utc": "13:23:00" + }, + { + "day": 4, + "flight": "AF596", + "utc": "12:09:00" + }, + { + "day": 4, + "flight": "AF818", + "utc": "08:02:00" + }, + { + "day": 5, + "flight": "AF967", + "utc": "11:33:00" + }, + { + "day": 5, + "flight": "AF730", + "utc": "19:42:00" + }, + { + "day": 6, + "flight": "AF882", + "utc": "17:07:00" + }, + { + "day": 6, + "flight": "AF485", + "utc": "17:03:00" + }, + { + "day": 6, + "flight": "AF898", + "utc": "10:01:00" + }, + { + "day": 6, + "flight": "AF496", + "utc": "07:00:00" + } +// tag::extract[] + ], + "sourceairport": "TLV", + "stops": 0, + "type": "route" + } + } +] +// end::extract[] \ No newline at end of file diff --git a/modules/n1ql/examples/select/lookup-nest.n1ql b/modules/n1ql/examples/select/lookup-nest.n1ql new file mode 100644 index 000000000..8c3c6b8d5 --- /dev/null +++ b/modules/n1ql/examples/select/lookup-nest.n1ql @@ -0,0 +1,5 @@ +SELECT * +FROM route + INNER NEST airline + ON KEYS route.airlineid +LIMIT 1; \ No newline at end of file diff --git a/modules/n1ql/examples/select/order-by-union.jsonc b/modules/n1ql/examples/select/order-by-union.jsonc new file mode 100644 index 000000000..d81621b3b --- /dev/null +++ b/modules/n1ql/examples/select/order-by-union.jsonc @@ -0,0 +1,22 @@ +[ + { + "sort": ""Hippie Temptation" house", + "type": "landmark" + }, + { + "sort": "'La Mirande Hotel", + "type": "hotel" + }, + { + "sort": "'The Argyll Arms Hotel", + "type": "landmark" + }, + { + "sort": "'Visit the Hut of the Shadows and other End of the Road sculptures", + "type": "landmark" + }, + { + "sort": "02 Shepherd's Bush Empire", + "type": "landmark" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/order-by-union.n1ql b/modules/n1ql/examples/select/order-by-union.n1ql new file mode 100644 index 000000000..aea6db704 --- /dev/null +++ b/modules/n1ql/examples/select/order-by-union.n1ql @@ -0,0 +1,6 @@ +SELECT name AS sort, type + FROM landmark +UNION SELECT name AS sort, type + FROM hotel +ORDER BY sort ASC +LIMIT 5; \ No newline at end of file diff --git a/modules/n1ql/examples/select/order-by.jsonc b/modules/n1ql/examples/select/order-by.jsonc new file mode 100644 index 000000000..b0bce77eb --- /dev/null +++ b/modules/n1ql/examples/select/order-by.jsonc @@ -0,0 +1,22 @@ +[ + { + "city": "Évreux", + "name": "Cafe des Arts" + }, + { + "city": "Épinal", + "name": "Marché Couvert (covered market)" + }, + { + "city": "Épinal", + "name": "Musée de l'Image/Imagerie d'Épinal" + }, + { + "city": "Yosemite Valley", + "name": "Lower Yosemite Fall" + }, + { + "city": "Yosemite Valley", + "name": "Mirror Lake/Meadow" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/order-by.n1ql b/modules/n1ql/examples/select/order-by.n1ql new file mode 100644 index 000000000..12f51990b --- /dev/null +++ b/modules/n1ql/examples/select/order-by.n1ql @@ -0,0 +1,4 @@ +SELECT city, name +FROM landmark +ORDER BY city DESC, name ASC +LIMIT 5; \ No newline at end of file diff --git a/modules/n1ql/examples/select/ordered-hint.jsonc b/modules/n1ql/examples/select/ordered-hint.jsonc new file mode 100644 index 000000000..73eb5c645 --- /dev/null +++ b/modules/n1ql/examples/select/ordered-hint.jsonc @@ -0,0 +1,12 @@ +[ + { + "airline": "40-Mile Air", + "route": 46586, + "source": "Fairbanks Intl" + }, + { + "airline": "40-Mile Air", + "route": 46587, + "source": "Healy River Airport" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/ordered-hint.n1ql b/modules/n1ql/examples/select/ordered-hint.n1ql new file mode 100644 index 000000000..11dd8a43c --- /dev/null +++ b/modules/n1ql/examples/select/ordered-hint.n1ql @@ -0,0 +1,35 @@ +UPDATE STATISTICS FOR airport INDEX ALL; +UPDATE STATISTICS FOR airline INDEX ALL; +UPDATE STATISTICS FOR route INDEX (def_inventory_route_sourceairport); + +/* tag::simple[] */ +SELECT /*+ ORDERED */ + a.airportname AS source, r.id AS route, l.name AS airline +FROM airport AS a +JOIN route AS r -- <1> + ON r.sourceairport = a.faa +JOIN airline AS l -- <2> + ON r.airlineid = META(l).id +WHERE l.name = "40-Mile Air"; +/* end::simple[] */ + +/* tag::json[] */ +SELECT /*+ {"ordered": true} */ + a.airportname AS source, r.id AS route, l.name AS airline +FROM airport AS a +JOIN route AS r -- <1> + ON r.sourceairport = a.faa +JOIN airline AS l -- <2> + ON r.airlineid = META(l).id +WHERE l.name = "40-Mile Air"; +/* end::json[] */ + +/* tag::none[] */ +SELECT a.airportname AS source, r.id AS route, l.name AS airline +FROM airport AS a +JOIN route AS r -- <1> + ON r.sourceairport = a.faa +JOIN airline AS l -- <2> + ON r.airlineid = META(l).id +WHERE l.name = "40-Mile Air"; +/* end::none[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/query-keyspace-idx.jsonc b/modules/n1ql/examples/select/query-keyspace-idx.jsonc new file mode 100644 index 000000000..c743c8bd6 --- /dev/null +++ b/modules/n1ql/examples/select/query-keyspace-idx.jsonc @@ -0,0 +1,6 @@ +[ + { + "airportname": "Anaktuvuk Pass Airport", + "city": "Anaktuvuk Pass", + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/query-keyspace-idx.n1ql b/modules/n1ql/examples/select/query-keyspace-idx.n1ql new file mode 100644 index 000000000..25ab2894c --- /dev/null +++ b/modules/n1ql/examples/select/query-keyspace-idx.n1ql @@ -0,0 +1,4 @@ +SELECT t.airportname, t.city +FROM airport t +WHERE tz = "America/Anchorage" + AND geo.alt >= 2100; \ No newline at end of file diff --git a/modules/n1ql/examples/select/unnest-array.jsonc b/modules/n1ql/examples/select/unnest-array.jsonc new file mode 100644 index 000000000..818e1145c --- /dev/null +++ b/modules/n1ql/examples/select/unnest-array.jsonc @@ -0,0 +1,75 @@ +[ + { + "Monday_flights": [ + { + "day": 1, + "flight": "AF356", + "utc": "12:40:00" + }, + { + "day": 1, + "flight": "AF480", + "utc": "08:58:00" + }, + { + "day": 1, + "flight": "AF250", + "utc": "12:59:00" + }, + { + "day": 1, + "flight": "AF130", + "utc": "04:45:00" + } + ], + "destinationairport": "MRS", + "sourceairport": "TLV" + }, + { + "Monday_flights": [ + { + "day": 1, + "flight": "AF517", + "utc": "13:36:00" + }, + { + "day": 1, + "flight": "AF279", + "utc": "21:35:00" + }, + { + "day": 1, + "flight": "AF753", + "utc": "00:54:00" + }, + { + "day": 1, + "flight": "AF079", + "utc": "15:29:00" + }, + { + "day": 1, + "flight": "AF756", + "utc": "06:16:00" + } + ], + "destinationairport": "NCE", + "sourceairport": "TLV" + }, + { + "Monday_flights": [ + { + "day": 1, + "flight": "AF975", + "utc": "11:23:00" + }, + { + "day": 1, + "flight": "AF225", + "utc": "16:05:00" + } + ], + "destinationairport": "CDG", + "sourceairport": "TNR" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/unnest-array.n1ql b/modules/n1ql/examples/select/unnest-array.n1ql new file mode 100644 index 000000000..52b40c423 --- /dev/null +++ b/modules/n1ql/examples/select/unnest-array.n1ql @@ -0,0 +1,5 @@ +SELECT route.sourceairport, route.destinationairport, +ARRAY item FOR item IN schedule WHEN item.day = 1 END AS Monday_flights +FROM route +WHERE ANY item IN schedule SATISFIES item.day = 1 END +LIMIT 3; \ No newline at end of file diff --git a/modules/n1ql/examples/select/unnest-raw.jsonc b/modules/n1ql/examples/select/unnest-raw.jsonc new file mode 100644 index 000000000..167bb0a1e --- /dev/null +++ b/modules/n1ql/examples/select/unnest-raw.jsonc @@ -0,0 +1,6 @@ +[ + "Kayli Cronin", + "Shanelle Streich", + "Catharine Funk", + "Tyson Beatty" +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/unnest-raw.n1ql b/modules/n1ql/examples/select/unnest-raw.n1ql new file mode 100644 index 000000000..39a093074 --- /dev/null +++ b/modules/n1ql/examples/select/unnest-raw.n1ql @@ -0,0 +1,5 @@ +SELECT RAW r.author +FROM hotel +UNNEST reviews AS r +WHERE r.ratings.Rooms < 2 +LIMIT 4; \ No newline at end of file diff --git a/modules/n1ql/examples/select/unnest.jsonc b/modules/n1ql/examples/select/unnest.jsonc new file mode 100644 index 000000000..9c75e8074 --- /dev/null +++ b/modules/n1ql/examples/select/unnest.jsonc @@ -0,0 +1,20 @@ +[ + { + "destinationairport": "MRS", + "flight": "AF356", + "sourceairport": "TLV", + "utc": "12:40:00" + }, + { + "destinationairport": "MRS", + "flight": "AF480", + "sourceairport": "TLV", + "utc": "08:58:00" + }, + { + "destinationairport": "MRS", + "flight": "AF250", + "sourceairport": "TLV", + "utc": "12:59:00" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/unnest.n1ql b/modules/n1ql/examples/select/unnest.n1ql new file mode 100644 index 000000000..d7373f69f --- /dev/null +++ b/modules/n1ql/examples/select/unnest.n1ql @@ -0,0 +1,5 @@ +SELECT route.sourceairport, route.destinationairport, sched.flight, sched.utc +FROM route +UNNEST schedule sched +WHERE sched.day = 1 +LIMIT 3; \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-build-hint.jsonc b/modules/n1ql/examples/select/use-hash-build-hint.jsonc new file mode 100644 index 000000000..f30acddc8 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-build-hint.jsonc @@ -0,0 +1,183 @@ +{ + "cardinality": 1, + "cost": 38152.742951506196, + "optimizer_hints": { + "hints_followed": [ + { + "hint": "{\"use_hash\":{\"keyspace\":\"rte\",\"option\":\"BUILD\"}}" + } + ] + }, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "aline", + "bucket": "travel-sample", + "covers": [ + "cover ((meta(`aline`).`id`))" + ], + "index": "def_inventory_airline_primary", + "index_id": "11aa5c3f9d710599", + "keyspace": "airline", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 187, + "cost": 45.30545926533892, + "fr_cost": 12.178104060242454, + "size": 13 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, +// tag::method[] + { + "#operator": "HashJoin", + "build_aliases": [ + "rte" + ], + "build_exprs": [ + "(`rte`.`airlineid`)" + ], + "on_clause": "(((`rte`.`airlineid`) = cover ((meta(`aline`).`id`))))", +// end::method[] +// tag::ellipsis[] + // ... +// end::ellipsis[] + "optimizer_estimates": { + "cardinality": 44924.88, + "cost": 37703.450047564605, + "fr_cost": 33338.278136855406, + "size": 581 + }, +// tag::method[] + "probe_exprs": [ + "cover ((meta(`aline`).`id`))" + ], +// end::method[] + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "as": "rte", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 24024, + "cost": 4108.612246388904, + "fr_cost": 12.170521655277593, + "size": 11 + }, + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "rte", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "nested_loop": true, + "optimizer_estimates": { + "cardinality": 24024, + "cost": 32748.51223783082, + "fr_cost": 25.36215918405889, + "size": 568 + }, + "scope": "inventory" + } + ] + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.69884756461, + "fr_cost": 38152.69884756461, + "size": 581 + } + } + ] + } + }, + { + "#operator": "IntermediateGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.70884756461, + "fr_cost": 38152.70884756461, + "size": 581 + } + }, + { + "#operator": "FinalGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.71884756461, + "fr_cost": 38152.71884756461, + "size": 581 + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.742951506196, + "fr_cost": 38152.742951506196, + "size": 581 + }, + "result_terms": [ + { + "as": "Total_Count", + "expr": "count(1)" + } + ] + } + ] + } + } + ] + }, + "text": "\nSELECT /*+ { \"use_hash\": { \"keyspace\": \"rte\", \"option\": \"build\" } } */ -- <.>\n COUNT(1) AS Total_Count\nFROM `travel-sample`.inventory.airline aline\nINNER JOIN `travel-sample`.inventory.route rte\nON (rte.airlineid = META(aline).id);" +} \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-build-hint.n1ql b/modules/n1ql/examples/select/use-hash-build-hint.n1ql new file mode 100644 index 000000000..440baa7e4 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-build-hint.n1ql @@ -0,0 +1,11 @@ +UPDATE STATISTICS FOR airline INDEX (def_inventory_airline_primary); +UPDATE STATISTICS FOR route INDEX (def_inventory_route_primary); + +EXPLAIN +/* tag::query[] */ +SELECT /*+ { "use_hash": { "keyspace": "rte", "option": "build" } } */ + COUNT(1) AS Total_Count +FROM airline aline +INNER JOIN route rte +ON (rte.airlineid = META(aline).id); +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-build-legacy.n1ql b/modules/n1ql/examples/select/use-hash-build-legacy.n1ql new file mode 100644 index 000000000..859dfb1f2 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-build-legacy.n1ql @@ -0,0 +1,11 @@ +UPDATE STATISTICS FOR airline INDEX (def_inventory_airline_primary); +UPDATE STATISTICS FOR route INDEX (def_inventory_route_primary); + +EXPLAIN +/* tag::query[] */ +SELECT COUNT(1) AS Total_Count +FROM airline aline +INNER JOIN route rte +USE HASH (BUILD) +ON (rte.airlineid = META(aline).id); +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-null-hint.jsonc b/modules/n1ql/examples/select/use-hash-null-hint.jsonc new file mode 100644 index 000000000..bbfcbd84a --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-null-hint.jsonc @@ -0,0 +1,183 @@ +[ + { + "cardinality": 1, + "cost": 38147.80957213704, + "optimizer_hints": { + "hints_followed": [ + "USE_HASH(aline)" + ] + }, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "as": "rte", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 24024, + "cost": 4108.612246388904, + "fr_cost": 12.170521655277593, + "size": 11 + }, + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "rte", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "nested_loop": true, + "optimizer_estimates": { + "cardinality": 24024, + "cost": 32748.51223783082, + "fr_cost": 25.36215918405889, + "size": 568 + }, + "scope": "inventory" + }, +// tag::method[] + { + "#operator": "HashJoin", + "build_aliases": [ + "aline" + ], + "build_exprs": [ + "cover ((meta(`aline`).`id`))" + ], + "on_clause": "(((`rte`.`airlineid`) = cover ((meta(`aline`).`id`))))", +// end::method[] +// tag::ellipsis[] + // ... +// end::ellipsis[] + "optimizer_estimates": { + "cardinality": 44924.88, + "cost": 37698.51666819545, + "fr_cost": 71.43827230425512, + "size": 581 + }, +// tag::method[] + "probe_exprs": [ + "(`rte`.`airlineid`)" + ], +// end::method[] + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "aline", + "bucket": "travel-sample", + "covers": [ + "cover ((meta(`aline`).`id`))" + ], + "index": "def_inventory_airline_primary", + "index_id": "11aa5c3f9d710599", + "keyspace": "airline", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 187, + "cost": 45.30545926533892, + "fr_cost": 12.178104060242454, + "size": 13 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + } + ] + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.76546819545, + "fr_cost": 38147.76546819545, + "size": 581 + } + } + ] + } + }, + { + "#operator": "IntermediateGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.775468195454, + "fr_cost": 38147.775468195454, + "size": 581 + } + }, + { + "#operator": "FinalGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.785468195456, + "fr_cost": 38147.785468195456, + "size": 581 + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.80957213704, + "fr_cost": 38147.80957213704, + "size": 581 + }, + "result_terms": [ + { + "as": "Total_Count", + "expr": "count(1)" + } + ] + } + ] + } + } + ] + }, + "text": "\n/* tag::query[] */\nSELECT /*+ USE_HASH (aline) */\n COUNT(1) AS Total_Count\nFROM `travel-sample`.inventory.route rte\nINNER JOIN `travel-sample`.inventory.airline aline\nON rte.airlineid = META(aline).id;\n/* end::query[] */" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-null-hint.n1ql b/modules/n1ql/examples/select/use-hash-null-hint.n1ql new file mode 100644 index 000000000..a62c463e9 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-null-hint.n1ql @@ -0,0 +1,11 @@ +UPDATE STATISTICS FOR airline INDEX (def_inventory_airline_primary); +UPDATE STATISTICS FOR route INDEX (def_inventory_route_primary); + +EXPLAIN +/* tag::query[] */ +SELECT /*+ USE_HASH (aline) */ + COUNT(1) AS Total_Count +FROM route rte +INNER JOIN airline aline +ON rte.airlineid = META(aline).id; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-opt.jsonc b/modules/n1ql/examples/select/use-hash-opt.jsonc new file mode 100644 index 000000000..0bb569416 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-opt.jsonc @@ -0,0 +1,178 @@ +[ + { + "cardinality": 1, + "cost": 38147.80957213704, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "as": "rte", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 24024, + "cost": 4108.612246388904, + "fr_cost": 12.170521655277593, + "size": 11 + }, + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "rte", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "nested_loop": true, + "optimizer_estimates": { + "cardinality": 24024, + "cost": 32748.51223783082, + "fr_cost": 25.36215918405889, + "size": 568 + }, + "scope": "inventory" + }, +// tag::method[] + { + "#operator": "HashJoin", + "build_aliases": [ + "aline" + ], + "build_exprs": [ + "cover ((meta(`aline`).`id`))" + ], + "on_clause": "(((`rte`.`airlineid`) = cover ((meta(`aline`).`id`))))", +// end::method[] +// tag::ellipsis[] + // ... +// end::ellipsis[] + "optimizer_estimates": { + "cardinality": 44924.88, + "cost": 37698.51666819545, + "fr_cost": 71.43827230425512, + "size": 581 + }, +// tag::method[] + "probe_exprs": [ + "(`rte`.`airlineid`)" + ], +// end::method[] + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "aline", + "bucket": "travel-sample", + "covers": [ + "cover ((meta(`aline`).`id`))" + ], + "index": "def_inventory_airline_primary", + "index_id": "11aa5c3f9d710599", + "keyspace": "airline", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 187, + "cost": 45.30545926533892, + "fr_cost": 12.178104060242454, + "size": 13 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + } + ] + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.76546819545, + "fr_cost": 38147.76546819545, + "size": 581 + } + } + ] + } + }, + { + "#operator": "IntermediateGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.775468195454, + "fr_cost": 38147.775468195454, + "size": 581 + } + }, + { + "#operator": "FinalGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.785468195456, + "fr_cost": 38147.785468195456, + "size": 581 + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 1, + "cost": 38147.80957213704, + "fr_cost": 38147.80957213704, + "size": 581 + }, + "result_terms": [ + { + "as": "Total_Count", + "expr": "count(1)" + } + ] + } + ] + } + } + ] + }, + "text": "\n/* tag::query[] */\nSELECT COUNT(1) AS Total_Count\nFROM `travel-sample`.inventory.route rte\nINNER JOIN `travel-sample`.inventory.airline aline\nON rte.airlineid = META(aline).id;\n/* end::query[] */" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-opt.n1ql b/modules/n1ql/examples/select/use-hash-opt.n1ql new file mode 100644 index 000000000..28d8bc14e --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-opt.n1ql @@ -0,0 +1,10 @@ +UPDATE STATISTICS FOR airline INDEX (def_inventory_airline_primary); +UPDATE STATISTICS FOR route INDEX (def_inventory_route_primary); + +EXPLAIN +/* tag::query[] */ +SELECT COUNT(1) AS Total_Count +FROM route rte +INNER JOIN airline aline +ON rte.airlineid = META(aline).id; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-probe-hint.jsonc b/modules/n1ql/examples/select/use-hash-probe-hint.jsonc new file mode 100644 index 000000000..cdc571b6b --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-probe-hint.jsonc @@ -0,0 +1,181 @@ +{ + "cardinality": 1, + "cost": 38152.742951506196, + "optimizer_hints": { + "hints_followed": [ + "USE_HASH(aline/PROBE)" + ] + }, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "aline", + "bucket": "travel-sample", + "covers": [ + "cover ((meta(`aline`).`id`))" + ], + "index": "def_inventory_airline_primary", + "index_id": "11aa5c3f9d710599", + "keyspace": "airline", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 187, + "cost": 45.30545926533892, + "fr_cost": 12.178104060242454, + "size": 13 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, +// tag::method[] + { + "#operator": "HashJoin", + "build_aliases": [ + "rte" + ], + "build_exprs": [ + "(`rte`.`airlineid`)" + ], + "on_clause": "(((`rte`.`airlineid`) = cover ((meta(`aline`).`id`))))", +// end::method[] +// tag::ellipsis[] + // ... +// end::ellipsis[] + "optimizer_estimates": { + "cardinality": 44924.88, + "cost": 37703.450047564605, + "fr_cost": 33338.278136855406, + "size": 581 + }, +// tag::method[] + "probe_exprs": [ + "cover ((meta(`aline`).`id`))" + ], +// end::method[] + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "as": "rte", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 24024, + "cost": 4108.612246388904, + "fr_cost": 12.170521655277593, + "size": 11 + }, + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "rte", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "nested_loop": true, + "optimizer_estimates": { + "cardinality": 24024, + "cost": 32748.51223783082, + "fr_cost": 25.36215918405889, + "size": 568 + }, + "scope": "inventory" + } + ] + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.69884756461, + "fr_cost": 38152.69884756461, + "size": 581 + } + } + ] + } + }, + { + "#operator": "IntermediateGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.70884756461, + "fr_cost": 38152.70884756461, + "size": 581 + } + }, + { + "#operator": "FinalGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.71884756461, + "fr_cost": 38152.71884756461, + "size": 581 + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 1, + "cost": 38152.742951506196, + "fr_cost": 38152.742951506196, + "size": 581 + }, + "result_terms": [ + { + "as": "Total_Count", + "expr": "count(1)" + } + ] + } + ] + } + } + ] + }, + "text": "\nSELECT /*+ USE_HASH (aline/PROBE) */ -- <.>\n COUNT(1) AS Total_Count\nFROM `travel-sample`.inventory.route rte\nINNER JOIN `travel-sample`.inventory.airline aline\nON rte.airlineid = META(aline).id;" +} \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-probe-hint.n1ql b/modules/n1ql/examples/select/use-hash-probe-hint.n1ql new file mode 100644 index 000000000..806d42b83 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-probe-hint.n1ql @@ -0,0 +1,11 @@ +UPDATE STATISTICS FOR airline INDEX (def_inventory_airline_primary); +UPDATE STATISTICS FOR route INDEX (def_inventory_route_primary); + +EXPLAIN +/* tag::query[] */ +SELECT /*+ USE_HASH (aline/PROBE) */ + COUNT(1) AS Total_Count +FROM route rte +INNER JOIN airline aline +ON rte.airlineid = META(aline).id; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-hash-probe-legacy.n1ql b/modules/n1ql/examples/select/use-hash-probe-legacy.n1ql new file mode 100644 index 000000000..07c7175e5 --- /dev/null +++ b/modules/n1ql/examples/select/use-hash-probe-legacy.n1ql @@ -0,0 +1,11 @@ +UPDATE STATISTICS FOR airline INDEX (def_inventory_airline_primary); +UPDATE STATISTICS FOR route INDEX (def_inventory_route_primary); + +EXPLAIN +/* tag::query[] */ +SELECT COUNT(1) AS Total_Count +FROM route rte +INNER JOIN airline aline +USE HASH (PROBE) +ON rte.airlineid = META(aline).id; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-nl-hint.jsonc b/modules/n1ql/examples/select/use-nl-hint.jsonc new file mode 100644 index 000000000..e980bbde7 --- /dev/null +++ b/modules/n1ql/examples/select/use-nl-hint.jsonc @@ -0,0 +1,190 @@ +{ + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "r", + "bucket": "travel-sample", + "index": "def_inventory_route_sourceairport", + "index_id": "10962bf412f58e32", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 249, + "cost": 409.3918315518446, + "fr_cost": 13.595951130730299, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "index_key": "`sourceairport`", + "low": "\"SFO\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "r", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 249, + "cost": 718.1095762183879, + "fr_cost": 26.7875886595116, + "size": 568 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`r`.`sourceairport`) = \"SFO\")", + "optimizer_estimates": { + "cardinality": 249, + "cost": 724.0439311117188, + "fr_cost": 26.811421410087224, + "size": 568 + } + }, +// tag::method[] + { + "#operator": "NestedLoopJoin", +// end::method[] + "alias": "a", + "filter": "((`a`.`faa`) = (`r`.`sourceairport`))", + "on_clause": "(((`a`.`faa`) = (`r`.`sourceairport`)))", + "optimizer_estimates": { + "cardinality": 241.59705066624267, + "cost": 6894.97492813281, + "fr_cost": 1199.3543889498105, + "size": 858 + }, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "a", + "bucket": "travel-sample", + "index": "def_inventory_airport_faa", + "index_id": "da117c64837f7ad", + "index_projection": { + "primary_key": true + }, + "keyspace": "airport", + "namespace": "default", + "nested_loop": true, + "optimizer_estimates": { + "cardinality": 0.970269279784107, + "cost": 12.173544240859432, + "fr_cost": 12.173544240859432, + "size": 12 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "(`r`.`sourceairport`)", + "inclusion": 3, + "index_key": "`faa`", + "low": "(`r`.`sourceairport`)" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "a", + "bucket": "travel-sample", + "keyspace": "airport", + "namespace": "default", + "nested_loop": true, + "optimizer_estimates": { + "cardinality": 0.970269279784107, + "cost": 24.64293012049035, + "fr_cost": 24.64293012049035, + "size": 290 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`a`.`faa`) is not null)", + "optimizer_estimates": { + "cardinality": 0.8425763207068288, + "cost": 24.659453210934785, + "fr_cost": 24.659453210934785, + "size": 290 + } + } + ] + } + } + ] + } + }, + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 241.59705066624267, + "cost": 6909.128474364926, + "fr_cost": 1199.412972223874, + "size": 858 + }, + "result_terms": [ + { + "as": "airport", + "expr": "(`a`.`airportname`)" + }, + { + "as": "route", + "expr": "(`r`.`id`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "4", + "optimizer_estimates": { + "cardinality": 4, + "cost": 1270.6365967049305, + "fr_cost": 1199.4422638609058, + "size": 858 + } + } + ] +} \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-nl-hint.n1ql b/modules/n1ql/examples/select/use-nl-hint.n1ql new file mode 100644 index 000000000..6aa32d6f9 --- /dev/null +++ b/modules/n1ql/examples/select/use-nl-hint.n1ql @@ -0,0 +1,13 @@ +UPDATE STATISTICS FOR route INDEX (def_inventory_route_sourceairport); +UPDATE STATISTICS FOR airport INDEX (def_inventory_airport_faa); + +EXPLAIN +/* tag::query[] */ +SELECT /*+ USE_NL (a) */ -- <.> + a.airportname AS airport, r.id AS route +FROM route AS r, + airport AS a -- <.> +WHERE a.faa = r.sourceairport + AND r.sourceairport = "SFO" +LIMIT 4; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-nl-legacy.n1ql b/modules/n1ql/examples/select/use-nl-legacy.n1ql new file mode 100644 index 000000000..73358d8ca --- /dev/null +++ b/modules/n1ql/examples/select/use-nl-legacy.n1ql @@ -0,0 +1,13 @@ +UPDATE STATISTICS FOR route INDEX (def_inventory_route_sourceairport); +UPDATE STATISTICS FOR airport INDEX (def_inventory_airport_faa); + +EXPLAIN +/* tag::query[] */ +SELECT a.airportname AS airport, r.id AS route +FROM route AS r +JOIN airport AS a +USE NL +ON a.faa = r.sourceairport +WHERE r.sourceairport = "SFO" +LIMIT 4; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-nl-opt.jsonc b/modules/n1ql/examples/select/use-nl-opt.jsonc new file mode 100644 index 000000000..915c7ae4a --- /dev/null +++ b/modules/n1ql/examples/select/use-nl-opt.jsonc @@ -0,0 +1,203 @@ +{ + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "a", + "bucket": "travel-sample", + "index": "def_inventory_airport_faa", + "index_id": "da117c64837f7ad", + "index_projection": { + "primary_key": true + }, + "keyspace": "airport", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1708.9999999999986, + "cost": 317.67504692590336, + "fr_cost": 12.17886193500638, + "size": 12 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 0, + "index_key": "`faa`", + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "a", + "bucket": "travel-sample", + "keyspace": "airport", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 1708.9999999999986, + "cost": 1784.8361118943133, + "fr_cost": 25.0303312533027, + "size": 290 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`a`.`faa`) is not null)", + "optimizer_estimates": { + "cardinality": 1708.9999999999986, + "cost": 1813.9393331936815, + "fr_cost": 25.047360639668625, + "size": 290 + } + } + ] + } + }, +// tag::method[] + { + "#operator": "HashJoin", +// end::method[] + "build_aliases": [ + "r" + ], + "build_exprs": [ + "(`r`.`sourceairport`)" + ], + "filter": "((`a`.`faa`) = (`r`.`sourceairport`))", + "on_clause": "(((`a`.`faa`) = (`r`.`sourceairport`)))", + "optimizer_estimates": { + "cardinality": 241.59705066624267, + "cost": 2603.7479879964294, + "fr_cost": 762.7780175474376, + "size": 858 + }, + "probe_exprs": [ + "(`a`.`faa`)" + ], + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "r", + "bucket": "travel-sample", + "index": "def_inventory_route_sourceairport", + "index_id": "10962bf412f58e32", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 249, + "cost": 409.3918315518446, + "fr_cost": 13.595951130730299, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"SFO\"", + "inclusion": 3, + "index_key": "`sourceairport`", + "low": "\"SFO\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "as": "r", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 249, + "cost": 718.1095762183879, + "fr_cost": 26.7875886595116, + "size": 568 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`r`.`sourceairport`) = \"SFO\")", + "optimizer_estimates": { + "cardinality": 249, + "cost": 724.0439311117188, + "fr_cost": 26.811421410087224, + "size": 568 + } + } + ] + } + } + ] + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 241.59705066624267, + "cost": 2617.9015342285447, + "fr_cost": 762.8366008215011, + "size": 858 + }, + "result_terms": [ + { + "as": "airport", + "expr": "(`a`.`airportname`)" + }, + { + "as": "route", + "expr": "(`r`.`id`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Limit", + "expr": "4", + "optimizer_estimates": { + "cardinality": 4, + "cost": 785.9966614551204, + "fr_cost": 762.8658924585328, + "size": 858 + } + } + ] +} \ No newline at end of file diff --git a/modules/n1ql/examples/select/use-nl-opt.n1ql b/modules/n1ql/examples/select/use-nl-opt.n1ql new file mode 100644 index 000000000..ed4841dc7 --- /dev/null +++ b/modules/n1ql/examples/select/use-nl-opt.n1ql @@ -0,0 +1,12 @@ +UPDATE STATISTICS FOR route INDEX (def_inventory_route_sourceairport); +UPDATE STATISTICS FOR airport INDEX (def_inventory_airport_faa); + +EXPLAIN +/* tag::query[] */ +SELECT a.airportname AS airport, r.id AS route +FROM route AS r, + airport AS a +WHERE a.faa = r.sourceairport + AND r.sourceairport = "SFO" +LIMIT 4; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/settings/node-level-settings.jsonc b/modules/n1ql/examples/settings/node-level-settings.jsonc new file mode 100644 index 000000000..4660e03da --- /dev/null +++ b/modules/n1ql/examples/settings/node-level-settings.jsonc @@ -0,0 +1,38 @@ +{ + "atrcollection": "", + "auto-prepare": false, + "cleanupclientattempts": true, + "cleanuplostattempts": true, + "cleanupwindow": "1m0s", + "completed": { + "aborted": null, + "threshold": 1000 + }, + "completed-limit": 4000, + "completed-threshold": 1000, + "controls": false, + "cpuprofile": "", + "debug": false, + "functions-limit": 16384, + "keep-alive-length": 16384, + "loglevel": "INFO", + "max-index-api": 4, + "max-parallelism": 1, + "memory-quota": 0, + "memprofile": "", + "mutexprofile": false, + "n1ql-feat-ctrl": 76, + "numatrs": 1024, + "pipeline-batch": 16, + "pipeline-cap": 512, + "plus-servicers": 16, + "prepared-limit": 16384, + "pretty": false, + "profile": "off", + "request-size-cap": 67108864, + "scan-cap": 512, + "servicers": 4, + "timeout": 0, + "txtimeout": "0s", + "use-cbo": true +} \ No newline at end of file diff --git a/modules/n1ql/examples/settings/node-level-settings.sh b/modules/n1ql/examples/settings/node-level-settings.sh new file mode 100644 index 000000000..2a42a58df --- /dev/null +++ b/modules/n1ql/examples/settings/node-level-settings.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# tag::curl[] +curl $BASE_URL/admin/settings -u $USER:$PASSWORD +# end::curl[] \ No newline at end of file diff --git a/modules/n1ql/examples/settings/param-names.n1ql b/modules/n1ql/examples/settings/param-names.n1ql new file mode 100644 index 000000000..5f8fccaa4 --- /dev/null +++ b/modules/n1ql/examples/settings/param-names.n1ql @@ -0,0 +1,9 @@ +/* tag::arguments[] */ +\SET -@country "France"; +\SET -$altitude 500; +/* end::arguments[] */ + +/* tag::statement[] */ +SELECT COUNT(*) FROM airport +WHERE country = $country AND geo.alt > @altitude; +/* end::statement[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/settings/param-numbers.n1ql b/modules/n1ql/examples/settings/param-numbers.n1ql new file mode 100644 index 000000000..83121fa65 --- /dev/null +++ b/modules/n1ql/examples/settings/param-numbers.n1ql @@ -0,0 +1,8 @@ +/* tag::arguments[] */ +\SET -args ["France", 500]; +/* end::arguments[] */ + +/* tag::statement[] */ +SELECT COUNT(*) FROM airport +WHERE country = $1 AND geo.alt > @2; +/* end::statement[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/settings/param-positions.n1ql b/modules/n1ql/examples/settings/param-positions.n1ql new file mode 100644 index 000000000..697b37d6b --- /dev/null +++ b/modules/n1ql/examples/settings/param-positions.n1ql @@ -0,0 +1,8 @@ +/* tag::arguments[] */ +\SET -args ["France", 500]; +/* end::arguments[] */ + +/* tag::statement[] */ +SELECT COUNT(*) FROM airport +WHERE country = ? AND geo.alt > ?; +/* end::statement[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/settings/save-node-level-settings.sh b/modules/n1ql/examples/settings/save-node-level-settings.sh new file mode 100644 index 000000000..6d83ed494 --- /dev/null +++ b/modules/n1ql/examples/settings/save-node-level-settings.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# tag::curl[] +curl $BASE_URL/admin/settings -u $USER:$PASSWORD -o ./query_settings.json +# end::curl[] \ No newline at end of file diff --git a/modules/n1ql/examples/transactions/multiple.n1ql b/modules/n1ql/examples/transactions/multiple.n1ql new file mode 100644 index 000000000..f5c132350 --- /dev/null +++ b/modules/n1ql/examples/transactions/multiple.n1ql @@ -0,0 +1,128 @@ +/* tag::settings[] */ +\SET -txtimeout "2m"; -- <.> +\SET -scan_consistency "not_bounded"; -- <.> +\SET -durability_level "none"; -- <.> +/* end::settings[] */ + +/* tag::context[] */ +\SET -query_context travel-sample.tenant_agent_00; +/* end::context[] */ + +/* tag::index[] */ +CREATE PRIMARY INDEX ON bookings; +/* end::index[] */ + +/* tag::transaction[] */ +/* tag::begin-plain[] */ +-- Start the transaction +/* end::begin-plain[] */ +/* tag::begin-mark[] */ +-- pass:[Start the transaction] +/* end::begin-mark[] */ +/* tag::begin[] */ +BEGIN WORK; +/* end::begin[] */ + +/* tag::set-plain[] */ +-- Specify transaction settings +/* end::set-plain[] */ +/* tag::set-mark[] */ +-- pass:[Specify transaction settings] +/* end::set-mark[] */ +/* tag::set[] */ +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +/* end::set[] */ + +-- Create a booking document +/* tag::upsert[] */ +UPSERT INTO bookings +VALUES("bf7ad6fa-bdb9-4099-a840-196e47179f03", { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "price": 964.13, + "route": "63986" +}); +/* end::upsert[] */ + +/* tag::savepoint-plain[] */ +-- Set a savepoint +/* end::savepoint-plain[] */ +/* tag::savepoint-mark[] */ +-- pass:[Set a savepoint] +/* end::savepoint-mark[] */ +/* tag::savepoint-1[] */ +SAVEPOINT s1; +/* end::savepoint-1[] */ + +-- Update the booking document to include a user +/* tag::update-1[] */ +UPDATE bookings AS b +SET b.`user` = "0" +WHERE META(b).id = "bf7ad6fa-bdb9-4099-a840-196e47179f03"; +/* end::update-1[] */ + +-- Check the content of the booking and user +/* tag::check-1[] */ +SELECT b.*, u.name +FROM bookings b +JOIN users u +ON b.`user` = META(u).id +WHERE META(b).id = "bf7ad6fa-bdb9-4099-a840-196e47179f03"; +/* end::check-1[] */ + +/* tag::savepoint-plain[] */ +-- Set a second savepoint +/* end::savepoint-plain[] */ +/* tag::savepoint-mark[] */ +-- pass:[Set a second savepoint] +/* end::savepoint-mark[] */ +/* tag::savepoint-2[] */ +SAVEPOINT s2; +/* end::savepoint-2[] */ + +-- Update the booking documents to change the user +/* tag::update-2[] */ +UPDATE bookings AS b +SET b.`user` = "1" +WHERE META(b).id = "bf7ad6fa-bdb9-4099-a840-196e47179f03"; +/* end::update-2[] */ + +-- Check the content of the booking and user +/* tag::check-2[] */ +SELECT b.*, u.name +FROM bookings b +JOIN users u +ON b.`user` = META(u).id +WHERE META(b).id = "bf7ad6fa-bdb9-4099-a840-196e47179f03"; +/* end::check-2[] */ + +/* tag::rollback-plain[] */ +-- Roll back the transaction to the second savepoint +/* end::rollback-plain[] */ +/* tag::rollback-mark[] */ +-- pass:[Roll back the transaction to the second savepoint] +/* end::rollback-mark[] */ +/* tag::rollback[] */ +ROLLBACK TRAN TO SAVEPOINT s2; +/* end::rollback[] */ + +-- Check the content of the booking and user again +/* tag::check-3[] */ +SELECT b.*, u.name +FROM bookings b +JOIN users u +ON b.`user` = META(u).id +WHERE META(b).id = "bf7ad6fa-bdb9-4099-a840-196e47179f03"; +/* end::check-3[] */ + +/* tag::commit-plain[] */ +-- Commit the transaction +/* end::commit-plain[] */ +/* tag::commit-mark[] */ +-- pass:[Commit the transaction] +/* end::commit-mark[] */ +/* tag::commit[] */ +COMMIT WORK; +/* end::commit[] */ +/* end::transaction[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/transactions/multiple.sh b/modules/n1ql/examples/transactions/multiple.sh new file mode 100644 index 000000000..66a924947 --- /dev/null +++ b/modules/n1ql/examples/transactions/multiple.sh @@ -0,0 +1,163 @@ +#!/bin/sh + +# tag::index[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "CREATE PRIMARY INDEX ON bookings;", + "query_context": "`travel-sample`.tenant_agent_00", +}' +# end::index[] + +# tag::transaction[] +# tag::begin[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "BEGIN WORK", + "query_context": "`travel-sample`.tenant_agent_00", + "txtimeout": "2m", + "scan_consistency": "request_plus", + "durability_level": "none" +}' +# end::begin[] + +# tag::set[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "SET TRANSACTION ISOLATION LEVEL READ COMMITTED;", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::set[] + +# tag::upsert[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "UPSERT INTO bookings VALUES(\"bf7ad6fa-bdb9-4099-a840-196e47179f03\", { + \"date\": \"07/24/2021\", + \"flight\": \"WN533\", + \"flighttime\": 7713, + \"price\": 964.13, + \"route\": \"63986\" +});", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::upsert[] + +# tag::savepoint-1[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "SAVEPOINT s1;", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::savepoint-1[] + +# tag::update-1[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "UPDATE bookings AS b + SET b.`user` = \"0\" + WHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::update-1[] + +# tag::check-1[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "SELECT b.*, u.name + FROM bookings b JOIN users u ON b.`user` = META(u).id + WHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::check-1[] + +# tag::savepoint-2[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "SAVEPOINT s2;", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::savepoint-2[] + +# tag::update-2[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "UPDATE bookings AS b + SET b.`user` = \"1\" + WHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::update-2[] + +# tag::check-2[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "SELECT b.*, u.name + FROM bookings b JOIN users u ON b.`user` = META(u).id + WHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::check-2[] + +# tag::rollback[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "ROLLBACK TRAN TO SAVEPOINT s2;", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::rollback[] + +# tag::check-3[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "SELECT b.*, u.name + FROM bookings b JOIN users u ON b.`user` = META(u).id + WHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::check-3[] + +# tag::commit[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "COMMIT TRANSACTION", + "query_context": "`travel-sample`.tenant_agent_00", + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" +}' # <1> +# end::commit[] +# end::transaction[] \ No newline at end of file diff --git a/modules/n1ql/examples/transactions/results.jsonc b/modules/n1ql/examples/transactions/results.jsonc new file mode 100644 index 000000000..42397db01 --- /dev/null +++ b/modules/n1ql/examples/transactions/results.jsonc @@ -0,0 +1,101 @@ +// tag::extract[] +// tag::extract-1[] +[ + { + "batchQuery": "-- Start the transaction\nBEGIN WORK;", + "batchQueryResult": [ +// tag::begin[] + { + "txid": "d3bbf182-1179-42ba-8900-eb20fda69e42" // <.> + } +// end::begin[] + ] + }, +// end::extract-1[] +// tag::extract-2[] + { + "batchQuery": "\n\n-- Specify transaction settings\nSET TRANSACTION ISOLATION LEVEL READ COMMITTED;", + "batchQueryResult": [] + }, + { + "batchQuery": "\n\n-- Create a booking document\nUPSERT INTO bookings\nVALUES(\"bf7ad6fa-bdb9-4099-a840-196e47179f03\", {\n \"date\": \"07/24/2021\",\n \"flight\": \"WN533\",\n \"flighttime\": 7713,\n \"price\": 964.13,\n \"route\": \"63986\"\n});", + "batchQueryResult": [] + }, +// end::extract[] +// tag::ellipsis[] +// ... +// end::ellipsis[] + { + "batchQuery": "\n\n-- Set a savepoint\nSAVEPOINT s1;", + "batchQueryResult": [] + }, + { + "batchQuery": "\n\n-- Update the booking document to include a user\nUPDATE bookings AS b\nSET b.`user` = \"0\"\nWHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "batchQueryResult": [] + }, + { + "batchQuery": "\n\n-- Check the content of the booking and user\nSELECT b.*, u.name\nFROM bookings b\nJOIN users u\nON b.`user` = META(u).id\nWHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "batchQueryResult": [ + { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "name": "Keon Hoppe", + "price": 964.13, + "route": "63986", + "user": "0" // <.> + } + ] + }, +// end::extract-2[] +// tag::extract-3[] + { + "batchQuery": "\n\n-- Set a second savepoint\nSAVEPOINT s2;", + "batchQueryResult": [] + }, + { + "batchQuery": "\n\n-- Update the booking documents to change the user\nUPDATE bookings AS b\nSET b.`user` = \"1\"\nWHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "batchQueryResult": [] + }, + { + "batchQuery": "\n\n-- Check the content of the booking and user\nSELECT b.*, u.name\nFROM bookings b\nJOIN users u\nON b.`user` = META(u).id\nWHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "batchQueryResult": [ + { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "name": "Rigoberto Bernier", + "price": 964.13, + "route": "63986", + "user": "1" // <.> + } + ] + }, +// end::extract-3[] +// tag::extract-4[] + { + "batchQuery": "\n\n-- Roll back the transaction to the second savepoint\nROLLBACK TRAN TO SAVEPOINT s2;", + "batchQueryResult": [] + }, + { + "batchQuery": "\n\n-- Check the content of the booking and user again\nSELECT b.*, u.name\nFROM bookings b\nJOIN users u\nON b.`user` = META(u).id\nWHERE META(b).id = \"bf7ad6fa-bdb9-4099-a840-196e47179f03\";", + "batchQueryResult": [ +// tag::check-3[] + { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "name": "Keon Hoppe", + "price": 964.13, + "route": "63986", + "user": "0" // <.> + } +// end::check-3[] + ] + }, + { + "batchQuery": "\n\n-- Commit the transaction\nCOMMIT WORK;", + "batchQueryResult": [] + } +] +// end::extract-4[] \ No newline at end of file diff --git a/modules/n1ql/examples/transactions/single.n1ql b/modules/n1ql/examples/transactions/single.n1ql new file mode 100644 index 000000000..d5d4c3afb --- /dev/null +++ b/modules/n1ql/examples/transactions/single.n1ql @@ -0,0 +1,9 @@ +/* tag::settings[] */ +\SET -tximplicit true; +/* end::settings[] */ + +/* tag::query[] */ +UPDATE hotel +SET price = "from £89" +WHERE name = "Glasgow Grand Central"; +/* end::query[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/transactions/single.sh b/modules/n1ql/examples/transactions/single.sh new file mode 100644 index 000000000..d4c21cf9b --- /dev/null +++ b/modules/n1ql/examples/transactions/single.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +# tag::query[] +curl http://localhost:8093/query/service \ +-u Administrator:password \ +-H 'Content-Type: application/json' \ +-d '{ + "statement": "UPDATE `travel-sample`.inventory.hotel + SET price = \"from £89\" + WHERE name = \"Glasgow Grand Central\";", + "tximplicit": true +}' +# end::query[] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-cbo.jsonc b/modules/n1ql/examples/utility/advise-cbo.jsonc new file mode 100644 index 000000000..3af4a38fd --- /dev/null +++ b/modules/n1ql/examples/utility/advise-cbo.jsonc @@ -0,0 +1,27 @@ +[ + { + "#operator": "Advise", + "advice": { + "#operator": "IndexAdvice", + "adviseinfo": { + "current_indexes": [ + { + "index_statement": "CREATE PRIMARY INDEX def_inventory_hotel_primary ON `default`:`travel-sample`.`inventory`.`hotel`", + "keyspace_alias": "hotel_a" + } + ], + "recommended_indexes": { + "indexes": [ + { + "index_statement": "CREATE INDEX adv_country ON `default`:`travel-sample`.`inventory`.`hotel`(`country`)", + "keyspace_alias": "hotel_a", + "recommending_rule": "Index keys follow cost-based order.", // <.> + "update_statistics": "UPDATE STATISTICS FOR `default`:`travel-sample`.`inventory`.`hotel`(`country`)" // <.> + } + ] + } + } + }, + "query": "SELECT * FROM `travel-sample`.inventory.hotel a WHERE a.country = 'France';" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-cbo.n1ql b/modules/n1ql/examples/utility/advise-cbo.n1ql new file mode 100644 index 000000000..1ce11a13e --- /dev/null +++ b/modules/n1ql/examples/utility/advise-cbo.n1ql @@ -0,0 +1 @@ +ADVISE SELECT * FROM hotel a WHERE a.country = 'France'; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-identical.jsonc b/modules/n1ql/examples/utility/advise-identical.jsonc new file mode 100644 index 000000000..616f8a0d7 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-identical.jsonc @@ -0,0 +1,20 @@ +[ + { + "#operator": "Advise", + "advice": { + "#operator": "IndexAdvice", + "adviseinfo": { + "current_indexes": [ + { + "index_statement": "CREATE INDEX def_inventory_landmark_city ON `default`:`travel-sample`.`inventory`.`landmark`(`city`)", + "index_status": "SAME TO THE INDEX WE CAN RECOMMEND", + "keyspace_alias": "landmark", + "recommending_rule": "Index keys follow order of predicate types: 1. Common leading key for disjunction (4. not less than/between/not greater than)." + } + ], + "recommended_indexes": "No index recommendation at this time." + } + }, + "query": "SELECT * FROM `travel-sample`.inventory.landmark WHERE city LIKE \"Par%\" OR city LIKE \"Lon%\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-identical.n1ql b/modules/n1ql/examples/utility/advise-identical.n1ql new file mode 100644 index 000000000..82e496130 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-identical.n1ql @@ -0,0 +1,2 @@ +ADVISE SELECT * FROM landmark +WHERE city LIKE "Par%" OR city LIKE "Lon%"; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-indexes.jsonc b/modules/n1ql/examples/utility/advise-indexes.jsonc new file mode 100644 index 000000000..41c95d31f --- /dev/null +++ b/modules/n1ql/examples/utility/advise-indexes.jsonc @@ -0,0 +1,32 @@ +[ + { + "#operator": "Advise", + "advice": { + "#operator": "IndexAdvice", + "adviseinfo": { + "current_indexes": [ + { + "index_statement": "CREATE PRIMARY INDEX idx_airport_primary ON `default`:`travel-sample`.`inventory`.`airport`", + "keyspace_alias": "airport" + } + ], + "recommended_indexes": { + "covering_indexes": [ + { + "index_statement": "CREATE INDEX adv_geo_alt_airportname ON `default`:`travel-sample`.`inventory`.`airport`(`geo`.`alt`,`airportname`)", + "keyspace_alias": "airport" + } + ], + "indexes": [ + { + "index_statement": "CREATE INDEX adv_geo_alt ON `default`:`travel-sample`.`inventory`.`airport`(`geo`.`alt`)", + "keyspace_alias": "airport", + "recommending_rule": "Index keys follow order of predicate types: 1. Common leading key for disjunction (5. less than/greater than)." + } + ] + } + } + }, + "query": "SELECT airportname FROM `travel-sample`.inventory.airport WHERE geo.alt NOT BETWEEN 0 AND 100;" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-indexes.n1ql b/modules/n1ql/examples/utility/advise-indexes.n1ql new file mode 100644 index 000000000..6c0a7d779 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-indexes.n1ql @@ -0,0 +1,2 @@ +ADVISE SELECT airportname FROM airport +WHERE geo.alt NOT BETWEEN 0 AND 100; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-none.jsonc b/modules/n1ql/examples/utility/advise-none.jsonc new file mode 100644 index 000000000..74a04ab12 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-none.jsonc @@ -0,0 +1,18 @@ +[ + { + "#operator": "Advise", + "advice": { + "#operator": "IndexAdvice", + "adviseinfo": { + "current_indexes": [ + { + "index_statement": "CREATE PRIMARY INDEX def_inventory_landmark_primary ON `default`:`travel-sample`.`inventory`.`landmark`", + "keyspace_alias": "landmark" + } + ], + "recommended_indexes": "No index recommendation at this time." + } + }, + "query": "SELECT * FROM `travel-sample`.inventory.landmark LIMIT 5;" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-none.n1ql b/modules/n1ql/examples/utility/advise-none.n1ql new file mode 100644 index 000000000..a72857767 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-none.n1ql @@ -0,0 +1 @@ +ADVISE SELECT * FROM landmark LIMIT 5; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-optimal.jsonc b/modules/n1ql/examples/utility/advise-optimal.jsonc new file mode 100644 index 000000000..563822e76 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-optimal.jsonc @@ -0,0 +1,19 @@ +[ + { + "#operator": "Advise", + "advice": { + "#operator": "IndexAdvice", + "adviseinfo": { + "current_indexes": [ + { + "index_statement": "CREATE INDEX def_inventory_landmark_city ON `default`:`travel-sample`.`inventory`.`landmark`(`city`)", + "index_status": "THIS IS AN OPTIMAL COVERING INDEX.", + "keyspace_alias": "landmark" + } + ], + "recommended_indexes": "No index recommendation at this time." + } + }, + "query": "SELECT city FROM `travel-sample`.inventory.landmark WHERE city LIKE \"Par%\" OR city LIKE \"Lon%\";" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/advise-optimal.n1ql b/modules/n1ql/examples/utility/advise-optimal.n1ql new file mode 100644 index 000000000..852342105 --- /dev/null +++ b/modules/n1ql/examples/utility/advise-optimal.n1ql @@ -0,0 +1,2 @@ +ADVISE SELECT city FROM landmark +WHERE city LIKE "Par%" OR city LIKE "Lon%"; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-delete-all.n1ql b/modules/n1ql/examples/utility/analyze-delete-all.n1ql new file mode 100644 index 000000000..1d4bb879b --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-delete-all.n1ql @@ -0,0 +1 @@ +ANALYZE KEYSPACE airport DELETE STATISTICS; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-delete.n1ql b/modules/n1ql/examples/utility/analyze-delete.n1ql new file mode 100644 index 000000000..6d4be9349 --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-delete.n1ql @@ -0,0 +1,2 @@ +ANALYZE KEYSPACE hotel +DELETE STATISTICS (city, country, free_breakfast); \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-index-on.n1ql b/modules/n1ql/examples/utility/analyze-index-on.n1ql new file mode 100644 index 000000000..3057f6f05 --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-index-on.n1ql @@ -0,0 +1 @@ +ANALYZE INDEX def_inventory_airport_city ON airport; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-index.n1ql b/modules/n1ql/examples/utility/analyze-index.n1ql new file mode 100644 index 000000000..92fc422ed --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-index.n1ql @@ -0,0 +1 @@ +ANALYZE INDEX airport.def_inventory_airport_city; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-indexes-all.n1ql b/modules/n1ql/examples/utility/analyze-indexes-all.n1ql new file mode 100644 index 000000000..bc9ba596c --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-indexes-all.n1ql @@ -0,0 +1 @@ +ANALYZE KEYSPACE airport INDEX ALL; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-indexes-subquery.n1ql b/modules/n1ql/examples/utility/analyze-indexes-subquery.n1ql new file mode 100644 index 000000000..4ae0bd534 --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-indexes-subquery.n1ql @@ -0,0 +1,8 @@ +ANALYZE KEYSPACE airport INDEX (( + SELECT RAW name + FROM system:indexes + WHERE state = "online" + AND `using` = "gsi" + AND bucket_id = "travel-sample" + AND scope_id = "inventory" + AND keyspace_id = "airport" )); \ No newline at end of file diff --git a/modules/n1ql/examples/utility/analyze-indexes.n1ql b/modules/n1ql/examples/utility/analyze-indexes.n1ql new file mode 100644 index 000000000..343cdee2f --- /dev/null +++ b/modules/n1ql/examples/utility/analyze-indexes.n1ql @@ -0,0 +1,2 @@ +ANALYZE KEYSPACE airport +INDEX (def_inventory_airport_faa, def_inventory_airport_city); \ No newline at end of file diff --git a/modules/n1ql/examples/utility/execute-names.n1ql b/modules/n1ql/examples/utility/execute-names.n1ql new file mode 100644 index 000000000..6a382e4c9 --- /dev/null +++ b/modules/n1ql/examples/utility/execute-names.n1ql @@ -0,0 +1,2 @@ +EXECUTE NameParam +USING {"city": "Paris", "country": "France"}; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/execute-numbers.n1ql b/modules/n1ql/examples/utility/execute-numbers.n1ql new file mode 100644 index 000000000..d40e320ba --- /dev/null +++ b/modules/n1ql/examples/utility/execute-numbers.n1ql @@ -0,0 +1,2 @@ +EXECUTE NumParam +USING ["Paris", "France"]; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/explainfunction.jsonc b/modules/n1ql/examples/utility/explainfunction.jsonc new file mode 100644 index 000000000..fab456550 --- /dev/null +++ b/modules/n1ql/examples/utility/explainfunction.jsonc @@ -0,0 +1,72 @@ +[ + { + "function": "default:travel-sample.inventory.func1", + "plans": [ + { + "cardinality": 24024, + "cost": 33346.763562464446, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 24024, + "cost": 4108.612246388904, + "fr_cost": 12.170521655277593, + "size": 11 + }, + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 24024, + "cost": 32773.70177195316, + "fr_cost": 25.36320769946525, + "size": 569 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "discard_original": true, + "optimizer_estimates": { + "cardinality": 24024, + "cost": 33346.763562464446, + "fr_cost": 25.387061420349003, + "size": 569 + }, + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "statement": "select self.* from `default`:`travel-sample`.`inventory`.`route`" + } + ] + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/explainfunction.n1ql b/modules/n1ql/examples/utility/explainfunction.n1ql new file mode 100644 index 000000000..43bd39cf3 --- /dev/null +++ b/modules/n1ql/examples/utility/explainfunction.n1ql @@ -0,0 +1,4 @@ +CREATE FUNCTION func1() { + (SELECT * FROM default:`travel-sample`.inventory.route)}; + +EXPLAIN FUNCTION func1; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/explainfunctionjs.js b/modules/n1ql/examples/utility/explainfunctionjs.js new file mode 100644 index 000000000..9ef56f591 --- /dev/null +++ b/modules/n1ql/examples/utility/explainfunctionjs.js @@ -0,0 +1,4 @@ +function function1() { + SELECT * FROM default:`travel-sample`; // <.> + N1QL("SELECT 100"); // <.> +} \ No newline at end of file diff --git a/modules/n1ql/examples/utility/explainfunctionjs.jsonc b/modules/n1ql/examples/utility/explainfunctionjs.jsonc new file mode 100644 index 000000000..21bdfa449 --- /dev/null +++ b/modules/n1ql/examples/utility/explainfunctionjs.jsonc @@ -0,0 +1,99 @@ +[ + { + "function": "default:travel-sample.inventory.jsfunction1", + "line_numbers": [ + 3 //<.> + ], + "plans": [ //<.> + { + "cardinality": 31591, + "cost": 47086.49704894546, + "plan": { + "#operator": "Authorize", + "privileges": { + "List": [ + { + "Target": "default:travel-sample", + "Priv": 7, + "Props": 0 + } + ] + }, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "index": "def_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "travel-sample", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 31591, + "cost": 5402.279801258844, + "fr_cost": 12.170627071041082, + "size": 11 + }, + "using": "gsi" + }, + { + "#operator": "Fetch", + "keyspace": "travel-sample", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 31591, + "cost": 46269.39474997121, + "fr_cost": 25.46387878667884, + "size": 669 + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "discard_original": true, + "optimizer_estimates": { + "cardinality": 31591, + "cost": 47086.49704894546, + "fr_cost": 25.489743820991595, + "size": 669 + }, + "preserve_order": true, + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Stream", + "optimizer_estimates": { + "cardinality": 31591, + "cost": 47086.49704894546, + "fr_cost": 25.489743820991595, + "size": 669 + }, + "serializable": true + } + ] + } + }, + "statement": "SELECT * FROM default:`travel-sample` ;" + } + ] + } + ] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/explainfunctionjs.n1ql b/modules/n1ql/examples/utility/explainfunctionjs.n1ql new file mode 100644 index 000000000..b8337d4cb --- /dev/null +++ b/modules/n1ql/examples/utility/explainfunctionjs.n1ql @@ -0,0 +1,5 @@ +CREATE FUNCTION jsfunction1() + LANGUAGE JAVASCRIPT + AS "function1" AT "lib1"; + +EXPLAIN FUNCTION jsfunction1; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/prepare-names.jsonc b/modules/n1ql/examples/utility/prepare-names.jsonc new file mode 100644 index 000000000..5c2e6361c --- /dev/null +++ b/modules/n1ql/examples/utility/prepare-names.jsonc @@ -0,0 +1,130 @@ +[ + { + "encoded_plan": "H4sIAAAAAAAA/wEAAP//AAAAAAAAAAA=", + "featureControls": 76, + "indexApiVersion": 4, + "indexScanKeyspaces": { + "default:travel-sample.inventory.hotel": false + }, +// tag::extract[] + "name": "[127.0.0.1:8091]NameParam", // <.> +// end::extract[] + "namespace": "default", + "operator": { + "#operator": "Authorize", + "privileges": { + "List": [ + { + "Priv": 7, + "Props": 0, + "Target": "default:travel-sample.inventory.hotel" + } + ] + }, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "def_inventory_hotel_city", + "index_id": "b5cdc2005f6dc75a", + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 91.7, + "cost": 27.786686386654388, + "fr_cost": 12.172155794838107, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "$city", + "inclusion": 3, + "index_key": "`city`", + "low": "$city" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 91.7, + "cost": 346.296594097645, + "fr_cost": 27.51468477750976, + "size": 4469 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(((`hotel`.`city`) = $city) and ((`hotel`.`country`) = $country))", + "optimizer_estimates": { + "cardinality": 9.17, + "cost": 352.42679225186487, + "fr_cost": 28.18319057404409, + "size": 4469 + } + }, + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 9.17, + "cost": 353.03981206728685, + "fr_cost": 28.250041153697524, + "size": 4469 + }, + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Stream", + "optimizer_estimates": { + "cardinality": 9.17, + "cost": 353.03981206728685, + "fr_cost": 28.250041153697524, + "size": 4469 + } + } + ] + } + }, + "queryContext": "", + "reqType": "SELECT", + "signature": { + "*": "*" + }, + "text": "PREPARE NameParam AS\n/* tag::query[] */\nSELECT * FROM `travel-sample`.inventory.hotel\nWHERE city=$city AND country=$country;\n/* end::query[] */", + "useCBO": true + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/prepare-names.n1ql b/modules/n1ql/examples/utility/prepare-names.n1ql new file mode 100644 index 000000000..a47025c9e --- /dev/null +++ b/modules/n1ql/examples/utility/prepare-names.n1ql @@ -0,0 +1,3 @@ +PREPARE NameParam AS +SELECT * FROM hotel +WHERE city=$city AND country=$country; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/prepare-numbers.jsonc b/modules/n1ql/examples/utility/prepare-numbers.jsonc new file mode 100644 index 000000000..6aedaff10 --- /dev/null +++ b/modules/n1ql/examples/utility/prepare-numbers.jsonc @@ -0,0 +1,130 @@ +[ + { + "encoded_plan": "H4sIAAAAAAAA/wEAAP//AAAAAAAAAAA=", + "featureControls": 76, + "indexApiVersion": 4, + "indexScanKeyspaces": { + "default:travel-sample.inventory.hotel": false + }, +// tag::extract[] + "name": "[127.0.0.1:8091]NumParam", // <.> +// end::extract[] + "namespace": "default", + "operator": { + "#operator": "Authorize", + "privileges": { + "List": [ + { + "Priv": 7, + "Props": 0, + "Target": "default:travel-sample.inventory.hotel" + } + ] + }, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "def_inventory_hotel_city", + "index_id": "b5cdc2005f6dc75a", + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 91.7, + "cost": 27.786686386654388, + "fr_cost": 12.172155794838107, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "$1", + "inclusion": 3, + "index_key": "`city`", + "low": "$1" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { + "cardinality": 91.7, + "cost": 346.296594097645, + "fr_cost": 27.51468477750976, + "size": 4469 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(((`hotel`.`city`) = $1) and ((`hotel`.`country`) = $2))", + "optimizer_estimates": { + "cardinality": 9.17, + "cost": 352.42679225186487, + "fr_cost": 28.18319057404409, + "size": 4469 + } + }, + { + "#operator": "InitialProject", + "optimizer_estimates": { + "cardinality": 9.17, + "cost": 353.03981206728685, + "fr_cost": 28.250041153697524, + "size": 4469 + }, + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Stream", + "optimizer_estimates": { + "cardinality": 9.17, + "cost": 353.03981206728685, + "fr_cost": 28.250041153697524, + "size": 4469 + } + } + ] + } + }, + "queryContext": "", + "reqType": "SELECT", + "signature": { + "*": "*" + }, + "text": "PREPARE NumParam AS\n/* tag::query[] */\nSELECT * FROM `travel-sample`.inventory.hotel\nWHERE city=$1 AND country=$2;\n/* end::query[] */", + "useCBO": true + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/prepare-numbers.n1ql b/modules/n1ql/examples/utility/prepare-numbers.n1ql new file mode 100644 index 000000000..78d277cb1 --- /dev/null +++ b/modules/n1ql/examples/utility/prepare-numbers.n1ql @@ -0,0 +1,3 @@ +PREPARE NumParam AS +SELECT * FROM hotel +WHERE city=$1 AND country=$2; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/prepare-positions.n1ql b/modules/n1ql/examples/utility/prepare-positions.n1ql new file mode 100644 index 000000000..9b7c31989 --- /dev/null +++ b/modules/n1ql/examples/utility/prepare-positions.n1ql @@ -0,0 +1,3 @@ +PREPARE NumParam AS +SELECT * FROM hotel +WHERE city=? AND country=?; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-delete-all.n1ql b/modules/n1ql/examples/utility/statistics-delete-all.n1ql new file mode 100644 index 000000000..9c50df57a --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-delete-all.n1ql @@ -0,0 +1 @@ +UPDATE STATISTICS FOR airport DELETE ALL; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-delete.n1ql b/modules/n1ql/examples/utility/statistics-delete.n1ql new file mode 100644 index 000000000..08ee9d2d1 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-delete.n1ql @@ -0,0 +1,2 @@ +UPDATE STATISTICS FOR hotel +DELETE (city, country, free_breakfast); \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr-array.jsonc b/modules/n1ql/examples/utility/statistics-expr-array.jsonc new file mode 100644 index 000000000..2563fc241 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr-array.jsonc @@ -0,0 +1,58 @@ +[ + { + "cardinality": 1, + "cost": 39.80787755862344, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "optimizer_estimates": { + "cardinality": 105.64354562889939, + "cost": 39.44754768187852, + "fr_cost": 39.44754768187852, + "size": 11 + }, + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((distinct ((`hotel`.`public_likes`))))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "cover (any `p` in (`hotel`.`public_likes`) satisfies (`p` like \"A%\") end)", + "filter_covers": { + "cover (any `p` in (`hotel`.`public_likes`) satisfies ((\"A\" <= `p`) and (`p` < \"B\")) end)": true, + "cover (any `p` in (`hotel`.`public_likes`) satisfies (`p` like \"A%\") end)": true + }, + "index": "idx_public_likes", + // ... + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialGroup", + "aggregates": [ + "count(1)" + ], + "group_keys": [], + "optimizer_estimates": { + "cardinality": 1, + "cost": 39.797927684252365, + "fr_cost": 39.797927684252365, + "size": 11 + } + } + ] + } + }, + // ... + ] + }, + "text": "SELECT COUNT(1)\nFROM `travel-sample`.inventory.hotel\nWHERE ANY p IN public_likes SATISFIES p LIKE 'A%' END;" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr-array.n1ql b/modules/n1ql/examples/utility/statistics-expr-array.n1ql new file mode 100644 index 000000000..37bef35f1 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr-array.n1ql @@ -0,0 +1,16 @@ +/* tag::indexes[] */ +CREATE INDEX idx_public_likes +ON hotel((DISTINCT (`public_likes`))); +/* end::indexes[] */ + +/* tag::update[] */ +UPDATE STATISTICS FOR hotel((DISTINCT (`public_likes`))); +/* end::update[] */ + +/* tag::explain[] */ +EXPLAIN +/* tag::query[] */ +SELECT COUNT(1) FROM hotel +WHERE ANY p IN public_likes SATISFIES p LIKE 'A%' END; +/* end::query[] */ +/* end::explain[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr-nested.jsonc b/modules/n1ql/examples/utility/statistics-expr-nested.jsonc new file mode 100644 index 000000000..aff1337da --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr-nested.jsonc @@ -0,0 +1,34 @@ +[ + { + "cardinality": 1, + "cost": 118.0080501905589, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((distinct (array ((`r`.`ratings`).`Overall`) for `r` in (`hotel`.`reviews`) end)))", + "cover ((meta(`hotel`).`id`))", + "cover (count(1))" + ], + "filter_covers": { + "cover (any `r` in (`hotel`.`reviews`) satisfies (((`r`.`ratings`).`Overall`) = 4) end)": true + }, + "index": "idx_reviews_ratings_overall", + // ... + "optimizer_estimates": { + "cardinality": 1, + "cost": 118.00369129161537, + "fr_cost": 12.312997158401616, + "size": 19 + }, + // ... + }, + // ... + ] + }, + "text": "SELECT COUNT(1)\nFROM `travel-sample`.inventory.hotel\nWHERE ANY r IN reviews SATISFIES r.ratings.Overall = 4 END;" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr-nested.n1ql b/modules/n1ql/examples/utility/statistics-expr-nested.n1ql new file mode 100644 index 000000000..06b1a0727 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr-nested.n1ql @@ -0,0 +1,19 @@ +/* tag::indexes[] */ +CREATE INDEX idx_reviews_ratings_overall +ON hotel(DISTINCT ARRAY r.ratings.Overall +FOR r IN reviews END); +/* end::indexes[] */ + +/* tag::update[] */ +UPDATE STATISTICS +FOR hotel(DISTINCT ARRAY r.ratings.Overall +FOR r IN reviews END); +/* end::update[] */ + +/* tag::explain[] */ +EXPLAIN +/* tag::query[] */ +SELECT COUNT(1) FROM hotel +WHERE ANY r IN reviews SATISFIES r.ratings.Overall = 4 END; +/* end::query[] */ +/* end::explain[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr-predicate.jsonc b/modules/n1ql/examples/utility/statistics-expr-predicate.jsonc new file mode 100644 index 000000000..27b9c889b --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr-predicate.jsonc @@ -0,0 +1,135 @@ +[ + { + "cardinality": 1, // <1> + "cost": 1319.7883498503274, + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "index": "idx_country_city", + "index_id": "9071bf247db9d656", + "index_projection": { + "primary_key": true + }, + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { // <2> + "cardinality": 361.00000000000006, + "cost": 74.51787485734917, + "fr_cost": 12.173179708746119, + "size": 11 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"United States\"", + "inclusion": 3, + "low": "\"United States\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { // <3> + "cardinality": 361.00000000000006, + "cost": 1292.900802248151, + "fr_cost": 27.514960671047508, + "size": 4467 + }, + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "(((`hotel`.`country`) = \"United States\") and ((`hotel`.`free_breakfast`) = true))", + "optimizer_estimates": { // <4> + "cardinality": 267.3053435114504, + "cost": 1317.028460795967, + "fr_cost": 27.605223208379773, + "size": 4467 + } + }, + { + "#operator": "InitialGroup", + "aggregates": [ + "count(*)" + ], + "group_keys": [], + "optimizer_estimates": { // <5> + "cardinality": 1, + "cost": 1319.7015142310815, + "fr_cost": 1319.7015142310815, + "size": 4467 + } + } + ] + } + }, + { + "#operator": "IntermediateGroup", + "aggregates": [ + "count(*)" + ], + "group_keys": [], + "optimizer_estimates": { // <6> + "cardinality": 1, + "cost": 1319.7115142310815, + "fr_cost": 1319.7115142310815, + "size": 4467 + } + }, + { + "#operator": "FinalGroup", + "aggregates": [ + "count(*)" + ], + "group_keys": [], + "optimizer_estimates": { // <7> + "cardinality": 1, + "cost": 1319.7215142310815, + "fr_cost": 1319.7215142310815, + "size": 4467 + } + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { // <8> + "cardinality": 1, + "cost": 1319.7883498503274, + "fr_cost": 1319.7883498503274, + "size": 4467 + }, + "result_terms": [ + { + "expr": "count(*)" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT COUNT(*) FROM `travel-sample`.inventory.hotel\nWHERE country = 'United States' AND free_breakfast = true;" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr-predicate.n1ql b/modules/n1ql/examples/utility/statistics-expr-predicate.n1ql new file mode 100644 index 000000000..729d1d587 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr-predicate.n1ql @@ -0,0 +1,19 @@ +/* tag::indexes[] */ +CREATE INDEX idx_country_city IF NOT EXISTS +ON hotel(country, city); + +CREATE INDEX idx_city_country IF NOT EXISTS +ON hotel(city, country); +/* end::indexes[] */ + +/* tag::update[] */ +UPDATE STATISTICS FOR hotel(city, country, free_breakfast); +/* end::update[] */ + +/* tag::explain[] */ +EXPLAIN +/* tag::query[] */ +SELECT COUNT(*) FROM hotel +WHERE country = 'United States' AND free_breakfast = true; +/* end::query[] */ +/* end::explain[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr.jsonc b/modules/n1ql/examples/utility/statistics-expr.jsonc new file mode 100644 index 000000000..c1137d288 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr.jsonc @@ -0,0 +1,83 @@ +[ + { + "cardinality": 1, // <1> + "cost": 36.39093947963759, // <2> + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`hotel`.`country`))", + "cover ((`hotel`.`city`))", + "cover ((meta(`hotel`).`id`))", + "cover (count(*))" + ], + "index": "idx_country_city", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "expr": "1", + "id": 3, + "keypos": -1 + } + ] + }, + "index_id": "9071bf247db9d656", + "index_projection": { + "entry_keys": [ + 3 + ] + }, + "keyspace": "hotel", + "namespace": "default", + "optimizer_estimates": { // <3> + "cardinality": 1, + "cost": 36.386580580694044, + "fr_cost": 12.314601064983428, + "size": 19 + }, + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"France\"", + "inclusion": 3, + "low": "\"France\"" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "optimizer_estimates": { // <4> + "cardinality": 1, + "cost": 36.39093947963759, + "fr_cost": 12.318959963926968, + "size": 19 + }, + "result_terms": [ + { + "expr": "cover (count(*))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT COUNT(*) FROM `travel-sample`.inventory.hotel WHERE country = 'France';" + } +] \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-expr.n1ql b/modules/n1ql/examples/utility/statistics-expr.n1ql new file mode 100644 index 000000000..2cc19ede4 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-expr.n1ql @@ -0,0 +1,15 @@ +/* tag::indexes[] */ +CREATE INDEX idx_country_city ON hotel(country, city); +CREATE INDEX idx_city_country ON hotel(city, country); +/* end::indexes[] */ + +/* tag::update[] */ +UPDATE STATISTICS FOR hotel(city, country); +/* end::update[] */ + +/* tag::explain[] */ +EXPLAIN +/* tag::query[] */ +SELECT COUNT(*) FROM hotel WHERE country = 'France'; +/* end::query[] */ +/* end::explain[] */ \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-index-on.n1ql b/modules/n1ql/examples/utility/statistics-index-on.n1ql new file mode 100644 index 000000000..5ffec2887 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-index-on.n1ql @@ -0,0 +1,2 @@ +UPDATE STATISTICS FOR +INDEX def_inventory_airport_city ON airport; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-index.n1ql b/modules/n1ql/examples/utility/statistics-index.n1ql new file mode 100644 index 000000000..d47aa4775 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-index.n1ql @@ -0,0 +1,2 @@ +UPDATE STATISTICS FOR +INDEX airport.def_inventory_airport_city; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-indexes-all.n1ql b/modules/n1ql/examples/utility/statistics-indexes-all.n1ql new file mode 100644 index 000000000..2ef786c86 --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-indexes-all.n1ql @@ -0,0 +1 @@ +UPDATE STATISTICS FOR airport INDEX ALL; \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-indexes-subquery.n1ql b/modules/n1ql/examples/utility/statistics-indexes-subquery.n1ql new file mode 100644 index 000000000..5a90e9dea --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-indexes-subquery.n1ql @@ -0,0 +1,8 @@ +UPDATE STATISTICS FOR airport INDEX (( -- <1> + SELECT RAW name -- <2> + FROM system:indexes + WHERE state = "online" + AND `using` = "gsi" -- <3> + AND bucket_id = "travel-sample" + AND scope_id = "inventory" + AND keyspace_id = "airport" )); \ No newline at end of file diff --git a/modules/n1ql/examples/utility/statistics-indexes.n1ql b/modules/n1ql/examples/utility/statistics-indexes.n1ql new file mode 100644 index 000000000..562949f9b --- /dev/null +++ b/modules/n1ql/examples/utility/statistics-indexes.n1ql @@ -0,0 +1,2 @@ +UPDATE STATISTICS FOR airport +INDEX (def_inventory_airport_faa, def_inventory_airport_city); \ No newline at end of file diff --git a/modules/n1ql/pages/.n1ql_application_continuity.adoc b/modules/n1ql/pages/.n1ql_application_continuity.adoc new file mode 100644 index 000000000..84e82d9df --- /dev/null +++ b/modules/n1ql/pages/.n1ql_application_continuity.adoc @@ -0,0 +1,6 @@ += {sqlpp} Application Continuity +:description: No special strategy is required to ensure {sqlpp} application continuity during Couchbase Server upgrades. + +{description} + +Refer to xref:clusters:upgrade-database.html.adoc[] for more information about upgrades. diff --git a/modules/n1ql/pages/advanced.adoc b/modules/n1ql/pages/advanced.adoc new file mode 100644 index 000000000..1d8c3b020 --- /dev/null +++ b/modules/n1ql/pages/advanced.adoc @@ -0,0 +1,45 @@ += Advanced Query Features +:page-role: tiles -toc +:page-aliases: guides:optimize.adoc +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +include::ROOT:partial$component-signpost.adoc[] + +== Cost-Based Optimizer + +The cost-based optimizer takes into account the cost of memory, CPU, network transport, and disk usage when choosing the optimal plan to execute a query. + +* xref:n1ql:n1ql-language-reference/cost-based-optimizer.adoc[] +* xref:guides:cbo.adoc[] + +== {sqlpp} Support for Couchbase Transactions + +{sqlpp} offers full support for Couchbase ACID transactions. + +* xref:n1ql:n1ql-language-reference/transactions.adoc[] +* xref:guides:transactions.adoc[] + +== Flex Indexes + +Flex Indexes enable a {sqlpp} query to use a Search index transparently with standard {sqlpp} syntax. + +* xref:n1ql:n1ql-language-reference/flex-indexes.adoc[] + +== Time Series Data + +In clusters using Couchbase Server 7.2 and later, {sqlpp} enables you to store and query time series data. + +* xref:n1ql:n1ql-language-reference/time-series.adoc[] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-intro/cbq.adoc b/modules/n1ql/pages/n1ql-intro/cbq.adoc new file mode 100644 index 000000000..aac48142c --- /dev/null +++ b/modules/n1ql/pages/n1ql-intro/cbq.adoc @@ -0,0 +1,2409 @@ += cbq: The Command Line Shell for {sqlpp} +:description: cbq is a comprehensive command line shell for {sqlpp}. +:tabs: +:page-partial: + +[abstract] +{description} +It is a powerful, developer friendly tool that enables you to query and update data from Couchbase Capella. +The cbq shell enables you to perform all the operations that are supported by the Query tab and more, such as additional scripting functionality. + +include::ROOT:partial$component-signpost.adoc[] + +The cbq shell executable, [.cmd]`cbq`, is available in the Couchbase xref:reference:command-line-tools.adoc[command line tools] package beginning with version 7.6.2. + +== Prerequisites + +The procedures on this page assume the following: + +* You have xref:reference:command-line-tools.adoc[downloaded and installed] the command line tools package. +* You have xref:get-started:connect.adoc[copied the connection string] for your cluster. +* You have xref:clusters:manage-database-users.adoc[configured cluster access] by creating cluster access credentials. +You'll need the username and password for the cluster credentials to connect to the cluster. +* You have xref:clusters:allow-ip-address.adoc[added your IP address] to the cluster's list of allowed IPs. +* You have xref:get-started:create-account.adoc#next-steps[downloaded the security certificate] for your cluster. + +You can do all of this from a single location using the Connect page in the Capella UI. +See xref:get-started:connect.adoc[] and follow the instructions for the CLI tools. + +== Examples on this Page + +The examples on this page use the `travel-sample` dataset, which is supplied with Couchbase Capella. +For instructions on how to install the sample data, see xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data]. + +[tabs] +==== +Linux:: ++ +-- +In the command line examples: + +* `$BASE_URL` is the connection string generated by Couchbase Capella. +* `$USER` is the user name for the cluster credentials. +* `$PASSWORD` is the password for the cluster credentials. +* `$CACERT` is the name and path of the cluster security certificate. +-- + +macOS:: ++ +-- +In the command line examples: + +* `$BASE_URL` is the connection string generated by Couchbase Capella. +* `$USER` is the user name for the cluster credentials. +* `$PASSWORD` is the password for the cluster credentials. +* `$CACERT` is the name and path of the cluster security certificate. +-- + +Microsoft Windows:: ++ +-- +In the command line examples: + +* `%BASE_URL%` is the connection string generated by Couchbase Capella. +* `%USER%` is the user name for the cluster credentials. +* `%PASSWORD%` is the password for the cluster credentials. +* `%CACERT%` is the name and path of the cluster security certificate. +-- + +Shell Command:: ++ +-- +In the shell command examples: + +* `` is the connection string generated by Couchbase Capella. +* `` is the user name for the cluster credentials. +* `` is the password for the cluster credentials. +* `` is the name and path of the cluster security certificate. +-- +==== + +== Running the cbq Shell + +When starting the cbq shell you can provide a set of command line options. +If no options are present then cbq assumes default values for expected options. + +To run [.cmd]`cbq`: + +. Open a command window. +. Change to the directory where you installed the Couchbase command line tools. ++ +[tabs] +==== +Linux:: ++ +-- +[source,sh] +---- +cd couchbase-server-tools/bin +---- +-- + +macOS:: ++ +-- +[source,sh] +---- +cd couchbase-server-tools/bin +---- +-- + +Microsoft Windows:: ++ +-- +[source,cmd] +---- +cd couchbase-server-tools\bin +---- +-- +==== + +. Run the following command to connect to the Couchbase Capella cluster and start the interactive query shell: ++ +[tabs] +==== +Linux:: ++ +-- +[source,sh] +---- +./cbq -u $USER -p $PASSWORD -e $BASE_URL --cacert $CACERT -skip-verify +---- +-- + +macOS:: ++ +-- +[source,sh] +---- +./cbq -u $USER -p $PASSWORD -e $BASE_URL --cacert $CACERT -skip-verify +---- +-- + +Microsoft Windows:: ++ +-- +[source,cmd] +---- +cbq -u %USER% -p %PASSWORD% -e %BASE_URL% --cacert %CACERT% -skip-verify +---- +-- +==== + +For more information about connecting to Couchbase Capella, see <>, <>, and <>. + +For the complete list of command line options, see <>. + + +=== Executing a Single Command + +When you start the cbq shell, the cbq shell prompt is displayed. + +==== +[source,console] +---- +cbq> +---- +==== + +The cbq shell interface accepts accepts shell commands as well as {sqlpp} commands. +All the cbq shell commands start with a backslash (`\`). +If the command does not start with a backslash (`\`), the cbq shell interprets the command as a {sqlpp} command. + +* To execute a {sqlpp} query at the cbq prompt, type the query. +At the end of the query, type a semicolon `;` and press kbd:[Enter]. + +* To execute a cbq command at the cbq prompt, type the command name starting with a backslash `\`. +At the end of the command, type a semicolon `;` and press kbd:[Enter]. + +The cbq shell enables you to manipulate query parameters. +See <> for details. + +For the complete list of shell commands, see <>. + +=== Support for Multi-line Queries + +The cbq shell supports multi-line queries by default, enabling you to enter a query over multiple lines. +When entering a query, you can hit kbd:[Enter] without specifying a semicolon (`;`) at the end of the line to move the cursor to the next line. +The prompt `>` indicates that the shell is in multi-line mode. +For example: + +==== +[source,console] +---- +cbq> SELECT * + > FROM `travel-sample`.inventory.airline + > LIMIT 1; +---- +==== + +When you're done, use a semicolon `;` to indicate the end of the query, and then press kbd:[Enter] to execute the query. + +=== Handling Comments + +You can add comments in your query by preceding the comment with a `#` or `--`. +The cbq shell interprets a line that starts with `#` or `--` as a comment, logs the line into history, and returns a new prompt. +No other action is taken. + +==== +[source,sqlpp] +---- +SELECT * +#This is the first comment +FROM `travel-sample`.inventory.airline +--This is the second comment +LIMIT 1; +---- +==== + +However, if a comment exists within a statement, it is considered as part of the {sqlpp} command. +If the cbq shell encounters a block comment (enclosed between `/{asterisk}` \... `{asterisk}/`) within a statement, it sends the block comment to the query service. + +==== +[source,sqlpp] +---- +SELECT * FROM `travel-sample`.inventory.airline /* Block comment */ LIMIT 1; +---- +==== + +=== File Based Operations + +The cbq shell can execute {sqlpp} and shell commands contained in files using file-based commands and options. +See <> for more information. + +=== History + +The [.cmd]`cbq` shell stores the history for every session. +All the commands executed in a session are stored in history. +By default, history is stored in `~/.cbq_history`. +You can change the name of the file using the SET command to set the predefined parameter [.var]`histfile`. +See <> for more information. + +By default, all the commands are stored in the specified file. +You can scroll through history and retrieve the commands from history using the scrolling arrow keys. +Once the query is on the command prompt, you can edit it before executing the updated query. + +=== Help + +Help displays the help information for the shell commands and for the general usage of cbq. + +[tabs] +==== +Command Line Option:: ++ +-- +Use the `-h` or `--help` command line option when bringing up the shell to display the information for all available options. + +''' + +.Example +[source,sh] +---- +./cbq -h +---- +-- + +Shell Command:: ++ +-- +Use the [.cmd]`\HELP` shell command during a session to display information for specific shell commands. +If you specify one or more commands, the shell displays the usage information for the specified commands. + +If you do not specify a command, the cbq shell lists all the commands for which syntax help is available. + +''' + +.Example +[source,sqlpp] +---- +\HELP; +---- +-- +==== + +[#cbq-connect-to-cluster] +== Connecting to the Cluster + +To connect the cbq shell to the cluster, use the connection string generated by Couchbase Capella. + +[tabs] +==== +Command Line Option:: ++ +-- +To establish a connection on startup, use the `-e` or `--engine` command line option, followed by the connection string. + +''' + +.Example +[source,sh] +---- +./cbq -e $BASE_URL -u $USER -p $PASSWORD --cacert $CACERT -skip-verify +---- + +.Result +---- +Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. + +Path to history file for the shell : ~/.cbq_history +---- +-- + +Shell Command:: ++ +-- +To establish a connection during a session, use the `\CONNECT` shell command, followed by the connection string. + +''' + +.Example +[source,sqlpp] +---- +\CONNECT ; +---- + +.Result +---- +Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. +---- +-- +==== + +By default, the connection string is a URL, consisting of the protocol scheme and the host. + +To connect to Couchbase Capella, you must use the `couchbases://` protocol scheme. +This protocol scheme is encrypted. +For more details, refer to <>. + +Note that you cannot specify the port when using the `couchbases://` protocol scheme. + +If you do not specify the connection string, the default URL `+http://localhost:8091+` is used. +This does not enable you to connect to Couchbase Capella. +An error is thrown if the URL is invalid. + +=== Disconnecting + +You can close the connection with a Couchbase Capella cluster during the session without exiting the shell using the [.cmd]`\DISCONNECT` command. +If the shell is not connected to a cluster, an error with a message that the shell is not connected to any instance is thrown. + +==== +.Example +[source,sqlpp] +---- +\DISCONNECT; +---- + +.Result +---- +Couchbase query shell not connected to any endpoint. Use \CONNECT command to connect. +---- +==== + +=== Bringing Up an Unconnected Instance + +You can bring up the shell without connecting to a Couchbase Capella cluster by using the [.opt]`-ne` or [.opt]`--no-engine` option. +After starting cbq without any connection, you can connect to a cluster using the [.cmd]`\CONNECT` command. + +==== +.Example +[source,sh] +---- +./cbq -ne +---- + +.Result +---- +Path to history file for the shell : ~/.cbq_history +---- +==== + +=== Exiting the cbq Shell + +You can exit the cbq shell by pressing kbd:[Ctrl+D] or by using the `\EXIT` or `\QUIT` command. + +The cbq shell first saves the history, closes existing connections, saves the current session in a session file, resets all environment variables, and then closes the shell liner interface. + +==== +.Example +[source,sqlpp] +---- +\EXIT; +---- + +.Result +[source,console] +---- +$ +---- +==== + +[#cbq-single-cred] +== Providing Credentials + +You can pass a single user name credential to the cbq shell on startup using the `-u` or `--username` command line option, followed by the user name. +The shell then prompts you for a password. + +==== +.Example +[source,sh] +---- +./cbq -e $BASE_URL -u $USER --cacert $CACERT -skip-verify +---- + +.Result +---- +Enter Password: +Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. +---- +==== + +You can also provide a single password credential using the `-p` or `--password` command line option, followed by the password. +You cannot use this option by itself. +It must be used with the `-u` option to specify the user name that the password is associated with. + +==== +.Example +[source,sh] +---- +./cbq -e $BASE_URL -u $USER -p $PASSWORD --cacert $CACERT -skip-verify +---- + +.Result +---- +Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. +---- +==== + +[#accessing-a-secure-keyspace] +=== Providing Credentials in the Connection String + +You can pass the username and password by inserting them into the connection string. +This method is not recommended when starting cbq, as you must quote or URL-encode any special characters in the username or password. +However, this method may be useful for specifying the username and password when connecting to Couchbase Capella within a cbq session. + +To pass credentials in the connection string: + +. Add the username immediately after the `couchbases://` protocol scheme. +. After the username, add a colon `:` followed by the password. +. After the password, add an at sign `@` followed by the rest of the connection string. + +[tabs] +==== +Command Line Option:: ++ +-- +To pass credentials on startup, use the `-e` or `--engine` command line option, and specify the username and password in the connection string. + +''' + +In this example, `$HOST` is the part of the connection string following the `couchbases://` protocol scheme. + +.Example +[source,sh] +---- +./cbq -engine="couchbases://$USER:$PASSWORD@$HOST/" --cacert $CACERT -skip-verify +---- +-- + +Shell Command:: ++ +-- +To pass credentials during a session, use the `\CONNECT` shell command, and specify the username and password in the connection string. + +''' + +In this example, `` is the part of the connection string following the `couchbases://` protocol scheme. + +.Example +[source,sqlpp] +---- +\CONNECT couchbases://:@; +---- +-- +==== + +[#cbq-multiple-creds] +=== Switching Between Credentials + +When starting the cbq shell, you can set the credentials using a single command line option, as an alternative to specifying the username and password separately. +This method is not recommended, as you must quote or escape any special characters in the username or password. + +You can also use the `\SET` or `\PUSH` shell command to set the credentials query parameter within a session. +This enables you to change credentials before executing a query, for example to switch to a cluster user with access to another keyspace. +Note that the credentials are set for the remainder of the shell session and not just on a per query basis. + +The list of credentials can contain one or multiple credentials. +Each credential consists of an identity and a password separated by a colon `:`. +However, if you specify multiple credentials, Couchbase Capella only recognizes the first credential. + +[tabs#pass-cred-shell-cmd] +==== +Command Line Option:: ++ +-- +To set the credentials on startup, use the `-c` or `--credentials` command line option, followed by the list of credentials. + +''' + +.Example +[source,sh] +---- +./cbq -e $BASE_URL -c=$USER:$PASSWORD --cacert $CACERT -skip-verify +---- +-- + +Shell Command:: ++ +-- +To change credentials during a session, use the `\SET` shell command to specify the [.param]`-creds` query parameter, followed by the list of credentials. + +''' + +.Example +[source,sqlpp] +---- +\SET -creds :; +---- +-- +==== + +ifdef::flag-devex-rest-api[] +For more information about using multiple credentials, see xref:n1ql-rest-query:intro.adoc#creds[Query Service REST API] and xref:n1ql:n1ql-rest-api/exauthrequest.adoc[]. +endif::flag-devex-rest-api[] + +=== Displaying the Credentials + +You can display the credentials for the current session using the <> shell command. +This command displays only the user names (and not the passwords). + +==== +.Example +[source,sqlpp] +---- +\ECHO -creds; +---- + +.Result +---- +:* +---- +==== + +You can also display a full list of variables using the <> command specified without any arguments. + +==== +.Example +[source,sqlpp] +---- +\SET; +---- + +.Result +---- + Query Parameters : + Parameter name : creds + Value : [ ":*" ] + + + Named Parameters : + + User Defined Session Parameters : + + Predefined Session Parameters : + Parameter name : histfile + Value : [".cbq_history"] + + Parameter name : batch + Value : ["off"] + + Parameter name : quiet + Value : [false] +---- +==== + +[#cbq-encrypted] +== Using an Encrypted Connection + +You must use the encrypted `couchbases://` protocol scheme with a domain name to connect to a cluster deployed in Couchbase Capella. +To do this, you can provide the root CA certificate, the chain certificate, and the client key file using the <>, <>, and <> options. +You can use the <> option to skip the verification of certificates. + +For more details, refer to <>. + +[#cbq-parameter-manipulation] +== Parameter Manipulation + +The cbq shell categorizes parameters into the following types: + +* Query parameters +* Named parameters +* User-defined session variables +* Pre-defined session variables + +=== Parameter Configuration + +When using parameters, you can set a stack of values for each parameter. +You can either push a new value onto the stack using the `\PUSH` command, or set the current value for a parameter using the `\SET` command. +The `\SET` command always modifies the top of a variable's stack while the `\PUSH` command adds to the stack. +When you use `\PUSH` with no arguments, it copies the top element of every parameter's stack (except the predefined parameters) and pushes that copy to the top of its respective stack. +As a result, each stack grows by 1, but the values are preserved. +You can then use the `\SET` command to modify the top value. + +To unset the values from a parameter's stack, you can use the `\UNSET` command to remove all the values from the stack and delete the corresponding parameter stack. +However, if you want to delete a single value from the settings, use the `\POP` command. +When you use the `\POP` command with no arguments, it pops the one value from the top of each parameter's stack. + +To display all the parameters defined in a session, use the `\SET` command with no arguments. + +=== Setting Variable Values + +To set the value of a parameter, use the `\SET` or `\PUSH` shell command, followed by a parameter name and parameter value. + +The parameter name may have a prefix, depending on the type of parameter: query parameter, named parameter, user-defined session variable, or predefined session variable. +The cbq shell uses the prefix to differentiate between the different types of parameters. + +.Prefixes for Parameters +[#table_ltk_c5s_5v,cols="2,5"] +|=== +| Prefix | Parameter Type + +| `-` +| Query parameter + +| `-$` or `-@` +| Named parameters + +| `$` +| User defined session variable + +| No prefix +| Predefined (built-in) session variable +|=== + +NOTE: Positional parameters are set using the [.param]`-args` query parameter. + +For more details about the available query parameters (prefixed by `-`), see xref:n1ql:n1ql-manage/query-settings.adoc#section_nnj_sjk_k1b[Request-Level Parameters]. +As a best practice, save the initial set of basic parameters and their default values using the [.cmd]`\PUSH` command (with no arguments). + +==== +The following example sets the `airport` named parameter, pushes two positional parameters to the `args` query parameter stack, and then displays all parameters. + +.Example +[source,sqlpp] +---- +\SET -$airport "SJC"; +\PUSH -args ["LAX", 6]; +\SET; +---- + +.Result +---- +Query Parameters :: +Parameter name : args Value [["LAX",6]] + +Named Parameters :: +Parameter name : airport Value ["SJC"] + +User Defined Session Parameters :: + +Predefined Session Parameters :: +Parameter name : histfile Value [".cbq_history"] +---- + +The following example pushes a new value to the `airport` named parameter stack, duplicates the top value in each stack except the predefined session parameters, and then displays all parameters. + +.Example +[source,sqlpp] +---- +\PUSH -$airport "SFO"; +\PUSH; +\SET; +---- + +.Result +---- +Query Parameters :: +Parameter name : args Value [["LAX",6] ["LAX",6]] + +Named Parameters :: +Parameter name : airport Value ["SJC" "SFO" "SFO"] + +User Defined Session Parameters :: + +Predefined Session Parameters :: +Parameter name : histfile Value [".cbq_history"] +---- + +The following example sets the top level of the `airport` named parameter stack to a new value, and then displays all parameters. + +.Example +[source,sqlpp] +---- +\SET -args ["SFO", 8]; +\SET; +---- + +.Result +---- +Query Parameters :: +Parameter name : args Value [["LAX",6] ["SFO",8]] + +Named Parameters :: +Parameter name : airport Value ["SJC" "SFO" "SFO"] + +User Defined Session Parameters :: + +Predefined Session Parameters :: +Parameter name : histfile Value [".cbq_history"] +---- +==== + +=== Handling Named Parameters + +To define named parameters, use the `\SET` or `\PUSH` command. +For each named parameter, prefix the variable name with `-$` or `-@`. + +For more details about named parameters, see xref:n1ql:n1ql-manage/query-settings.adoc#section_srh_tlm_n1b[Named Parameters and Positional Parameters]. + +==== +The following example creates named parameters `r` and `date` with values `9.5` and `"1-1-2016"` respectively. + +.Example +[source,sqlpp] +---- +\SET -$r 9.5; +\SET -@date "1-1-2016"; +---- +==== + +=== Handling Positional Parameters + +To define positional parameters, use the `\SET` or `\PUSH` command with the [.param]`-args` query parameter, followed by an array containing the different values that correspond to positions within the query. + +For more details about positional parameters, see xref:n1ql:n1ql-manage/query-settings.adoc#section_srh_tlm_n1b[Named Parameters and Positional Parameters]. + +==== +.Example +[source,sqlpp] +---- +\SET -args [ 9.5, "1-1-2016"]; +---- +==== + +=== Handling Predefined Session Variables + +The following table lists the available predefined session variables. + +.Predefined Session Variables +[cols="1,1,2"] +|=== +| Variable Name | Possible Values | Description + +| `histfile` +| Valid file name +| Specifies the file name to store the command history. +By default the file is saved in the user's home directory. + +Default: `.cbq_history` + +| `batch` +| String (`"on"`, `"off"`) +| This variable is available only with the Analytics Service. +When specified, cbq sends the queries to Analytics only when you hit EOF or \ to indicate the end of the batch input. + +Default: `"off"` + +| `quiet` +| Boolean +| When specified, disables the startup connection message for the cbq shell. + +Default: `false` +|=== + +=== Resetting Variable Values + +You can reset the value of a variable by either popping it or deleting it altogether. + +To pop the top of every parameter's stack once, use the `\POP` command without any arguments. + +==== +.Example +[source,sqlpp] +---- +\POP; +\SET; +---- + +.Result +---- +Query Parameters :: +Parameter name : args Value [["LAX",6]] + +Named Parameters :: +Parameter name : airport Value ["SJC" "SFO"] + +User Defined Session Parameters :: + +Predefined Session Parameters :: +Parameter name : histfile Value [".cbq_history"] +---- +==== + +To pop the top value from a single parameter's stack, use the `\POP` command, followed by the parameter prefix and parameter name. + +==== +.Example +[source,sqlpp] +---- +\POP -$airport; +\SET; +---- + +.Result +---- +Query Parameters :: +Parameter name : args Value [["LAX",6]] + +Named Parameters :: +Parameter name : airport Value ["SJC"] + +User Defined Session Parameters :: + +Predefined Session Parameters :: +Parameter name : histfile Value [".cbq_history"] +---- +==== + +To pop all the values of a parameter's stack and then delete the parameter, use the `\UNSET` command, followed by the parameter prefix and parameter name. + +==== +.Example +[source,sqlpp] +---- +\UNSET -$airport; +\SET; +---- + +.Result +---- +Query Parameters :: +Parameter name : args Value [["LAX",6]] + +Named Parameters :: + +User Defined Session Parameters :: + +Predefined Session Parameters :: +Parameter name : histfile Value [".cbq_history"] +---- +==== + +[#cbq-shell-cmd-echo] +== Using ECHO to Display Values of Parameters and More + +The ECHO command displays the current values of the parameters set for a session. +You can use it to display any input string or command aliases that have been created using the ALIAS shell command. + +=== Echo a String or Statement + +To echo a string or a {sqlpp} statement, use the `\ECHO` command, followed by the string or statement. + +==== +.Example +[source,sqlpp] +---- +\ECHO hello; +---- + +.Result +---- +hello +---- +==== + +=== Echo an Alias + +To echo a command alias, use the `\ECHO` command, followed by two backslashes and the command alias name. + +==== +.Example +[source,sqlpp] +---- +\ECHO \\travel-alias1; +---- + +.Result +[source,sqlpp] +---- +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +---- +==== + +=== Echo a Parameter + +To echo a parameter, use the `\ECHO` command, followed by the parameter prefix and parameter name. + +If you do not include the parameter prefix, the shell considers the parameter as a generic statement and displays the parameter as is. + +==== +.Example +[source,sqlpp] +---- +\ECHO -$r; +---- + +.Result +---- +9.5 +---- +==== + +[#cbq-shell-cmd-alias] +== Command Alias + +Using the ALIAS shell command, you can define and store aliases for commands. +This is useful when you have lengthy queries that need to be executed often. + +=== Create Command Aliases + +To define an alias, use the `\ALIAS` command, followed by the command alias name and the query. + +==== +.Example +[source,sqlpp] +---- +\ALIAS travel-alias1 SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +---- +==== + +=== Run Command Aliases + +To run the command alias, type two backslashes `\\`, followed by the command alias name. + +==== +.Example +[source,sqlpp] +---- +\\travel-alias1; +---- + +.Result +[source,json] +---- +{ + "requestID": "b25c84d6-7b7b-440a-a286-5027e6ecbbb5", + "signature": { + "*": "*" + }, + "results": [ + { + "airline": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + } + } + ], + "status": "success", + // ... +} +---- +==== + +=== List Command Aliases + +To list all the existing aliases, use the `\ALIAS` command without options. + +==== +.Example +[source,sqlpp] +---- +\ALIAS; +---- + +.Result +---- +serverversion select version() +travel-alias1 SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +---- +==== + +=== Delete Command Aliases + +You can delete a defined alias using the `\UNLIAS` command, followed by the alias name. +This command can take multiple arguments and deletes the defined alias for every input name. + +==== +.Example +[source,sqlpp] +---- +\UNALIAS serverversion travel-alias1; +---- + +.Check aliases +[source,sqlpp] +---- +\ALIAS; +---- + +.Result +---- + ERROR 141 : Alias does not exist : +---- +==== + +[#cbq-prepared-stmts] +== Executing Prepared Statements + +You can use the shell command to execute prepared statements. +As a pre-requisite, you must first prepare a statement. +To prepare and execute a statement, follow these steps: + +. Set the named and positional parameters that are present in the prepared statement. +. Prepare a statement using the {sqlpp} xref:n1ql:n1ql-language-reference/prepare.adoc[PREPARE] statement. +If you do not specify a name for the prepared statement, a unique name is assigned. +You can use this auto-assigned name when executing the prepared statement. +If you specify a name, you can use this name to run the prepared statement. +. Execute the prepared statement using the {sqlpp} xref:n1ql:n1ql-language-reference/execute.adoc[EXECUTE] statement. + +== Canceling a Query + +You can cancel a running query by using the kbd:[Ctrl+C] keys. + +=== Connection Timeout Parameter + +You can use the timeout parameter to limit the running time of a query. +This parameter specifies the time to wait before returning an error when executing a query. + +Timeout can be specified in the following units: `ns` for nanoseconds, `μs` for microseconds, `ms` for milliseconds, `s` for seconds, `m` for minutes, and `h` for hours. +Examples of valid values include `"0.5s"`, `"10ms"`, or `"1m"`. +An error is thrown if the timeout is invalid. + +[tabs] +==== +Command Line Option:: ++ +-- +Use the `-t` or `--timeout` command line option, followed by the length of the timeout. + +''' + +.Example +[source,sh] +---- +./cbq -e $BASE_URL -u $USER -p $PASSWORD --cacert $CACERT -skip-verify --timeout="2s" +---- +-- + +Shell Command:: ++ +-- +Use the `\SET` shell command to set the `TIMEOUT` parameter, followed by the length of the timeout. + +''' + +.Example +[source,sqlpp] +---- +\SET -TIMEOUT 1ms; +---- +-- +==== + +[#cbq-file-based-ops] +== File Based Operations + +Using the file based commands and options, the cbq shell can execute {sqlpp} and shell commands contained in files. +There are two ways to accomplish this. + +[tabs] +==== +Command Line Option:: ++ +-- +Use the `-f` or `--file` command line option, followed by the input file. + +The cbq shell executes the commands present in the input file, prints them to stdout (or to a file if using redirects), and exits. + +''' +// tag::sample-txt[] +Consider the input file, `sample.txt`, containing the following commands. + +[source,sqlpp] +.sample.txt +---- +CREATE PRIMARY INDEX ON `travel-sample`.inventory.airline USING GSI; +SELECT * from `travel-sample`.inventory.airline LIMIT 2; +SELECT callsign from `travel-sample`.inventory.airline LIMIT 3; +\HELP; +---- +// end::sample-txt[] + +[source,sh] +.Example +---- +./cbq -e $BASE_URL -u $USER -p $PASSWORD --cacert $CACERT -skip-verify -f=sample.txt +---- + +.Results +[source,console] +---- + Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. + + Path to history file for the shell : ~/.cbq_history +CREATE PRIMARY INDEX ON `travel-sample`.inventory.airline USING GSI; +{ ... + "results": [ ], + ... +} +SELECT * from `travel-sample`.inventory.airline LIMIT 2; +{ ... + "results": [ ], + ... +} +SELECT callsign from `travel-sample`.inventory.airline LIMIT 3; +{ ... + "results": [ ], + ... +} +\HELP; +Help information for all shell commands. +... +$ +---- +-- + +Shell Command:: ++ +-- +Use the `\SOURCE` shell command, followed by the input file. + +The cbq shell executes the commands present in the input file and prints them to stdout, or to a file if using redirects. + +''' + +include::cbq.adoc[tag=sample-txt] + +[source,sqlpp] +.Example +---- +\SOURCE sample.txt; +---- + +.Results +[source,console] +---- +CREATE PRIMARY INDEX ON `travel-sample`.inventory.airline USING GSI; +{ ... + "results": [ ], + ... +} +SELECT * from `travel-sample`.inventory.airline LIMIT 2; +{ ... + "results": [ ], + ... +} +SELECT callsign from `travel-sample`.inventory.airline LIMIT 3; +{ ... + "results": [ ], + ... +} +\HELP; +Help information for all shell commands. +... +cbq> +---- +-- +==== + +=== Redirecting Results to a File + +You can redirect all the output for a session or part of a session to a specified output file. +If the file doesn't exist, it is created. +If the file already exists, it is overwritten. + +[tabs] +==== +Command Line Option:: ++ +-- +Use the `-o` or `--output` command line option, followed by the output file. + +''' + +.Example +[source,sh] +---- +./cbq -e $BASE_URL -u $USER -p $PASSWORD --cacert $CACERT -skip-verify -o temp_output.txt +---- +-- + +Shell Command:: ++ +-- +To start redirecting commands during a session, use `\REDIRECT` followed by the output file. +To stop redirecting commands, use `\REDIRECT OFF`. +All the commands specified after `\REDIRECT` and before `\REDIRECT OFF` are saved into the specified output file. + +You can specify multiple `\REDIRECT` commands. +When you do so, the output file changes to the specified files and switches back to [.out]`stdout` only when you specify `\REDIRECT OFF`. + +You can append redirected output to an existing file using <>. + +''' + +.Example +[source,sqlpp] +---- +\REDIRECT temp_output.txt; +CREATE PRIMARY INDEX ON `travel-sample`.inventory.airline USING GSI; +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +\HELP; +\REDIRECT OFF; +---- +-- +==== + +[[file-append-mode]] +=== File Append Mode + +You can use file append mode to specify that cbq should append redirected output to the end of an existing file, rather than overwriting the existing file. + +Note that file append mode is only available with the `\REDIRECT` command within a shell session. +It is not available for the `-o` or `--output` command line option. +When you use the `-o` or `--output` command line option, the specified output file is always overwritten. + +To use file append mode, include a plus sign `+` at the start of the output path or filename. + +==== +.Example +[source,sqlpp] +---- +\REDIRECT +temp_output.txt; +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +\REDIRECT OFF; +---- + +Every time you start appending to the output file, a timestamp is added to the end of the output file, followed by any redirected commands and results. + +---- +-- <2021-07-30T14:48:43.661+01:00> : opened in append mode + +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1 +... +---- +==== + +[#cbq-server-shell-info] +== Cluster and Shell Information + +The cbq shell provides commands that convey information about the shell or Couchbase Capella cluster. + +=== Version + +You can find the version of the client (shell) by using either the command line option to display the current version of the shell and exit, or as a shell command to print the version of the shell during the shell session. + +To display the version of the query service, use the xref:n1ql:n1ql-language-reference/metafun.adoc#version[VERSION()] function in {sqlpp}. + +[tabs] +==== +Command Line Option:: ++ +-- +Use the `-v` or `--version` command line option. + +''' + +.Example +[source,sh] +---- +./cbq -v +---- + +.Result +---- +GO VERSION : go1.22.2 +SHELL VERSION : 7.6.2-3721 + +Use N1QL queries select version(); or select min_version(); to display server version. +---- +-- + +Shell Command:: ++ +-- +Use the `\VERSION` shell command. + +''' + +.Example +[source,sqlpp] +---- +\VERSION; +---- + +.Result +---- +GO VERSION : go1.22.2 +SHELL VERSION : 7.6.2-3721 + +Use N1QL queries select version(); or select min_version(); to display server version. +---- +-- +==== + +=== Copyright + +You can view the copyright, attributions, and distribution terms of the command line query tool using the `\COPYRIGHT` shell command. + +==== +.Example +[source,sqlpp] +---- +\COPYRIGHT; +---- + +.Result +---- +Copyright (c) 2016 Couchbase, Inc. Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under the +License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific language governing permissions +and limitations under the License. +---- +==== + +== Exiting the cbq Shell + +You can exit the cbq shell by pressing kbd:[Ctrl+D] or by using the `\EXIT` or `\QUIT` command. + +The cbq shell first saves the history, closes existing connections, saves the current session in a session file, resets all environment variables, and then closes the shell liner interface. + +==== +.Example +[source,sqlpp] +---- +\EXIT; +---- + +.Result +[source,console] +---- +$ +---- +==== + +[#executing-a-script] +== Executing a Script + +You can use the [.param]`--script` option to start cbq, execute a single {sqlpp} query, and exit the shell. + +==== +.Example +[source,sh] +---- +./cbq -u $USER -p $PASSWORD -e $BASE_URL --cacert $CACERT -skip-verify \ +--script="SELECT * FROM \`travel-sample\`.inventory.airline LIMIT 1;" +---- + +.Results +---- +Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. + +Path to history file for the shell : ~/.cbq_history + +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +{ + ... +} +---- +==== + +=== Exit On Error + +When you specify the argument `--exit-on-error`, the cbq shell checks the result returned after executing the query for any error and exits when the first error is encountered. + +=== Exit Status + +The cbq shell returns the exit status 0 for successful exit with no errors and 1 if an error was encountered before exiting. + +== Available Command Line Options and Shell Commands + +NOTE: The <> are case sensitive. +The <> are case insensitive. + +.Command Line Options for cbq Shell +[#table_a3h_rhz_dw,cols="~,~,55"] +|=== +| Option | Arguments | Description and Examples + +| [[opt-engine]] +`-e` + +`--engine` +| string (url) +a| The connection string consists of a protocol scheme, followed by a host. + +For more details, refer to <>. + +Shell command: <> + +.Default +`+http://localhost:8091+` + +.Examples +[source,sh] +---- +./cbq --engine $BASE_URL \ +-u $USER -p $PASSWORD -skip-verify +---- + +[source,sh] +---- +./cbq -e $BASE_URL \ +-u $USER -p $PASSWORD -skip-verify +---- + +.Result +---- +Connected to : https://:18091/. Type Ctrl-D or \QUIT to exit. +Path to history file for the shell : /Users/myuser1/.cbq_history +---- + +| [[opt-no-engine]] +`-ne` + +`--no-engine` +| boolean footnote:boolean[Invoking a boolean option with no value sets the value to `true`.] +a| When specified, the cbq shell does not connect to any query service. +You must explicitly connect to a query service using the <> shell command. + +.Default +`false` + +.Example +[source,sh] +---- +./cbq --no-engine +---- + +| [[opt-ncfg]] +`-ncfg` + +`--networkconfig` +| string (`auto`, `default`, `external`) +a| Specifies whether to connect to a node's principal or alternate address. + +* `auto` -- Select the principal address or alternate address automatically, depending on the input IP. +* `default` -- Use the principal address. +* `external` -- Use the alternate addresses. + +.Default +`auto` + +.Example +[source,sh] +---- +./cbq -ncfg default \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-quiet]] +`-q` + +`--quiet` +| boolean footnote:boolean[] +a| When specified, disables the startup connection message for the cbq shell. + +.Default +`false` + +.Example +[source,sh] +---- +./cbq -q \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +.Result +[source,console] +---- +cbq> +---- + +| [[opt-advise]] +`-ad` + +`--advise` +| boolean footnote:boolean[] +a| Runs ADVISE on all queries in the specified file, or that are read from standard input, if a file is not provided with the `-file` option. + +.Default +`false` + +.Example +[source, sh] +---- +./cbq -advise -file queries.txt \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +.queries.txt +[source, sqlpp] +---- +SELECT ADVISOR(["select * from collection1 where id = 1;", + "select * from collection2 where name is not missing;"]) +---- + +.Result +[source, json] +---- +{ + "requestID": "15ed5c93-e5f6-4193-83fa-6fdc87847552", + "signature": { + "$1": "object" + }, + "results": [ + { + "$1": { + "recommended_indexes": [ + { + "index": "CREATE INDEX adv_id ON `collection1`(`id`)", + "statements": [ + { + "run_count": 1, + "statement": "select * from collection1 where id = 1;" + } + ] + }, + { + "index": "CREATE INDEX adv_name ON `collection2`(`name`)", + "statements": [ + { + "run_count": 1, + "statement": "select * from collection2 where name is not missing;" + } + ] + } + ] + } + } + ] +} +---- + +| [[opt-analytics]] +`-a` + +`--analytics` +| boolean footnote:boolean[] +a| Only applicable when connecting to the Analytics Service. +If specified, when you connect to a Couchbase Capella cluster, cbq automatically discovers and connects to the Analytics service. +This option also switches on <>. + +.Default +`false` + +.Example +[source,sh] +---- +./cbq --analytics \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-batch]] +`-b` + +`--batch` +| string (`on`, `off`) footnote:[Invoking this option with no value sets the value to `on`.] +a| This option is available only with the Analytics Service. +When specified, cbq sends the queries to Analytics only when you hit EOF or \ to indicate the end of the batch input. + +.Default +`off` + +.Examples +[source,sh] +---- +./cbq --batch \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +You can also set the batch mode in the interactive session using the <> command: + +[source,sqlpp] +---- +\set batch on; +\set batch off; +---- + +| [[opt-qc]] +`-qc` + +`--query_context` +| string +a| Sets the query context parameter. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +Shell command: <> `-query_context` + +.Default +none + +.Example +[source,sh] +---- +./cbq -qc "travel-sample.inventory" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-timeout]] +`-t` + +`--timeout` +| string (duration) +a| Sets the query timeout parameter. +For more information, see xref:n1ql:n1ql-manage/query-settings.adoc#timeout_req[timeout]. + +Shell command: <> `-timeout` + +.Default +`0ms` + +.Example +[source,sh] +---- +./cbq --timeout="1s" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +For further examples, see <>. + +| [[opt-user]] +`-u` + +`--user` +| string +a| Specifies a single user name to log in to Couchbase. +When used by itself, without the `-p` option to specify the password, you will be prompted for the password. + +This option requires administration credentials and you cannot switch the credentials during a session. + +Couchbase recommends using the `-u` and `-p` option if your password contains special characters such as #, $, %, &, (,), or '. + +.Default +none + +.Example +[source,sh] +---- +./cbq -u $USER \ +-e $BASE_URL -skip-verify +---- + +.Result +---- +Enter Password: +---- + +| [[opt-password]] +`-p` + +`--password` +| string +a| Specifies the password for the given user name. +You cannot use this option by itself. +It must be used with the -u option to specify the user name. + +This option requires administration credentials and you cannot switch the credentials during a session. + +Couchbase recommends using the `-u` and `-p` option if your password contains special characters such as #, $, %, &, (,), or '. + +.Default +none + +.Example +[source,sh] +---- +./cbq -u $USER -p $PASSWORD \ +-e $BASE_URL -skip-verify +---- + +| [[opt-credentials]] +`-c` + +`--credentials` +| string +a| Specify the login credentials in the form of [.var]`username`:[.var]``password``. +If you specify more than one credential with this option, Couchbase Capella only uses the first one. + +Shell command: <> `-creds` + +ifdef::flag-devex-rest-api[] +REST API: `-creds` parameter +endif::flag-devex-rest-api[] + +.Default +none + +.Example +[source,sh] +---- +./cbq -c=$USER:$PASSWORD \ +-e $BASE_URL -skip-verify +---- + +| [[opt-version]] +`-v` + +`--version` +| boolean footnote:boolean[] +a| When specified, provides the version of the cbq shell. +To display the version of the query engine (this is not the same as the version of the Couchbase Capella cluster), use one of the following {sqlpp} queries: + +[source,sqlpp] +---- +select version(); +---- + +[source,sqlpp] +---- +select min_version(); +---- + +Shell command: <> + +.Default +`false` + +.Example +[source,sh] +---- +./cbq --version +---- + +.Result +---- +GO VERSION : go1.21.6 +SHELL VERSION : 7.6.0-2176 + +Use N1QL queries select version(); or select min_version(); to display server version. +---- + +| [[opt-help]] +`-h` + +`--help` +| none +a| Provides help for the command line options. + +Shell command: <> + +.Default +none + +.Example +[source,sh] +---- +./cbq --help +---- + +| [[opt-script]] +`-s` + +`-script` +| string +a| Provides a single command mode to execute a query from the command line. + +You can also use multiple `-s` options on the command line. +If one of the commands is incorrect, an error is displayed for that command and cbq continues to execute the remaining commands. + +.Default +none + +.Examples +[source,sh] +---- +./cbq -s="SELECT * FROM \`travel-sample\`.inventory.airline LIMIT 1;" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +[source,sh] +---- +./cbq -s="\SET v 1" -s="\SET b 2" -s="\PUSH b3" \ +-s="\SET b 5" -s="\SET" -ne +---- + +.Result +---- +Path to history file for the shell : ~/.cbq_history + + \SET v 1 + \SET b 2 + \PUSH b3 + ERROR 139 : Too few input arguments to command. + \SET b 5 + \SET + + Query Parameters : + Named Parameters : + User Defined Session Parameters : + Predefined Session Parameters : + Parameter name : histfile + Value : [".cbq_history"] + Parameter name : batch + Value : ["off"] + Parameter name : quiet + Value : [false] + Parameter name : v + Value : [1] + Parameter name : b + Value : [5] +---- + +| [[opt-file]] +`-f` + +`--file` +| string (path) +a| Provides an input file which contains all the commands to be run. + +Shell command: <> + +.Default +none + +.Example +[source,sh] +---- +./cbq --file="sample.txt" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-output]] +`-o` + +`--output` +| string (path) +a| Specifies an output file where the commands and their results are to be written. + +If the file doesn't exist, it is created. +If the file already exists, it is overwritten. + +Shell command: <> + +.Default +none + +.Example +[source,sh] +---- +./cbq -o="results.txt" -s="SELECT * FROM \`travel-sample\`.inventory.airline LIMIT 1;" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-pretty]] +`--pretty` +| boolean footnote:boolean[] +a| Specifies whether the output should be formatted with line breaks and indents. + +This option is set to `true` by default. +To specify that the output should _not_ be formatted with line breaks and indents, you must explicitly set this option to `false`. + +.Default +`true` + +.Example +[source,sh] +---- +./cbq --pretty=false -s="SELECT * FROM \`travel-sample\`.inventory.airline LIMIT 1;" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-exit-on-error]] +`--exit-on-error` +| boolean footnote:boolean[] +a| When specified, the cbq shell must exit when it encounters the first error. + +.Default +`false` + +.Example +[source,sh] +---- +./cbq --exit-on-error -f="sample.txt" \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-cacert]] +`--cacert` +| string (path) +a| Only applicable when using an encrypted protocol scheme, such as `couchbases://`. + +Specifies the path to the root CA certificate to verify the identity of the cluster. + +.Default +none + +.Example +[source,sh] +---- +./cbq --cacert $CACERT \ +-e $BASE_URL -u $USER -p $PASSWORD -skip-verify +---- + +| [[opt-cert]] +`--cert` +| string (path) +a| Only applicable when using an encrypted protocol scheme, such as `couchbases://`. + +Specifies the path to the chain certificate. + +.Default +none + +.Example +[source,sh] +---- +./cbq --cert ./client/client/chain.pem +---- + +| [[opt-key]] +`--key` +| string (path) +a| Only applicable when using an encrypted protocol scheme, such as `couchbases://`. + +Specifies the path to the client key file. + +.Default +none + +.Examples +[source,sh] +---- +./cbq --key ./client/client/client.key +---- + +| [[opt-skip-verify]] +`--no-ssl-verify` or + +`-skip-verify` +| boolean footnote:boolean[] +a| Only applicable when using an encrypted protocol scheme, such as `couchbases://`. + +When specified, the cbq shell can skip the verification of certificates. + +.Default +`false` + +.Examples +[source,sh] +---- +./cbq --no-ssl-verify -f="sample.txt" \ +-e $BASE_URL -u $USER -p $PASSWORD +---- + +[source,sh] +---- +./cbq -skip-verify \ +-e $BASE_URL -u $USER -p $PASSWORD +---- +|=== + +.cbq Shell Commands +[#table_htk_hgc_fw,cols="~,~,55"] +|=== +| Shell Command | Arguments | Description and Examples + +| [[cbq-connect]] +[.cmd]`\CONNECT` +| [.var]`url` +a| Connects cbq shell to the specified Couchbase Capella cluster. + +The connection string consists of a protocol scheme, followed by a host. + +For more details, refer to <>. + +Command Line Option: <> or <> + +.Examples +[source,sqlpp] +---- +\CONNECT ; +---- + +| [[cbq-disconnect]] +[.cmd]`\DISCONNECT` +| none +a| Disconnects the cbq shell from the Couchbase Capella cluster. + +.Example +[source,sqlpp] +---- +\DISCONNECT; +---- + +.Result +---- + Couchbase query shell not connected to any endpoint. + Use \CONNECT command to connect. +---- + +| [[cbq-quit]] +[.cmd]`\EXIT` + +[.cmd]`\QUIT` +| none +a| Exits cbq shell. + +.Examples +[source,sqlpp] +---- +\EXIT; +---- + +[source,sqlpp] +---- +\QUIT; +---- + +| [[cbq-set]] +[.cmd]`\SET` +| [.var]`parameter` [.var]`value` + +[.var]`parameter` = [.var]`prefix` : [.var]`variable name` +a| Sets the top most value of the stack for the given variable with the specified value. + +Variables can be of the following types: + +* Query parameters +* Session variables +* User-defined +* Pre-defined and named parameters. + +When the [.cmd]`\SET` command is used without any arguments, it displays the values for all the parameters of the current session. + +.Examples +[source,sqlpp] +---- +\SET -args [5, "12-14-1987"]; +---- + +[source,sqlpp] +---- +\SET -args [6,7]; +---- + +| [[cbq-push]] +[.cmd]`\PUSH` +| [.var]`parameter` [.var]`value` +a| Pushes the specified value on to the given parameter stack. + +When the [.cmd]`\PUSH` command is used without any arguments, it copies the top element of every variable's stack, and then pushes that copy to the top of the respective variable's stack. + +While each variable stack grows by 1, the previous values are preserved. + +.Examples +[source,sqlpp] +---- +\PUSH -args [8]; +\PUSH; +---- + +.Check variable stack +[source,sqlpp] +---- +\SET; +---- + +.Result +---- + Query Parameters : + Parameter name : args + Value : [[6,7] [8] [8]] +... +---- + +| [[cbq-unset]] +[.cmd]`\UNSET` +| [.var]`parameter` +a| Deletes or resets the entire stack for the specified parameter. + +.Examples +[source,sqlpp] +---- +\UNSET -args; +\SET; +---- + +.Result +---- + Query Parameters : + ... +---- + +| [[cbq-pop]] +[.cmd]`\POP` +| [.var]`parameter` +a| Pops the top most value from the specified parameter's stack. + +When the [.cmd]`\POP` command is used without any arguments, it pops the top most value of every variable's stack. + +.Examples +[source,sqlpp] +---- +\POP -args; +\SET; +---- + +.Result +---- + Query Parameters : + Parameter name : args + Value : [[6,7] [8]] +---- + +| [[cbq-alias]] +[.cmd]`\ALIAS` +| [.var]`shell-command` or [.var]`n1ql-statement` +a| Creates a command alias for the specified cbq shell command or {sqlpp} statement. +You can then execute the alias using `\\alias-name;`. + +When the [.cmd]`\ALIAS` command is used without any arguments, it lists all the available aliases. + +.Examples +[source,sqlpp] +---- +\ALIAS travel-limit1 SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +\ALIAS; +---- + +.Result +---- +serverversion select version() +travel-limit1 SELECT * FROM `travel-sample`.inventory.airline LIMIT 1 +---- + +.Execute alias +[source,sqlpp] +---- +\\serverversion; +---- + +.Result +[source,json] +---- +{ + "requestID": "ef63f01b-f159-437f-a4df-28d6145fa3c2", + "signature": { + "$1": "string" + }, + "results": [ + { + "$1": "7.0.0-N1QL" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "14.54962ms", + "executionTime": "13.164635ms", + "resultCount": 1, + "resultSize": 34, + "serviceLoad": 12 + } +} +---- + +| [[cbq-unalias]] +[.cmd]`\UNALIAS` +| [.var]`alias-name` +a| Deletes the specified alias. + +.Examples +[source,sqlpp] +---- +\UNALIAS travel-limit1; +\ALIAS; +---- + +.Result +---- +serverversion select version() +---- + +| [[cbq-echo]] +[.cmd]`\ECHO` +| [.var]`args` + +where [.var]`args` can be parameters, aliases, or any input. +a| If the input is a parameter, this command echoes (displays) the value of the parameter. +The parameter must be prefixed according to its type. +See <> for details. + +If the input is not a parameter, the command echoes the statement as is. + +If the input is an alias, the command displays the value of an alias command. + +.Examples +[source,sqlpp] +---- +\ECHO -$r; +\ECHO \\serverversion; +---- + +.Result +---- +select version() +---- + +| [[cbq-version]] +[.cmd]`\VERSION` +| none +a| Displays the version of the client shell. + +Command Line Option: <> or <> + +.Example +[source,sqlpp] +---- +\VERSION; +---- + +.Result +---- +GO VERSION : go1.21.6 +SHELL VERSION : 7.6.0-2176 + +Use N1QL queries select version(); or select min_version(); to display server version. +---- + +| [[cbq-help]] +[.cmd]`\HELP` +| [.var]`command` +a| Displays the help information for the specified command. +When used without any arguments, it lists all the commands supported by the cbq shell. + +Command Line Option: <> or <> + +.Example +[source,sqlpp] +---- +\HELP ECHO; +---- + +.Result +---- +\ECHO args ... +Echo the input value. args can be a name (a prefixed-parameter), an alias (command alias) or +a value (any input statement). +Example : +\ECHO -$r ; +\ECHO \\tempalias; +---- + +| [[cbq-copyright]] +[.cmd]`\COPYRIGHT` +| none +a| Displays the copyright, attributions, and distribution terms. + +.Example +[source,sqlpp] +---- +\COPYRIGHT; +---- + +| [[cbq-source]] +[.cmd]`\SOURCE` +| [.var]`input-file` +a| Reads and executes the commands from a file. +Multiple commands in the input file must be separated by `;` and a new line. + +Command Line Option: <> or <> + +For example, `sample.txt` contains the following commands: + +[source,sqlpp] +.sample.txt +---- +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +\ECHO this; +#This is a comment; +---- + +.Example +[source,sqlpp] +---- +\SOURCE sample.txt; +---- + +| [[cbq-redirect]] +[.cmd]`\REDIRECT` +| [.var]`filename` +a| Redirects the output of all the commands to the specified file until the cbq shell receives the [.cmd]`\REDIRECT OFF` command. +By default, the file is created in the directory that you were in when you started the cbq shell. +You can specify a different location using relative paths. + +If the file doesn't exist, it is created. +If the file already exists, it is overwritten. +You can append redirected output to an existing file using <>. + +Command Line Option: <> or <> + +.Example +[source,sqlpp] +---- +\REDIRECT temp_out.txt; +---- + +| [[cbq-redirect-off]] +[.cmd]`\REDIRECT OFF` +| none +a| Redirects the output of subsequent commands from a custom file to standard output (os.stdout). + +.Example +[source,sqlpp] +---- +\REDIRECT OFF; +---- +|=== + +== Shortcut Keys for cbq Shell + +The following table lists the shortcut keys used by the [.cmd]`cbq` shell. + +.Shortcut Keys for cbq Shell +[cols="100,197"] +|=== +| Keystroke | Action + +| kbd:[Ctrl+A], kbd:[Home] +| Move cursor to beginning of line + +| kbd:[Ctrl+E], kbd:[End] +| Move cursor to end of line + +| kbd:[Ctrl+B], kbd:[Left] +| Move cursor one character left + +| kbd:[Ctrl+F], kbd:[Right] +| Move cursor one character right + +| kbd:[Ctrl+Left] +| Move cursor to previous word + +| kbd:[Ctrl+Right] +| Move cursor to next word + +| kbd:[Ctrl+D], kbd:[Del] +| (if line is not empty) Delete character under cursor + +| kbd:[Ctrl+D] +| (if line is empty) End of File - usually quits application + +| kbd:[Ctrl+C] +| Reset input (create new empty prompt) + +| kbd:[Ctrl+L] +| Clear screen (line is unmodified) + +| kbd:[Ctrl+T] +| Transpose previous character with current character + +| kbd:[Ctrl+H], kbd:[BackSpace] +| Delete character before cursor + +| kbd:[Ctrl+W] +| Delete word leading up to cursor + +| kbd:[Ctrl+K] +| Delete from cursor to end of line + +| kbd:[Ctrl+U] +| Delete from start of line to cursor + +| kbd:[Ctrl+P], kbd:[Up] +| Previous match from history + +| kbd:[Ctrl+N], kbd:[Down] +| Next match from history + +| kbd:[Ctrl+R] +| Reverse Search history (kbd:[Ctrl+S] forward, kbd:[Ctrl+G] cancel) + +| kbd:[Ctrl+Y] +| Paste from Yank buffer (kbd:[Alt+Y] to paste next yank instead) + +| kbd:[Tab] +| Next completion + +| kbd:[Shift+Tab] +| (after kbd:[Tab]) Previous completion +|=== + +Source: https://github.com/peterh/liner[] diff --git a/modules/n1ql/pages/n1ql-intro/index.adoc b/modules/n1ql/pages/n1ql-intro/index.adoc new file mode 100644 index 000000000..60fa614ff --- /dev/null +++ b/modules/n1ql/pages/n1ql-intro/index.adoc @@ -0,0 +1,49 @@ += Understand Queries +:page-role: tiles -toc +:page-aliases: n1ql:tutorial.adoc +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +include::ROOT:partial$component-signpost.adoc[] + +== Query Concepts + +An overview of common concepts that you will need to understand in order to use the Query service. + +* xref:n1ql:n1ql-intro/queriesandresults.adoc[] + +== Query Tools + +The Query service provides the following tools for running queries: + +* xref:n1ql:n1ql-intro/cbq.adoc[] +* xref:clusters:query-service/query-workbench.adoc[] + +== Related Links + +The interactive {sqlpp} tutorial provides web modules where you can learn about {sqlpp} without having to configure Couchbase Capella or have Couchbase Server installed in your own environment. +The modules are self-contained and let you modify and run sample queries. + +* https://query-tutorial.couchbase.com/tutorial/#1[{sqlpp} Query Language Tutorial^] + +ifdef::flag-devex-cheatsheet[] + +== {sqlpp} Cheat Sheet + +The {sqlpp} cheat sheet provides a concise summary of the basic syntax elements of {sqlpp}. + +* http://docs.couchbase.com/files/Couchbase-N1QL-CheatSheet.pdf[{sqlpp} Cheat Sheet^] + +endif::flag-devex-cheatsheet[] diff --git a/modules/n1ql/pages/n1ql-intro/queriesandresults.adoc b/modules/n1ql/pages/n1ql-intro/queriesandresults.adoc new file mode 100644 index 000000000..fcb425774 --- /dev/null +++ b/modules/n1ql/pages/n1ql-intro/queriesandresults.adoc @@ -0,0 +1,238 @@ += Query Concepts +:description: An overview of common concepts that you will need to understand in order to use the Query service. +:page-topic-type: concept +:keywords: n1ql, sqlpp, query, result, parameter, prepared, prepared statement, index + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== {sqlpp} Queries + +A {sqlpp} query is a string parsed by the Query service. +The {sqlpp} query language is based on SQL, but designed for structured and flexible JSON documents. + +* As with SQL, a {sqlpp} query can have nested sub-queries. + +* {sqlpp} queries run on JSON documents, and you can query over multiple documents by using the `JOIN` clause. + +* Data in JSON documents can be nested. +There are operators and functions that let you navigate through nested arrays. + +* Data in JSON documents can be irregular. +You can specify conditions in the `WHERE` clause to retrieve data. + +* You can transform the results using standard `GROUP BY`, `ORDER BY`, `LIMIT`, and `OFFSET` clauses as well as a rich set of functions. + +== Results + +The result for each query is a set of JSON documents. +The returned document set may be uniform or non-uniform. + +* A `SELECT` statement that specifies a fixed set of attribute (column) names results in a uniform set of documents. +* A `SELECT` statement that specifies the wild card (*) results in a non-uniform result set. + +Every returned document meets the query criteria. + +Here's a sample query and the result returned: + +.Query +[source,sqlpp] +---- +SELECT name, brewery_id from `beer-sample` WHERE brewery_id IS NOT MISSING LIMIT 2; +---- + +.Result +[source,json] +---- +{ + "requestID": "fbea9e79-a2e2-4ab8-9fdc-14e098838cc1", + "signature": { + "brewery_id": "json", + "name": "json" + }, + "results": [ + { + "brewery_id": "big_horn_brewing_the_ram_2", + "name": "Schaumbergfest" + }, + { + "brewery_id": "ballast_point_brewing", + "name": "Wahoo Wheat Beer" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "131.492184ms", + "executionTime": "131.261322ms", + "resultCount": 2, + "resultSize": 205 + } +} +---- + +[#logical-hierarchy] +== Logical Hierarchy + +Couchbase stores data within a xref:clusters:data-service/about-buckets-scopes-collections.adoc[logical hierarchy] of buckets, scopes, and collections. +This enables separation between documents of different types. + +Datastores:: + +Datastores are similar to sites. +A datastore is a database deployment, for example, a Couchbase Capella cluster or mobile installation. +It is analogous to a relation database instance. + +Namespaces:: + +Namespaces are similar to pools. +A namespace is a unit of authorization, resource allocation, and tenancy. +It is analogous to a relational database or schema. +Currently, only the `default` and `system` namespaces are available. + +Buckets:: + +A bucket is the fundamental space for storing data in Couchbase Capella. +Each bucket contains at least one scope by default, and you can create more scopes as required. +It is analogous to a relational database table space or file group. + +Scopes:: + +A scope is a set of one or more collections. +Each scope contains at least one collection by default, and you can create more collections as required. +It is analogous to a group of relational database tables. + +Collections:: + +A collection is a set of documents that may vary in structure. +It is a unit of authorization and resource allocation. +It is analogous to a relational database table. + +Keyspaces:: + +Keyspaces map to collections in Couchbase Capella. +You must refer to a keyspace using a <>. ++ +The term keyspace is also used to refer to any of the catalogs in the xref:n1ql:n1ql-intro/sysinfo.adoc[system] namespace. + +[#keyspace-reference] +== Keyspace References + +For most queries, you must provide one or more keyspace references to specify the data sources for the query. + +A keyspace reference may be: + +* A [dfn]#full keyspace reference#: a path comprising the optional namespace, the bucket, the scope, and the collection which contains the documents you want. +For example, `default:{backtick}travel-sample{backtick}.inventory.airline`. + +* A [dfn]#partial keyspace reference#, comprising the collection name only. +For example, `airline`. + +When a query contains partial keyspace references, you must set the <> to specify a bucket and scope before running a query. +Partial keyspace references are resolved using the bucket and scope supplied by the query context. + +For compatibility with legacy versions of Couchbase Server, a keyspace reference may comprise the bucket name only, when referring to the default collection in the default scope within a bucket. +In this case, the <> must not be set. + +[#query-context] +== Query Context + +The [dfn]#query context# specifies the the namespace, bucket, and scope used to resolve partial keyspace references. + +When the query context is set, you can refer to a collection using just the collection name, without having to enter the keyspace path. +When the query context is not set, it defaults to the `default` namespace, with no bucket, scope, or collection. + +* To set the query context in the Query tab, use the xref:clusters:query-service/query-workbench.adoc#specify-bucket-and-scope-context[Query Context] drop-down menus in the Query Editor. + +* To set the query context from +ifdef::flag-devex-rest-api[] +the REST API or +endif::flag-devex-rest-api[] +the cbq shell, use the xref:n1ql:n1ql-manage/query-settings.adoc#query_context[query_context] request-level parameter. + +.Tenant separation +[IMPORTANT] +-- +By using queries with partial keyspace references, which are resolved using the query context, a database application can be switched from one scope to another simply by changing the query context. +This can be used to support the separation of tenant data in a multi-tenancy environment. +-- + +[#paths] +== Sub-Document Paths + +One of the main differences between JSON and flat rows is that JSON supports a nested structure, allowing documents to contain other documents, also known as sub-documents. +{sqlpp} provides [dfn]#sub-document paths# to support nested data. +Paths use dot notation syntax to identify the logical location of an attribute within a document. +For example, to get the street from a customer order, use the path `orders.billTo.street`. +This path refers to the value for `street` in the `billTo` object. +A path is used with arrays or nested objects to get to attributes within the data structure. + +Array syntax in the path can also be used to get to information. +For example, the path `orders.items[0].productId` evaluates to the `productId` value for the first array element under the order item, `items`. + +Paths provide a method for finding data in document structures without having to retrieve the entire document or handle it within an application. +Any document data can be requested and returned to an application. +When only relevant information is returned to an application, querying bandwidth is reduced. + +See xref:n1ql-language-reference/index.adoc#nested-path-exp[Nested Path Expressions] for more details. + +[#named-placeholders] +== Parameterized Queries + +Use placeholders to declare dynamic query parameters in {sqlpp}. +When you run the query, you can pass arguments to it, with each argument being used as the placeholder value in the query. + +Placeholders in the query may be numbered positional placeholders, unnumbered positional placeholders, or named placeholders. + +* A numbered positional placeholder takes the form `$1` or `@1`. +Thus, in the query, `$1` or `@1` refers to the first argument,`$2` or `@2` to the second, and so on. + +* An unnumbered positional parameter takes the form of a question mark `?`. +The first occurrence of `?` refers to the first argument, the second occurrence of `?` to the second, and so on. + +* Named placeholders take the form of `$name` or `@name`. +This is particularly useful when there are many query parameters, and ensuring that they are all in the correct order may be cumbersome. + +To set query parameter values when you run the query, use +ifdef::flag-devex-rest-api[] +the {sqlpp} REST API, +endif::flag-devex-rest-api[] +the cbq query shell, or the Query tab. + +For more information and examples, refer to xref:n1ql:n1ql-manage/query-settings.adoc#section_srh_tlm_n1b[Named Parameters and Positional Parameters]. + +[#prepare-stmts] +== Prepared Statements + +When a {sqlpp} query is sent to the server, the server inspects the query and parses it, planning which indexes to use, if any. +Once this is done, it generates a [dfn]#query plan#. +The computation for the plan adds some additional processing time and overhead for the query. + +You can [dfn]#prepare# a frequently-used query so that its plan is generated only once. +Subsequent queries using the same query will use the pre-generated plan instead, saving on the overhead and processing of the plan each time. + +NOTE: Parameterized queries are considered the same query for caching and planning purposes, even if the supplied parameters are different. + +For more information on how to optimize queries using prepared statements, refer to the xref:n1ql:n1ql-language-reference/prepare.adoc[PREPARE] statement. + +== Indexes + +Indexes help to improve the performance of a query. +An index replicates a subset of the fields and documents stored in the Data service. +This allows specific data (for example, specific fields) to be retrieved quickly. + +The Index service enables you to create two types of index: primary indexes and global secondary indexes. + +* You can define a [dfn]#primary index# on a keyspace. +Primary indexes are based on the unique key of every item in a specified collection. A primary index is intended to be used for simple queries, which have no filters or predicates. + +* You can also create a [dfn]#secondary index# on specific fields in a keyspace. +Secondary indexes, often referred to as Global Secondary Indexes or GSIs, constitute the principal means of indexing documents to be accessed by the Query service. ++ +For example, creating a secondary index on the `name` and `email` fields in the `users` keyspace would allow you to query the keyspace regarding a document's `name` or `email` properties. + +Note that you do not need to create an index on a keyspace to be able to query that keyspace. +If no indexes exist on a keyspace, Couchbase Capella uses a sequential scan to query that index. + +For more information, refer to xref:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[]. diff --git a/modules/n1ql/pages/n1ql-intro/sysinfo.adoc b/modules/n1ql/pages/n1ql-intro/sysinfo.adoc new file mode 100644 index 000000000..080c6a84b --- /dev/null +++ b/modules/n1ql/pages/n1ql-intro/sysinfo.adoc @@ -0,0 +1,1615 @@ += Get System Information +:page-topic-type: concept +:description: {sqlpp} has a system namespace that stores metadata about data containers, the Query service, and the system as a whole. \ +You can query the system namespace to get this information. + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +Within the `system` namespace, the following catalogs are provided. +Most catalog names are plural in order to avoid conflicting with {sqlpp} keywords. + +[cols="4"] +|=== +| Data Containers | Monitoring Catalogs | Security Catalogs | Other + +a| [%hardbreaks] +<> +<> +<> +<> +<> +<> +<> + +a| [%hardbreaks] +xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc#vitals[system:vitals] +xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc#sys-active-req[system:active_requests] +xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc#sys-prepared[system:prepareds] +xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc#sys-completed-req[system:completed_requests] + +a| [%hardbreaks] +<> +<> +<> +<> + +a| [%hardbreaks] +<> +<> +<> +<> +<> +<> +<> +<> +|=== + +== Authentication and Client Privileges + +Client applications must be authenticated with sufficient privileges to access system keyspaces. + +* Users must have permission to access restricted system keyspaces. +For more details about cluster credentials, see xref:clusters:manage-database-users.adoc[]. + +* In addition, users must have permission to access a bucket, scope, or collection to be able to view that item in the system catalog. +Similarly, users must have SELECT permission on the target of an index to be able to view that index in the system catalog. + +* The following system keyspaces are considered open, that is, all users can access them without any special privileges: + ** `system:dual` + ** `system:datastores` + ** `system:namespaces` + +[#querying-datastores] +== Query Datastores + +You can query datastores using the `system:datastores` keyspace as follows: + +[source,sqlpp] +---- +SELECT * FROM system:datastores +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**id** + +__required__ +|ID of the datastore. +|String + +|**url** + +__required__ +|URL of the datastore instance. +|String +|=== + +[#querying-namespaces] +== Query Namespaces + +You can query namespaces using the `system:namespaces` keyspace as follows: + +[source,sqlpp] +---- +SELECT * FROM system:namespaces +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**id** + +__required__ +|ID of the namespace. +|String + +|**name** + +__required__ +|Name of the namespace. +|String + +|**datastore_id** + +__required__ +|ID of the datastore to which the namespace belongs. +|String +|=== + +[#querying-buckets] +== Query Buckets + +You can query buckets using the `system:buckets` keyspace as follows: + +[source,sqlpp] +---- +SELECT * FROM system:buckets +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**datastore_id** + +__required__ +|ID of the datastore to which the bucket belongs. +|String + +|**name** + +__required__ +|Name of the bucket. +|String + +|**namespace** + +__required__ +|Namespace to which the bucket belongs. +|String + +|**namespace_id** + +__required__ +|ID of the namespace to which the bucket belongs. +|String + +|**path** + +__required__ +|Path of the bucket. +|String +|=== + +[#querying-scopes] +== Query Scopes + +You can query scopes using the `system:scopes` keyspace as follows: + +[source,sqlpp] +---- +SELECT * FROM system:scopes +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**bucket** + +__required__ +|Bucket to which the scope belongs. +|String + +|**datastore_id** + +__required__ +|ID of the datastore to which the scope belongs. +|String + +|**name** + +__required__ +|Name of the scope. +|String + +|**namespace** + +__required__ +|Namespace to which the scope belongs. +|String + +|**namespace_id** + +__required__ +|ID of the namespace to which the scope belongs. +|String + +|**path** + +__required__ +|Path of the scope. +|String +|=== + +NOTE: Querying `system:scopes` only returns named scopes -- that is, non-default scopes. +To return all scopes, including the default scopes, you can query `system:all_scopes`. + +[#querying-keyspaces] +== Query Collections + +You can query collections using the `system:keyspaces` keyspace as follows: + +[source,sqlpp] +---- +SELECT * FROM system:keyspaces +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**bucket** + +__optional__ +|For a named, non-default collection: +Bucket to which the keyspace belongs. +|String + +|**datastore_id** + +__required__ +|ID of the datastore to which the keyspace belongs. +|String + +|**id** + +__required__ +|For the default collection in the default scope: +ID of the bucket to which the keyspace belongs. + +''' + +For a named, non-default collection: +ID of the keyspace. +|String + +|**name** + +__required__ +|For the default collection in the default scope: +Bucket to which the keyspace belongs. + +''' + +For a named, non-default collection: +Name of the keyspace. +|String + +|**namespace** + +__required__ +|Namespace to which the keyspace belongs. +|String + +|**namespace_id** + +__required__ +|ID of the namespace to which the keyspace belongs. +|String + +|**path** + +__required__ +|Path of the keyspace. +|String + +|**scope** + +__optional__ +|For a named, non-default collection: +Scope to which the keyspace belongs. +|String +|=== + +NOTE: Querying `system:keyspaces` only returns non-system keyspaces. +To return all keyspaces, including the system keyspaces, you can query `system:all_keyspaces`. + +[#querying-indexes] +== Query Indexes + +You can query indexes using the `system:indexes` keyspace as follows: + +[source,sqlpp] +---- +SELECT * FROM system:indexes +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**bucket_id** + +__optional__ +|For an index on a named, non-default collection: +ID of the bucket to which the index belongs. +|String + +|**condition** + +__optional__ +|Index filter, if present. +|String + +|**datastore_id** + +__required__ +|ID of the datastore to which the index belongs. +|String + +|**id** + +__required__ +|ID of the index. +|String + +|**index_key** + +__required__ +|List of index keys. +|String array + +|**is_primary** + +__required__ +|True if the index is a primary index. +|Boolean + +|**keyspace_id** + +__required__ +|For an index on the default collection in the default scope: +ID of the bucket to which the index belongs. + +''' + +For an index on a named, non-default collection: +ID of the keyspace to which the index belongs. +|String + +|**name** + +__required__ +|Name of the index. +|String + +|**metadata** + +__required__ +|Metadata for the index. +|<> object + +|**namespace_id** + +__required__ +|ID of the namespace to which the index belongs. +|String + +|**state** + +__required__ +|State of index. + +*Example*: `online` +|String + +|**using** + +__required__ +|Type of index. + +*Example*: `gsi` +|String +|=== + +[[metadata]] +**Metadata** +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**last_scan_time** + +__required__ +|The last scan timestamp of the index. +|String + +|**num_replica** + +__required__ +|The index replica count. +|String + +|**stats** + +__required__ +|Statistics for the index. +|<> object +|=== + +[[stats]] +**Stats** +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**last_known_scan_time** + +__required__ +|The index last scan time from the indexer, in UNIX Epoch format. +|Number +|=== + +NOTE: Querying `system:indexes` only returns indexes on non-system keyspaces. +To return all indexes, including indexes on system keyspaces, you can query `system:all_indexes`. + +[#querying-dual] +== Query Dual + +You can use dual to evaluate constant expressions. + +[source,sqlpp] +---- +SELECT 2+5 FROM system:dual +---- + +The query returns the result of the expression, 7 in this case. + +[#sys_my-user-info] +== Monitor Your User Info + +The `system:my_user_info` catalog maintains a list of all information of your profile. + +To see your current information, use: + +[source,sqlpp] +---- +SELECT * FROM system:my_user_info; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "my_user_info": { + "domain": "local", + "external_groups": [], + "groups": [], + "id": "jane", + "name": "Jane Doe", + "password_change_date": "2019-05-07T02:31:53.000Z", + "roles": [ + { + "origins": [ + { + "type": "user" + } + ], + "role": "admin" + } + ] + } + } +] +---- + +[#sys-user-info] +== Monitor All User Info + +The `system:user_info` catalog maintains a list of all current users in your bucket and their information. + +To see the list of all current users, use: + +[source,sqlpp] +---- +SELECT * FROM system:user_info; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "user_info": { + "domain": "local", + "external_groups": [], + "groups": [], + "id": "jane", + "name": "Jane Doe", + "password_change_date": "2019-05-07T02:31:53.000Z", + "roles": [ + { + "origins": [ + { + "type": "user" + } + ], + "role": "admin" + } + ] + } + }, + { + "user_info": { + "domain": "ns_server", + "id": "Administrator", + "name": "Administrator", + "roles": [ + { + "role": "admin" + } + ] + } + } +] +---- + +[#sys-nodes] +== Monitor Nodes + +The `system:nodes` catalog shows the datastore topology information. +This is separate from the Query clustering view, in that Query clustering shows a map of the Query cluster, as provided by the cluster manager, while `system:nodes` shows a view of the nodes and services that make up the actual datastore, which may or may not include Query nodes. + +* The dichotomy is important in that Query nodes could be clustered by one entity (e.g. Zookeeper) and be connected to a clustered datastore (e.g. Couchbase) such that each does not have visibility of the other. +* Should {sqlpp} be extended to be able to concurrently connect to multiple datastores, each datastore will report its own topology, so that `system:nodes` offers a complete view of all the storage nodes, whatever those may be. +* The `system:nodes` keyspace provides a way to report services advertised by each node as well as services that are actually running. +This is datastore dependent. +* Query clustering is still reported by the `/admin` endpoints. + +To see the list of all current node information, use: + +[source,sqlpp] +---- +SELECT * FROM system:nodes; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "nodes": { + "name": "127.0.0.1:8091", + "ports": { + "cbas": 8095, + "cbasAdmin": 9110, + "cbasCc": 9111, + "cbasSSL": 18095, + "eventingAdminPort": 8096, + "eventingSSL": 18096, + "fts": 8094, + "ftsSSL": 18094, + "indexAdmin": 9100, + "indexHttp": 9102, + "indexHttps": 19102, + "indexScan": 9101, + "indexStreamCatchup": 9104, + "indexStreamInit": 9103, + "indexStreamMaint": 9105, + "kv": 11210, + "kvSSL": 11207, + "n1ql": 8093, + "n1qlSSL": 18093 + }, + "services": [ + "cbas", + "eventing", + "fts", + "index", + "kv", + "n1ql" + ] + } + } +] +---- + +[#sys-app-roles] +== Monitor Applicable Roles + +The `system:applicable_roles` catalog maintains a list of all applicable roles and grantee of each bucket. + +To see the list of all current applicable role information, use: + +[source,sqlpp] +---- +SELECT * FROM system:applicable_roles; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "applicable_roles": { + "grantee": "anil", + "role": "replication_admin" + } + }, + { + "applicable_roles": { + "bucket_name": "travel-sample", + "grantee": "anil", + "role": "select" + } + }, + { + "applicable_roles": { + "bucket_name": "*", + "grantee": "anil", + "role": "select" + } + } +] +---- + +For more examples, take a look at the blog: https://blog.couchbase.com/optimize-n1ql-performance-using-request-profiling/[Optimize {sqlpp} performance using request profiling^]. + +[#sys-dictionary] +== Monitor Statistics + +The `system:dictionary` catalog maintains a list of the on-disk optimizer statistics stored in the `_query` collection within the `_system` scope. + +If you have multiple query nodes, the data retrieved from this catalog will be the same, regardless of the node on which you run the query. + +To see the list of on-disk optimizer statistics, use: + +[source,sqlpp] +---- +SELECT * FROM system:dictionary; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "dictionary": { + "avgDocKeySize": 12, + "avgDocSize": 278, + "bucket": "travel-sample", + "distributionKeys": [ + "airportname", + "faa", + "city" + ], + "docCount": 1968, + "indexes": [ + { + "indexId": "bc3048e87bf84828", + "indexName": "def_inventory_airport_primary", + "indexStats": [ + { + "avgItemSize": 24, + "avgPageSize": 11760, + "numItems": 1968, + "numPages": 4, + "resRatio": 1 + } + ] + }, + // ... + ], + "keyspace": "airport", + "namespace": "default", + "scope": "inventory" + } + }, + // ... +] +---- + +This catalog contains an array of dictionaries, one for each keyspace for which optimizer statistics are available. +Each dictionary gives the following information: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**avgDocKeySize** + +__required__ +|Average doc key size. +|Integer + +|**avgDocSize** + +__required__ +|Average doc size. +|Integer + +|**bucket** + +__required__ +|The bucket for which statistics are available. +|String + +|**keyspace** + +__required__ +|The keyspace for which statistics are available. +|String + +|**namespace** + +__required__ +|The namespace for which statistics are available. +|String + +|**scope** + +__required__ +|The scope for which statistics are available. +|String + +|**distributionKeys** + +__required__ +|Distribution keys for which histograms are available. +|String array + +|**docCount** + +__required__ +|Document count. +|Integer + +|**indexes** + +__required__ +|An array of indexes in this keyspace for which statistics are available. +|<> array + +|**node** + +__required__ +|The query node where this dictionary cache is resident. +|String +|=== + +[[indexes]] +**Indexes** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**indexId** + +__required__ +|The index ID. +|String + +|**indexName** + +__required__ +|The index name. +|String + +|**indexStats** + +__required__ +|An array of statistics for each index, with one element for each index partition. +|<> array +|=== + +[[indexStats]] +**Index Statistics** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**avgItemSize** + +__required__ +|Average item size. +|Integer + +|**avgPageSize** + +__required__ +|Average page size. +|Integer + +|**numItems** + +__required__ +|Number of items. +|Integer + +|**numPages** + +__required__ +|Number of pages. +|Integer + +|**resRatio** + +__required__ +|Resident ratio. +|Integer +|=== + +For further details, see xref:n1ql:n1ql-language-reference/updatestatistics.adoc[]. + +[#sys-dictionary-cache] +== Monitor Cached Statistics + +The `system:dictionary_cache` catalog maintains a list of the in-memory cached subset of the optimizer statistics. + +If you have multiple query nodes, the data retrieved from this node shows cached optimizer statistics from all nodes. +Individual nodes may have a different subset of cached information. + +To see the list of in-memory optimizer statistics, use: + +[source,sqlpp] +---- +SELECT * FROM system:dictionary_cache; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "dictionary_cache": { + "avgDocKeySize": 12, + "avgDocSize": 278, + "bucket": "travel-sample", + "distributionKeys": [ + "airportname", + "faa", + "city" + ], + "docCount": 1968, + "indexes": [ + { + "indexId": "bc3048e87bf84828", + "indexName": "def_inventory_airport_primary", + "indexStats": [ + { + "avgItemSize": 24, + "avgPageSize": 11760, + "numItems": 1968, + "numPages": 4, + "resRatio": 1 + } + ] + }, + // ... + ], + "keyspace": "airport", + "namespace": "default", + "node": "172.23.0.3:8091", + "scope": "inventory" + } + }, + // ... +] +---- + +This catalog contains an array of dictionary caches, one for each keyspace for which optimizer statistics are available. +Each dictionary cache gives the same information as the <> catalog. + +For further details, see xref:n1ql:n1ql-language-reference/updatestatistics.adoc[]. + +[#sys-functions] +== Monitor Functions + +The `system:functions` catalog maintains a list of all user-defined functions across all nodes. +To see the list of all user-defined functions, use: + +[source,sqlpp] +---- +SELECT * FROM system:functions; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "functions": { + "definition": { + "#language": "inline", + "expression": "(((`fahrenheit` - 32) * 5) / 9)", + "parameters": [ + "fahrenheit" + ], + "text": "((fahrenheit - 32) * 5/9)" + }, + "identity": { + "bucket": "travel-sample", + "name": "celsius", + "namespace": "default", + "scope": "inventory", + "type": "scope" + } + } + }, + { + "functions": { + "definition": { + "#language": "javascript", + "library": "geohash-js", + "name": "geohash-js", + "object": "calculateAdjacent", + "parameters": [ + "src", + "dir" + ] + }, + "identity": { + "name": "adjacent", + "namespace": "default", + "type": "global" + } + } + }, + // ... +] +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**definition** + +__required__ +|The definition of the function. +|<> object + +|**identity** + +__required__ +|The identity of the function. +|<> object +|=== + +[[definition]] +**Definition** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**#language** + +__required__ +|The language of the function. + +*Example*: `inline` +|String + +|**parameters** + +__required__ +|The parameters required by the function. +|String array + +|**expression** + +__optional__ +|For inline functions only: the expression defining the function. +|String + +|**text** + +__optional__ +|For inline functions: the verbatim text of the function. + +''' + +For {sqlpp} managed user-defined functions: the external code defining the function. +|String + +|**library** + +__optional__ +|For external functions only: the library containing the function. +|String + +|**name** + +__optional__ +|For external functions only: the relative name of the library. +|String + +|**object** + +__optional__ +|For external functions only: the object defining the function. +|String +|=== + +[[identity]] +**Identity** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**name** + +__required__ +|The name of the function. +|String + +|**namespace** + +__required__ +|The namespace of the function. + +*Example*: `default` +|String + +|**type** + +__required__ +|The type of the function. + +*Example*: `global` +|String + +|**bucket** + +__optional__ +|For scoped functions only: the bucket containing the function. +|String + +|**scope** + +__optional__ +|For scoped functions only: the scope containing the function. +|String +|=== + +[#sys-functions-cache] +== Monitor Cached Functions + +The `system:functions_cache` catalog maintains a list of recently-used user-defined functions across all nodes. +The catalog also lists user-defined functions that have been called recently, but do not exist. +To see the list of recently-used user-defined functions, use: + +[source,sqlpp] +---- +SELECT * FROM system:functions_cache; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "functions_cache": { + "#language": "inline", + "avgServiceTime": "3.066847ms", + "expression": "(((`fahrenheit` - 32) * 5) / 9)", + "lastUse": "2022-03-09 00:17:59.60659793 +0000 UTC m=+35951.429537902", + "maxServiceTime": "3.066847ms", + "minServiceTime": "0s", + "name": "celsius", + "namespace": "default", + "node": "127.0.0.1:8091", + "parameters": [ + "fahrenheit" + ], + "scope": "inventory", + "text": "((fahrenheit - 32) * 5/9)", + "type": "scope", + "uses": 1 + } + }, + { + "functions_cache": { + "#language": "javascript", + "avgServiceTime": "56.892636ms", + "lastUse": "2022-03-09 00:15:46.289934029 +0000 UTC m=+35818.007560703", + "library": "geohash-js", + "maxServiceTime": "146.025426ms", + "minServiceTime": "0s", + "name": "geohash-js", + "namespace": "default", + "node": "127.0.0.1:8091", + "object": "calculateAdjacent", + "parameters": [ + "src", + "dir" + ], + "type": "global", + "uses": 4 + } + }, + { + "functions_cache": { + "avgServiceTime": "3.057421ms", + "lastUse": "2022-03-09 00:17:25.396840275 +0000 UTC m=+35917.199008929", + "maxServiceTime": "3.057421ms", + "minServiceTime": "0s", + "name": "notFound", + "namespace": "default", + "node": "127.0.0.1:8091", + "type": "global", + "undefined_function": true, + "uses": 1 + } + } +] +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**#language** + +__required__ +|The language of the function. + +*Example*: `inline` +|String + +|**name** + +__required__ +|The name of the function. +|String + +|**namespace** + +__required__ +|The namespace of the function. + +*Example*: `default` +|String + +|**parameters** + +__required__ +|The parameters required by the function. +|String array + +|**type** + +__required__ +|The type of the function. + +*Example*: `global` +|String + +|**scope** + +__optional__ +|For scoped functions only: the scope containing the function. +|String + +|**expression** + +__optional__ +|For inline functions only: the expression defining the function. +|String + +|**text** + +__optional__ +|For inline functions: the verbatim text of the function. + +''' + +For {sqlpp} managed user-defined functions: the external code defining the function. +|String + +|**library** + +__optional__ +|For external functions only: the library containing the function. +|String + +|**object** + +__optional__ +|For external functions only: the object defining the function. +|String + +|**avgServiceTime** + +__required__ +|The mean service time for the function. +|String + +|**lastUse** + +__required__ +|The date and time when the function was last used. +|String + +|**maxServiceTime** + +__required__ +|The maximum service time for the function. +|String + +|**minServiceTime** + +__required__ +|The minimum service time for the function. +|String + +|**node** + +__required__ +|The query node where the function is cached. +|String + +|**undefined_function** + +__required__ +|Whether the function exists or is undefined. +|Boolean + +|**uses** + +__required__ +|The number of uses of the function. +|Number +|=== + +Each query node keeps its own cache of recently-used user-defined functions, so you may see the same function listed for multiple nodes. + +[#sys-tasks-cache] +== Monitor Cached Tasks + +The `system:tasks_cache` catalog maintains a list of recently-used scheduled tasks, such as index advisor sessions. +To see the list of recently-used scheduled tasks, use: + +[source,sqlpp] +---- +SELECT * FROM system:tasks_cache; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "tasks_cache": { + "class": "advisor", + "delay": "1h0m0s", + "id": "bcd9f8e4-b324-504c-a98b-ace90dba869f", + "name": "aa7f688a-bf29-438f-888f-eeaead87ca40", + "node": "10.143.192.101:8091", + "state": "scheduled", + "subClass": "analyze", + "submitTime": "2019-09-17 05:18:12.903122381 -0700 PDT m=+8460.550715992" + } + }, + { + "tasks_cache": { + "class": "advisor", + "delay": "5m0s", + "id": "254abec5-5782-543e-9ee0-d07da146b94e", + "name": "ca2cfe56-01fa-4563-8eb0-a753af76d865", + "node": "10.143.192.101:8091", + "results": [ + // ... + ], + "startTime": "2019-09-17 05:03:31.821597725 -0700 PDT m=+7579.469191487", + "state": "completed", + "stopTime": "2019-09-17 05:03:31.963133954 -0700 PDT m=+7579.610727539", + "subClass": "analyze", + "submitTime": "2019-09-17 04:58:31.821230131 -0700 PDT m=+7279.468823737" + } + } +] +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**class** + +__required__ +|The class of the task. + +*Example*: ``advisor`` +|string + +|**delay** + +__required__ +|The scheduled duration of the task. +|string + +|**id** + +__required__ +|The internal ID of the task. +|string + +|**name** + +__required__ +|The name of the task. +|string + +|**node** + +__required__ +|The node where the task was started. +|string + +|**state** + +__required__ +|The state of the task. + +*Values*: `scheduled`, `cancelled`, `completed` +|string + +|**subClass** + +__required__ +|The subclass of the task. + +*Example*: `analyze` +|string + +|**submitTime** + +__required__ +|The date and time when the task was submitted. +|string + +|**results** + +__optional__ +|Not scheduled tasks: the results of the task. +|Any array + +|**startTime** + +__optional__ +|Not scheduled tasks: the date and time when the task started. +|string (date-time) + +|**stopTime** + +__optional__ +|Not scheduled tasks: the date and time when the task stopped. +|string (date-time) +|=== + +Refer to xref:n1ql:n1ql-language-reference/advisor.adoc[ADVISOR Function] for more information on index advisor sessions. + +[#sys-transactions] +== Monitor Transactions + +The `system:transactions` catalog maintains a list of active Couchbase transactions. +To see the list of active transactions, use: + +[source,sqlpp] +---- +SELECT * FROM system:transactions; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "transactions": { + "durabilityLevel": "majority", + "durabilityTimeout": "2.5s", + "expiryTime": "2021-04-21T12:53:48.598+01:00", + "id": "85aea637-2288-434b-b7c5-413ad8e7c175", + "isolationLevel": "READ COMMITED", + "lastUse": "2021-04-21T12:51:48.598+01:00", + "node": "127.0.0.1:8091", + "numAtrs": 1024, + "scanConsistency": "unbounded", + "status": 0, + "timeout": "2m0s", + "usedMemory": 960, + "uses": 1 + } + // ... + } +] +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**durabilityLevel** + +__required__ +|Durability level for all mutations within a transaction. +|string + +|**durabilityTimeout** + +__required__ +|Durability timeout per mutation within the transaction. +|string (duration) + +|**expiryTime** + +__required__ +| +|string (date-time) + +|**id** + +__required__ +|The transaction ID. +|string + +|**isolationLevel** + +__required__ +|The isolation level of the transaction. +|string + +|**lastUse** + +__required__ +| +|string (date-time) + +|**node** + +__required__ +|The node where the transaction was started. +|string + +|**numAtrs** + +__required__ +|The total number of active transaction records. +|integer + +|**scanConsistency** + +__required__ +|The transactional scan consistency. +|string + +|**status** + +__required__ +| +|integer + +|**timeout** + +__required__ +|The transaction timeout duration. +|string (duration) + +|**usedMemory** + +__required__ +| +|integer + +|**uses** + +__required__ +| +|integer +|=== + +Refer to xref:n1ql:n1ql-language-reference/transactions.adoc[{sqlpp} Support for Couchbase Transactions] for more information. + +[#sys-sequences] +== Monitor Sequences + +The `system:sequences` catalog maintains a list of loaded sequences on any node: that is, sequences that have been accessed since the last restart. +To see the list of loaded sequences, use: + +[source,sqlpp] +---- +SELECT * FROM system:sequences; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "sequences": { + "bucket": "travel-sample", + "cache": 50, + "cycle": false, + "increment": 1, + "max": 9223372036854776000, + "min": -9223372036854776000, + "name": "seq1", + "namespace": "default", + "namespace_id": "default", + "path": "`default`:`travel-sample`.`inventory`.`seq1`", + "scope_id": "inventory", + "value": { + "73428daec3c68d8632ae66b09b70f14d": null, + "~next_block": 0 + } + } + }, +// ... +] +---- + +This catalog contains the following attributes: + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**bucket** + +__required__ +|The bucket containing the sequence. +|string + +|**cache** + +__required__ +|The sequence's cache size. +|integer + +|**cycle** + +__required__ +|Whether the sequence is set to cycle. +|boolean + +|**increment** + +__required__ +|The sequence step value. +|integer + +|**min** + +__required__ +|The minimum value permitted for the sequence. +|integer + +|**max** + +__required__ +|The maximum value permitted for the sequence. +|integer + +|**name** + +__required__ +|The name of the sequence. +|string + +|**namespace** + +__required__ +|Namespace to which the sequence belongs. +|string + +|**namespace_id** + +__required__ +|ID of the namespace to which the sequence belongs. +|string + +|**path** + +__required__ +|The fully qualified sequence name. +|string + +|**scope_id** + +__required__ +|ID of the scope to which the sequence belongs. +|string + +|**value** + +__required__ +|The current value of the sequence on each Query node. +| <> object +|=== + +[[value]] +**Values** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**** + +__required__ +|The name of this property is the UUID of a Query node. + +The value of this property is the current value of the sequence on that node. +|Integer + +|**~next_block** + +__optional__ +|The starting vale of the next block of values that can be reserved for the sequence. +|Integer +|=== + +For further details, see xref:n1ql:n1ql-language-reference/createsequence.adoc[]. + +[#sys-all-sequences] +== Monitor All Sequences + +The `system:all_sequences` catalog maintains a list of all defined sequences. +To see the list of all defined sequences, use: + +[source,sqlpp] +---- +SELECT * FROM system:all_sequences; +---- + +This will result in a list similar to: + +[source,json] +---- +[ + { + "sequences": { + "bucket": "travel-sample", + "cache": 50, + "cycle": false, + "increment": -1, + "max": 9223372036854776000, + "min": 0, + "name": "seq4", + "namespace": "default", + "namespace_id": "default", + "path": "`default`:`travel-sample`.`inventory`.`seq4`", + "scope_id": "inventory", + "value": { + "73428daec3c68d8632ae66b09b70f14d": 10, + "~next_block": -40 + } + } + }, + { + "sequences": { + "bucket": "travel-sample", + "cache": 50, + "cycle": true, + "increment": 5, + "max": 1000, + "min": 0, + "name": "seq3", + "namespace": "default", + "namespace_id": "default", + "path": "`default`:`travel-sample`.`inventory`.`seq3`", + "scope_id": "inventory", + "value": { + "73428daec3c68d8632ae66b09b70f14d": 5, + "~next_block": 255 + } + } + }, +// ... +] +---- + +This catalog gives the same information as the <> catalog. + +For further details, see xref:n1ql:n1ql-language-reference/createsequence.adoc[]. + +== Related Links + +* Refer to xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc[] for more information on the system namespace. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/.curl.adoc b/modules/n1ql/pages/n1ql-language-reference/.curl.adoc new file mode 100644 index 000000000..d8742c557 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/.curl.adoc @@ -0,0 +1,776 @@ += CURL Function +:description: The CURL() function implements a subset of cURL functionality and enables {sqlpp} queries to interact and integrate with external JSON data sources available over HTTP/REST. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:url-wiki-curl: https://en.wikipedia.org/wiki/CURL +:url-google-maps: https://maps.googleapis.com +:url-yahoo-api: https://developer.yahoo.com/api/ +:url-google-geo: https://developers.google.com/maps/documentation/geocoding/intro + +The `CURL()` function implements a subset of {url-wiki-curl}[cURL^] functionality and enables {sqlpp} queries to interact and integrate with external JSON data sources available over HTTP/REST. +This allows federated queries against external data sources, such as the {url-google-maps}[Google geocoding API^], {url-yahoo-api}[Yahoo API^], or other Couchbase clusters. +The federated queries can leverage full querying capabilities of {sqlpp}, including functions, expressions, sub-queries, JOINs, NESTs, UNNESTs etc. + +The `CURL()` function can be used in various {sqlpp} expressions and in various clauses of the DML statements such as projection, WHERE predicates, FROM data source, and so on. +For example, you can use the CURL function with the INSERT-SELECT statement to import external data into Couchbase Capella. + + +== Syntax + +[subs=normal] +.... +CURL(__url__, [__options__]) +.... + +=== Arguments + +`url`:: A string representing the URL of the data source. +The URL needs to point to a JSON endpoint and must be either `http://` or `https://` only. +No other protocol is supported. +The redirection of URL is not allowed. +`options`:: An optional JSON object representing various supported options. +This includes options and parameters to be sent to the URL source endpoint. + +=== Options + +.Security Options +[#table_security_options,cols="1,3,2"] +|=== +| Option | Description | Value + +| `user` +| Server user name and password. +| USERNAME[:PASSWORD] + +| `basic` +| Use HTTP Basic Authentication. +| Boolean + +| `insecure` +| Allow connections to SSL sites without certificates (H). +| Boolean + +| `anyauth` +a| +CURL to figure out authentication method by itself, and use the most secure one. + +NOTE: This supports only basic authentication. +| Boolean + +| `cacert` +a| +Specify CA signed certificate file name. +Certificates should be stored on the local machine, on each query node within a cluster. + +* To store certificates, access [.path]_/Couchbase/var/lib/couchbase/n1qlcerts_. +This is not visible to the user. +* The file name cannot contain a path. +* If the certificate is not a match to the existing contents of [.path]_n1qlcerts_ directory, the function returns an error. +* All expired and invalid certificates return an error. +| FILENAME + +For example, this is the certificate `.pem` file for AWS. +|=== + +.Transfer-related Options +[#table_transfer_options,cols="1,2,3"] +|=== +| Option | Description | Value + +| `get` +| The Get request for CURL. +| BOOLEAN + +Example: `{"get": true}` + +| `request` +| Sets the request method. +This only accepts GET or POST requests. +This is case sensitive. +| String + +Example: `{"request":"POST"}` + +| `connect-timeout` +| The maximum time allowed for connection in seconds. +| Integer + +Example: `{"connect-timeout":30}` + +| `max-time` +| The maximum time allowed for the transfer in seconds. +| Integer + +Example: `{"max-time":30}` + +| `data` +| POST data to be sent to the HTTP/REST service. +The string data should be formatted exactly same as HTTP POST data. +| String or [\...string, string….] + +Example: `{"data":"address=Half+Moon+Bay"}` + +`{"data":"address=Half+Moon+Bay,california"}` + +| `header` +| Passes custom header line to the server. +| String or [\...string, string….] + +Example: `{"header":"Content-Type: application/json"}` + +`{"header":["Content-Type: application/json", "Content-Length: 115"]}` + +| `show-error` +| Displays error message. +| Boolean + +Example: `{"show-error": true}` + +| `silent` +| The silent mode. +| Boolean + +Example: `{"silent": false}` + +| `keepalive-time` +| The number of seconds to wait between the `keepalive` probes. +| Integer + +Example: `{"keepalive-time":20}` + +| `user-agent` +| The value for the user-agent to send it to the server. +| String + +Example: `{"header":[ "user-agent: bsmith","Content-Type: application/json"]}` + +| `data-urlencode` +| Encode the data and send it to the server. + +This is a test \=> this%20is%20a%20test +| String or [\...string, string….] +|=== + +=== Return Value +The CURL() function returns either a single JSON object, or multiple objects in an array. +These objects are returned by the HTTP/REST service at the URL. +Note that the result is expected to be JSON, and the function itself doesn't do any additional processing. +However, if the query parameter `pretty=true`, then the data received is in pretty format. +If the returned data from the URL is not a well defined JSON, it may result in errors or undefined behavior. +The errors returned by CURL (such as moved permanently) can be in different formats, like HTML, XML, plain strings, and can be a large blob. +The {sqlpp} function returns a "Not a JSON endpoint" error when it returns any other format other than JSON. + +== Security + +It is important to understand the potential security implications in using the `CURL()` function. +Note that `CURL()` function can connect to any REST end point accessible to the Query node (where the function is executed) inside or outside the firewall. +To avoid security vulnerabilities, multiple security measures have been implemented. +These can be used to control and minimize the risks associated with using the `CURL()` function. +See <> for the list of security options that can be used with the `CURL()` function. + +In addition to the security options, a Full Administrator can also list URLs and REST endpoints that can be accessed by the `CURL()` function. +The `CURL()` function can access URLs that satisfy a prefix match, which means only URLs specified on the list or the prefixes. + +//// +Consider the following use case where a deployment of Couchbase Server and Mobile Sync Gateway exist on the same machine, and the user has access to the query service but not the Sync Gateway admin endpoint. +Let's assume that the user has been granted QUERY_EXTERNAL_ACCESS role by the Full Administrator. +This means that the user can write queries using the CURL() function and potentially use CURL to access the Mobile Sync Gateway admin endpoint. +To avoid this, the Full Administrator can create an access list for CURL() access and add the Admin endpoint of Sync Gateway to the `disallowed_urls` list. +//// + +For more details on creating the access list and the structure of the access list file, see <>. + +The following security measures help control risks when using the `CURL()` function: + +* Enable the `CURL()` function only for the Full Administrator role. +* For all other users, the RBAC role QUERY_EXTERNAL_ACCESS is required to run the `CURL()` function. +Only the Full Administrator can assign the QUERY_EXTERNAL_ACCESS role to other users. +* An access list of URLs and REST points must be configured on the query nodes before being able to use the `CURL()` function. +See <> for details. +* Each query node in the cluster must define its access list file. +* The `CURL()` function internally supports a specific set of SSL ciphers (MEDIUM or HIGH). +This is dependent on the `COUCHBASE_SSL_CIPHER_LIST`. +* The `CURL()` function runs on the query node within a cluster. +In order to identify a request from {sqlpp}'s `CURL()` function, a custom header is always set for all requests. +The custom header format is: `"X-N1QL-User-Agent: couchbase/n1ql/"`. +External clients that wish to disallow {sqlpp} `CURL()` from accessing their REST API endpoints can explicitly check for the above header and block it. +The general external endpoints will ignore this header value. +* A `user-agent` is always set by default. +This can be reset using the `-user-agent` option. +The value set by default is `couchbase/n1ql/`. ++ +NOTE: The current is "1.7.0-N1QL". + +[#curl-access-list] +=== Creating an Access List for CURL() + +An access list allows a Full Administrator to list out the permitted REST endpoints and URLs for the `CURL()` function. +To enable access based on the access list, a Full Administrator must create the file containing the access list, which can be created two ways: + +. From the Query Workbench UI in the menu:Settings[Advanced Query Settings] section. +. From CBQ via a cURL command. + +==== From the Query Workbench + +In the Query Workbench, navigate to the menu:Settings[Advanced Query Settings] section as shown below: + +image::CURL_Access.png["The Settings Screen showing the Advanced Query Settings",720] + +After expanding the Advanced Query Settings section, you can choose the Function Access: + +[horizontal] +[ui]*Restricted*:: Access applies only the sites explicitly listed. +[ui]*Unrestricted*:: Access applies to all sites within the explicitly listed sites. + +Under the *Allowed CURL URLs* and *Disallowed CURL URLs* headings, enter your allowed or disallowed URL in the appropriate textbox, and press the kbd:[Enter] key or click anywhere else on this screen to enter your URL. + +Click btn:[+] to add another URL to the list. + +Click btn:[-] to remove a URL from the list. + +==== From CBQ + +From a CBQ prompt, you can send a CURL() command to allow or disallow specific URLs, for example: + +[source,sh] +---- +include::server:rest-api:example$query-settings-post-access.sh[] +---- + +The access list file command structure is described in the following table. + +.Structure of Access List for CURL() +include::server:rest-api:partial$query-settings/definitions.adoc[tag=access] + +== Design Considerations + +Here are some of the design considerations to keep in mind when using CURL: + +* The URL needs to point to a JSON endpoint. +The redirection of URL is not allowed. +* Only HTTP and HTTPS protocols are supported. +This means that files on the local file system cannot be accessed. +* The amount of memory used for the CURL result is controlled using the `result-cap` option. +The default is 20MB. +* Any values passed to the arguments of `CURL()` must be static values. +That means, they cannot include any references to names, aliases of documents, attributes in the documents, or any {sqlpp} functions or expressions that need to be evaluated. ++ +Consider the following example: ++ +[source,sqlpp] +---- +SELECT CURL(b.url, { "data" : "address="||b.data }) +FROM keyspace b; +---- ++ +The above example is invalid, because the first argument `b.url` refers to the alias `b` and the attribute `url` in the document. +In the second argument, the string concatenation operator (||) cannot be evaluated. + +== Examples + +. xref:Ex1[xrefstyle=basic] +. xref:Ex2[xrefstyle=basic] +. xref:Ex3[xrefstyle=basic] +. xref:Ex4[xrefstyle=basic] +. xref:Ex5[xrefstyle=basic] +. xref:Ex6[xrefstyle=basic] +. xref:Ex7[xrefstyle=basic] +. xref:Ex8[xrefstyle=basic] +. xref:Ex9[xrefstyle=basic] +. xref:Ex10[xrefstyle=basic] +. xref:Ex11[xrefstyle=basic] +. xref:Ex12[xrefstyle=basic] +. xref:Ex13[xrefstyle=basic] +. xref:Ex14[xrefstyle=basic] + +The following examples are using CURL in the query projection list. + +[[Ex1]] +.Use Google Maps API to convert static address into coordinates +==== +The following {sqlpp} query fetches details about the address "Half Moon Bay" using the {url-google-maps}[Google maps API^]. +The Geocoding API from Google Maps allows you to convert static addresses into coordinates. +(For more information refer to the {url-google-geo}[Geocoding API Developer Guide^].) +The corresponding `curl` command is also provided below. + +.Request +[source,sh] +---- +curl https://maps.googleapis.com/maps/api/geocode/json?address=Half+Moon+Bay +---- + +.Query +[source,sqlpp] +---- +SELECT CURL("https://maps.googleapis.com/maps/api/geocode/json", + {"data":"address=Half+Moon+Bay" , "request":"GET"} ); +---- + +.Results +[source,json] +---- +[ + { + "$1": { + "results": [ + { + "address_components": [ + { + "long_name": "Half Moon Bay", + "short_name": "Half Moon Bay", + "types": [ + "locality", + "political" + ] + }, + { + "long_name": "San Mateo County", + "short_name": "San Mateo County", + "types": [ + "administrative_area_level_2", + "political" + ] + }, + { + "long_name": "California", + "short_name": "CA", + "types": [ + "administrative_area_level_1", + "political" + ] + }, + { + "long_name": "United States", + "short_name": "US", + "types": [ + "country", + "political" + ] + } + ], + "formatted_address": "Half Moon Bay, CA, USA", + "geometry": { + "bounds": { + "northeast": { + "lat": 37.5226389, + "lng": -122.4165183 + }, + "southwest": { + "lat": 37.4249286, + "lng": -122.4778879 + } + }, + "location": { + "lat": 37.4635519, + "lng": -122.4285862 + }, + "location_type": "APPROXIMATE", + "viewport": { + "northeast": { + "lat": 37.5226389, + "lng": -122.4165183 + }, + "southwest": { + "lat": 37.4249286, + "lng": -122.4774494 + } + } + }, + "place_id": "ChIJC8sZCqULj4ARVJvnNcic_V4", + "types": [ + "locality", + "political" + ] + } + ], + "status": "OK" + } + } +] +---- +==== + +[[Ex2]] +.Use Google Maps API to extract geometry (address and geographic location bounds) of a given street address +==== +This is similar to <>, but following {sqlpp} query fetches details about Santa Cruz in Spain using the {url-google-maps}[Google geocoding API^] and extracts the `geometry` field from the result. +This query retrieves the address and geographic location bounds of the address, Santa Cruz, ES. +We use the `address` and `components` parameters from the Geocoding API. +The `data` option represents the HTTP POST data. + +.Request +[source,sh] +---- +curl https://maps.googleapis.com/maps/api/geocode/json?address=santa+cruz&components=country:ES +---- + +.Query +[source,sqlpp] +---- +SELECT CURL("https://maps.googleapis.com/maps/api/geocode/json", + {"data":["address=santa+cruz","components=country:ES"],"get":true}); +---- + +.Results +[source,json] +---- +[ + { + "$1": { + "results": [ + { + "address_components": [ + { + "long_name": "Santa Cruz de Tenerife", + "short_name": "Santa Cruz de Tenerife", + "types": [ + "locality", + "political" + ] + }, + { + "long_name": "Santa Cruz de Tenerife", + "short_name": "TF", + "types": [ + "administrative_area_level_2", + "political" + ] + }, + { + "long_name": "Canary Islands", + "short_name": "CN", + "types": [ + "administrative_area_level_1", + "political" + ] + }, + { + "long_name": "Spain", + "short_name": "ES", + "types": [ + "country", + "political" + ] + } + ], + "formatted_address": "Santa Cruz de Tenerife, Spain", + "geometry": { + "bounds": { + "northeast": { + "lat": 28.487616, + "lng": -16.2356646 + }, + "southwest": { + "lat": 28.4280248, + "lng": -16.3370045 + } + }, + "location": { + "lat": 28.4636296, + "lng": -16.2518467 + }, + "location_type": "APPROXIMATE", + "viewport": { + "northeast": { + "lat": 28.487616, + "lng": -16.2356646 + }, + "southwest": { + "lat": 28.4280248, + "lng": -16.3370045 + } + } + }, + "place_id": "ChIJcUElzOzMQQwRLuV30nMUEUM", + "types": [ + "locality", + "political" + ] + } + ], + "status": "OK" + } + } +] +---- +==== + +[[Ex3]] +.Join two keyspaces on different Couchbase clusters +==== +This {sqlpp} query shows how to JOIN two keyspaces on different Couchbase clusters. +The JOIN is the same as is explained in the section on the xref:n1ql-language-reference/join.adoc[JOIN Clause], but the left and right side keyspaces are in two different Couchbase clusters. + +* The left side keyspace `route` is from the cluster running on `hostname`. +If you don't have a second cluster running, you should substitute the `hostname` with 127.0.0.1 or the IP-address of the local cluster. +* The right side keyspace `airline` is from the local cluster. + +include::ROOT:partial$query-context.adoc[tag=example] + +// TODO: For Capella, change query_context in CURL options + +.Query +[source,sqlpp] +---- +SELECT DISTINCT airline.name, airline.callsign, + route.destinationairport, route.stops, route.airline +FROM CURL("http://localhost:8093/query/service", + {"data": "statement=SELECT * FROM route t + WHERE t.sourceairport = 'SFO' + & query_context=travel-sample.inventory", + "user": "Administrator:password"}).results[*].t route +JOIN airline +ON KEYS route.airlineid +LIMIT 4; +---- + +Note that the results from the `CURL()` output are embedded in the `results[]` array under the keyspace alias `t` used in the remote query. +So, we extract the result documents appropriately with the expression `+CURL(...).results[*].t+` and alias it to `route` as the left side keyspace for the `JOIN`. + +RBAC credentials are required when CURL() is accessing Couchbase Capella. + +.Results +[source,json] +---- +[ + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "AUS", + "name": "JetBlue Airways", + "stops": 0 + }, // … +] +---- +==== + +[[Ex4]] +.Full text search (FTS) in a {sqlpp} query +==== +The following example shows how to use the `CURL()` function to include a full text search from the xref:server:fts:full-text-intro.adoc[Search service] in a {sqlpp} query. +Assuming the FTS index `fts_travel` is created on the default collection in the default scope of the travel sample dataset, running the following {sqlpp} query finds all documents that have "sanfrancisco" anywhere in the document. + +You can use xref:n1ql-language-reference/searchfun.adoc[search functions] to use a full text search in a {sqlpp} query, as long as the Search service is available on the cluster. +You can still use the `CURL()` function if you need to access the Search service on another cluster. + +.Query +[source,sqlpp] +---- +SELECT result.hits[*].id +FROM CURL("http://Administrator:password@127.0.0.1:8094/api/index/fts_index/query", + {"header":"Content-Type: application/json", + "request" : "POST", + "data":'{"explain":false,"fields": ["*"],"highlight": {}, + "query": {"query": "san fran isco"}}' }) result; +---- + +.Results +[source,json] +---- +[ + { + "id": [ + "hotel_25509", + "hotel_25508", + "hotel_26139", + "hotel_25587", + "hotel_25503", + "hotel_25667", + "hotel_25502", + "hotel_25597", + "hotel_26493", + "hotel_25670" + ] + } +] +---- +==== + +[[Ex5]] +.Use Yahoo Finance API in a WHERE clause to find a stock's lowest value for the day +==== +// FIXME: Yahoo Finance API unavailable. +// Use https://docs.data.nasdaq.com/docs instead. + +The following example uses the `CURL()` function with a WHERE clause. +It uses the Yahoo finance API to find the day's low value (i.e `DaysLow`) of HDP stock and finds all the documents in the `users` keyspace that have `min_threshold` attribute value greater than the DaysLow stock value. + +include::ROOT:partial$query-context.adoc[tag=unset] + +// TODO: completely overhaul this to use `travel-sample`.tenant_agent_00.users + +Insert the following documents, representing customers and their minimum thresholds, into the default collection in the default scope of the travel sample data, and then run the `SELECT` query: + +.Data +[source,sqlpp] +---- +INSERT INTO `travel-sample` (KEY, VALUE) + VALUES + ("k1", + {"custID" : 12345, "min_threshold" : 4}), + ("k2", + {"custID" : 44444, "min_threshold" : 12}); +---- + +.Query +[source,sqlpp] +---- +SELECT min_threshold, + meta().id, + to_number(hdp_low) hdp_low +FROM `travel-sample` +USE KEYS ["k1", "k2"] +LET hdp_low = curl("https://query.yahooapis.com/v1/public/yql", {"data":"q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22HDP%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback="}).query.results.quote.DaysLow +WHERE to_number(hdp_low) < min_threshold; +---- + +.Results +[source,json] +---- +[ + { + "hdp_low": 9.48, + "id": "k2", + "min_threshold": 12 + } +] +---- +==== + +[[Ex6]] +.Use CURL() to allow two URLs and disallow one URL +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": true, +"allowed_urls" : ["company1.com", "couchbase.com"], +"disallowed_urls" : ["company2.com"] +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex7]] +.Use CURL() to allow all access to all endpoints +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": true +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex8]] +.Use CURL() to turn off access to all endpoints and clear the Allowed and Disallowed lists +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": false, +"allowed_urls" : [], +"disallowed_urls" : [] +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex9]] +.Use CURL() to turn off access to all endpoints but make no changes to the Allowed and Disallowed lists +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": false +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex10]] +.Use CURL() to turn off access to all endpoints, allow one URL, and clear the Disallowed list +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": false, +"allowed_urls" : ["https://maps.googleapis.com/maps/api/geocode/json"], +"disallowed_urls" : [] +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex11]] +.Use CURL() to turn off access to all endpoints, disallow one URL, and clear the Allowed list +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": false, +"disallowed_urls" : ["https://maps.googleapis.com/maps/api/geocode/json"], +"allowed_urls" : [] +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex12]] +.Use CURL() to allow an IP address and port instead of a website name +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": false, +"disallowed_urls" : ["https://maps.googleapis.com/maps/api/geocode/json"], +"allowed_urls" : ["http://127.0.0.1:9499/query/service"] +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex13]] +.Use CURL() to allow and disallow the same URL -- and get an error +==== +.Request +[source,sh] +---- +curl -X POST -u Administrator:password \ +-d '{ +"all_access": false, +"disallowed_urls" : ["https://maps.googleapis.com/maps/api/geocode/json"], +"allowed_urls" : ["https://maps.googleapis.com/maps/api/geocode/json"] +}' http://localhost:8091/settings/querySettings/curlWhitelist +---- +==== + +[[Ex14]] +.Use CURL() with dynamic named parameters +==== +.Query +[source,sqlpp] +---- +SELECT CURL(b.url, $params) FROM keyspace b WHERE b.username = "joe"; +---- + +If we wanted to use Node.JS, we would use: + +[source,javascript] +---- +keyspace.query(SELECT CURL(b.url, $params) FROM keyspace b WHERE b.username = "joe", { params: { data: "..." } }, + (error, result) => {} ); +---- + +`$params` is a named parameter, so we name it in the parameters object when executing the query. +Then we populate the properties with the data that's in the documents since those properties can be variables. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/adaptive-indexing.adoc b/modules/n1ql/pages/n1ql-language-reference/adaptive-indexing.adoc new file mode 100644 index 000000000..8c30848b6 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/adaptive-indexing.adoc @@ -0,0 +1,584 @@ += Adaptive Index +:description: Adaptive Indexes are a special type of GSI array index that can index all or specified fields of a document. +:imagesdir: ../../assets/images + +:pairs: xref:n1ql-language-reference/metafun.adoc#pairs +:createindex: xref:n1ql-language-reference/createindex.adoc +:indexing-arrays: xref:n1ql-language-reference/indexing-arrays.adoc +:partial-index: xref:learn:services-and-indexes/indexes/indexing-and-query-perf.adoc#partial-index + +{description} +Such an index is generic in nature, and it can efficiently index and lookup any of the index-key values. +This enables efficient ad hoc queries (that may have WHERE clause predicates on any of the index-key fields) without requiring to create various composite indexes for different combinations of fields. +Adaptive Index is a functional array index created using the {sqlpp} function {pairs}[PAIRS()]. + +Basically, the idea is to be able to simply load data and start querying: + +* using a single secondary index, and +* not worrying about creating appropriate secondary indexes for each query. + +Note that without Adaptive Indexes: + +* Only primary index can help run any ad hoc query. +But using primary index can be expensive for queries with predicates on any of the non-key fields of the document. +* Each query will need a compatible secondary index that can qualify for the predicates in the WHERE clause. +See section <> for details. + +For instance, consider a user profile or hotel reservation search use case. +A person's profile may need to be searched based on any of the personal attributes such as first name, last name, age, city, address, job, title, company, etc. +Similarly, a hotel room availability may be searched based on wide criteria, such as room facilities, amenities, price, and other features. +In this scenario, traditional secondary indexes or composite indexes can't be used effectively -- see section <> to understand some of the concerns. +Adaptive indexes can help effectively and efficiently run such ad hoc search queries. + +== Syntax + +An adaptive index is a type of array index. +To create an adaptive index, the overall syntax is the same as for an array index. + +Refer to the {createindex}[CREATE INDEX] statement for details of the syntax. + +[[index-key,index-key]] +=== Index Key + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=simple-array-expr] +---- + +image::n1ql-language-reference/simple-array-expr.png["Syntax diagram: refer to source code listing", align=left] + +To create an adaptive index, the index key must be a simple array expression containing a {pairs}[PAIRS()] function. + +[[pairs-function,pairs-function]] +=== PAIRS() Function + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=pairs-function] +---- + +image::n1ql-language-reference/pairs-function.png["Syntax diagram: refer to source code listing", align=left] + +When the `SELF` keyword is used, the adaptive index is created with all fields in the documents of the keyspace. + +If you want to create an adaptive index on selected fields only, you must specify an index key object. + +[[index-key-object,index-key-object]] +=== Index Key Object + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=object] +---- + +image::n1ql-language-reference/object.png["Syntax diagram: refer to source code listing", align=left] + +For the purposes of an adaptive index, the index key object should be an xref:n1ql-language-reference/constructionops.adoc#object-construction[object constructor] that generates an object of name-value pairs from the document fields to be indexed. + +_name-expr_:: +The field name that corresponds to `_expr_`. + +_expr_:: +A {sqlpp} expression that is allowed in {createindex}[CREATE INDEX]. +This must be an expression over any document fields. + +When the value expression is an identifier directly referring to a named document field, then you may omit the name expression. +In this case, the name of the field in the data source will be used as the name of the field in the object constructor. + +[NOTE] +==== +When using {pairs}[PAIRS()] with an object constructor, you need to keep in mind: + +* If two fields have the same name, such as `{a, c.a}` -- when evaluated, both will inherit the same name of `a`, causing one value to overwrite the other. +Neither value will be indexed. +A better way to handle this is to name one field explicitly, such as `{a, "ca":c.a}`. +* If the value expression is _not_ an identifier directly referring to a named document field, such as `{abs(a)}` -- the name of the object field is null, and this will generate an error. +A better way to handle this is to use a field name explicitly, such as `{"abs_a":abs(a)}`. +==== + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +Consider the following indexes, which are included with the `travel-sample` data that is shipped with the product. + +==== +[[C1]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c1.n1ql[] +---- + +[[C2]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c2.n1ql[] +---- + +[[C3]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c3.n1ql[] +---- +==== + +Here, three different indexes are needed to help different queries whose WHERE clause predicates may refer to different fields. +For instance, the following queries <>, <>, and <> will use the indexes created in <>, <>, and <>, respectively: + +==== +[[Q1]] +.Q{counter:q1} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q1.n1ql[] +---- + +[[Q2]] +.Q{counter:q1} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q2.n1ql[] +---- + +[[Q3]] +.Q{counter:q1} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q3.n1ql[] +---- +==== + +However, the following single adaptive index <> can serve all three of the following queries <>, <>, and <>: + +==== +[[C4]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c4.n1ql[] +---- +==== + +==== +[[Q1A]] +.Q{counter:q2}A +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q1a.n1ql[] +---- + +[[Q2A]] +.Q{counter:q2}A +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q2a.n1ql[] +---- + +[[Q3A]] +.Q{counter:q2}A +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q3a.n1ql[] +---- +==== + +Similarly, the following adaptive index over `SELF` in <> is also qualified for these queries. +In fact, an adaptive index that includes all fields in the documents can serve any query on the keyspace, though it might have different performance characteristics when compared to specific indexes created for a particular query. +See the section <> for details. +For example, the following queries <> and <> show how the generic adaptive index <> is used to query predicates on different fields of the "airport" documents. + +==== +[[C5]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c5.n1ql[] +---- + +[[Q5]] +.Q{ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q5.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-q5.jsonc[tag=excerpt] +// ... +---- + +[[Q5A]] +.Q{ai}A +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q5a.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-q5a.jsonc[tag=excerpt] +// ... +---- +==== + +[#section_w31_bnm_5z] +== Contrast with Composite Indexes + +include::ROOT:partial$query-context.adoc[tag=section] + +Traditionally, composite secondary indexes are used to create indexes with multiple index keys. +For example, consider the following index in <>: + +==== +[[C6]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c6.n1ql[] +---- +==== + +Such composite indexes are very different from the adaptive index in <> in many ways: + +. *Order of index keys is vital for composite indexes.* When an index key is used in the WHERE clause, all prefixing index keys in the index definition must also be specified in the WHERE clause. +For example, to use the index <>, a query to _"find details of airports with FAA code SFO"_, must specify the prefixing index key `city` also in the WHERE clause just to qualify the index <>. +Contrast the following query <> with <> above that uses the adaptive index in <>. ++ +==== +[[Q6]] +.Q{ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q6.n1ql[] +---- +==== ++ +The problem is not just the addition of an extraneous predicate, but the performance. +The predicate on the first index key `city IS NOT MISSING` is highly selective (i.e. +most of the index entries in the index will match it) and hence, it will result in almost a full index scan. + +. *Complication in Queries.* If a document has many fields to index, then the composite index will end up with all those fields as index keys. +Subsequently, queries that only need to use index keys farther in the index key order will need many unnecessary predicates referring to all the preceding index keys. +For example, if the index is: ++ +==== +[source,sqlpp] +---- +CREATE INDEX idx_name ON `travel-sample`(field1, field2, ..., field9); +---- +==== ++ +A query that has a predicate on [.var]`field9` will get unnecessarily complicated, as it needs to use all preceding index keys from [.var]`field1` to [.var]`field8`. + +. *Explosion of number of indexes for ad hoc queries.* At some point, it becomes highly unnatural and overly complicated to write ad hoc queries using composite indexes. +For instance, consider a user profile or inventory search use case where a person or item may need to be searched based on many criteria. ++ +One approach is to create indexes on all possible attributes. +If that query can include any of the attributes, then it may require creation of innumerable indexes. +For example, a modest 20 attributes will result in 20 factorial (2.43×10^18^) indexes in order to consider all combinations of sort orders of the 20 attributes. + +== Partial Adaptive Indexes + +include::ROOT:partial$query-context.adoc[tag=section] + +An adaptive index may also be a {partial-index}[partial index]. +For a partial adaptive index, you must ensure that any fields filtered by the WHERE clause in the index definition are also referenced by the {pairs}[PAIRS()] function. + +For example, the following query <> cannot select the index defined in <>. + +==== +[[C9A]] +.C{counter:ai}A +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c9a.n1ql[] +---- + +<1> The WHERE clause filters on `activity`, but the {pairs}[PAIRS()] function does not include the `activity` field. + +[[Q9]] +.Q{ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q9.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-partial-1.jsonc[tag=excerpt] +// ... +---- + +<1> The query does not use the incorrectly-defined partial adaptive index. +==== + +However, the same query <> does select the partial adaptive index defined in <>. + +==== +[[C9B]] +.C{ai}B +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c9b.n1ql[] +---- + +<1> The WHERE clause filters on `activity`, and the {pairs}[PAIRS()] function includes the `activity` field. + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-partial-2.jsonc[tag=excerpt] +// ... +---- + +<2> The query does an IntersectScan, including the correct partial adaptive index. +==== + +Alternatively, you can use the `SELF` keyword to ensure that the fields used in the WHERE clause are included in the {pairs}[PAIRS()] function. +Refer to <> for an example. + +An IntersectScan does not eliminate redundant queries, and this may impact performance. +Refer to <> for details. + +[[section_m12_552_dbb]] +== Performance Implications + +include::ROOT:partial$query-context.adoc[tag=section] + +While Adaptive Indexes are very useful, there are performance implications you need to keep in mind: + +. *If a query is not covered by a regular index, then an unnested index will not have any elimination of redundant indexes*; and it will instead do an IntersectScan on all the indexes, which can impact performance. ++ +==== +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-perform-1.n1ql[] +---- + +<1> Index on the `name` field. +<2> Adaptive index on the whole document. + +.Results +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-perform-1.jsonc[tags=excerpt;ellipsis] +---- + +<1> IntersectScan of `idx_name` AND `idx_self`. +==== ++ +Here's another example with a partial Adaptive Index that uses IntersectScan on the index conditions: ++ +==== +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-perform-2.n1ql[] +---- +==== ++ +The above query requires only a regular index, so it uses index `idx_reg1` and ignores index `idx_reg2`. +When the adaptive index `idx_adpt` has only the clause `city="Paris"` and is used with the above query, then index `idx_adpt` will still use IntersectScan. +Here, we have only a single adaptive index instead of a reduction in the number of indexes. +To fix this, you may need to remove the index condition from the predicate while spanning generations. + +[#section_u4c_gzm_5z] +== Functional Limitations + +include::ROOT:partial$query-context.adoc[tag=section] + +It is important to understand that adaptive indexes are not a panacea and that they have trade-offs compared to traditional composite indexes: + +. *Adaptive Indexes are bound to the limitations of Array Indexes* because they are built over {indexing-arrays}[Array Indexing] technology. +Index Joins can’t use Adaptive Indexes because Index Joins can’t use array indexes, and Adaptive Index is basically an array index. +. *Indexed entries of the Adaptive Index are typically larger in size compared to the simple index* on respective fields because the indexed items are elements of the {pairs}[PAIRS()] array, which are basically name-value pairs of the document fields. +So, it may be relatively slower when compared with equivalent simple index. +For example, in the following equivalent queries, <>/<> may perform better than <>/<>. ++ +==== +This example uses the `def_inventory_hotel_city` index, which is installed with the `travel-sample` bucket. + +[[C7]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c7.n1ql[] +---- + +[[Q7]] +.Q{ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q7.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-limits-1.jsonc[tag=excerpt] +// ... +---- +==== ++ +==== +[[C8]] +.C{counter:ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c8.n1ql[] +---- + +[[Q8]] +.Q{ai} +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q8.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-limits-2.jsonc[tag=excerpt] +// ... +---- + +<1> Note how the index key values are represented in the spans. +==== + +. *Adaptive index requires more storage and memory*, especially in case of Memory Optimized Indexes. + + .. The size of the index and the number of indexed items in an Adaptive Index grow rapidly with the number of fields in the documents, as well as, with the number of different values for various fields in the documents or keyspace. + .. Moreover, if the documents have nested sub-objects, then the adaptive index will index the sub-documents and related fields at each level of nesting. + .. Similarly, if the documents have array fields, then each of array elements are explored and indexed. + .. For example, the following queries show that a single route document in `travel-sample` generates 103 index items and that all route documents produce ~2.3 million items. ++ +==== +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-limits-3.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-limits-3.jsonc[] +---- + +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-limits-4.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-limits-4.jsonc[] +---- +==== + ++ +So, the generic adaptive indexes (with `SELF`) should be employed carefully. +Whenever applicable, it is recommended to use the following techniques to minimize the size and scope of the adaptive index: + + ** Instead of `SELF`, use selective adaptive indexes by specifying the field names of interest to the {pairs}[PAIRS()] function. +For examples, refer to <>, <>, <>, and <> above. + ** Use partial adaptive indexes with a WHERE clause that will filter the number of documents that will be indexed. +For examples, refer to <>, <>, and <> above. + +. *A generic adaptive index (on SELF) will be qualified for all queries on the keyspace*. +So, when using with other GSI indexes, this will result in more IntersectScan operations for queries that qualify other non-adaptive indexes. +This may impact query performance and overall load on query and indexer nodes. +To alleviate the negative effects, you may want to specify the `USE INDEX` clause in `SELECT` queries whenever possible. +. *Adaptive Indexes cannot be used as Covered Indexes* for any queries. +See example <> above. +. *Adaptive Indexes can be created only on document field identifiers*, not on functional expressions on the fields. +For example, the following query uses a default index, such as [.var]`def_inventory_hotel_city`, instead of the specified adaptive index [.var]`ai_city1`: ++ +==== +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c10.n1ql[] +---- + +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q10.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-q10.jsonc[tag=excerpt] +// ... +---- + +<1> The query does not use the specified [.var]`ai_city1` index because the index uses a functional index expression on the field `city`. +==== + +. *Adaptive Indexes do not work with NOT LIKE predicates with a leading wildcard* (see https://issues.couchbase.com/browse/MB-23981[MB-23981^]). +For example, the following query also uses a default index, such as [.var]`def_city`, instead of the specified adaptive index [.var]`ai_city`. +However, it works fine for LIKE predicates with a leading wildcard. ++ +==== +.Query: NOT LIKE with leading wildcard +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q11.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-q11.jsonc[tag=excerpt] +// ... +---- + +<1> Doesn't use `ai_city` with `NOT LIKE` and leading wildcard. + +.Query: LIKE with leading wildcard +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q12.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-q12.jsonc[tag=excerpt] +// ... +---- + +<1> Uses `ai_city` with `LIKE` and leading wildcard. +==== + +. *Adaptive indexes can't use Covered Scans*. +An adaptive index can't be a covering index, as seen in the following example: ++ +==== +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-c13.n1ql[] +---- + +[source,sqlpp] +---- +include::example$n1ql-language-reference/adaptive-idx-q13.n1ql[] +---- + +<1> No index specified in query. + +.Result +[source,json] +---- +include::example$n1ql-language-reference/adaptive-idx-q13.jsonc[tag=excerpt] +// ... +---- + +<1> Doesn't use `ai_city2` as a covering index. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/advise.adoc b/modules/n1ql/pages/n1ql-language-reference/advise.adoc new file mode 100644 index 000000000..e0400595c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/advise.adoc @@ -0,0 +1,482 @@ += ADVISE +:description: The ADVISE statement provides index recommendations to optimize query response time. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// N1QL cross-references +:n1ql: xref:n1ql-language-reference +:cbo: {n1ql}/cost-based-optimizer.adoc +:select: {n1ql}/selectintro.adoc +:update: {n1ql}/update.adoc +:delete: {n1ql}/delete.adoc +:merge: {n1ql}/merge.adoc +:join: {n1ql}/join.adoc +:comparisonops: {n1ql}/comparisonops.adoc +:collection-op-in: {n1ql}/collectionops.adoc#collection-op-in +:collection-op-any: {n1ql}/collectionops.adoc#collection-op-any +:schema-output: {n1ql}/infer.adoc#schema-output + +// Aggregate function cross-references +:min: {n1ql}/aggregatefun.adoc#min +:max: {n1ql}/aggregatefun.adoc#max +:sum: {n1ql}/aggregatefun.adoc#sum +:count: {n1ql}/aggregatefun.adoc#count +:countn: {n1ql}/aggregatefun.adoc#countn +:avg: {n1ql}/aggregatefun.adoc#avg +:aggregate-quantifier: {n1ql}/aggregatefun.adoc#aggregate-quantifier + +// Indexing and Query Performance cross-references +:indexing-and-query-perf: xref:learn:services-and-indexes/indexes/indexing-and-query-perf.adoc +:secondary-index: {indexing-and-query-perf}#secondary-index +:partial-index: {indexing-and-query-perf}#partial-index +:array-index: {indexing-and-query-perf}#array-index +:functional-index: {indexing-and-query-perf}#functional-index + +// Tools cross-references +:query-workbench: xref:clusters:query-service/query-workbench.adoc + +[abstract] +{description} + +== Purpose + +The ADVISE statement invokes the _index advisor_ to provide index recommendations for a single query. +You can use the ADVISE statement with any of the following types of query: + +* {select}[SELECT] queries +* {update}[UPDATE] queries +* {delete}[DELETE] queries +* {merge}[MERGE] queries + +The index advisor can recommend regular secondary indexes, partial indexes, and array indexes for the following predicates and conditions: + +* Predicates in the WHERE clause +* Join conditions in the ON clause for INDEX JOIN, ANSI JOIN, ANSI NEST, INDEX NEST, and ANSI MERGE operations +* Predicates of elements in an UNNEST array +* Predicates with the ANY expression +* Predicates of subqueries in the FROM clause + +The index advisor also suggests covering indexes and covering array indexes for queries in a single keyspace, including JOIN operations, ANY expressions, and UNNEST predicates. + +The index advisor checks the indexes currently used by the query. +If the query is already using the recommended indexes, the index advisor informs you, and does not recommend an index unnecessarily. +Similarly, if the query is already using the optimal covering index, the index advisor informs you, and does not recommend a covering index. + +== Prerequisites + +To execute the ADVISE statement, you must have the privileges required for the {sqlpp} statement for which you want advice. +For more details about user roles, see xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=advise] +---- + +image::n1ql-language-reference/advise.png["Syntax diagram: refer to source code listing", align=left] + +The statement consists of the `ADVISE` keyword, and optionally the `INDEX` keyword, followed by the query for which you want index advice -- a {select}[SELECT] query, an {update}[UPDATE] query, a {delete}[DELETE] query, or a {merge}[MERGE] query. + +== Usage + +include::partial$n1ql-language-reference/advice-workbench.adoc[] + +== Return Value + +The ADVISE statement returns an object with the following properties. + +[options="header", cols="3a,11a,4a"] +|=== +|Name|Description|Schema + +|**#operator** + +__required__ +|The name of the operator -- in this case, `Advise`. +|string + +|**advice** + +__required__ +|An object giving advice returned by the operator. +|<> + +|**query** + +__required__ +|The {sqlpp} query used to generate the advice. +|string +|=== + +[[advice]] +**Advice** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**#operator** + +__required__ +|The name of the operator -- in this case, `IndexAdvice`. +|string + +|**adviseinfo** + +__required__ +|An object giving index information. +|<> +|=== + +[[information]] +**Information** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**current_indexes** + +__required__ +|An array of Index objects, each giving information about one of the indexes (primary or secondary) that is currently used by the query. +|< <> > array + +|**recommended_indexes** + +__required__ +|If the index advisor recommends any indexes, this is an object giving information about the recommended indexes. + +If the index advisor cannot recommend any indexes, this is a string stating that there are no recommended indexes at this time. +|<> +|=== + +[[recommended_indexes]] +**Recommended Indexes** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**covering_indexes** + +__optional__ +|If there are any recommended covering indexes, this is an array of Index objects, each giving information about one of the recommended covering indexes. + +If there are no recommended covering indexes, this field does not appear. +|< <> > array + +|**indexes** + +__required__ +|An array of Index objects, each giving information about one of the recommended secondary indexes. +|< <> > array +|=== + +[[indexes]] +**Indexes** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**index_statement** + +__required__ +|The {sqlpp} command used to define the index. +|string + +|**keyspace_alias** + +__required__ +|The keyspace to which the index belongs. +If the query specifies an alias for this keyspace, the alias is appended to the keyspace name, joined by an underscore. +This may help to distinguish the indexes for either side of a JOIN operation. +|string + +|**index_property** + +__optional__ +|The <> supported by the index. + +This field is only returned for covering indexes. +If no index pushdowns are supported by the covering index, this field does not appear. +|string + +|**index_status** + +__optional__ +|Information on the status of the index, stating whether the index is identical to the recommended index, or whether the index is an optimal covering index. + +This field is only returned for current indexes. +If the index is not identical to the recommended index, or if it is not an optimal covering index, this field does not appear. +|string + +|**recommending_rule** + +__optional__ +|The <> used to generate the recommendation. + +This field is only returned for recommended indexes, or for current indexes if they are identical to the recommended index. +|string + +|**update_statistics** + +__optional__ +|The {sqlpp} command recommended for updating statistics on the index, for use by the cost-based optimizer. + +This field is only returned for indexes which are recommended by the cost-based optimizer, and only if optimizer statistics are missing for the index. +|string +|=== + +[[recommendation-rules]] +=== Recommendation Rules + +The index advisor recommends secondary indexes based on the query predicate. + +In Couchbase Capella, the index advisor initially makes use of the {cbo}[cost-based optimizer]. +To do this, the cost-based optimizer must be enabled, and statistics for the keyspace must already exist. +If these prerequisites are met, the cost-based optimizer analyzes the query predicate and attempts to recommend an index. + +If the cost-based optimizer cannot recommend an index, the index advisor falls back on a rules-based approach. +The rules are listed below in priority order. +Within each recommended index, if there is more than one index key, they are sorted according to the priority order of these rules. + +[options="header", cols="30a,35a,35a"] +|=== +|Rule +|Description +|Recommendation + +|[start=1] +. Leading array index for UNNEST +|The query uses a predicate which applies to individual elements in an unnested array. + +.Example +---- +UNNEST schedule AS x +WHERE x.day = 1 +---- +|An {array-index}[array index], where the leading index key is an array expression indexing all elements in the unnested array. + +|[#rule-2,reftext="Rule 2",start=2] +. Equality / NULL / MISSING +|The query has a predicate with an {comparisonops}[equality], {comparisonops}[IS NULL], or {comparisonops}[IS MISSING] expression. + +.Examples +---- +WHERE ANY v IN schedule +SATISFIES v.utc = "19:00" END + +WHERE LOWER(name) = "john" + +WHERE id = 10 +---- +|If the predicate contains an {collection-op-any}[ANY] expression: an {array-index}[array index], where the index key is an array expression recursively indexing all elements referenced by the predicate expression. + +If the predicate contains an indexable function: a {functional-index}[functional index], where the index key contains the function referenced by the predicate expression. + +Otherwise: a {secondary-index}[secondary index], where one index key is the field referenced by the predicate expression. + +|[start=3] +. IN predicates +|The query has a predicate with an {collection-op-in}[IN] expression. + +.Examples +---- +WHERE ANY v IN schedule +SATISFIES v.utc +IN ["19:00", "20:00"] END + +WHERE LOWER(name) +IN ["jo", "john"] + +WHERE id IN [10, 20] +---- +|Refer to <>. + +|[start=4] +. Not less than / between / not greater than +|The query has a predicate with a {comparisonops}[+<=+], {comparisonops}[BETWEEN], or {comparisonops}[+>=+] expression. + +.Examples +---- +WHERE ANY v IN schedule +SATISFIES v.utc BETWEEN +"19:00" AND "20:00" END + +WHERE LOWER(name) +BETWEEN "jo" AND "john" + +WHERE id BETWEEN 10 AND 25 +---- +|Refer to <>. + +|[start=5] +. Less than / greater than +|The query has a predicate with a {comparisonops}[<] or {comparisonops}[>] expression. + +.Examples +---- +WHERE ANY v IN schedule +SATISFIES v.utc > "19:00" END + +WHERE LOWER(name) > "jo" + +WHERE id > 10 AND id < 25 +---- +|Refer to <>. + +|[start=6] +. Derived join filter as leading key +|The query has a {join}[join] using an ON clause which filters on the left-hand side keyspace. + +.Example +---- +FROM route r JOIN airline a +ON r.airlineid = META(a).id +---- +|A {secondary-index}[secondary index], where the leading index key is the field from the left-hand side keyspace in the ON clause. + +|[start=7] +. IS NOT NULL / MISSING / VALUED predicates +|The query has a predicate with {comparisonops}[IS NOT NULL], {comparisonops}[IS NOT MISSING], or {comparisonops}[IS NOT VALUED]. + +.Examples +---- +WHERE ANY v IN schedule +SATISFIES v.utc IS NOT NULL +END + +WHERE LOWER(name) IS NOT NULL + +WHERE id IS NOT NULL +---- +|Refer to <>. + +|[start=8] +. LIKE predicates +|The query has a predicate with a {comparisonops}[LIKE] expression, where there is a `%` wildcard at the start of the match string. + +.Example +---- +WHERE name LIKE "%base" +---- +|A {secondary-index}[secondary index], where one index key is the field referenced by the predicate expression. + +|[start=9] +. Non-static join predicate +|The query has a {join}[join] using an ON clause in which neither the left-hand side source object nor the right-hand side source object is static. + +.Example +---- +FROM route r JOIN airline a +ON r.airline = a.iata +---- +|A {secondary-index}[secondary index], where one index key is the field from the right-hand side keyspace in the ON clause. + +|[start=10] +. Flavor for partial index +|The query includes filters on a particular {schema-output}[flavor] of document. + +.Example +---- +WHERE type = "hotel" +---- +|A {partial-index}[partial index] for that flavor of document. +|=== + +[[pushdown-properties]] +=== Pushdown Properties + +The index advisor optimizes any covering indexes that it recommends, in order to support the following pushdowns: + +* LIMIT pushdown +* OFFSET pushdown +* ORDER pushdown +* Partial GROUP BY and aggregates pushdown +* Full GROUP BY and aggregates pushdown + +The GROUP BY and aggregate pushdowns support aggregation using the {min}[MIN()], {max}[MAX()], {sum}[SUM()], {countn}[COUNTN()], and {avg}[AVG()] functions, with the {aggregate-quantifier}[DISTINCT] aggregate quantifier if necessary. + +The GROUP BY and aggregate pushdowns may be _full_ or _partial_. +Full pushdown means the indexer handles the group aggregation fully, and the query engine can skip the entire operator. +Partial pushdown means the indexer sends part of the group aggregation to the query, and the query engine merges the intermediate groups to create the final group and aggregation. + +=== Index Names + +The index advisor suggests a name for each index it recommends, starting with `adv_`, followed by the `DISTINCT` or `ALL` keyword for array indexes if applicable, and including the names of the fields referenced in the index definition, separated by underscores -- for example, `adv_city_type_name`. +Some field names may be truncated if they are too long. + +NOTE: The names that the index advisor suggests are not guaranteed to be unique. +You should check the suggested index names and change any that are duplicates. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Recommended index only +==== +Assume that the cost-based optimizer is enabled, and that statistics exist for the keyspace. + +[source,sqlpp] +---- +include::example$utility/advise-cbo.n1ql[] +---- + +.Result +[source,json] +---- +include::example$utility/advise-cbo.jsonc[] +---- + +<.> Index is recommended by the cost-based optimizer +<.> Recommended command for updating statistics +==== + +.Recommended index and covering index +==== +[source,sqlpp] +---- +include::example$utility/advise-indexes.n1ql[] +---- + +.Result +[source,json] +---- +include::example$utility/advise-indexes.jsonc[] +---- +==== + +.Current index is identical to the recommended index +==== +[source,sqlpp] +---- +include::example$utility/advise-identical.n1ql[] +---- + +.Result +[source,json] +---- +include::example$utility/advise-identical.jsonc[] +---- +==== + +.Current index is an optimal covering index +==== +[source,sqlpp] +---- +include::example$utility/advise-optimal.n1ql[] +---- + +.Result +[source,json] +---- +include::example$utility/advise-optimal.jsonc[] +---- +==== + +.No index can be recommended +==== +[source,sqlpp] +---- +include::example$utility/advise-none.n1ql[] +---- + +.Result +[source,json] +---- +include::example$utility/advise-none.jsonc[] +---- +==== + +== Related Links + +* The xref:clusters:query-service/query-workbench.adoc#index-advisor[Index Advisor] in the Query tab +* The xref:n1ql-language-reference/advisor.adoc[ADVISOR] function +* Blog post: https://blog.couchbase.com/?p=7370&preview=true[Index Advisor for N1QL Query Statement^] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/advisor.adoc b/modules/n1ql/pages/n1ql-language-reference/advisor.adoc new file mode 100644 index 000000000..816837a54 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/advisor.adoc @@ -0,0 +1,579 @@ += ADVISOR Function +:description: The ADVISOR function provides index recommendations to optimize query response time. +:page-topic-type: reference +:example-caption!: +:imagesdir: ../../assets/images + +:n1ql: xref:n1ql-language-reference +:select: {n1ql}/selectintro.adoc +:update: {n1ql}/update.adoc +:delete: {n1ql}/delete.adoc +:merge: {n1ql}/merge.adoc +:advise: {n1ql}/advise.adoc +:rules: {n1ql}/advise.adoc#recommendation-rules + +:monitor: xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc +:sys-completed-req: {monitor}#sys-completed-req +:sys-tasks-cache: {monitor}#sys-tasks-cache + +:index-advisor: xref:clusters:query-service/query-workbench.adoc#index-advisor +:completed-limit: xref:n1ql:n1ql-manage/query-settings.adoc#completed-limit + +{description} +There are two main scenarios for using this function. +One is to invoke the index advisor _immediately_ for a given query or set of queries; the other is to start a session in which every query of interest is collected for a set time period, then invoke the index advisor _asynchronously_ for that collection of queries when the session ends. +Within these two scenarios, this function has several different usages. +The operation and output of each usage depends on the function's single argument. +For clarity, each usage is listed separately on this page. + +[[advisor-string]] +== ADVISOR(`string`) + +=== Description + +When used with a string argument, the function invokes the index advisor for a single {sqlpp} query. +The index advisor works with {select}[SELECT], {update}[UPDATE], {delete}[DELETE], or {merge}[MERGE] queries. + +=== Arguments + +string:: +A string, or an expression which resolves to a string, containing a single {sqlpp} query. + +=== Return Value + +Returns an index advisor results object with the following properties. + +[[results]] +**Results** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**current_used_indexes** + +__optional__ +|If the query engine can select any current primary or secondary indexes to use with an input query, this is an array of Index objects, each giving information about one of the current indexes. + +If the query engine cannot select a current index to use with an input query, this field does not appear. +|< <> > array + +|**recommended_covering_indexes** + +__optional__ +|If the index advisor recommends any indexes, this is an array of Index objects, each giving information about one of the recommended indexes. + +If the index advisor cannot recommend any covering indexes, this field does not appear. +|< <> > array + +|**recommended_indexes** + +__optional__ +|If the index advisor recommends any indexes, this is an array of Index objects, each giving information about one of the recommended indexes. + +If the index advisor cannot recommend any indexes, this field does not appear. +|< <> > array +|=== + +[[indexes]] +**Indexes** + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**index** + +__required__ +|The {sqlpp} command used to define the index. +|string + +|**statements** + +__required__ +|An array of Statement objects, each giving information about one of the {sqlpp} input queries associated with this index. +|< <> > array +|=== + +[[statements]] +**Statements** + +[options="header", cols="3a,11a,4a"] +|=== +|Name|Description|Schema + +|**run_count** + +__required__ +|When the function is used with a single {sqlpp} input query, this is always 1. + +When the function is used with an array of queries, or a collection of queries from a session, this is the number of times that this {sqlpp} input query occurs in the input array or session. +|integer + +|**statement** + +__required__ +|The {sqlpp} input query. +|string +|=== + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +.Get index advice for a single query +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-single.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-single.jsonc[] +---- + +Only one statement occurs in these results, because the function was called with a single query input. +In this case, the index advisor identifies one index which is currently used by the query, and recommends one secondary index. +No covering indexes are recommended. +==== + +[[advisor-array]] +== ADVISOR(`array`) + +=== Description + +When used with an array argument, the function invokes the index advisor for multiple {sqlpp} queries. +The index advisor works with {select}[SELECT], {update}[UPDATE], {delete}[DELETE], or {merge}[MERGE] queries. + +=== Arguments + +array:: +An array of strings, or an expression which resolves to an array of strings, each of which contains a {sqlpp} query. + +=== Return Value + +Returns an <> object. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Get index advice for multiple queries +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-multiple.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-multiple.jsonc[] +---- + +In this case, the index advisor recommends an index which would be suitable for both of the input queries. +==== + +.Get index advice for recent completed requests +==== +This example uses a subquery to get an array of statements from the {sys-completed-req}[system:completed_requests] catalog. + +.Query +[source,sqlpp] +---- +include::example$functions/advisor-recent.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-recent.jsonc[tags=current;recommended;ellipsis] +---- + +In this case, the index advisor recommends several covering indexes and secondary indexes, each of which would be suitable for multiple recent queries. +(Results are truncated for brevity.) +==== + +[[advisor-session-start]] +== ADVISOR(`start_obj`) + +=== Description + +When used with a `start_obj` object argument, the function can be used to start an index advisor session. +As long as the session is running, any queries that meet the criteria you specify are collected for later analysis. + +By default, the session continues running for the duration you specify when you start the session. +At the end of the duration, the index advisor analyzes any queries that have been collected by this session. +The session and any resulting index advice are retained in the _tasks cache_. +You can then <> for this session to see the index advice. + +=== Arguments + +start_obj:: +An object with the following properties: + +action;; +[Required] The string `start`. + +profile;; +[Optional] A string specifying the user profile whose queries you want to collect. +If omitted, all queries are collected. + +response;; +[Optional] A string representing a duration. +All completed queries lasting longer than this threshold are collected for analysis by the index advisor. +Valid time units are `ns` (nanoseconds), `us` (microseconds), `ms` (milliseconds), `s` (seconds), `m` (minutes), or `h` (hours). +If omitted, the default setting is `0s`. + +duration;; +[Required] A string representing a duration. +The index advisor session runs for the length of this duration. +Valid time units are `ns` (nanoseconds), `us` (microseconds), `ms` (milliseconds), `s` (seconds), `m` (minutes), or `h` (hours). + +query_count;; +[Optional] An integer specifying the maximum number of queries to be collected for analysis by the index advisor. +If omitted, the default setting is the same as the service-level {completed-limit}[completed-limit] setting. +You can change the service-level `completed-limit` setting to change the default for this property. + +=== Return Value + +Returns an object with the following property: + +[options="header", cols="3a,11a,4a"] +|=== +|Name|Description|Schema + +|**session** + +__required__ +|The name of the index advisor session. +You will need to refer to this name to <> for this session, or to <>, <>, or <> this session. +|string (UUID) +|=== + +=== Example + +.Start an index advisor session +==== +The following example starts an index advisor session to run for one hour. +All completed queries taking longer than 0 seconds will be collected. + +.Query +[source,sqlpp] +---- +include::example$functions/advisor-start.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-start.jsonc[] +---- +==== + +[[advisor-session-list]] +== ADVISOR(`list_obj`) + +=== Description + +When used with a `list_obj` object argument, the function can be used to list index advisor sessions. +Each index advisor session is stored as a scheduled task in the {sys-tasks-cache}[system:tasks_cache] catalog. + +=== Arguments + +list_obj:: +An object with the following properties: + +action;; +[Required] The string `list`. + +status;; +[Optional] A string specifying the status of the index advisor sessions to list. +This must be one of the following: ++ +-- +* `completed` -- only list completed sessions +* `active` -- only list active sessions +* `all` -- list all sessions +-- ++ +If omitted, the default is `all`. + +=== Return Value + +Returns an array of tasks cache objects, each of which has the following properties. + +[[tasks-cache]] +**Tasks Cache** + +[options="header", cols="3a,11a,4a"] +|=== +|Name|Description|Schema + +|**tasks_cache** + +__required__ +|A nested object that gives information about an index advisor session. +|<> +|=== + +[[session]] +**Session** + +[options="header", cols="3a,11a,4a"] +|=== +|Name|Description|Schema + +|**class** + +__required__ +|The class of the session; in this case, `advisor`. +|string + +|**delay** + +__required__ +|The scheduled duration of the session. +|string (duration) + +|**id** + +__required__ +|The internal ID of the session. +|string (UUID) + +|**name** + +__required__ +|The name of the session. +You will need to refer to this name to <> for this session, or to <>, <>, or <> this session. +|string (UUID) + +|**node** + +__required__ +|The node where the session was started. +|string (address) + +|**state** + +__required__ +|The state of the session: + +* `scheduled` -- the session is active. +* `cancelled` -- the session was stopped. +* `completed` -- the session is completed. +|enum (cancelled, completed, scheduled) + +|**subClass** + +__required__ +|The subclass of the session; in this case, `analyze`. +|string + +|**submitTime** + +__required__ +|The date and time when the function was called to start the session. +|string (date-time) + +|**startTime** + +__optional__ +|The date and time when the session started. + +If the session is still active, this field is not present. +|string (date-time) + +|**stopTime** + +__optional__ +|The date and time when the session stopped. + +If the session is still active, this field is not present. +|string (date-time) + +|**results** + +__optional__ +|An array containing a single <> object. + +If the session is still active, this field is not present. +|< <> > array +|=== + +Returns an empty array if there are no index advisor sessions in the tasks cache. + +=== Example + +.List all index advisor sessions +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-list.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-list.jsonc[tags=completed;cancelled;ellipsis] +---- + +(Results are truncated for brevity.) +==== + +[[advisor-session-stop]] +== ADVISOR(`stop_obj`) + +=== Description + +When used with a `stop_obj` object argument, the function can be used to stop an index advisor session. +In this case, the session is stopped, and the index advisor analyzes any queries that have been collected by this session so far. +The session and any resulting index advice are retained in the tasks cache. +You can then <> for this session to see the index advice. + +=== Arguments + +stop_obj:: +An object with the following properties: + +action;; +[Required] The string `stop`. + +session;; +[Required] A string specifying the name of a session. + +=== Return Value + +Returns an empty array. + +=== Example + +.Stop an index advisor session +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-stop.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-stop.jsonc[] +---- +==== + +[[advisor-session-abort]] +== ADVISOR(`abort_obj`) + +=== Description + +When used with an `abort_obj` object argument, the function can be used to abort an index advisor session. +In this case, the session is stopped, and the session is removed from the tasks cache. + +=== Arguments + +abort_obj:: +An object with the following properties: + +action;; +[Required] The string `abort`. + +session;; +[Required] A string specifying the name of a session. + +=== Return Value + +Returns an empty array. + +=== Example + +.Abort an index advisor session +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-abort.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-abort.jsonc[] +---- +==== + +[[advisor-session-get]] +== ADVISOR(`get_obj`) + +=== Description + +When used with a `get_obj` object argument, the function can be used to get the results of a completed index advisor session. +The index advisor is invoked for any collected {select}[SELECT], {update}[UPDATE], {delete}[DELETE], or {merge}[MERGE] queries. + +=== Arguments + +get_obj:: +An object with the following properties: + +action;; +[Required] The string `get`. + +session;; +[Required] A string specifying the name of a session. + +=== Return Value + +Returns an array containing an array, which in turn contains an <> object. + +Returns an empty array if the specified session collected no queries, or if the specified session does not exist. + +=== Example + +.Get index advice for an index advisor session +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-get.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-get.jsonc[tags=current;covering;recommended;ellipsis] +---- + +(Results are truncated for brevity.) +==== + +[[advisor-session-purge]] +== ADVISOR(`purge_obj`) + +=== Description + +When used with a `purge_obj` object argument, the function can be used to purge the results of a completed index advisor session from the tasks cache. + +=== Arguments + +purge_obj:: +An object with the following properties: + +action;; +[Required] The string `purge`. + +session;; +[Required] A string specifying the name of a session. + +=== Return Value + +Returns an empty array. + +=== Example + +.Purge an index advisor session +==== +.Query +[source,sqlpp] +---- +include::example$functions/advisor-purge.n1ql[] +---- + +.Result +[source,json] +---- +include::example$functions/advisor-purge.jsonc[] +---- +==== + +== Related Links + +* The {advise}[ADVISE] statement -- also describes the index advisor {rules}[recommendation rules] +* The {index-advisor}[Index Advisor] in the Query tab +* The {sys-tasks-cache}[system:tasks_cache] catalog \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/aggregatefun.adoc b/modules/n1ql/pages/n1ql-language-reference/aggregatefun.adoc new file mode 100644 index 000000000..a9fc5d3f0 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/aggregatefun.adoc @@ -0,0 +1,1029 @@ += Aggregate Functions +:stem: asciimath +:imagesdir: ../../assets/images +:page-topic-type: reference +:example-caption!: +:description: Aggregate functions take multiple values from documents, perform calculations, and return a single value as the result. +:page-topic-type: reference + +:expression: xref:n1ql-language-reference/index.adoc#N1QL_Expressions +:path: xref:n1ql-language-reference/index.adoc#nested-path-exp +:identifier: xref:n1ql-language-reference/identifiers.adoc +:window: xref:n1ql-language-reference/window.adoc +:window-definition: {window}#window-definition +:groupby: xref:n1ql-language-reference/groupby.adoc +:windowfun: xref:n1ql-language-reference/windowfun.adoc +:additional-storage-use: xref:server:learn:data/transactions.adoc#additional-storage-use + +// Footnotes +:doc-count: When counting all the documents within a collection, this function usually relies on the collection statistics, which include any {additional-storage-use}[transaction records] that may be stored in that collection. \ +However, if the query performs an index scan using the primary index on that collection, counting all documents does not include any transaction records. +ifeval::["{asciidoctor-version}" < "2.0.0"] +:doc-count: When counting all the documents within a collection, this function usually relies on the collection statistics, which include any {additional-storage-use}[transaction records\] that may be stored in that collection. \ +However, if the query performs an index scan using the primary index on that collection, counting all documents does not include any transaction records. +endif::[] + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +{description} +The function names are case insensitive. + +You can only use aggregate functions in `SELECT`, `LETTING`, `HAVING`, and `ORDER BY` clauses. +When using an aggregate function in a query, the query operates as an aggregate query. + +In Couchbase Capella, aggregate functions can also be used as {windowfun}[window functions] when they are used with a window specification, which is introduced by the `OVER` keyword. + +include::partial$n1ql-language-reference/window-intro.adoc[tag=syntax] + +== Syntax + +This section describes the generic syntax of aggregate functions. +Refer to sections below for details of individual aggregate functions. + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=aggregate-function] +---- + +image::n1ql-language-reference/aggregate-function.png["Syntax diagram", align=left] + +[horizontal.compact] +aggregate-quantifier:: <> icon:caret-down[] +filter-clause:: <> icon:caret-down[] +over-clause:: <> icon:caret-down[] + +=== Arguments + +Aggregate functions take a single {expression}[expression] as an argument, which is used to compute the aggregate function. +The `COUNT` function can instead take a wildcard ({asterisk}) or a {path}[path] with a wildcard (path.{asterisk}) as its argument. + +[[aggregate-quantifier]] +=== Aggregate Quantifier + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=aggregate-quantifier] +---- + +image::n1ql-language-reference/aggregate-quantifier.png["Syntax diagram", align=left] + +The *aggregate quantifier* determines whether the function aggregates all values in the group, or distinct values only. + +`ALL`:: All objects are included in the computation. +`DISTINCT`:: Only distinct objects are included in the computation. + +This quantifier can only be used with aggregate functions. + +This quantifier is optional. +If omitted, the default value is `ALL`. + +[[filter-clause]] +=== FILTER Clause + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=filter-clause] +---- + +image::n1ql-language-reference/filter-clause.png["Syntax diagram", align=left] + +The FILTER clause enables you to specify which values are included in the aggregate. +This clause is available for aggregate functions, and aggregate functions used as window functions. +(It is not permitted for dedicated window functions.) + +The FILTER clause is useful when a query contains several aggregate functions, each of which requires a different condition. + +cond:: [Required] Conditional expression. +Values for which the condition resolves to TRUE are included in the aggregation. + +The conditional expression is subject to the same rules as the conditional expression in the query WHERE clause, and the same rules as aggregation operands. +It may not contain a subquery, a window function, or an outer reference. + +NOTE: If the query block contains an aggregate function which uses the FILTER clause, the aggregation is not pushed down to the indexer. +Refer to xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc#filter-clause[Grouping and Aggregate Pushdown] for more details. + +[[over-clause]] +=== OVER Clause + +include::partial$n1ql-language-reference/over-clause.adoc[tag=body] + +[[defaults]] +=== Default Values + +If there is no input row for the group, `COUNT` functions return `0`. +All other aggregate functions return NULL. + +[[array_agg,ARRAY_AGG()]] +== [[array_agg_distinct]]ARRAY_AGG( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value +With the `ALL` quantifier, or no quantifier, returns an array of the non-MISSING values in the group, including NULL values. + +With the `DISTINCT` quantifier, returns an array of the distinct non-MISSING values in the group, including NULL values. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +List all values of the `Cleanliness` reviews given: + +.Query +[source,sqlpp] +---- +SELECT ARRAY_AGG(reviews[0].ratings.Cleanliness) AS Reviews +FROM hotel; +---- + +.Results +[source,json] +---- +[ + { + "Reviews": [ + -1, + -1, + -1, + -1, + -1, + // ... + ] + } +] +---- +==== + +==== +List all unique values of the `Cleanliness` reviews given: + +.Query +[source,sqlpp] +---- +SELECT ARRAY_AGG(DISTINCT reviews[0].ratings.Cleanliness) AS Reviews +FROM hotel; +---- + +.Results +[source,json] +---- +[ + { + "UniqueReviews": [ + -1, + 1, + 2, + 3, + 4, + 5 + ] + } +] +---- +==== + +[[avg,AVG()]] +== [[avg_distinct]]AVG( {startsb} ALL | DISTINCT {endsb} `expression`) + +This function has an alias <>. + +=== Return Value +With the `ALL` quantifier, or no quantifier, returns the arithmetic mean (average) of all the number values in the group. + +With the `DISTINCT` quantifier, returns the arithmetic mean (average) of all the distinct number values in the group. + +Returns NULL if there are no number values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the average altitude of airports in the `airport` keyspace: + +.Query +[source,sqlpp] +---- +include::example$functions/avg.n1ql[] +---- + +.Results +[source,json] +---- +include::example$functions/avg.jsonc[] +---- +==== + +==== +Find the average number of stops per route vs. the average of distinct numbers of stops: + +.Query +[source,sqlpp] +---- +include::example$functions/avg-all.n1ql[] +---- + +Results in 0.0002 since nearly all routes have 0 stops. + +[source,sqlpp] +---- +include::example$functions/avg-distinct.n1ql[] +---- + +Results in 0.5 since all routes have only 1 or 0 stops. +==== + +[[count_all,COUNT(*)]] +== COUNT(*) + +=== Return Value +Returns count of all the input rows for the group, regardless of value. footnote:count[{doc-count}] + +=== Example +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the number of documents in the `landmark` keyspace: + +.Query +[source,sqlpp] +---- +SELECT COUNT(*) AS CountAll FROM landmark; +---- + +.Results +[source,json] +---- +[ + { + "CountAll": 4495 + } +] +---- +==== + +[[count,COUNT()]] +== [[count_distinct]]COUNT( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value +With the `ALL` quantifier, or no quantifier, returns count of all the non-NULL and non-MISSING values in the group. footnote:count[] + +With the `DISTINCT` quantifier, returns count of all the distinct non-NULL and non-MISSING values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the number of documents with an airline route stop in the `route` keyspace regardless of its value: + +.Query +[source,sqlpp] +---- +SELECT COUNT(stops) AS CountOfStops FROM route; +---- + +.Results +[source,json] +---- +[ + { + "CountOfStops": 24024 + } +] +---- +==== + +==== +Find the number of unique values of airline route stops in the `route` keyspace: + +.Query +[source,sqlpp] +---- +SELECT COUNT(DISTINCT stops) AS CountOfDistinctStops +FROM route; +---- + +.Results +[source,json] +---- +[ + { + "CountOfSDistinctStops": 2 <1> + } +] +---- + +<1> Results in 2 because there are only 0 or 1 stops. +==== + +[[countn,COUNTN()]] +== COUNTN( {startsb} ALL {vbar} DISTINCT {endsb} `expression` ) + +=== Return Value +With the `ALL` quantifier, or no quantifier, returns a count of all the numeric values in the group. footnote:count[] + +With the `DISTINCT` quantifier, returns a count of all the distinct numeric values in the group. + +=== Examples +==== +The count of numeric values in a mixed group. + +[source,sqlpp] +---- +SELECT COUNTN(list.val) AS CountOfNumbers +FROM [ + {"val":1}, + {"val":1}, + {"val":2}, + {"val":"abc"} +] AS list; +---- + +.Results +[source,json] +---- +[ + { + "CountOfNumbers": 3 + } +] +---- +==== + +==== +The count of unique numeric values in a mixed group. + +[source,sqlpp] +---- +SELECT COUNTN(DISTINCT list.val) AS CountOfNumbers +FROM [ + {"val":1}, + {"val":1}, + {"val":2}, + {"val":"abc"} +] AS list; +---- + +.Results +[source,json] +---- +[ + { + "CountOfNumbers": 2 + } +] +---- +==== + +[[max,MAX()]] +== MAX( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +Returns the maximum non-NULL, non-MISSING value in the group in {sqlpp} collation order. + +This function returns the same result with the `ALL` quantifier, the `DISTINCT` quantifier, or no quantifier. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +.Max of an integer field +==== +Find the northernmost latitude of any hotel in the `hotel` keyspace: + +.Query +[source,sqlpp] +---- +SELECT MAX(geo.lat) AS MaxLatitude FROM hotel; +---- + +.Results +[source,json] +---- +[ + { + "MaxLatitude": 60.15356 + } +] +---- +==== + +.Max of a string field +==== +Find the hotel whose name is last alphabetically in the `hotel` keyspace: + +.Query +[source,sqlpp] +---- +SELECT MAX(name) AS MaxName FROM hotel; +---- + +.Results +[source,json] +---- +[ + { + "MaxName": "pentahotel Birmingham" + } +] +---- +==== + +That result might have been surprising since lowercase letters come after uppercase letters and are therefore "higher" than uppercase letters. +To avoid this uppercase/lowercase confusion, you should first make all values uppercase or lowercase, as in the following example. + +.Max of a string field, regardless of case +==== +Find the hotel whose name is last alphabetically in the `hotel` keyspace: + +.Query +[source,sqlpp] +---- +SELECT MAX(UPPER(name)) AS MaxName FROM hotel; +---- + +.Results +[source,json] +---- +[ + { + "MaxName": "YOSEMITE LODGE AT THE FALLS" + } +] +---- +==== + +[[mean,MEAN()]] +== [[mean_distinct]]MEAN( {startsb} ALL | DISTINCT {endsb} `expression`) + +Alias for <>. + +[[median,MEDIAN()]] +== [[median_distinct]]MEDIAN( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +With the `ALL` quantifier, or no quantifier, returns the median of all the number values in the group. +If there is an even number of number values, returns the mean of the median two values. + +With the `DISTINCT` quantifier, returns the median of all the distinct number values in the group. +If there is an even number of distinct number values, returns the mean of the median two values. + +Returns NULL if there are no number values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the median altitude of airports in the `airport` keyspace: + +.Query +[source,sqlpp] +---- +SELECT MEDIAN(geo.alt) AS MedianAltitude +FROM airport; +---- + +.Results +[source,json] +---- +[ + { + "MedianAltitude": 361.5 + } +] +---- +==== + +==== +Find the median of distinct altitudes of airports in the `airport` keyspace: + +.Query +[source,sqlpp] +---- +SELECT MEDIAN(DISTINCT geo.alt) AS MedianAltitude FROM airport; +---- + +.Results +[source,json] +---- +[ + { + "MedianDistinctAltitude": 758 + } +] +---- +==== + +[[min,MIN()]] +== MIN( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +Returns the minimum non-NULL, non-MISSING value in the group in {sqlpp} collation order. + +This function returns the same result with the `ALL` quantifier, the `DISTINCT` quantifier, or no quantifier. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +.Min of an integer field +==== +Find the southernmost latitude of any hotel in the `hotel` keyspace: + +.Query +[source,sqlpp] +---- +include::example$functions/min-num.n1ql[] +---- + +.Results +[source,json] +---- +include::example$functions/min-num.jsonc[] +---- +==== + +.Min of a string field +==== +Find the hotel whose name is first alphabetically in the `hotel` keyspace: + +.Query +[source,sqlpp] +---- +include::example$functions/min-string.n1ql[] +---- + +.Results +[source,json] +---- +include::example$functions/min-string.jsonc[] +---- +==== + +That result might have been surprising since some symbols come before letters and are therefore "lower" than letters. +To avoid this symbol confusion, you can specify letters only, as in the following example. + +.Min of a string field, regardless of preceding non-letters +==== +Find the first hotel alphabetically in the `hotel` keyspace: + +.Query +[source,sqlpp] +---- +include::example$functions/min-filter.n1ql[] +---- + +.Results +[source,json] +---- +include::example$functions/min-filter.jsonc[] +---- +==== + +[[stddev,STDDEV()]] +== [[stddev_distinct]]STDDEV( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +With the `ALL` quantifier, or no quantifier, returns the <> of all the number values in the group. + +With the `DISTINCT` quantifier, returns the <> of all the distinct number values in the group. + +Returns NULL if there are no number values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the sample standard deviation of all values: + +.Query +[source,sqlpp] +---- +SELECT STDDEV(reviews[0].ratings.Cleanliness) AS StdDev +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "StdDev": 2.0554275433769753 + } +] +---- +==== + +==== +Find the sample standard deviation of a single value: + +.Query +[source,sqlpp] +---- +SELECT STDDEV(reviews[0].ratings.Cleanliness) AS StdDevSingle +FROM hotel +WHERE name="Sachas Hotel"; +---- + +.Results +[source,json] +---- +[ + { + "StdDevSingle": 0 <1> + } +] +---- + +<1> There is only one matching result in the input, so the function returns `0`. +==== + +==== +Find the sample standard deviation of distinct values: + +.Query +[source,sqlpp] +---- +SELECT STDDEV(DISTINCT reviews[0].ratings.Cleanliness) AS StdDev +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "StdDevDistinct": 2.1602468994692865 + } +] +---- +==== + +[[stddev_pop,STDDEV_POP()]] +== [[stddev_pop_distinct]]STDDEV_POP( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +With the `ALL` quantifier, or no quantifier, returns the <> of all the number values in the group. + +With the `DISTINCT` quantifier, returns the <> of all the distinct number values in the group. + +Returns NULL if there are no number values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the population standard deviation of all values: + +.Query +[source,sqlpp] +---- +SELECT STDDEV_POP(reviews[0].ratings.Cleanliness) AS PopStdDev +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "PopStdDev": 2.0390493736539432 + } +] +---- +==== + +==== +Find the population standard deviation of distinct values: + +.Query +[source,sqlpp] +---- +SELECT STDDEV_POP(DISTINCT reviews[0].ratings.Cleanliness) AS PopStdDev +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "PopStdDevDistinct": 1.9720265943665387 + } +] +---- +==== + +[[stddev_samp,STDDEV_SAMP()]] +== [[stddev_samp_distinct]]STDDEV_SAMP( {startsb} ALL | DISTINCT {endsb} `expression`) + +A near-synonym for <>. +The only difference is that `STDDEV_SAMP()` returns NULL if there is only one matching element. + +=== Example +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the sample standard deviation of a single value: + +.Query +[source,sqlpp] +---- +SELECT STDDEV_SAMP(reviews[0].ratings.Cleanliness) AS StdDevSingle +FROM hotel +WHERE name="Sachas Hotel"; +---- + +.Results +[source,json] +---- +[ + { + "StdDevSamp": null <1> + } +] +---- + +<1> There is only one matching result in the input, so the function returns NULL. +==== + +[[sum,SUM()]] +== [[sum_distinct]]SUM( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +With the `ALL` quantifier, or no quantifier, returns the sum of all the number values in the group. + +With the `DISTINCT` quantifier, returns the arithmetic sum of all the distinct number values in the group. + +Returns NULL if there are no number values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the sum total of all airline route stops in the `route` keyspace: + +.Query +[source,sqlpp] +---- +SELECT SUM(stops) AS SumOfStops FROM route; +---- + +NOTE: In the `route` keyspace, nearly all flights are non-stop (0 stops) and only six flights have 1 stop, so we expect 6 flights of 1 stop each, a total of 6. + +.Results +[source,json] +---- +[ + { + "SumOfStops": 6 <1> + } +] +---- + +<1> There are 6 routes with 1 stop each. +==== + +==== +Find the sum total of all unique numbers of airline route stops in the `route` keyspace: + +.Query +[source,sqlpp] +---- +SELECT SUM(DISTINCT stops) AS SumOfStops FROM route; +---- + +.Results +[source,json] +---- +[ + { + "SumOfDistinctStops": 1 <1> + } +] +---- + +<1> There are only 0 and 1 stops per route; and 0 + 1 = 1. +==== + +[[variance,VARIANCE()]] +== [[variance_distinct]]VARIANCE( {startsb} ALL | DISTINCT {endsb} `expression`) + +=== Return Value + +With the `ALL` quantifier, or no quantifier, returns the unbiased sample variance (the square of the <>) of all the number values in the group. + +With the `DISTINCT` quantifier, returns the unbiased sample variance (the square of the <>) of all the distinct number values in the group. + +Returns NULL if there are no number values in the group. + +This function has a near-synonym <>. +The only difference is that `VARIANCE()` returns NULL if there is only one matching element. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the sample variance of all values: + +.Query +[source,sqlpp] +---- +SELECT VARIANCE(reviews[0].ratings.Cleanliness) AS Variance +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "Variance": 4.224782386072708 + } +] +---- +==== + +==== +Find the sample variance of a single value: + +.Query +[source,sqlpp] +---- +SELECT VARIANCE(reviews[0].ratings.Cleanliness) AS VarianceSingle +FROM hotel +WHERE name="Sachas Hotel"; +---- + +.Results +[source,json] +---- +[ + { + "VarianceSingle": 0 <1> + } +] +---- + +<1> There is only one matching result in the input, so the function returns `0`. +==== + +==== +Find the sampling variance of distinct values: + +.Query +[source,sqlpp] +---- +SELECT VARIANCE(DISTINCT reviews[0].ratings.Cleanliness) AS Variance +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "VarianceDistinct": 4.666666666666667 + } +] +---- +==== + +[[variance_pop,VARIANCE_POP()]] +== [[variance_pop_distinct]]VARIANCE_POP( {startsb} ALL | DISTINCT {endsb} `expression`) + +This function has an alias <>. + +=== Return Value + +With the `ALL` quantifier, or no quantifier, returns the population variance (the square of the <>) of all the number values in the group. + +With the `DISTINCT` quantifier, returns the population variance (the square of the <>) of all the distinct number values in the group. + +Returns NULL if there are no number values in the group. + +=== Examples +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the population variance of all values: + +.Query +[source,sqlpp] +---- +SELECT VARIANCE_POP(reviews[0].ratings.Cleanliness) AS PopVariance +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "PopVariance": 4.157722348198537 + } +] +---- +==== + +==== +Find the population variance of distinct values: + +.Query +[source,sqlpp] +---- +SELECT VARIANCE_POP(DISTINCT reviews[0].ratings.Cleanliness) AS PopVarianceDistinct +FROM hotel +WHERE city="London"; +---- + +.Results +[source,json] +---- +[ + { + "PopVarianceDistinct": 3.8888888888888893 + } +] +---- +==== + +[[variance_samp,VARIANCE_SAMP()]] +== [[variance_samp_distinct]]VARIANCE_SAMP( {startsb} ALL | DISTINCT {endsb} `expression`) + +A near-synonym for <>. +The only difference is that `VARIANCE_SAMP()` returns NULL if there is only one matching element. + +This function has an alias <>. + +=== Example +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the sample standard deviation of a single value: + +.Query +[source,sqlpp] +---- +SELECT VARIANCE_SAMP(reviews[0].ratings.Cleanliness) AS VarianceSamp +FROM hotel +WHERE name="Sachas Hotel"; +---- + +.Results +[source,json] +---- +[ + { + "VarianceSamp": null <1> + } +] +---- + +<1> There is only one matching result in the input, so the function returns NULL. +==== + +[[var_pop,VAR_POP()]] +== [[var_pop_distinct]]VAR_POP( {startsb} ALL | DISTINCT {endsb} `expression`) + +Alias for <>. + +[[var_samp,VAR_SAMP()]] +== [[var_samp_distinct]]VAR_SAMP( {startsb} ALL | DISTINCT {endsb} `expression`) + +Alias for <>. + +== Formulas + +[[eqn_samp_std_dev]] +.Corrected Sample Standard Deviation +The corrected sample standard deviation is calculated according to the following formula. + +[stem] +++++ +s = sqrt(1/(n-1) sum_(i=1)^n (x_i - barx)^2) +++++ + +[[eqn_pop_std_dev]] +.Population Standard Deviation +The population standard deviation is calculated according to the following formula. + +[stem] +++++ +sigma = sqrt((sum(x_i - mu)^2)/N)" +++++ + +== Related Links + +* {groupby}[GROUP BY Clause] for GROUP BY, LETTING, and HAVING clauses. +* {window}[WINDOW Clause] for WINDOW clauses. +* {windowfun}[Window Functions] for window functions. diff --git a/modules/n1ql/pages/n1ql-language-reference/alterindex.adoc b/modules/n1ql/pages/n1ql-language-reference/alterindex.adoc new file mode 100644 index 000000000..7166bc8ba --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/alterindex.adoc @@ -0,0 +1,544 @@ += ALTER INDEX +:description: The ALTER INDEX statement moves the placement of an existing index or replica among different GSI nodes. +:imagesdir: ../../assets/images + +:rebalancing-the-index-service: xref:server:learn:clusters-and-availability/rebalance.adoc#rebalancing-the-index-service +:console-indexes: xref:server:manage:manage-ui/manage-ui.adoc#console-indexes +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:querying-indexes: xref:n1ql-intro/sysinfo.adoc#querying-indexes + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +You can use the `ALTER INDEX` statement to change the placement of an existing index or replica among different GSI nodes, to increase or decrease the number of replicas, or to drop a specified index replica temporarily. +You can also use it to perform the same alterations to a partitioned index and any replica partitions. +You may use this statement when you encounter any of the following situations: + +* An imbalance occurs due to a particular index growing faster than expected and is needed on a different node. +* An imbalance occurs due to a cluster of indexes being dropped on a single node. +* A machine is scheduled for removal, so its indexes need to move off its current node. +* The automated process of rebalancing does not give the expected results. +* Other types of scaling up or scaling down are needed. + +For example, if a node fails, you can use the `ALTER INDEX` statement to move an index to another node. +See <> below. + +NOTE: The ALTER INDEX move operation is asynchronous. +As soon as the move alter index command is executed, the command returns. +If there is no error in the input, the move operation can be tracked through the console UI and any error can be found in the Console logs and Indexer logs. + +If a node goes down while an ALTER INDEX operation is in progress, then the index would rollback to its original node (not affecting queries) and a notification would appear. + +IMPORTANT: It is not possible to move an index or index replica and change the number of index replicas at the same time. + +== Prerequisites + +Only users with the RBAC role of `Administrator` are allowed to run the `ALTER INDEX` directive. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=alter-index] +---- + +image::n1ql-language-reference/alter-index.png["Syntax diagram: refer to source code listing", align=left] + +The ALTER INDEX statement provides two possible syntaxes for specifying the index and the keyspace where the index is located. + +// TODO: Automatic links in EBNF. + +[horizontal] +index-name:: (Required) A unique name that identifies the index. + +index-path:: (Optional) One possible syntax for specifying the keyspace. +Refer to <> below. + +keyspace-ref:: (Optional) The other possible syntax for specifying the keyspace. +Refer to <> below. + +index-using:: (Optional) Specifies the index type. +Refer to <> below. + +index-with:: (Required) Specifies options for the index. +Refer to <> below. + +[[index-path]] +=== Index Path + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-path] +---- + +image::n1ql-language-reference/index-path.png["Syntax diagram: refer to source code listing", align=left] + +You can use a dotted notation to specify the index and the keyspace on which the index is built. +This syntax provides compatibility with legacy versions of Couchbase Server. +The index path may be a <>, a <>, or a <>. + +NOTE: If there is a hyphen (-) inside the index name or any part of the index path, you must wrap the index name or that part of the index path in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-full-index,full keyspace path]] +==== Index Path: Full Keyspace + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=keyspace-full] +---- + +image::n1ql-language-reference/keyspace-full.png["Syntax diagram: refer to source code listing", align=left] + +If the index is built on a named collection, the index path may be a full keyspace path, including namespace, bucket, scope, and collection, followed by the index name. +In this case, the {query-context}[query context] is ignored. + +[horizontal] +namespace:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. + +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `default:{backtick}travel-sample{backtick}.inventory.airline.{backtick}idx-name{backtick}` indicates the `idx-name` index on the `airline` collection in the `inventory` scope in the `default:{backtick}travel-sample{backtick}` bucket. +==== + +[[keyspace-prefix-index,keyspace prefix]] +==== Index Path: Keyspace Prefix + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=keyspace-prefix] +---- + +image::n1ql-language-reference/keyspace-prefix.png["Syntax diagram: refer to source code listing", align=left] + +If the index is built on the default collection in the default scope within a bucket, the index path may be just an optional namespace and the bucket name, followed by the index name. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +==== +For example, `default:{backtick}travel-sample{backtick}.def_type` indicates the `def_type` index on the default collection in the default scope in the `default:{backtick}travel-sample{backtick}` bucket. +==== + +[[keyspace-partial-index,keyspace partial]] +==== Index Path: Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the index path may be just the collection name, followed by the index name. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `airline.{backtick}idx-name{backtick}` indicates the `idx-name` index on the `airline` collection, assuming that the query context is set. +==== + +[[keyspace-ref]] +=== Index Name ON Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +You can use the index name with the `ON` keyword and a keyspace reference to specify the keyspace on which the index is built. +The keyspace reference may be a <> or a <>. + +NOTE: If there is a hyphen (-) inside the index name or any part of the keyspace reference, you must wrap the index name or that part of the keyspace reference in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-path,keyspace path]] +==== Keyspace Reference: Keyspace Path + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +If the keyspace is a named collection, or the default collection in the default scope within a bucket, the keyspace reference may be a keyspace path. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. +If omitted, the bucket's default scope is used. + +collection:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. +If omitted, the default collection in the bucket's default scope is used. + +==== +For example, `def_type ON default:{backtick}travel-sample{backtick}` indicates the `def_type` index on the default collection in the default scope in the `default:{backtick}travel-sample{backtick}` bucket. + +Similarly, `{backtick}idx-name{backtick} ON default:{backtick}travel-sample{backtick}.inventory.airline` indicates the `idx-name` index on the `airline` collection in the `inventory` scope in the `default:{backtick}travel-sample{backtick}` bucket. +==== + +[[keyspace-partial,keyspace partial]] +==== Keyspace Reference: Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the keyspace reference may be just the collection name. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `{backtick}idx-name{backtick} ON airline` indicates the `idx-name` index on the `airline` collection, assuming the query context is set. +==== + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +The index type for a secondary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +[[index-with]] +=== WITH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-with] +---- + +image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] + +Use the `WITH` clause to specify additional options. + +[horizontal] +expr:: +An object with the following properties. + +[options="header", cols="1a,4a,1a"] +|=== +|Name|Description|Schema + +|**action** + +__required__ +| A string denoting the operation to be performed. +The possible values are: + +move::: +Moves an index (or its replicas) to a different node while not making any changes to the index topology -- for example, the number of replicas remains the same. +You must use the `nodes` property to specify the target node or nodes. + +replica_count::: +Alters the number of replicas. +You must use the `num_replica` property to specify the required number of replicas. +You can use the `nodes` property to restrict the placement of index replicas to the specified nodes. +The planner decides where to place any new index replicas on the available index nodes, based on the server load. + +drop_replica::: +Drops a specified replica temporarily; for example, to repair a replica. +You must use the `replicaId` property to specify the replica to drop. +| enum (move, replica_count, drop_replica) + +|**num_replica** + +__optional__ +| Required if `action` is set to `replica_count`. + +An integer specifying the number of replicas of the index. +The index service will automatically distribute these indexes amongst the index nodes in the cluster for load balancing and high availability purposes. +The index service attempts to distribute the replicas based on the server groups in use in the cluster where possible. +(You can restrict the number of index nodes available for index and index replica placement using the `nodes` property, described below.) +| Integer + +|**nodes** + +__optional__ +| Required if `action` is set to `move`; + +Optional if `action` is set to `replica_count`. + +An array of strings, specifying a list of nodes. +If `action` is set to `move`, the node list determines the new destination nodes for the index and its replicas. +If `action` is set to `replica_count` and you are increasing the number of replicas, the node list restricts the set of nodes available for placement of the index and its replicas. +However, if `action` is set to `replica_count` and you are decreasing the number of replicas, the `nodes` property is ignored. + +NOTE: You cannot use this property in Couchbase Capella, as it defaults to file-based index rebalancing. +See xref:server:learn:clusters-and-availability/rebalance.adoc#index-rebalance-methods[Index Rebalance Methods]. +| String array + +|**replicaId** + +__optional__ +| Required if `action` is set to `drop_replica`. + +An integer, specifying a replica ID. +| Integer +|=== + +== Usage + +If you attempt to alter an index which is still scheduled for background creation, the request fails. + +`ALTER INDEX` will not work while the cluster is undergoing a rebalance. + +=== Moving an Index or Index Replicas + +When moving an index or index replicas, the number of destination nodes must be the same as the number of nodes on which the index and any replicas are currently placed. +You must specify the full node list, even if only one replica needs to be moved. + +Likewise, when moving a partitioned index, the number of destination nodes must be the same as the number of nodes on which the index partitions and any replicas are currently placed. +You cannot use this statement to repartition an index across a different number of nodes. + +The source and destination node ranges may overlap, for example you may move a partitioned index from `["192.168.0.15:9000", "27.0.0.1:9001"]` to `["192.168.0.15:9000", "127.0.0.1:9002"]`. + +=== Changing the Replica Count + +When changing the number of replicas, the specified number of replicas must be less than the number of index nodes available for placement. +If the specified number of replicas is greater than or equal to the number of index nodes available for placement, then the operation will fail. + +If you specify a node list when changing the number of replicas, the specified nodes must include all of the nodes on which the index or index partitions and any index replicas are currently placed. + +When increasing the number of replicas, whether you specify a node list or not, no single index node will host more than one replica of the same index, or the same partition of the same index. +Replicas are distributed across the available server groups. + +When reducing the number of replicas, the index service will first drop unhealthy replicas, where an unhealthy replica is a replica with missing partitions. +After all unhealthy replicas are dropped, the index service will if necessary drop replicas with the highest replica ID. +An unhealthy replica may not have the highest replica ID, so after an index reduction there may be "gaps" in the sequence of replica IDs -- for example, 1, 2, 4, where replica ID 3 was dropped. + +=== Dropping a Specific Replica + +When dropping a replica, the index topology does not change. +The indexing service remembers the number of partitions and replicas specified for this index. +Given sufficient capacity, the dropped replica is rebuilt after the next rebalance -- although it may be placed on a different index node, depending on the resource usage statistics of the available nodes. + +To find the ID of an index replica and see which node it is placed on, you can use the {console-indexes}[Indexes screen in the Couchbase Web Console] or query the {querying-indexes}[system:indexes] catalog. + +When dropping a replica, it is possible to leave a server group with no replica. +For a partitioned index, run a rebalance to move a replica into the vacant server group. + +== Return Value + +If the `ALTER INDEX` succeeds, then: + +* The query returns an empty array. +* The index progress is visible in the Query tab. +* After the movement is complete, the new indexes begin to service query scans. +* The command line displays the new index nodes. + +If the `ALTER INDEX` fails, then: + +* The original indexes continue to service query scans. +* The UI Log and Query tab have the appropriate error message. +* Some common errors include: ++ +|=== +| Error Message | Possible Cause + +| `GSI index xxxxxxxx not found` +a| +* Mistyped an index name + +| `Missing Node Information For Move Index` +a| +* Mistyped `"node"` instead of `"nodes"` +* Mistyped punctuation or other item + +| `No Index Movement Required for Specified Destination List` +a| +* Entered the current node instead of the target node + +| `syntax error - at \",\"` +a| +* Missed a double-quote mark (`"`) + +| `Unable to find Index service for destination xxx.xxx.xxx.xxx:8091 or destination is not part of the cluster` +a| +* Address doesn't exist or was mistyped +* Node isn't running +* Node not properly added to the cluster + +| `Unsupported action value` +a| +* Mistyped the `"action"` +|=== + +[[examples]] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Move the `def_inventory_airport_faa` index from one node to another +==== +Create a cluster of 3 nodes and then go to menu:Settings[Sample buckets] to install the `travel-sample` bucket. +The indexes are then installed in a round-robin fashion and distributed over the 3 nodes. + +image::alter-index_servers_step1.png["The Indexes tab showing def_inventory_airport_faa on 192.168.10.10"] + +Then move the `def_inventory_airport_faa` index from its original node (192.168.10.*10* in this example) to a new node (192.168.10.*11* in this example). + +[source,sqlpp] +---- +include::example$n1ql-language-reference/alter-idx-move.n1ql[] +---- + +You should see: + +[source,json] +---- +include::example$n1ql-language-reference/alter-idx-move.jsonc[] +---- + +image::alter-index_servers_step2.png["The Indexes tab showing def_inventory_airport_faa on 192.168.10.11"] +==== + +.Create and move an index replica from one node to another +==== +Create an index on node 192.168.10.10 with a replica on node 192.168.10.11, then move its replica from node 192.168.10.*11* to 192.168.10.*12*. + +[source,sqlpp] +---- +CREATE INDEX country_idx ON airport(country, city) + USING GSI + WITH {"nodes": ["192.168.10.10:8091", "192.168.10.11:8091"]}; + +ALTER INDEX country_idx ON airport +WITH {"action": "move", "nodes": ["192.168.10.10:8091", "192.168.10.12:8091"]}; +---- +==== + +.Moving multiple replicas +==== +Create an index on node 192.168.10.10 with replicas on nodes 192.168.10.*11* and 192.168.10.*12*, then move the replicas to nodes 192.168.10.*13* and 192.168.10.*14*. + +[source,sqlpp] +---- +CREATE INDEX country_idx ON airport(country, city) +WITH {"nodes": ["192.168.10.10:8091", "192.168.10.11:8091", "192.168.10.12:8091"]}; + +ALTER INDEX country_idx ON airport +WITH {"action": "move", + "nodes": ["192.168.10.10:8091", "192.168.10.13:8091", "192.168.10.14:8091"]}; +---- +==== + +.Increasing the number of replicas +==== +Create an index on node 192.168.10.10 with replicas on nodes 192.168.10.*11* and 192.168.10.*12*, then increase the number of replicas to 4 and specify that new replicas may be placed on any available index nodes in the cluster. + +[source,sqlpp] +---- +CREATE INDEX country_idx ON airport(country, city) +WITH {"nodes": ["192.168.10.10:8091", "192.168.10.11:8091", "192.168.10.12:8091"]}; + +ALTER INDEX country_idx ON airport +WITH {"action": "replica_count", "num_replica": 4}; +---- +==== + +.Increasing the number of replicas and restricting the nodes +==== +Create an index on node 192.168.10.10 with replicas on nodes 192.168.10.*11* and 192.168.10.*12*, then increase the number of replicas to 4, and specify that replicas may now also be placed on nodes 192.168.10.*13* and 192.168.10.*14*. + +[source,sqlpp] +---- +CREATE INDEX country_idx ON airport(country, city) +WITH {"nodes": ["192.168.10.10:8091", "192.168.10.11:8091", "192.168.10.12:8091"]}; + +ALTER INDEX country_idx ON airport +WITH {"action": "replica_count", + "num_replica": 4, + "nodes": ["192.168.10.10:8091", + "192.168.10.11:8091", + "192.168.10.12:8091", + "192.168.10.13:8091", + "192.168.10.14:8091"]}; +---- +==== + +.Decreasing the number of replicas +==== +Create an index on node 192.168.10.10 with replicas on nodes 192.168.10.*11* and 192.168.10.*12*, then decrease the number of replicas to 1. + +[source,sqlpp] +---- +CREATE INDEX country_idx ON airport(country, city) +WITH {"nodes": ["192.168.10.10:8091", "192.168.10.11:8091", "192.168.10.12:8091"]}; + +ALTER INDEX country_idx ON airport +WITH {"action": "replica_count", "num_replica": 1}; +---- +==== + +.Dropping a specific replica +==== +Create an index with two replicas, and specify that nodes 192.168.10.10, 192.168.10.11, 192.168.10.12, and 192.168.10.13 should be available for index and replica placement. +Then delete replica 2. + +[source,sqlpp] +---- +CREATE INDEX country_idx ON airport(country, city) +USING GSI +WITH {"num_replica": 2, + "nodes": ["192.168.10.10:8091", + "192.168.10.11:8091", + "192.168.10.12:8091", + "192.168.10.13:8091"]}; + +ALTER INDEX country_idx ON airport +WITH {"action": "drop_replica", "replicaId": 2}; +---- +==== + +== Related Links + +Using the ALTER INDEX command to move one index at a time may be cumbersome if there are a lot of indexes to be moved. +The _index redistribution_ setting enables you to specify how Couchbase Capella redistributes indexes automatically on rebalance. +Refer to {rebalancing-the-index-service}[Rebalance] for more information. diff --git a/modules/n1ql/pages/n1ql-language-reference/altersequence.adoc b/modules/n1ql/pages/n1ql-language-reference/altersequence.adoc new file mode 100644 index 000000000..23381eaff --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/altersequence.adoc @@ -0,0 +1,418 @@ += ALTER SEQUENCE +:page-topic-type: reference +:imagesdir: ../../assets/images +:description: The ALTER SEQUENCE statement enables you to alter an existing sequence in a given scope. + +// Cross-references +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +include::./sequenceops.adoc[tags=overview;attributes] + +=== Cache + +Sequences operate most efficiently with an in-memory cache of values. +You can specify the size of this cache when you alter the sequence. +A block of values is reserved by a node, and requests for values are satisfied from this cache. +When exhausted, a new block of values is reserved. +Reserving a cached block offers a performance boost, as it enables the Query service to return values directly from memory. + +Note however that if a Query node shuts down, or if you alter the sequence, the unused values in the cached block are lost: a new block is reserved when you restart the node, or request the next value. +You should choose a cache size with this in mind, along with the expected usage patterns for the sequence. + +=== Storage + +Sequences are stored in the bucket's hidden `_system` scope. +WhWhen you back up a bucket, sequences are included automatically, in accordance with the backup filters. +Similarly, when you restore a bucket, sequences are restored in accordance with the restore command -- if you select to restore specific scopes, the sequences associated with those scopes are restored, and no others. + +== Prerequisites + +.RBAC Privileges +To execute the ALTER SEQUENCE statement, you must have the _Query Manage Sequences_ privilege granted on the scope. +For more details about user roles, see {authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=alter-sequence] +---- + +image::n1ql-language-reference/alter-sequence.png["Syntax diagram: refer to source code listing", align=left] + +The ALTER SEQUENCE statement provides two possible syntaxes for specifying options for a sequence. + +// TODO: Automatic links in EBNF. + +[horizontal] +sequence:: (Required) A name that identifies the sequence within a namespace, bucket, and scope. +See <> below. + +alter-sequence-options:: (Optional) One possible syntax for specifying options for the sequence. +See <> below. + +sequence-with:: (Optional) The other possible syntax for specifying options for the sequence. +See <> below. + +[[sequence]] +=== Sequence Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=sequence] +---- + +image::n1ql-language-reference/sequence.png["Syntax diagram: refer to source code listing", align=left] + +The sequence name specifies the name of the sequence to alter. + +Each sequence is associated with a given namespace, bucket, and scope. +You must specify the namespace, bucket, and scope to refer to the sequence correctly. + +[horizontal] +namespace:: +(Optional) The {logical-hierarchy}[namespace] of the bucket which contains the sequence you want to alter. + +bucket:: +(Optional) The bucket which contains the sequence you want to alter. + +scope:: +(Optional) The scope which contains the sequence you want to alter. + +identifier:: +(Required) The name of the sequence. +The sequence name is case-sensitive. + +Currently, only the `default` namespace is available. +If you omit the namespace, the default namespace in the current session is used. + +If the {query-context}[query context] is set, you can omit the bucket and scope from the statement. +In this case, the bucket and scope for the sequence are taken from the query context. + +The namespace, bucket, scope, and sequence name must follow the rules for {identifiers}[identifiers]. +If the namespace, bucket, scope, or sequence name contain any special characters such as hyphens (-), you must wrap that part of the expression in backticks ({backtick} {backtick}). + +[[alter-sequence-options]] +=== Sequence Options + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=alter-sequence-options] +---- + +image::n1ql-language-reference/alter-sequence-options.png["Syntax diagram: refer to source code listing", align=left] + +You can use the following optional clauses to specify individual attributes for the sequence. +These clauses can occur in any order, but none of them can occur more than once in the statement. + +[horizontal.compact] +restart-with:: <> icon:caret-down[] +increment-by:: <> icon:caret-down[] +maxvalue:: <> icon:caret-down[] +minvalue:: <> icon:caret-down[] +cycle:: <> icon:caret-down[] +cache:: <> icon:caret-down[] + +[[restart-with]] +==== RESTART WITH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=restart-with] +---- + +image::n1ql-language-reference/restart-with.png["Syntax diagram: refer to source code listing", align=left] + +Use the RESTART keyword by itself to restart the sequence from its original starting value. + +Use the RESTART WITH clause to restart the sequence from a new value. + +If this clause is omitted, the sequence does not restart. + +[horizontal#restart-with-args] +integer:: +(Optional) The restart value for the sequence. + +[[increment-by]] +==== INCREMENT BY Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=increment-by] +---- + +image::n1ql-language-reference/increment-by.png["Syntax diagram: refer to source code listing", align=left] + +Use the INCREMENT BY clause to specify the increment value of each step in the sequence. + +If this clause is omitted, the increment value is not altered. + +[horizontal#increment-by-args] +integer:: +(Required) The step size for the sequence. +Use a negative value for a descending sequence. + +[[maxvalue]] +==== MAXVALUE Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=maxvalue] +---- + +image::n1ql-language-reference/maxvalue.png["Syntax diagram: refer to source code listing", align=left] + +Use the MAXVALUE clause to specify the maximum value for the sequence. + +Use NO MAXVALUE to specify that the maximum value is the highest signed 64-bit integer, `2^63^-1`. + +If this clause is omitted, the maximum value is not altered. + +[horizontal#maxvalue-args] +integer:: +(Optional) The maximum value for the sequence. + +[[minvalue]] +==== MINVALUE Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=minvalue] +---- + +image::n1ql-language-reference/minvalue.png["Syntax diagram: refer to source code listing", align=left] + +Use the MINVALUE clause to specify the minimum value for the sequence. + +Use NO MINVALUE to specify that the minimum value is the lowest signed 64-bit integer, `-2^63^`. + +If this clause is omitted, the minimum value is not altered. + +[horizontal#minvalue-args] +integer:: +(Optional) The minimum value for the sequence. + +[[cycle]] +==== CYCLE Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=cycle] +---- + +image::n1ql-language-reference/cycle.png["Syntax diagram: refer to source code listing", align=left] + +Use the CYCLE clause to specify the whether the sequence should loop when it reaches the maximum or minimum value. + +Use NO CYCLE to specify that the sequence should stop when it reaches the maximum or minimum value. + +If this clause is omitted, the sequence behavior is not altered. + +[[cache]] +==== CACHE Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=cache] +---- + +image::n1ql-language-reference/cache.png["Syntax diagram: refer to source code listing", align=left] + +Use the CACHE clause to specify the cache size for the sequence. + +Use NO CACHE to specify a cache size of `1`. + +If this clause is omitted, the cache size is not altered. + +[horizontal#cache-args] +integer:: +(Optional) The cache size for the sequence. +The value must be greater than `0`. + +[[sequence-with]] +=== WITH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-with] +---- + +image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] + +You can use the WITH clause to specify options for the sequence using a JSON object. + +[horizontal#sequence-with-args] +expr:: +(Required) An object with the following properties. + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**restart** + +__optional__ +|The restart value for the sequence. +If unspecified, the sequence does not restart. +|Integer + +|**increment** + +__optional__ +|The step size for the sequence. +Use a negative value for a descending sequence. +|Integer + +|**max** + +__optional__ +|The maximum value for the sequence. +|Integer (int64) + +|**min** + +__optional__ +|The minimum value for the sequence. +|Integer (int64) + +|**cycle** + +__optional__ +|Whether the sequence should continue when it reaches the specified maximum value or minimum value. +|Boolean + +|**cache** + +__optional__ +|The cache size for the sequence. +The value must be greater than `0`. +|Integer +|=== + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-alter-seq1]] +.Restart a sequence +==== +This example assumes that you have created a sequence as follows. + +[source,sqlpp] +---- +CREATE SEQUENCE seq3 IF NOT EXISTS START WITH 5 INCREMENT BY 5 MAXVALUE 1000 MINVALUE 0 CYCLE; +---- + +The following statement restarts the sequence at the original starting value. + +[source,sqlpp] +---- +ALTER SEQUENCE seq3 RESTART; +---- + +The following query tests the sequence. + +[source,sqlpp] +---- +SELECT NEXT VALUE FOR seq3; +---- + +The query returns the specified starting value, 5. + +[source,json] +---- +[ + { + "$1": 5 + } +] +---- +==== + +[[ex-alter-seq2]] +.Restart a sequence from a new starting value +==== +This example assumes that you have created a sequence as follows. + +[source,sqlpp] +---- +CREATE SEQUENCE seq3 IF NOT EXISTS START WITH 5 INCREMENT BY 5 MAXVALUE 1000 MINVALUE 0 CYCLE; +---- + +The following statement restarts the sequence at a new starting value. + +[source,sqlpp] +---- +ALTER SEQUENCE seq3 RESTART WITH 25; +---- + +The following query tests the sequence. + +[source,sqlpp] +---- +SELECT NEXT VALUE FOR seq3; +---- + +The query returns the specified starting value, 25. + +[source,json] +---- +[ + { + "$1": 25 + } +] +---- +==== + +[[ex-alter-seq3]] +.Alter the increment and maximum value of a sequence +==== +This example assumes that you have created a sequence as follows. + +[source,sqlpp] +---- +CREATE SEQUENCE seq3 IF NOT EXISTS START WITH 5 INCREMENT BY 5 MAXVALUE 1000 MINVALUE 0 CYCLE; +---- + +The following statement alters the increment and maximum value of the sequence. + +[source,sqlpp] +---- +ALTER SEQUENCE seq3 INCREMENT BY 1 MAXVALUE 250; +---- +==== + + +[[ex-alter-seq4]] +.Alter the cycling of a sequence +==== +This example assumes that you have created a descending sequence as follows. + +[source,sqlpp] +---- +CREATE SEQUENCE seq4 IF NOT EXISTS WITH {"start": 10, "increment": -1, "min": 0}; +---- + +The following statement specifies that the sequence should count down from 10 again when it reaches 0. + +[source,sqlpp] +---- +ALTER SEQUENCE seq4 WITH {"max": 10, "cycle": true}; +---- + +Note that you must specify the maximum value to be `10`, even though the starting value is already set. +If you didn't do this, the sequence would cycle to the highest possible value, `2^63^-1`. +==== + +== Related Links + +* To create a sequence, see xref:n1ql-language-reference/createsequence.adoc[]. +* To drop a sequence, see xref:n1ql-language-reference/dropsequence.adoc[]. +* To use a sequence in an expression, see xref:n1ql-language-reference/sequenceops.adoc[]. +* To monitor sequences, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-sequences[Monitor Sequences]. diff --git a/modules/n1ql/pages/n1ql-language-reference/arithmetic.adoc b/modules/n1ql/pages/n1ql-language-reference/arithmetic.adoc new file mode 100644 index 000000000..c0427f499 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/arithmetic.adoc @@ -0,0 +1,132 @@ += Arithmetic Operators +:description: Arithmetic operations perform the basic mathematical operations of addition, subtraction, multiplication, division, and modulo within an expression or any numerical value retrieved as part of query clauses. +:imagesdir: ../../assets/images +:page-topic-type: reference + +{description} +Additionally, {sqlpp} provides a negation operation which changes the sign of a value. + +[NOTE] +==== +These arithmetic operators only operate on numbers. +In {sqlpp}, arithmetic operators have their usual meaning. +However, in any of these expressions: + +* If any operand is MISSING, the value of the expression is MISSING. +* If any operand is NULL and no operand is MISSING, the value of the expression is NULL. +* If any operand is not a number, the operator evaluates to NULL. +==== + +== Syntax + +There are six different arithmetic syntaxes: + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=arithmetic-term] +---- + +image::n1ql-language-reference/arithmetic-term.png["Syntax diagram", align=left] + +[cols="1,4"] +|=== +| Operator | Description + +| + +| Add values. + +| - +| Subtract right value from left value. + +| * +| Multiply values. + +| / +| Divide left value by right value. + +| % +| Modulo. +Divide left value by right value and return the remainder. + +NOTE: Modulo is an integer operator and will use only the integer part of each value. + +| -[.var]`value` +| Negate value. +|=== + +== Arguments + +expr1, expr2:: Number or an expression that results in a number value. + +== Return Value + +A number, representing the value of the arithmetic operation. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Select the longest flight and return its two airports and the distance in feet +==== +.Query +[source,sqlpp] +---- +SELECT sourceairport, destinationairport, ROUND(distance) AS DistanceInMiles, + ROUND(distance)*5280 AS DistanceInFeet +FROM route +ORDER BY distance DESC +LIMIT 1; +---- + +.Returns +[source,json] +---- +[ + { + "DistanceInFeet": 72906240, + "DistanceInMiles": 13808, + "destinationairport": "DFW", + "sourceairport": "SYD" + } +] +---- +==== + +.Select the modulo of 5 and 3 and compare to the modulo of 5.4 and 3.4 +==== +.Modulo with integers +[source,sqlpp] +---- +SELECT 5 % 3; +---- + +.Returns +[source,json] +---- +[ + { + "$1": 2 + } +] +---- + +.Modulo with fractions +[source,sqlpp] +---- +SELECT 5.4 % 3.4; +---- + +.Returns +[source,json] +---- +[ + { + "$1": 2 + } +] +---- +==== + +== Related Links + +Refer to xref:n1ql:n1ql-language-reference/comparisonops.adoc[Comparison Operators] for numeric comparisons. diff --git a/modules/n1ql/pages/n1ql-language-reference/arrayfun.adoc b/modules/n1ql/pages/n1ql-language-reference/arrayfun.adoc new file mode 100644 index 000000000..ea211d7ed --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/arrayfun.adoc @@ -0,0 +1,1682 @@ += Array Functions +:description: You can use array functions to evaluate arrays, perform computations on elements in an array, and to return a new array based on a transformation. +:page-topic-type: reference + +[abstract] +{description} + +[[fn-array-agg,ARRAY_AGG()]] +== ARRAY_AGG([.var]`expr`) + +=== Description +This function returns an array of the non-`MISSING` group values in the input [.var]`expr`, including `NULL` values. + +=== Arguments +expr:: [Required] The group of elements you wish to output in an array. + +=== Return Values +An array of non-MISSING values. + +If the input [.var]`expression` is `MISSING` or if one of the elements in the array is `MISSING`, then it returns `MISSING`. + +=== Example +==== +Use `ARRAY_AGG` to group a list of three items into an array. + +[source,sqlpp] +---- +SELECT ARRAY_AGG(["abc",1,NULL]) AS array_aggregate; +---- + +.Results +[source,json] +---- +[ + { + "array_aggregate": [ + [ + "abc", + 1, + null + ] + ] + } +] +---- +==== + +[[fn-array-append,ARRAY_APPEND()]] +== ARRAY_APPEND([.var]`expr`, [.var]`val1`, [.var]`val2`, …) + +=== Description +This function takes an array [.var]`expr` and one or more [.var]`val` arguments to return a new array with the specified [.var]`val` argument(s) appended. + +It requires a minimum of two arguments and returns an error if there are fewer. + +=== Arguments +expr:: [Required] The array to be appended to. + +val1, val2, …:: [At least 1 is required] The text string(s) to be appended. + +=== Return Values +A new array with the specified [.var]`val` argument(s) appended. + +If either of the input argument types are `MISSING`, then it returns `MISSING`. + +If either of the input argument types are `NULL`, then it returns `NULL`. + +If the [.var]`expr` argument is not an array, then it returns `NULL`. + +If the [.var]`expr` is in the `WHERE` clause of a partial index, this function lists the expressions that are implicitly covered. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Use `ARRAY_APPEND` to add a user to the Public Likes array: + +[source,sqlpp] +---- +SELECT ARRAY_APPEND(t.public_likes, "Valerie Smith") AS add_user_likes +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "add_user_likes": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow", + "Valerie Smith" + ] + } +] +---- +==== + +[[fn-array-avg,ARRAY_AVG()]] +== ARRAY_AVG([.var]`expr`) + +=== Description +This function takes an array [.var]`expr` as an argument and returns the arithmetic mean (average) of all the non-`NULL` number values in the array, or `NULL` if there are no such values. + +=== Arguments +expr:: [Required] The array of numbers to be evaluated. + +=== Return Values +A number representing the arithmetic mean (average) of all the non-`NULL` number values in the array [.var]`expression`. + +If there are no number values in array [.var]`expr`, then it returns `NULL`. + +If the input [.var]`expr` is `MISSING`, then it returns `MISSING`. + +If the array size of [.var]`expr` is 0 (no elements), then it returns `NULL`. + +Any non-number elements in the array [.var]`expr` are ignored. + +=== Example +==== +Use `ARRAY_AVG` with a set of numbers. + +[source,sqlpp] +---- +SELECT ARRAY_AVG([0,1,1,2,3,5]) AS array_average; +---- + +.Results +[source,json] +---- +[ + { + "array_average": 2 + } +] +---- +==== + +[[fn-array-binary-search,ARRAY_BINARY_SEARCH()]] +== ARRAY_BINARY_SEARCH([.var]`expr`, [.var]`val`, …) + +=== Description +This function returns the first position of the specified value [.var]`val` within the sorted array [.var]`expr`. + +The array position is zero-based, that is, the first position is 0. + +NOTE: This function uses a binary search algorithm. +If the array is unsorted, the function may not be able to find the value. + +See also <>, <>. + +=== Arguments +expr:: [Required] The array you want to search, sorted in {sqlpp} collation order. + +val:: [Required] The value whose position you want to find. + +=== Return Values +An integer representing the first position of the input [.var]`val`, where the first position is 0. +If the value [.var]`val` occurs more than once within the array [.var]`expr`, only the first position is returned. + +It returns -1 if the input [.var]`val` is not found in the array. + +If one of the arguments is `MISSING`, it returns `MISSING`. + +If the input [.var]`expr` is not an array, it returns `NULL`. + +=== Example + +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find which position "Brian Kilback" is in the sorted `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_BINARY_SEARCH(ARRAY_SORT(t.public_likes), "Brian Kilback") +AS sorted_position +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "sorted_position": 0 + } +] +---- +==== + +[[fn-array-concat,ARRAY_CONCAT()]] +== ARRAY_CONCAT([.var]`expr1`, [.var]`expr2`, …) + +=== Description +This function takes two or more [.var]`expr` arrays and returns a new array after concatenating the input arrays. + +If there are fewer than two arguments, then it returns an error. + +=== Arguments +expression1, expression2, …:: [At least 2 are required] The arrays to be concatenated together. + +=== Return Values +A new array, concatenated from the input arrays. + +If any of the input [.var]`expr` arguments or one of the array elements are `MISSING`, then it returns `MISSING`. + +If any of the input [.var]`expr` arguments is `NULL`, then it returns `NULL`. + +If any of the input [.var]`expr` arguments is not an array, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Use `ARRAY_CONCAT` to add two people to the Public Likes array: + +[source,sqlpp] +---- +SELECT ARRAY_CONCAT(t.public_likes, ["John McHill", "Dave Smith"]) AS add_user_likes +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "add_user_likes": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow", + "John McHill", + "Dave Smith" + ] + } +] +---- +==== + +[[fn-array-contains,ARRAY_CONTAINS()]] +== ARRAY_CONTAINS([.var]`expr`, [.var]`val`) + +=== Description +This functions checks if the array [.var]`expression` contains the specified [.var]`value`. + +=== Arguments +expr:: [Required] The array to be searched. + +val:: [Required] The value that is being searched for. + +=== Return Values +If either of the input argument types are `MISSING`, then it returns `MISSING`. + +If either of the input argument types are `NULL`, then it returns `NULL`. + +If the [.var]`expr` argument is not an array, then it returns `NULL`. + +If the array [.var]`expr` contains [.var]`val`, then it returns `TRUE`; otherwise, it returns `FALSE`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Use `ARRAY_CONTAINS` with a Boolean function: + +[source,sqlpp] +---- +SELECT ARRAY_CONTAINS(t.public_likes, "Vallie Ryan") AS array_contains_value +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "array_contains_value": true + } +] +---- +==== + +[[fn-array-count,ARRAY_COUNT()]] +== ARRAY_COUNT([.var]`expr`) + +=== Description +This function counts all the non-NULL values in the input [.var]`expr` array. + +=== Arguments +expr:: [Required] The array to be searched and evaluate its values. + +=== Return Values +A count of all the non-`NULL` values in the array, or zero if there are no such values. + +If the [.var]`expr` argument is `MISSING`, then it returns `MISSING`. + +If the [.var]`expr` argument is `NULL`, then it returns `NULL`. + +If the [.var]`expr` argument is not an array, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Use `ARRAY_COUNT` to count the total hotel reviews: + +[source,sqlpp] +---- +SELECT ARRAY_COUNT(t.reviews) AS total_reviews +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "total_reviews": 2 + } +] +---- +==== + +[[fn-array-distinct,ARRAY_DISTINCT()]] +== ARRAY_DISTINCT([.var]`expr`) + +=== Description +This function returns a new array with distinct elements of the input array [.var]`expr`. + +=== Arguments +expr:: [Required] The array of items to be evaluated. + +=== Return Values +An array with distinct elements of the input array [.var]`expr`. + +If the input [.var]`expr` is `MISSING`, it returns `MISSING`. + +If the input [.var]`expr` is a non-array value, it returns `NULL`. + +=== Example +==== +Use `ARRAY_DISTINCT` with a group of items. + +[source,sqlpp] +---- +SELECT ARRAY_DISTINCT(["apples","bananas","grapes","oranges","apples","mangoes","bananas"]) +AS distinct_fruits; +---- + +.Results +[source,json] +---- +[ + { + "distinct_fruits": [ + "oranges", + "grapes", + "bananas", + "mangoes", + "apples" + ] + } +] +---- +==== + +[[fn-array-except,ARRAY_EXCEPT()]] +== ARRAY_EXCEPT([.var]`expr1`, [.var]`expr2`) + +=== Description +This function returns all the elements of the first array, except for those which are also included in the second array. + +=== Arguments +expr1:: [Required] The input array, from which specified elements may be excluded. + +expr2:: [Required] The array of elements to be excluded. + +=== Return Value +An array of all the elements in [.var]`expr1`, except for those which also occur in [.var]`expr2`. + +If any of the arguments is `MISSING`, it returns `MISSING`. + +If any of the arguments is a non-array, it returns `NULL`. + +=== Examples +==== +Return an array of even numbers by excluding odd numbers. + +[source,sqlpp] +---- +WITH Numbers AS ([1, 2, 3, 4, 5, 6]), +Odd AS ([1, 3, 5]) +SELECT ARRAY_EXCEPT(Numbers, Odd) AS Even; +---- + +.Results +[source,json] +---- +[ + { + "Even": [ + 2, + 4, + 6 + ] + } +] +---- +==== + +[[fn-array-flatten,ARRAY_FLATTEN()]] +== ARRAY_FLATTEN([.var]`expr`, [.var]`depth`) + +=== Description +This function flattens nested array elements into the top-level array, up to the specified depth. + +=== Arguments +expr:: [Required] The multilevel array to be flattened. + +depth:: [Required] The Integer representing the number of depths to flatten. + +=== Return Value +An array with [.var]`depth` fewer levels than the input array [.var]`expr`. + +If one of the arguments is `MISSING`, it returns `MISSING`. + +If the input [.var]`expr` is a non-array, or if the input [.var]`depth` argument is not an integer, it returns `NULL`. + +=== Examples +==== +Create a 3-level array of numbers to flatten by 1 level. + +[source,sqlpp] +---- +INSERT INTO default (KEY, value) + VALUES ("na", {"a":2, "b":[1,2,[31,32,33],4,[[511, 512], 52]]}); + +SELECT ARRAY_FLATTEN(b,1) AS flatten_by_1 FROM default USE KEYS ["na"]; +---- + +.Results +[source,json] +---- +[ + { + "flatten_by_1": [ + 1, + 2, + 31, + 32, + 33, + 4, + [ + 511, + 512 + ], + 52 + ] + } +] +---- +==== + +==== +Flatten the above example by 2 levels. + +[source,sqlpp] +---- +SELECT ARRAY_FLATTEN(b,2) AS flatten_by_2 FROM default USE KEYS ["na"]; +---- + +.Results +[source,json] +---- +[ + { + "flatten_by_2": [ + 1, + 2, + 31, + 32, + 33, + 4, + 511, + 512, + 52 + ] + } +] +---- +==== + +[[fn-array-ifnull,ARRAY_IFNULL()]] +== ARRAY_IFNULL([.var]`expr`) + +=== Description +This function parses the input array [.var]`expr` and returns the first non-`NULL` value in the array. + +=== Arguments +expr:: [Required] The array of values to be evaluated. + +=== Return Values +The first non-NULL value in the input array. + +If the input [.var]`expr` is MISSING, then it returns `MISSING`. + +If the input [.var]`expr` is a non-array, then it returns `NULL`. + +=== Examples +==== +Find the first non-`NULL` value in an array of items. + +[source,sqlpp] +---- +SELECT ARRAY_IFNULL( ["","apples","","bananas","grapes","oranges"]) AS check_null; +---- + +.Results +[source,json] +---- +[ + { + "check_null": "" + } +] +---- +==== + +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find the first non-`null` hotel reviewers: + +[source,sqlpp] +---- +SELECT ARRAY_IFNULL(t.public_likes) AS if_null +FROM hotel t +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "if_null": "Julius Tromp I" + }, + { + "if_null": null + } +] +---- +==== + +[[fn-array-insert,ARRAY_INSERT()]] +== ARRAY_INSERT([.var]`expr`, [.var]`pos`, [.var]`val1`, [.var]`val2`, …) + +=== Description +This function inserts the specified [.var]`value` or multiple [.var]`value` items into the specified [.var]`position` in the input array [.var]`expression`, and returns the new array. + +=== Arguments +expr:: [Required] The array to insert items into. + +pos:: [Required] The integer specifying the array position from the left of the input array [.var]`expr`, where the 1st position is 0 (zero). + +val1, val2, …:: [At least one is required] The value or multiple value items to insert into the input array expression. + +=== Return Values +An array with the input value or multiple value items inserted into the input array expression at position [.var]`pos`. + +If any of the three arguments are `MISSING`, then it returns `MISSING`. + +If the [.var]`expr` argument is a non-array or if the [.var]`position` argument is not an integer, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Insert "jsmith" into the 2nd position of the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_INSERT(public_likes, 2, "jsmith") AS insert_val +FROM hotel +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "insert_val": [ + "Julius Tromp I", + "Corrine Hilll", + "jsmith", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ] + } +] +---- +==== + +[[fn-array-intersect,ARRAY_INTERSECT()]] +== ARRAY_INTERSECT([.var]`expr1`, [.var]`expr2`, \...) + +=== Description +This function takes two or more arrays and returns the intersection of the input arrays as the result; that is, the array containing values that are present in all of the input arrays. + +=== Arguments +expr1, expr2, …:: [At least 2 are required] The two or more arrays to compare the values of. + +=== Return Values +An array containing the values that are present in all of the input arrays. + +If there are no common elements, then it returns an empty array. + +If any of the input arguments are `MISSING`, then it returns `MISSING`. + +If any of the input arguments are non-array values, then it returns `NULL`. + +=== Examples +==== +Compare three arrays of fruit for common elements. + +[source,sqlpp] +---- +SELECT ARRAY_INTERSECT( ["apples","bananas","grapes","orange"], ["apples","orange"], ["apples","grapes"]) +AS array_intersection; +---- + +.Results +[source,json] +---- +[ + { + "array_intersection": [ + "apples" + ] + } +] +---- +==== + +==== +Compare three arrays of fruit with no common elements. + +[source,sqlpp] +---- +SELECT ARRAY_INTERSECT( ["apples","grapes","oranges"], ["apples"],["oranges"],["bananas", "grapes"]) +AS array_intersection; +---- + +.Results +[source,json] +---- +[ + { + "array_intersection": [] + } +] +---- +==== + +[[fn-array-length,ARRAY_LENGTH()]] +== ARRAY_LENGTH([.var]`expr`) + +_Equivalent_: xref:n1ql-language-reference/metafun.adoc#len[LEN()] + +=== Description +This function returns the number of elements in the input array. + +=== Arguments +expr:: [Required] The array whose elements you want to know the number of. + +=== Return Values +An integer representing the number of elements in the input array. + +If the input argument is MISSING, then it returns `MISSING`. + +If the input argument is a non-array value, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find how many total `public_likes` there are in the `travel-sample` keyspace: + +[source,sqlpp] +---- +SELECT ARRAY_LENGTH(t.public_likes) AS total_likes +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "total_likes": 8 + } +] +---- +==== + +[[fn-array-max,ARRAY_MAX()]] +== ARRAY_MAX([.var]`expr`) + +=== Description +This function returns the largest non-`NULL`, non-`MISSING` array element, in {sqlpp} collation order. + +=== Arguments +expr:: [Required] The array whose elements you want to know the highest value of. + +=== Return Values +The largest non-`NULL`, non-`MISSING` array element, in {sqlpp} collation order. + +If the input [.var]`expr` is `MISSING`, then it returns `MISSING`. + +If the input [.var]`expr` is a non-array value, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find the maximum (last) value of the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_MAX(t.public_likes) AS max_val +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "max_val": "Vallie Ryan" + } +] +---- +==== + +[[fn-array-min,ARRAY_MIN()]] +== ARRAY_MIN([.var]`expr`) + +=== Description +This function returns the smallest non-`NULL`, non-`MISSING` array element, in {sqlpp} collation order. + +=== Arguments +expr:: [Required] The array whose elements you want to know the lowest value of. + +=== Return Values +The smallest non-`NULL`, non-`MISSING` array element, in {sqlpp} collation order. + +If the input [.var]`expr` is `MISSING`, then it returns `MISSING`. + +If the input [.var]`expr` is a non-array value, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find the minimum (first) value of the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_MIN(t.public_likes) AS min_val +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "min_val": "Brian Kilback" + } +] +---- +==== + +[[fn-array-move,ARRAY_MOVE()]] +== ARRAY_MOVE([.var]`expr`, [.var]`val1`, [.var]`val2`) + +=== Description +This function returns a new array containing all the elements of [.var]`expr`, with one element moved to a new position. + +=== Arguments +expr:: [Required] The input array containing an element that you want to move. + +val1:: [Required] An integer specifying the old location of the element to move. + +val2:: [Required] An integer specifying the new location of the element to move. + +If [.var]`val1` or [.var]`val2` are 0 or greater, the position is counted from the left of the input array, where the leftmost position in the array is 0 (zero). +If [.var]`val1` or [.var]`val2` are less than 0, the position is counted from the right of the input array, where the rightmost position in the array is -1. + +=== Return Values +An array with the element at the position specified by [.var]`val1` moved to a new position specified by [.var]`val2`. + +If either of the [.var]`val` arguments is outside the array, the function returns `NULL`. + +If any of the arguments is MISSING, then it returns `MISSING`. + +If the [.var]`expr` argument is a non-array, or if either of the [.var]`val` arguments is not an integer, then it returns `NULL`. + +=== Examples +==== +Move the first element in the array to the second position in the array. + +[source,sqlpp] +---- +WITH Letters AS (["a", "b", "c", "d", "e", "f"]) +SELECT ARRAY_MOVE(Letters, 0, 1) AS Second; +---- + +.Results +[source,json] +---- +[ + { + "Second": [ + "b", + "a", + "c", + "d", + "e", + "f" + ] + } +] +---- +==== + +==== +Move the first element in an array to the penultimate position in the array. + +[source,sqlpp] +---- +WITH Letters AS (["a", "b", "c", "d", "e", "f"]) +SELECT ARRAY_MOVE(Letters, 0, -2) AS Penultimate; +---- + +.Results +[source,json] +---- +[ + { + "Penultimate": [ + "b", + "c", + "d", + "e", + "a", + "f" + ] + } +] +---- +==== + +[[fn-array-position,ARRAY_POSITION()]] +== ARRAY_POSITION([.var]`expr`, [.var]`val`) + +=== Description +This function returns the first position of the specified [.var]`value` within the array [.var]`expression`. + +The array position is zero-based, that is, the first position is 0. + +See also <>. + +=== Arguments +expr:: [Required] The array you want to search. + +val:: [Required] The value whose position you want to know. + +=== Return Values +An integer representing the first position of the input [.var]`val`, where the first position is 0. +If the value [.var]`val` occurs more than once within the array [.var]`expr`, only the first position is returned. + +It returns -1 if the input [.var]`val` does not exist in the array. + +If one of the arguments is `MISSING`, it returns `MISSING`. + +If either of the arguments are non-array values, it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find which position "Brian Kilback" is in the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_POSITION(t.public_likes, "Brian Kilback") AS array_position +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "array_position": 4 + } +] +---- +==== + +[[fn-array-prepend,ARRAY_PREPEND()]] +== ARRAY_PREPEND([.var]`val1`, [.var]`val2`, … , [.var]`expr`) + +=== Description +This function returns the new array after prepending the array [.var]`expr` with the specified [.var]`val` or multiple [.var]`val` arguments. + +It requires a minimum of two arguments. + +=== Arguments +val1, val2, …:: [At least 1 is required] The value or multiple value arguments to prepend to the input [.var]`expr`. + +expression:: [Required] The array you want to have the input [.var]`value` argument(s) prepended to. + +=== Return Values +A new array with the input [.var]`val` argument(s) prepended to the input array [.var]`expr`. + +If one of the arguments is `MISSING`, it returns `MISSING`. + +If the last argument is a non-array, it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Prepend "Dave Smith" to the front of the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_PREPEND("Dave Smith",t.public_likes) AS prepend_val +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "prepend_val": [ + "Dave Smith", + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ] + } +] +---- +==== + +[[fn-array-put,ARRAY_PUT()]] +== ARRAY_PUT([.var]`expr`, [.var]`val1`, [.var]`val2`, …) + +=== Description +This function returns a new array with [.var]`val` or multiple [.var]`val` arguments appended if the [.var]`val` is not already present. +Otherwise, it returns the unmodified input array [.var]`expr`. + +It requires a minimum of two arguments. + +=== Arguments +expr:: [Required] The array you want to append the input [.var]`value` or [.var]`value` arguments. + +val1, val2, …:: [At least 1 is required] The value or multiple value arguments that you want appended to the end of the input array [.var]`expression`. + +=== Return Values +A new array with [.var]`val` or multiple [.var]`val` arguments appended if the [.var]`val` is not already present. +Otherwise, it returns the unmodified input array [.var]`expr`. + +If one of the arguments is `MISSING`, then it returns `MISSING`. + +If the first argument is a non-array, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Append "Dave Smith" to the end of the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_PUT(t.public_likes, "Dave Smith") AS array_put +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "array_put": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow", + "Dave Smith" + ] + } +] +---- +==== + +[[fn-array-range,ARRAY_RANGE()]] +== ARRAY_RANGE([.var]`start_num`, [.var]`end_num` [, [.var]`step_num` ]) + +=== Description +This function returns a new array of numbers, from [.var]`start_num` until the largest number less than [.var]`end_num`. +Successive numbers are incremented by [.var]`step_int`. + +If [.var]`step_int` is not specified, then the default value is 1. +If [.var]`step_num` is negative, then he function decrements until the smallest number greater than [.var]`end_num`. + +=== Arguments +start_num:: [Required] The integer to start a new array with. + +end_num:: [Required] The integer that is one number larger than the final integer in the output array. + +step_num:: +[Optional; default is 1] The number between each array element. + +If [.var]`step_num` is negative, then the function decrements until the smallest number greater than [.var]`end_num`. + +Output Values:: +A new array of numbers, from [.var]`start_num` until the largest number less than [.var]`end_num`. + +If any of the arguments are `MISSING`, then it returns `MISSING`. + +If any of the arguments do not start with a digit, then it returns an error. + +=== Examples +==== +Make an array from 0 to 20 by stepping every 5th number. + +[source,sqlpp] +---- +SELECT ARRAY_RANGE(0, 25, 5) AS gen_array_range_5; +---- + +.Results +[source,json] +---- +[ + { + "gen_array_range_5": [ + 0, + 5, + 10, + 15, + 20 + ] + } +] +---- +==== + +==== +Make an array from 0.1 to 1.1 by stepping every 2nd number. + +[source,sqlpp] +---- +SELECT ARRAY_RANGE(0.1, 2) AS gen_array_range_2; +---- + +.Results +[source,json] +---- +[ + { + "gen_array_range_2": [ + 0.1, + 1.1 + ] + } +] +---- +==== + +==== +Make an array from 10 to 3 by stepping down every 3rd number. + +[source,sqlpp] +---- +SELECT ARRAY_RANGE(10, 3, -3) AS gen_array_range_minus3; +---- + +.Results +[source,json] +---- +[ + { + "gen_array_range-3": [ + 10, + 7, + 4 + ] + } +] +---- +==== + +[[fn-array-remove,ARRAY_REMOVE()]] +== ARRAY_REMOVE([.var]`expr`, [.var]`val1`, [.var]`val2`, …) + +=== Description +This function returns a new array with all occurrences of the specified [.var]`value` or multiple [.var]`value` fields removed from the array [.var]``expression``. +It requires a minimum of two arguments. + +=== Arguments +expr:: [Required] The input array to have the specified [.var]`val` or multiple [.var]`val` fields removed. + +val1, val2, …:: [At least 1 is required] The input value or multiple values to remove from the input array [.var]`expr`. + +Output Values:: +A new array with all occurrences of the specified [.var]`val` or multiple [.var]`val` fields removed from the array [.var]`expr`. + +If any of the arguments are `MISSING`, then it returns `MISSING`. + +If the first argument is not an array, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Remove "Vallie Ryan" from the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_REMOVE(t.public_likes, "Vallie Ryan") AS remove_val +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "remove_val": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ] + } +] +---- +==== + +[[fn-array-repeat,ARRAY_REPEAT()]] +== ARRAY_REPEAT([.var]`val`, [.var]`rep_int`) + +=== Description +This function returns a new array with the specified [.var]`val` repeated [.var]`rep_int` times. + +=== Arguments +val:: [Required] The input value you want repeated. + +rep_int:: [Required] The integer number of times you want the input [.var]`val` repeated. + +Output Values:: +A new array with the specified [.var]`val` repeated [.var]`rep_int` times. + +If any of the arguments are `MISSING`, then it returns `MISSING`. + +If the [.var]`rep_int` argument is not an integer, then it returns `NULL`. + +=== Example +==== +Make an array with "Vallie Ryan" three times. + +[source,sqlpp] +---- +SELECT ARRAY_REPEAT("Vallie Ryan", 3) AS repeat_val; +---- + +.Results +[source,json] +---- +[ + { + "repeat_val": [ + "Vallie Ryan", + "Vallie Ryan", + "Vallie Ryan" + ] + } +] +---- +==== + +[[fn-array-replace,ARRAY_REPLACE()]] +== ARRAY_REPLACE([.var]`expr`, [.var]`val1`, [.var]`val2` [, [.var]`max_int` ]) + +=== Description +This function returns a new array with all occurrences of [.in]`value1` replaced with [.in]`value2`. + +If [.var]`max_int` is specified, than no more than [.var]`max_int` replacements will be performed. + +=== Arguments +expr:: [Required] The input array you want to replace [.var]`val1` with [.var]`val2`. + +val1:: [Required] The existing value in the input [.var]`expr` you want to replace. + +val2:: [Required] The new value you want to take the place of [.var]`val1` in the input [.var]`expr`. + +max_int:: +[Optional. Default is no maximum] The number of maximum replacements to perform. + +=== Return Values +A new array with all or [.var]`max_int` occurrences of [.in]`val1` replaced with [.in]`val2`. + +If any of the arguments are `MISSING`, then it returns `MISSING`. + +If the first argument is not an array or if the second argument is `NULL`, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Replace all occurrences of "Vallie Ryan" with "Valerie Ryan": + +[source,sqlpp] +---- +SELECT ARRAY_REPLACE(t.public_likes, "Vallie Ryan", "Valerie Ryan") AS replace_val +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "replace_val": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Valerie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ] + } +] +---- +==== + +[[fn-array-reverse,ARRAY_REVERSE()]] +== ARRAY_REVERSE([.var]`expr`) + +=== Description +This function returns a new array with all the elements of [.var]`expr` in reverse order. + +=== Arguments +expr:: [Required] The input array whose elements you want to reverse. + +=== Return Values +A new array with all the elements of [.var]`expr` in reverse order. + +If the argument is `MISSING`, then it returns `MISSING`. + +If the argument is a non-array value, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Reverse the values in the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_REVERSE(t.public_likes) AS reverse_val +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "reverse_val": [ + "Elnora Trantow", + "Ms. Moses Feeney", + "Lilian McLaughlin", + "Brian Kilback", + "Vallie Ryan", + "Jaeden McKenzie", + "Corrine Hilll", + "Julius Tromp I" + ] + } +] +---- +==== + +[[fn-array-sort,ARRAY_SORT()]] +== ARRAY_SORT([.var]`expr`) + +=== Description +This function returns a new array with the elements of [.var]`expr` sorted in {sqlpp} collation order. + +=== Arguments +expr:: [Required] The input array you want sorted. + +=== Return Values +A new array with the elements of [.var]`expr` sorted in {sqlpp} collation order. + +If the argument is `MISSING`, then it returns `MISSING`. + +If the argument is a non-array value, then it returns `NULL`. + +=== Example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Sort the `public_likes` array: + +[source,sqlpp] +---- +SELECT ARRAY_SORT(t.public_likes) AS sorted_array +FROM hotel t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "sorted_array": [ + "Brian Kilback", + "Corrine Hilll", + "Elnora Trantow", + "Jaeden McKenzie", + "Julius Tromp I", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Vallie Ryan" + ] + } +] +---- +==== + +[[fn-array-star,ARRAY_STAR()]] +== ARRAY_STAR([.var]`expr`) + +=== Description +This function converts an array of [.var]`expr` objects into an object of arrays. + +=== Arguments +expr:: [Required] The input array you want to convert into an object of arrays. + +=== Output Values +An object of arrays. + +If the argument is `MISSING`, then it returns `MISSING`. + +If the argument is a non-array value, then it returns `NULL`. + +=== Example +==== +Convert a given array of two documents each with five items into an object of five arrays each with two documents. + +[source,sqlpp] +---- +SELECT ARRAY_STAR( [ + { + "address": "Capstone Road, ME7 3JE", + "city": "Medway", + "country": "United Kingdom", + "name": "Medway Youth Hostel", + "url": "http://www.yha.org.uk" + }, + { + "address": "6 rue aux Juifs", + "city": "Giverny", + "country": "France", + "name": "The Robins", + "url": "http://givernyguesthouse.com/robin.htm" + }]) AS array_star; +---- + +.Results +[source,json] +---- +[ + { + "array_star": { + "address": [ + "Capstone Road, ME7 3JE", + "6 rue aux Juifs" + ], + "city": [ + "Medway", + "Giverny" + ], + "country": [ + "United Kingdom", + "France" + ], + "name": [ + "Medway Youth Hostel", + "The Robins" + ], + "url": [ + "http://www.yha.org.uk", + "http://givernyguesthouse.com/robin.htm" + ] + } + } +] +---- +==== + +=== Array References +You can use an asterisk (*) as an array subscript which converts the array to an object of arrays. +The following example returns an array of the ages of the given contact’s children: +==== +[source,sqlpp] +---- +SELECT children[*].age FROM contacts WHERE fname = "Dave" +---- +==== + +An equivalent query can be written using the [.api]`array_star()` function: +==== +[source,sqlpp] +---- +SELECT array_star(children).age FROM contacts WHERE fname = "Dave" +---- +==== + +[[fn-array-sum,ARRAY_SUM()]] +== ARRAY_SUM([.var]`expr`) + +=== Description +This function returns the sum of all the non-`NULL` number values in the [.var]`expr` array. + +=== Arguments +expr:: [Required] The input array of numbers you want to know the total value of. + +=== Return Values +The sum of all the non-`NULL` number values in the [.var]`expr` array. + +If there are no number values, then it returns 0 (zero). + +If the argument is `MISSING`, then it returns `MISSING`. + +If the argument is a non-array value, then it returns `NULL`. + +=== Example +==== +Find the total of a given array of numbers. + +[source,sqlpp] +---- +SELECT ARRAY_SUM([0,1,1,2,3,5]) as sum; +---- + +.Results +[source,json] +---- +[ + { + "sum": 12 + } +] +---- +==== + +[[fn-array-symdiff,ARRAY_SYMDIFF()]] +== ARRAY_SYMDIFF([.var]`expr1`, [.var]`expr2`, …) + +This function has a synonym <>. + +=== Description +This function returns a new array based on the set symmetric difference, or disjunctive union, of the input [.var]`expression` arrays. +The new array contains only those elements that appear in _exactly one_ of the input arrays, and it requires a minimum of two arguments. + +=== Arguments +expr1, expr2, …:: [At least 2 are required] The input arrays to compare. + +=== Return Values +A new array containing only those elements that appear in exactly one of the input arrays. + +If any of the arguments is `MISSING`, then it returns `MISSING`. + +If any of the arguments is a non-array value, then it returns `NULL`. + +[NOTE] +-- +The difference between <> and <> is that the former function includes the value when it appears only once, while the latter function includes the value when it appears an odd number of times in the input arrays. + +Refer to the following article for more information on the difference between a normal and n-ary symdiff: https://en.wikipedia.org/wiki/Symmetric_difference[^]. +-- + +=== Example +==== +Find the elements that appear in exactly one of these three input arrays. + +[source,sqlpp] +---- +SELECT ARRAY_SYMDIFF([1, 2], [1, 2, 4], [1, 3]) AS symm_diff1; +---- + +.Results +[source,json] +---- +[ + { + "symm_diff1": [ + 3, + 4 + ] + } +] +---- +==== + +[[fn-array-symdiff1,ARRAY_SYMDIFF1()]] +== ARRAY_SYMDIFF1([.var]`expr1`, [.var]`expr2`, …) + +Synonym of <>. + +[[fn-array-symdiffn,ARRAY_SYMDIFFN()]] +== ARRAY_SYMDIFFN([.var]`expr1`, [.var]`expr2`, …) + +=== Description +This function returns a new array based on the set symmetric difference, or disjunctive union, of the input arrays. +The new array contains only those elements that appear in _an odd number_ of input arrays, and it requires a minimum of two arguments. + +=== Arguments +expr1, expr2, …:: [At least 2 are required] The input arrays to compare. + +=== Return Values +A new array containing only those elements that appear in an odd number of the input arrays. + +If any of the arguments is `MISSING`, then it returns `MISSING`. + +If any of the arguments is a non-array value, then it returns `NULL`. + +[NOTE] +-- +The difference between <> and <> is that the former function includes the value when it appears only once, while the latter function includes the value when it appears an odd number of times in the input arrays. + +Refer to the following article for more information on the difference between a normal and n-ary symdiff: https://en.wikipedia.org/wiki/Symmetric_difference[^]. +-- + +=== Example +==== +Find the elements that appear in an odd number of these three input arrays. + +[source,sqlpp] +---- +SELECT ARRAY_SYMDIFFN([1, 2], [1, 2, 4], [1, 3]) AS symm_diffn; +---- + +.Results +[source,json] +---- +[ + { + "symm_diffn": [ + 1, + 3, + 4 + ] + } +] +---- +==== + +[[fn-array-union,ARRAY_UNION()]] +== ARRAY_UNION([.var]`expr1`, [.var]`expr2`, …) + +=== Description +This function returns a new array with the set union of the input arrays, and it requires a minimum of two arguments. + +=== Arguments +expr1, expr2, …:: [At least 2 are required] The input arrays to compare. + +=== Return Values +A new array with the set union of the input arrays. + +If any of the arguments is `MISSING`, then it returns `MISSING`. + +If any of the arguments is a non-array value, then it returns `NULL`. + +=== Examples +==== +List the union of three given arrays. + +[source,sqlpp] +---- +SELECT ARRAY_UNION([1, 2], [1, 2, 4], [1, 3]) AS array_union; +---- + +.Results +[source,json] +---- +[ + { + "array_union": [ + 3, + 2, + 1, + 4 + ] + } +] +---- +==== + +==== +List the union of two given arrays with a string. + +[source,sqlpp] +---- +SELECT ARRAY_UNION([1, 2], [1, 2, 4], "abc") AS array_union; +---- + +.Results +[source,json] +---- +[ + { + "array_union": null + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/begin-transaction.adoc b/modules/n1ql/pages/n1ql-language-reference/begin-transaction.adoc new file mode 100644 index 000000000..ec64bc3e3 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/begin-transaction.adoc @@ -0,0 +1,111 @@ += BEGIN TRANSACTION +:description: The BEGIN TRANSACTION statement enables you to begin a transaction. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:insert: xref:n1ql:n1ql-language-reference/insert.adoc +:upsert: xref:n1ql:n1ql-language-reference/upsert.adoc +:delete: xref:n1ql:n1ql-language-reference/delete.adoc +:update: xref:n1ql:n1ql-language-reference/update.adoc +:merge: xref:n1ql:n1ql-language-reference/merge.adoc +:select: xref:n1ql:n1ql-language-reference/selectintro.adoc +:execfunction: xref:n1ql:n1ql-language-reference/execfunction.adoc +:prepare: xref:n1ql:n1ql-language-reference/prepare.adoc +:execute: xref:n1ql:n1ql-language-reference/execute.adoc +:transactions: xref:n1ql:n1ql-language-reference/transactions.adoc +:preparation: xref:n1ql:n1ql-language-reference/transactions.adoc#preparation +:tximplicit: xref:n1ql:n1ql-manage/query-settings.adoc#tximplicit +:txid: xref:n1ql:n1ql-manage/query-settings.adoc#txid + +// Related links +:overview: xref:server:learn:data/transactions.adoc +:begin-transaction: xref:n1ql-language-reference/begin-transaction.adoc +:set-transaction: xref:n1ql-language-reference/set-transaction.adoc +:savepoint: xref:n1ql-language-reference/savepoint.adoc +:commit-transaction: xref:n1ql-language-reference/commit-transaction.adoc +:rollback-transaction: xref:n1ql-language-reference/rollback-transaction.adoc + +[abstract] +{description} + +== Purpose + +The `BEGIN TRANSACTION` statement enables you to begin a sequence of statements as an ACID transaction. +Refer to {transactions}[] for further information. + +include::partial$n1ql-language-reference/transaction-restrictions.adoc[] + +NOTE: You can also specify a single DML statement as an ACID transaction by setting the {tximplicit}[tximplicit] query parameter. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/tcl.ebnf[tag=begin-transaction] +---- + +image::n1ql-language-reference/begin-transaction.png["Syntax diagram: refer to source code listing", align=left] + +The `BEGIN` and `START` keywords are synonyms. +The statement must begin with one of these keywords. + +The `WORK`, `TRAN`, and `TRANSACTION` keywords are synonyms. +The statement must contain one of these keywords. + +=== Transaction Settings + +Currently, the only available transaction setting is "isolation level read committed". +This setting is enabled by default. +The `ISOLATION LEVEL READ COMMITTED` keywords are therefore optional and may be omitted. + +== Return Value + +The statement returns an object containing the following property. + +txid:: +The transaction ID. + +ifdef::flag-devex-rest-api[] +If you are using the Query REST API, you must set the {txid}[txid] query parameter to specify the transaction ID for any subsequent statements that form part of the same transaction. +endif::flag-devex-rest-api[] + +If you are using the Query tab, you don't need to specify the transaction ID for any statements that form a part of the same transaction within a multi-statement request. +If you start a transaction within a multi-statement request, all statements within the request are assumed to be part of the same transaction until you rollback or commit the transaction. + +Similarly, if you are using the cbq shell, you don't need to specify the transaction ID for any statements that form a part of the same transaction. +Once you have started a transaction, all statements within the cbq shell session are assumed to be part of the same transaction until you rollback or commit the transaction. +footnote:[You must be using cbq shell version 2.0 or above to use the automatic transaction ID functionality.] + +== Example + +If you want to try this example, first refer to {preparation}[Preparation] to set up your environment. + +.Begin a transaction +==== +// Line highlighting doesn't work with highlight.js. +// Markup for future use [source,n1ql,highlight=12..14] + +.Transaction +[source,sqlpp,subs=macros] +---- +include::example$transactions/multiple.n1ql[tags=transaction;begin-mark;!begin-plain;!set-mark;!savepoint-mark;!rollback-mark;!commit-mark] +---- + +.Results +[source,json] +---- +include::example$transactions/results.jsonc[tags=extract;ellipsis] +---- + +<.> Beginning a transaction returns a transaction ID. +==== + +== Related Links + +* For an overview of Couchbase transactions, refer to {overview}[]. +* To specify transaction settings, refer to {set-transaction}[]. +* To set a savepoint, refer to {savepoint}[]. +* To rollback a transaction, refer to {rollback-transaction}[]. +* To commit a transaction, refer to {commit-transaction}[]. +* Blog post: https://blog.couchbase.com/transactions-n1ql-couchbase-distributed-nosql/[Couchbase Transactions: Elastic, Scalable, and Distributed^]. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/bitwisefun.adoc b/modules/n1ql/pages/n1ql-language-reference/bitwisefun.adoc new file mode 100644 index 000000000..17d017b39 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/bitwisefun.adoc @@ -0,0 +1,972 @@ += Bitwise Functions +:page-topic-type: reference +:example-caption!: +:description: All Bit/Binary functions can only operate on 64-bit signed integers. +:page-topic-type: reference + +{description} + +NOTE: All non-integer numbers and other data types result in null. + +NOTE: Couchbase Capella uses two's complement representation. + +When looking at the value in binary form, bit 1 is the Least Significant Bit (LSB) and bit 32 is the Most Significant Bit (MSB). + +(MSB) Bit 32 → `0000 0000 0000 0000 0000 0000 0000 0000` ← Bit 1 (LSB) + +[#BitAND] +== BITAND ([.var]`int_value1`, [.var]`int_value2`, \...) + +=== Description + +Returns the result of a bitwise AND operation performed on all input integer values. + +The bitwise AND operation compares each bit of [.var]`int_value1` to the corresponding bit of every other [.var]`int_value`. +If all bits are 1, then the corresponding result bit is set to 1; otherwise it is set to 0 (zero). + +=== Arguments + +int_value1, int_value2, \...:: Integers, or any valid xref:n1ql-language-reference/index.adoc[expressions] which evaluate to integers, that are used to compare. + +=== Return Value + +An integer, representing the bitwise AND between all of the input integers. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.AND-1 +==== +Compare 3 (0011 in binary) and 6 (0110 in binary). + +[source,sqlpp] +---- +SELECT BITAND(3,6) AS BitAND; +---- + +.Results +[source,json] +---- +[ + { + "BitAND": 2 + } +] +---- + +This results in 2 (0010 in binary) because only bit 2 is set in both 3 (00**1**1) and 6 (01**1**0). +==== + +.AND-2 +==== +Compare 4.5 and 3 (0011 in binary). + +[source,sqlpp] +---- +SELECT BITAND(4.5,3) AS BitAND; +---- + +.Results +[source,json] +---- +[ + { + "BitAND": null + } +] +---- + +The result is null because 4.5 is not an integer. +==== + +.AND-3 +==== +Compare 4.0 (0100 in binary) and 3 (0011 in binary). + +[source,sqlpp] +---- +SELECT BITAND(4.0,3) AS BitAND; +---- + +.Results +[source,json] +---- +[ + { + "BitAND": 0 + } +] +---- + +This results in 0 (zero) because 4.0 (0100) and 3 (0011) do not share any bits that are both 1. +==== + +.AND-4 +==== +Compare 3 (0011 in binary) and 6 (0110 in binary) and 15 (1111 in binary). + +[source,sqlpp] +---- +SELECT BITAND(3,6,15) AS BitAND; +---- + +.Results +[source,json] +---- +[ + { + "BitAND": 2 + } +] +---- + +This results in 2 (0010 in binary) because only the 2nd bit from the right is 1 in all three numbers. +==== + +[#BitCLEAR] +== BITCLEAR ([.var]`int_value`, [.var]`positions`) + +=== Description + +Returns the result after clearing the specified bit, or array of bits in `int_value` using the given `positions`. + +NOTE: Specifying a negative or zero bit position makes the function return a null. + +=== Arguments + +int_value:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that contains the target bit or bits to clear. + +positions:: An integer or an array of integers specifying the position or positions to be cleared. + +=== Return Value + +An integer, representing the result after clearing the bit or bits specified. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.CLEAR-1 +==== +Clear bit 1 from 6 (0110 in binary). + +[source,sqlpp] +---- +SELECT BITCLEAR(6,1) AS BitCLEAR; +---- + +.Results +[source,json] +---- +[ + { + "BitCLEAR": 6 + } +] +---- + +This results in 6 (011**0** in binary) because bit 1 was already zero. +==== + +.CLEAR-2 +==== +Clear bits 1 and 2 from 6 (01**10** in binary). + +[source,sqlpp] +---- +SELECT BITCLEAR(6,[1,2]) AS BitCLEAR; +---- + +.Results +[source,json] +---- +[ + { + "BitCLEAR": 4 + } +] +---- + +This results in 4 (01**0**0 in binary) because bit 2 changed to zero. +==== + +.CLEAR-3 +==== +Clear bits 1, 2, 4, and 5 from 31 (0**11**1**11** in binary). + +[source,sqlpp] +---- +SELECT BITCLEAR(31,[1,2,4,5]) AS BitCLEAR; +---- + +.Results +[source,json] +---- +[ + { + "BitCLEAR": 4 + } +] +---- + +This results in 4 (0**00**1**00**) because bits 1, 2, 4, and 5 changed to zero. +==== + +[#BitNOT] +== BITNOT ([.var]`int_value`) + +=== Description + +Returns the results of a bitwise logical NOT operation performed on an integer value. + +The bitwise logical NOT operation reverses the bits in the value. +For each value bit that is 1, the corresponding result bit will be set to 0 (zero); and for each value bit that is 0 (zero), the corresponding result bit will be set to 1. + +NOTE: All bits of the integer will be altered by this operation. + +=== Arguments + +int_value:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that contains the target bits to reverse. + +=== Return Value + +An integer, representing the result after performing the logical NOT operation. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.NOT-1 +==== +Perform the NOT operation on 3 (0000 0000 0000 0000 0000 0000 0000 0011 in binary). + +[source,sqlpp] +---- +SELECT BITNOT(3) AS BitNOT; +---- + +.Results +[source,json] +---- +[ + { + "BitNOT": -4 + } +] +---- + +This results in -4 (*1111 1111 1111 1111 1111 1111 1111 1100* in binary) because all bits changed. +==== + +[#BitOR] +== BITOR ([.var]`int_value1`, [.var]`int_value2`, \...) + +=== Description + +Returns the result of a bitwise inclusive OR operation performed on all input integer values. + +compares each bit of [.var]`int_value1` to the corresponding bit of every other [.var]`int_value`. +If any bit is 1, the corresponding result bit is set to 1; otherwise, it is set to 0 (zero). + +=== Arguments + +int_value1, int_value2, \...:: Integers, or any valid xref:n1ql-language-reference/index.adoc[expressions] which evaluate to integers, that are used to compare. + +=== Return Value + +An integer, representing the bitwise OR between all of the input integers. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.OR-1 +==== +Perform OR on 3 (0011 in binary) and 6 (0110 in binary). + +[source,sqlpp] +---- +SELECT BITOR(3,6) AS BitOR; +---- + +.Results +[source,json] +---- +[ + { + "BitOR": 7 + } +] +---- + +This results in 7 (0**111** in binary) because at least 1 bit of each (00**11** and 0**11**0) is 1 in bits 1, 2, and 3. +==== + +.OR-2 +==== +Perform OR on 3 (0011 in binary) and -4 (1000 0000 0000 \... 0000 1100 in binary). + +[source,sqlpp] +---- +SELECT BITOR(3,-4) AS BitOR; +---- + +.Results +[source,json] +---- +[ + { + "BitOR": -1 + } +] +---- + +This results in -1 (*1111 1111 1111 \... 1111 1111* in binary) because the two 1 bits in 3 fill in the two 0 bits in -4 to turn on all the bits. +==== + +.OR-3 +==== +Perform OR on 3 (0011 in binary) and 6 (0110 in binary) and 15 (1111 in binary). + +[source,sqlpp] +---- +SELECT BITOR(3,6,15) AS BitOR; +---- + +.Results +[source,json] +---- +[ + { + "BitOR": 15 + } +] +---- + +This results in 15 (1111 in binary) because there is at least one 1 in each of the four rightmost bits. +==== + +[#BitSET] +== BITSET ([.var]`int_value`, [.var]`positions`) + +=== Description + +Returns the result after setting the specified bit `position`, or array of bit positions, to 1 in the given `int_value`. + +NOTE: Specifying a negative or zero position makes the function return a null. + +=== Arguments + +int_value:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that contains the target bit or bits to set. + +positions:: An integer or an array of integers specifying the position or positions to be set. + +=== Return Value + +An integer, representing the result after setting the bit or bits specified. +If the bit is already set, then it stays set. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.SET-1 +==== +Set bit 1 in the value 6 (011**0** in binary). + +[source,sqlpp] +---- +SELECT BITSET(6,1) AS BitSET; +---- + +.Results +[source,json] +---- +[ + { + "BitSET": 7 + } +] +---- + +This results in 7 (011**1** in binary) because bit 1 changed to 1. +==== + +.SET-2 +==== +Set bits 1 and 2 in the value 6 (01**10** in binary). + +[source,sqlpp] +---- +SELECT BITSET(6,[1,2]) AS BitSET; +---- + +.Results +[source,json] +---- +[ + { + "BitSET": 7 + } +] +---- + +This also results in 7 (01**11** in binary) because bit 1 changed while bit 2 remained the same. +==== + +.SET-3 +==== +Set bits 1 and 4 in the value 6 (**0**11**0** in binary). + +[source,sqlpp] +---- +SELECT BITSET(6,[1,4]) AS BitSET; +---- + +.Results +[source,json] +---- +[ + { + "BitSET": 15 + } +] +---- + +This results in 15 (**1**11**1** in binary) because bit 1 and 4 changed to ones. +==== + +[#BitSHIFT] +== BITSHIFT ([.var]`int_value`, [.var]`shift_amount`, [.var]`rotate`) + +=== Description + +Returns the result of a bit shift operation performed on the integer value `int`. +The `shift_amount` supports left and right shifts. +These are logical shifts. +The third parameter `rotate` supports circular shift. +This is similar to the BitROTATE function in Oracle. + +=== Arguments + +int_value:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that contains the target bit or bits to shift. + +shift_amount:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that contains the number of bits to shift. ++ +A positive (+) number means this is a LEFT shift. ++ +A negative (-) number means this is a RIGHT shift. + +rotate:: [Optional; FALSE by default] A boolean, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a boolean, where: + +* FALSE means this is a LOGICAL shift, where bits shifted off the end of a value are considered lost. + +* TRUE means this is a CIRCULAR shift (shift-and-rotate operation), where bits shifted off the end of a value are rotated back onto the value at the _other_ end. +In other words, the bits rotate in what might be thought of as a circular pattern; therefore, these bits are not lost. + ++ +For comparison, see the below table. + +[%header,cols="3,1,4,8"] +|=== +| Input | Shift | Result of Logical Shift + +(Rotate FALSE) | Result of Circular Shift + +(Rotate TRUE) + +| 6 (0000 0110) +| 4 +| 96 (0110 0000) +| 96 (0110 0000) + +| 6 (0000 0110) +| 3 +| 48 (0011 0000) +| 48 (0011 0000) + +| 6 (0000 0110) +| 2 +| 24 (0001 1000) +| 24 (0001 1000) + +| 6 (0000 0110) +| 1 +| 12 (0000 1100) +| 12 (0000 1100) + +| *6 (0000 0110)* +| *0* +| *6 (0000 0110)* +| *6 (0000 0110)* + +| 6 (0000 0110) +| -1 +| 3 (0000 0011) +| 3 (0000 0011) + +| 6 (0000 0110) +| -2 +| 1 (0000 0001) +| -9223372036854775807 (1000 0000 \... 0000 0001) + +| 6 (0000 0110) +| -3 +| 0 (0000 0000) +| -4611686018427387904 (1100 0000 \... 0000 0000) + +| 6 (0000 0110) +| -4 +| 0 (0000 0000) +| 6917529027641081856 (0110 0000 \... 0000 0000) +|=== + +=== Return Value + +An integer, representing the result of either a logical or circular shift of the given integer. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.SHIFT-1 +==== +Logical left shift of the number 6 (0110 in binary) by one bit. + +[source,sqlpp] +---- +SELECT BITSHIFT(6,1,FALSE) AS BitSHIFT; +---- + +.Results +[source,json] +---- +[ + { + "BitSHIFT": 12 + } +] +---- + +This results in 12 (1100 in binary) because the 1-bits moved from positions 2 and 3 to positions 3 and 4. +==== + +.SHIFT-2 +==== +Logical right shift of the number 6 (0110 in binary) by two bits. + +[source,sqlpp] +---- +SELECT BITSHIFT(6,-2) AS BitSHIFT; +---- + +.Results +[source,json] +---- +[ + { + "BitSHIFT": 1 + } +] +---- + +This results in 1 (0001 in binary) because the 1-bit in position 3 moved to position 1 and the 1-bit in position 2 was dropped. +==== + +.SHIFT-2b +==== +Circular right shift of the number 6 (0110 in binary) by two bits. + +[source,sqlpp] +---- +SELECT BITSHIFT(6,-2,TRUE) AS BitSHIFT; +---- + +.Results +[source,json] +---- +[ + { + "BitSHIFT": -9223372036854775807 + } +] +---- + +This results in -9223372036854775807 (1100 0000 0000 0000 0000 0000 0000 0000 in binary) because the two 1-bits wrapped right, around to the Most Significant Digit position and changed the integer's sign to negative. +==== + +.SHIFT-3 +==== +Circular left shift of the number 524288 (1000 0000 0000 0000 0000 in binary) by 45 bits. + +[source,sqlpp] +---- +SELECT BITSHIFT(524288,45,TRUE) AS BitSHIFT; +---- + +.Results +[source,json] +---- +[ + { + "BitSHIFT": 1 + } +] +---- + +This results in 1 because the 1-bit wrapped left, around to the Least Significant Digit position. +==== + +[#section_unf_2sv_s1b] +== BITTEST ([.var]`int_value`, [.var]`positions [, all_set]`) + +This function has a synonym <>. + +=== Description + +Returns TRUE if the specified bit, or bits, is a 1; otherwise, returns FALSE if the specified bit, or bits, is a 0 (zero). + +NOTE: Specifying a negative or zero bit position will result in NULL being returned. + +=== Arguments + +int_value:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that contains the target bit or bits to test. + +positions:: An integer or an array of integers specifying the position or positions to be tested. + +all_set:: +[Optional; FALSE by default] A boolean, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a boolean. ++ +When `all_set` is FALSE, then it returns TRUE even if one bit in one of the positions is set. ++ +When `all_set` is TRUE, then it returns TRUE only if all input positions are set. + +=== Return Value + +A boolean, that follows the below table: + +[cols="2,1,1"] +|=== +| [.var]`int_value` | [.var]`all_set` | Return Value + +| _all_ specified bits are TRUE +| FALSE +| TRUE + +| _all_ specified bits are TRUE +| TRUE +| TRUE + +| _some_ specified bits are TRUE +| FALSE +| TRUE + +| _some_ specified bits are TRUE +| TRUE +| FALSE +|=== + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.TEST-1 +==== +In the number 6 (0110 in binary), is bit 1 set? + +[source,sqlpp] +---- +SELECT ISBITSET(6,1) AS IsBitSET; +---- + +.Results +[source,json] +---- +[ + { + "IsBitSET": false + } +] +---- + +This returns FALSE because bit 1 of 6 (011**0** in binary) is not set to 1. +==== + +.TEST-2 +==== +In the number 1, is either bit 1 or bit 2 set? + +[source,sqlpp] +---- +SELECT BITTEST(1,[1,2],FALSE) AS BitTEST; +---- + +.Results +[source,json] +---- +[ + { + "BitTEST": true + } +] +---- + +This returns TRUE because bit 1 of the number 1 (000**1** in binary) is set to 1. +==== + +.TEST-3 +==== +In the number 6 (0110 in binary), are both bits 2 and 3 set? + +[source,sqlpp] +---- +SELECT ISBITSET(6,[2,3],TRUE) AS IsBitSET; +---- + +.Results +[source,json] +---- +[ + { + "IsBitSET": true + } +] +---- + +This returns TRUE because both bits 2 and 3 in the number 6 (0**11**0 in binary) are set to 1. +==== + +.TEST-4 +==== +In the number 6 (0110 in binary), are all the bits in positions 1 through 3 set? + +[source,sqlpp] +---- +SELECT BITTEST(6,[1,3],TRUE) AS BitTEST; +---- + +.Results +[source,json] +---- +[ + { + "BitTEST": false + } +] +---- + +This returns FALSE because bit 1 in the number 6 (011**0** in binary) is set to 0 (zero). +==== + +.TEST-5 +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Find only flights that have 1 layover (to rest and walk around). +That is, flight stops of 1 (0001 in binary) only: + +[source,sqlpp] +---- +SELECT airline, stops, schedule[0].day FROM `travel-sample`.inventory.route +WHERE stops = 1; +---- + +[source,json] +.Results +---- +[ + { + "airline": "FL", + "day": 0, + "stops": 1 + }, + { + "airline": "FL", + "day": 0, + "stops": 1 + }, + { + "airline": "FL", + "day": 0, + "stops": 1 + }, + { + "airline": "WN", + "day": 0, + "stops": 1 + }, + { + "airline": "WN", + "day": 0, + "stops": 1 + }, + { + "airline": "WN", + "day": 0, + "stops": 1 + } +] +---- +The above query returns the exact same results as the below query which uses a bit operation. + +[source,sqlpp] +---- +SELECT airline, stops, schedule[0].day FROM `travel-sample`.inventory.route +WHERE BITTEST(stops,1); +---- + +.Results +[source,json] +---- +[ + { + "airline": "FL", + "day": 0, + "stops": 1 + }, + { + "airline": "FL", + "day": 0, + "stops": 1 + }, + { + "airline": "FL", + "day": 0, + "stops": 1 + }, + { + "airline": "WN", + "day": 0, + "stops": 1 + }, + { + "airline": "WN", + "day": 0, + "stops": 1 + }, + { + "airline": "WN", + "day": 0, + "stops": 1 + } +] +---- +==== + +[#BitXOR] +== BITXOR ([.var]`int_value1`, [.var]`int_value2`, \...) + +=== Description + +Returns the result of a bitwise Exclusive OR operation performed on two or more integer values. + +The bitwise Exclusive OR operation compares each bit of `int_value1` to the corresponding bit of `int_value2`. + +If there are more than two input values, the first two are compared; then their result is compared to the next input value; and so on. + +When the compared bits do not match, the result bit is 1; otherwise, the compared bits do match, and the result bit is 0 (zero), as summarized: + +[cols="^1,^1,^2"] +|=== +| Bit 1 | Bit 2 | XOR Result Bit + +| 0 +| 0 +| 0 + +| 0 +| 1 +| 1 + +| 1 +| 0 +| 1 + +| 1 +| 1 +| 0 +|=== + +=== Arguments + +int_value1, int_value2, \...:: Integers, or any valid xref:n1ql-language-reference/index.adoc[expressions] which evaluate to integers, that are used to compare. + +=== Return Value + +An integer, representing the bitwise XOR between the input integers. + +=== Limitations + +Input values must be integers (such as 1 or 1.0) and cannot contain decimals (such as 1.2). + +=== Examples + +.XOR-1 +==== +Perform the XOR operation on 3 (0011 in binary) and 6 (0110 in binary). + +[source,sqlpp] +---- +SELECT BITXOR(3,6) AS BitXOR; +---- + +.Results +[source,json] +---- +[ + { + "BitXOR": 5 + } +] +---- + +This returns 5 (0101 in binary) because the 1st bit pair and 3rd bit pair are different (resulting in 1) while the 2nd bit pair and 4th bit pair are the same (resulting in 0): + +---- +0011 (3) +0110 (6) +======== +0101 (5) +---- +==== + +.XOR-2: +==== +Perform the XOR operation on 3 (0011 in binary) and 6 (0110 in binary) and 15 (1111 in binary). + +[source,sqlpp] +---- +SELECT BITXOR(3,6,15) AS BitXOR; +---- + +.Results +[source,json] +---- +[ + { + "BitXOR": 10 + } +] +---- + +This returns 10 (1010 in binary) because 3 XOR 6 equals 5 (0101 in binary), and then 5 XOR 15 equals 10 (1010 in binary). +==== + +[#IsBitSET] +== ISBITSET → see BITTEST + +Synonym of <>. diff --git a/modules/n1ql/pages/n1ql-language-reference/booleanlogic.adoc b/modules/n1ql/pages/n1ql-language-reference/booleanlogic.adoc new file mode 100644 index 000000000..697009329 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/booleanlogic.adoc @@ -0,0 +1,133 @@ += Boolean Logic +:description: pass:q[Some clauses, such as `WHERE`, `WHEN`, and `HAVING`, require values to be interpreted as Boolean values.] +:page-topic-type: reference + +[abstract] +{description} + +The following rules apply when evaluating these types of clauses: + +* MISSING, NULL, and FALSE are FALSE +* numbers +0, -0, and NaN are FALSE +* empty strings, arrays, and objects are FALSE +* all other values are TRUE + +== Four-valued logic + +In {sqlpp}, Boolean propositions can evaluate to NULL or MISSING (as well as to TRUE and FALSE). + +The following table describes how these values relate to the logical operators: + +[cols=5*^] +|=== +| a | b | a AND b | a OR b | NOT a + +.4+| TRUE +| TRUE +| TRUE +| TRUE +.4+| FALSE + +| FALSE +| FALSE +| TRUE + +| NULL +| NULL +| TRUE + +| MISSING +| MISSING +| TRUE + +.4+| FALSE +| TRUE +| FALSE +| TRUE +.4+| TRUE + +| FALSE +| FALSE +| FALSE + +| NULL +| FALSE +| NULL + +| MISSING +| FALSE +| MISSING + +.4+| NULL +| TRUE +| NULL +| TRUE +.4+| NULL + +| FALSE +| FALSE +| NULL + +| NULL +| NULL +| NULL + +| MISSING +| MISSING +| NULL + +.4+| MISSING +| TRUE +| MISSING +| TRUE +.4+| MISSING + +| FALSE +| FALSE +| MISSING + +| NULL +| MISSING +| NULL + +| MISSING +| MISSING +| MISSING +|=== + +== Comparing NULL and MISSING values + +[cols=4*^] +|=== +| Operator | Non-NULL Value | NULL | MISSING + +| IS NULL +| FALSE +| TRUE +| MISSING + +| IS NOT NULL +| TRUE +| FALSE +| MISSING + +| IS MISSING +| FALSE +| FALSE +| TRUE + +| IS NOT MISSING +| TRUE +| TRUE +| FALSE + +| IS VALUED +| TRUE +| FALSE +| FALSE + +| IS NOT VALUED +| FALSE +| TRUE +| TRUE +|=== diff --git a/modules/n1ql/pages/n1ql-language-reference/build-index.adoc b/modules/n1ql/pages/n1ql-language-reference/build-index.adoc new file mode 100644 index 000000000..8c2a81078 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/build-index.adoc @@ -0,0 +1,298 @@ += BUILD INDEX +:description: The BUILD INDEX statement enables you to build one or more GSI indexes that are marked for deferred building all at once. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:expression: xref:n1ql-language-reference/index.adoc +:selectclause: xref:n1ql-language-reference/selectclause.adoc +:subqueries: xref:n1ql-language-reference/subqueries.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:querying-indexes: xref:n1ql-intro/sysinfo.adoc#querying-indexes +:keyspace-ref: xref:n1ql-language-reference/createindex.adoc#keyspace-ref + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +By default, CREATE INDEX starts building the created index after the creation stage is complete. +However for more efficient building of multiple indexes, CREATE INDEX can mark indexes for deferred building using the `defer_build:true` option. +BUILD INDEX is capable of building multiple indexes at once, and can utilize a single scan of documents in the keyspace to feed many index build operations. + +BUILD INDEX is an asynchronous operation. +BUILD INDEX creates a task to build the primary or secondary GSI indexes and returns as soon as the task is queued for execution. +The full index build operation happens in the background. + +Index metadata provides a state field. +The index state may be `scheduled for creation`, `deferred`, `building`, `pending`, `online`, `offline`, or `abridged`. +This state field and other index metadata can be queried using {querying-indexes}[system:indexes]. +You can also monitor the index state using the Couchbase Web Console. + +If you attempt to build an index which is still scheduled for background creation, the request fails. + +[IMPORTANT] +==== +If you kick off multiple index build operations concurrently, then you may sometimes see transient errors similar to the following. + +[source,json] +---- +include::example$n1ql-language-reference/build-idx-error.jsonc[] +---- + +To work around this issue, wait for index building to complete (that is, for all indexes to get to the online state), then issue the BUILD INDEX command again. +==== + +BUILD INDEX is also idempotent. +On execution, the statement only builds indexes which have not already been built. +If any of the indexes specified by BUILD INDEX have already been built, BUILD INDEX skips those indexes. + +When building an index which has automatic index replicas, all of the replicas are also built as part of the BUILD INDEX statement, without having to manually specify them. + +== Prerequisites + +[discrete] +===== RBAC Privileges + +User executing the BUILD INDEX statement must have the _Query Manage Index_ privilege granted on the keyspace. +For more details about user roles, see +{authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=build-index] +---- + +image::n1ql-language-reference/build-index.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal] +keyspace-ref:: (Required) Specifies the keyspace where the indexes are built. +Refer to <> below. + +index-term:: (Required) Specifies the indexes to build. +Refer to <> below. + +index-using:: (Optional) Specifies the index type. +Refer to <> below. + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of the keyspace on which to build the index. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +[[index-term]] +=== Index Term + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-term] +---- + +image::n1ql-language-reference/index-term.png["Syntax diagram: refer to source code listing", align=left] + +You can specify one index term, or multiple index terms separated by commas. +An index term must be specified for each index to be built. + +Each index term may be an <>, an <>, or a <>. +The BUILD INDEX clause may contain a mixture of the different types of index term. + +[[index-name,index name]] +==== Index Name + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-name] +---- + +image::n1ql-language-reference/index-name.png["Syntax diagram: refer to source code listing", align=left] + +An {identifiers}[identifier] that refers to the name of an index. + +==== +[source,sqlpp] +---- +BUILD INDEX ON keyspace(ix1, ix2, ix3); +---- +==== + +[[index-expr,index expression]] +==== Index Expression + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-expr] +---- + +image::n1ql-language-reference/index-expr.png["Syntax diagram: refer to source code listing", align=left] + +An {expression}[expression] that may be a string, or an array of strings, each referring to the name of an index. + +==== +[source,sqlpp] +---- +BUILD INDEX ON keyspace('ix1', 'ix2', 'ix3'); +BUILD INDEX ON keyspace(['ix1', 'ix2', 'ix3']); +BUILD INDEX ON keyspace('ix1', ['ix2', 'ix3'], ['ix4']); +---- +==== + +[IMPORTANT] +==== +Arrays of identifiers are _not_ permitted. + +[source,sqlpp] +---- +BUILD INDEX ON keyspace([ix1, ix2, ix3]); +BUILD INDEX ON keyspace([ix1], [ix2, ix3]); +---- +==== + +[[subquery-expr,subquery expression]] +==== Subquery Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=subquery-expr] +---- + +image::n1ql-language-reference/subquery-expr.png["Syntax diagram: refer to source code listing", align=left] + +Use parentheses to specify a subquery. + +The subquery must return an array of strings, each string representing the name of an index. +See <> for details. + +For more details and examples, see {selectclause}[SELECT Clause] and {subqueries}[Subqueries]. + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +The index type for a deferred index build must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-create-idx-defer]] +.Create deferred indexes +==== +Create a set of primary and secondary indexes in the `landmark` keyspace with the `defer_build` option. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-defer-1.n1ql[] +---- + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-defer-2.n1ql[] +---- + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-defer-3.n1ql[] +---- +==== + +[[ex-check-idx-defer]] +.Check deferred index status +==== +Query `system:indexes` for the status of an index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/check-idx-defer.n1ql[] +---- + +.Results +[source,json] +---- +include::example$n1ql-language-reference/check-idx-defer.jsonc[] +---- + +<1> Note that the index is in the deferred state. +==== + +[[ex-build-idx-single]] +.Build a named index +==== +Kick off a deferred build using the index name. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/build-idx-single.n1ql[] +---- +==== + +[[ex-build-idx-all]] +.Build all indexes +==== +Alternatively, kick off all deferred builds in the keyspace, using a subquery to find the deferred builds. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/build-idx-all.n1ql[] +---- + +<1> One set of parentheses delimits the whole group of index terms, and another set of parentheses delimits the subquery. +In this case there is a double set of parentheses, as the subquery is the only index term. + +<2> The `RAW` keyword forces the subquery to return a flattened array of strings, each of which refers to an index name. + +Note that it is only possible to kick off all deferred builds in a single collection -- it is not possible to kick off all deferred builds in all collections in all scopes within a bucket. +==== + +[[ex-check-idx-online]] +.Check online index status +==== +Query `system:indexes` for the status of an index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/check-idx-online.n1ql[] +---- + +.Results +[source,json] +---- +include::example$n1ql-language-reference/check-idx-online.jsonc[] +---- + +<1> Note that the index has now been created. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/collectionops.adoc b/modules/n1ql/pages/n1ql-language-reference/collectionops.adoc new file mode 100644 index 000000000..aca4baf8e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/collectionops.adoc @@ -0,0 +1,916 @@ += Collection Operators +:description: Collection operators enable you to evaluate expressions over every element in an array. +:page-topic-type: reference +:page-toclevels: 2 +:imagesdir: ../../assets/images +:keywords: range condition, quantified expression + +{description} +The operators include <>, <>, and <>. + +NOTE: Although collection operators can be used with any array, they are particularly useful when used to evaluate expressions over an array of objects. +The term _collection_ is used here in a generic sense to refer to any array of objects, rather than in the specific sense of a xref:server:learn:data/scopes-and-collections.adoc[Couchbase collection]. + +[[range-cond]] +== Range Predicates + +Range predicates (<>, <>, or <>) enable you to test a Boolean condition over elements in an array. +They use the `IN` and `WITHIN` operators to range through the array. + +(((range condition))) +(((quantified expression))) +Range predicates may also be known as _range conditions_ or _quantified expressions_. + +[discrete] +==== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=range-cond] +---- + +image::n1ql-language-reference/range-cond.png["Syntax diagram", align=left] + +[source#range-cond-binding,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=range] +---- + +image::n1ql-language-reference/range.png["Syntax diagram", align=left] + +[discrete] +==== Arguments + +name-var:: [Optional] An xref:n1ql-language-reference/identifiers.adoc[identifier] that represents the position of a single element in an array, counting from 0. + +var:: An xref:n1ql-language-reference/identifiers.adoc[identifier] that represents a single element in an array. + +expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that returns an array to evaluate. + +cond:: A condition to evaluate for each specified element. +This condition may make use of the `var` and `name-var` identifiers as required. + +[#collection-op-any] +=== ANY + +`ANY` tests whether any element in an array matches a specified condition. +(If the array is empty, then no element in the array is deemed to match the condition.) + +Synonym: `SOME` is a synonym for `ANY`. + +==== Return Values + +If the array is non-empty and at least one element in the array matches the specified condition, then the operator returns `TRUE`; otherwise, it returns `FALSE`. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[AnyExA]] +.ANY with one matching element +==== +Retrieve the details of KL flight schedules from Albuquerque (ABQ) to Atlanta (ATL) if any of the flights are after 23:40. + +[source,sqlpp] +---- +SELECT * FROM route +WHERE airline="KL" AND sourceairport="ABQ" + AND destinationairport="ATL" + AND ANY departure IN schedule SATISFIES departure.utc > "23:40" END; +---- + +Since the last flight departs at 23:41, this query results in the entire array. + +.Results +[source,json] +---- +[ + { + "travel-sample": { + "airline": "KL", + "airlineid": "airline_3090", + "destinationairport": "ATL", + "distance": 2038.3535078909663, + "equipment": "757 320", + "id": 36159, + "schedule": [ + { + "day": 0, + "flight": "KL938", + "utc": "03:54:00" + }, +// ... + { + "day": 5, + "flight": "KL169", + "utc": "23:41:00" + }, +// ... + { + "day": 6, + "flight": "KL636", + "utc": "17:40:00" + } + ], + "sourceairport": "ABQ", + "stops": 0, + "type": "route" + } + } +] +---- +==== + +[[AnyExB]] +.ANY with no matching elements +==== +But if you change the `SATISFIES` clause to 1 minute after the last flight (23:42), then the resulting array is empty. + +.Results +[source,json] +---- +[] +---- +==== + +[[AnyExC]] +.ANY with empty array +==== +This example tests the ANY operator with an empty array. + +[source,sqlpp] +---- +SELECT ANY v IN [] SATISFIES v = "abc" END AS existential; +---- + +In this case, the operator returns `false`. + +.Results +[source,json] +---- +[ + { + "existential": false + } +] +---- +==== + +[#collection-op-every] +=== EVERY + +`EVERY` tests whether every element in an array matches a specified condition. +(If the array is empty, then every element in the array is deemed to match the condition.) + +==== Return Values + +If the array is empty, or if the array is non-empty and every element in the array matches the specified condition, then the operator returns `TRUE`; otherwise, it returns `FALSE`. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[EveryExA]] +.EVERY with all matching elements +==== +Retrieve the details of KL flight schedules from Albuquerque (ABQ) to Atlanta (ATL) if all of the flights are after 00:35. + +[source,sqlpp] +---- +SELECT * FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL" + AND EVERY departure IN schedule SATISFIES departure.utc > "00:35" END; +---- + +Since the earliest flight departs at 00:36, this query results in the entire array. + +.Results +[source,json] +---- +[ + { + "travel-sample": { + "airline": "KL", + "airlineid": "airline_3090", + "destinationairport": "ATL", + "distance": 2038.3535078909663, + "equipment": "757 320", + "id": 36159, + "schedule": [ +// ... + { + "day": 6, + "flight": "KL884", + "utc": "00:36:00" + }, +// ... + { + "day": 6, + "flight": "KL636", + "utc": "17:40:00" + } + ], + "sourceairport": "ABQ", + "stops": 0, + "type": "route" + } + } +] +---- +==== + +[[EveryExB]] +.EVERY with no matching elements +==== +But if you change the `SATISFIES` clause to 1 minute after the first flight (00:37), then the resulting array is empty. + +.Results +[source,json] +---- +[] +---- +==== + +[[EveryExC]] +.EVERY with empty array +==== +This example tests the EVERY operator with an empty array. + +[source,sqlpp] +---- +SELECT EVERY v IN [] SATISFIES v = "abc" END AS universal; +---- + +In this case, the operator returns `true`. + +.Results +[source,json] +---- +[ + { + "universal": true + } +] +---- +==== + +[#any-and-every] +=== ANY AND EVERY + +`ANY AND EVERY` tests whether every element in an array matches a specified condition. +(If the array is empty, then no element in the array is deemed to match the condition.) + +Synonym: `SOME AND EVERY` is a synonym for `ANY AND EVERY`. + +==== Return Values + +If the array is non-empty and every element in the array matches the specified condition, then the operator returns `TRUE`; otherwise, it returns `FALSE`. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[AnyAndEveryEx]] +.ANY AND EVERY with empty array +==== +This example tests the ANY AND EVERY operator with an empty array. + +[source,sqlpp] +---- +SELECT ANY AND EVERY v IN [] SATISFIES v = "abc" END AS universal; +---- + +In this case, the operator returns `false`. + +.Results +[source,json] +---- +[ + { + "universal": false + } +] +---- +==== + +[[range-xform]] +== Range Transformations + +Range transformations (<>, <>, and <>) enable you to map and filter elements and attributes from an input array. +They use the `IN` and `WITHIN` operators to range through the array. + +[discrete] +==== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=range-xform] +---- + +image::n1ql-language-reference/range-xform.png["Syntax diagram", align=left] + +[source#range-xform-binding,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=range] +---- + +image::n1ql-language-reference/range.png["Syntax diagram", align=left] + +[discrete] +==== Arguments + +name-expr:: [`OBJECT` only] An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that resolves to a string, to use as the name of an attribute in the output. +This expression may make use of the `var` and `name-var` identifiers as required. + +var-expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that returns a value to include in the output. +This expression may make use of the `var` and `name-var` identifiers as required. + +name-var:: [Optional] An xref:n1ql-language-reference/identifiers.adoc[identifier] that represents the position of a single element in an array, counting from 0. + +var:: An xref:n1ql-language-reference/identifiers.adoc[identifier] that represents a single element in an array. + +expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that returns an array to evaluate. + +cond:: [Optional] A condition to evaluate for each specified element. +This condition may make use of the `var` and `name-var` identifiers as required. + +[#array] +=== ARRAY + +The `ARRAY` operator generates a new array, using values in the input array. + +==== Return Values + +The operator returns a new array, which contains one element for each element in the input array. +If the `WHEN` clause is specified, only elements in the input array which satisfy the `WHEN` clause are considered. + +The value of each element in the output array is the output of the `var-expr` argument for one element in the input array. + +If the input array is empty, or no elements in the input array satisfy the `WHEN` clause, the operator returns an empty array. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ArrayEx1a]] +.ARRAY with array of objects +==== +List the details of KL flights from Albuquerque to Atlanta on Fridays. + +[source,sqlpp] +---- +SELECT ARRAY v FOR v IN schedule WHEN v.day = 5 END AS fri_flights +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- + +.Results +[source,json] +---- +[ + { + "fri_flights": [ + { + "day": 5, + "flight": "KL347", + "utc": "08:51:00" + }, + { + "day": 5, + "flight": "KL281", + "utc": "06:26:00" + }, + { + "day": 5, + "flight": "KL567", + "utc": "03:54:00" + }, + { + "day": 5, + "flight": "KL169", + "utc": "23:41:00" + } + ] + } +] +---- + +Compare this with the results of <> and <>. +==== + +[[ArrayEx1b]] +.ARRAY with multiple range terms +==== +List the details of KL flights from Albuquerque to Atlanta on Fridays after 7pm only. + +[source,sqlpp] +---- +SELECT ARRAY v + FOR v IN schedule, w IN schedule WHEN v.utc > "19:00" AND w.day = 5 END + AS fri_evening_flights +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- + +.Results +[source,json] +---- +[ + { + "fri_evening_flights": [ + { + "day": 5, + "flight": "KL169", + "utc": "23:41:00" + } + ] + } +] +---- + +The same results can be reached by writing the query as follows: + +[source,sqlpp] +---- +SELECT ARRAY v + FOR v IN schedule WHEN v.utc > "19:00" AND v.day = 5 END + AS fri_evening_flights +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- +==== + +[[ArrayEx0b]] +.ARRAY with position variable +==== +List the first two KL flights from Albuquerque to Atlanta. +This example uses the position variable `i` to return just the first two elements in the input array. + +[source,sqlpp] +---- +SELECT ARRAY v FOR i:v IN schedule WHEN i < 2 END AS two_flights +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- + +.Results +[source,json] +---- +[ + { + "two_flights": [ + { + "day": 0, + "flight": "KL938", + "utc": "03:54:00" + }, + { + "day": 0, + "flight": "KL270", + "utc": "16:57:00" + } + ] + } +] +---- + +Refer to <> for another example with position variables. +==== + +[#first] +=== FIRST + +The `FIRST` operator generates a new value, using a single value in the input array. + +==== Return Values + +The operator returns the output of the `var-expr` argument for the first element in the input array. +If the `WHEN` clause is specified, only elements in the input array which satisfy the `WHEN` clause are considered. + +If the input array is empty, or no elements in the input array satisfy the `WHEN` clause, the operator returns MISSING. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[FirstEx]] +.FIRST +==== +List the first KL flight from Albuquerque to Atlanta after 7pm. + +[source,sqlpp] +---- +SELECT FIRST v FOR v IN schedule WHEN v.utc > "19:00" END AS first_flight +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- + +.Results +[source,json] +---- +[ + { + "first_flight": [ + { + "day": 1, + "flight": "KL672", + "utc": "19:19:00" + } + ] + } +] +---- + +Compare this with the results of <> and <>. +==== + +[#object] +=== OBJECT + +The `OBJECT` operator generates a new object, using values in the input array. + +==== Return Values + +The operator returns an object, which contains one attribute for each element in the input array. +If the `WHEN` clause is specified, only elements in the input array which satisfy the `WHEN` clause are considered. + +The value of each attribute in the output object is the output of the `var-expr` argument for one element in the input array. + +The name of each attribute in the output object is specified by the `name-expr` argument. +This argument must be an expression that generates a unique name string for every value in the output object. +If the expression does not generate a string, then the current attribute is not output. +If the expression does not generate a unique name string for each value, then only the last attribute is output; all previous attributes are suppressed. + +The `name-expr` argument may reference the `var` argument or the `name-var` argument, or use any other expression that generates a unique value. + +If the input array is empty, or no elements in the input array satisfy the `WHEN` clause, the operator returns an empty object. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ObjectExA]] +.OBJECT with array of objects +==== +List the details of KL flights from Albuquerque to Atlanta on Fridays. +This example uses the xref:n1ql:n1ql-language-reference/metafun.adoc#uuid[UUID()] function to generate a unique name for each attribute in the output object. + +[source,sqlpp] +---- +SELECT OBJECT UUID():v FOR v IN schedule WHEN v.day = 5 END AS fri_flights +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- + +.Results +[source,json] +---- +[ + { + "fri_flights": { + "14c040c6-2247-442f-bc27-0d7b3ff403b5": { + "day": 5, + "flight": "KL169", + "utc": "23:41:00" + }, + "645a53d6-53a2-4c0c-9431-75073c48806b": { + "day": 5, + "flight": "KL281", + "utc": "06:26:00" + }, + "6d93a43f-ecec-4e9d-89bf-2468f2771fa0": { + "day": 5, + "flight": "KL567", + "utc": "03:54:00" + }, + "f2823bc0-86e0-4a1a-a9d8-4ca496de8193": { + "day": 5, + "flight": "KL347", + "utc": "08:51:00" + } + } + } +] +---- + +Compare this with the results of <> and <>. +==== + +[[ObjectExB]] +.OBJECT with position variable +==== +An alternative version of <>. +This example uses the xref:n1ql:n1ql-language-reference/typefun.adoc#tostring[TOSTRING()] function and the position variable `i` to generate a unique name for each attribute in the output object. + +[source,sqlpp] +---- +SELECT OBJECT "num_" || TOSTRING(i):v + FOR i:v IN schedule WHEN v.day = 5 END + AS fri_flights +FROM route +WHERE airline="KL" + AND sourceairport="ABQ" + AND destinationairport="ATL"; +---- + +Notice that the position of each element in the input array is calculated _before_ applying the `WHEN` condition -- so the Friday flights are numbered from 14 to 17. + +.Results +[source,json] +---- +[ + { + "fri_flights": { + "num_14": { + "day": 5, + "flight": "KL347", + "utc": "08:51:00" + }, + "num_15": { + "day": 5, + "flight": "KL281", + "utc": "06:26:00" + }, + "num_16": { + "day": 5, + "flight": "KL567", + "utc": "03:54:00" + }, + "num_17": { + "day": 5, + "flight": "KL169", + "utc": "23:41:00" + } + } + } +] +---- + +Refer to <> for another example with position variables. +==== + +[[membership-and-existence-tests,Membership and Existence Tests]] +== Membership and Existence + +Membership tests (<> and <>) enable you to test whether a value exists within an array. +Membership tests are efficient over arrays with a large number of elements -- up to approximately 8000. + +The existence test (<>) enables you to test whether an array contains any elements at all. + +[#collection-op-in] +=== IN + +The `IN` operator specifies the search depth to include only the current level of an array, and not to include any child or descendant arrays. + +==== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=in-expr] +---- + +image::n1ql-language-reference/in-expr.png["Syntax diagram", align=left] + +==== Arguments + +earch-expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that returns the value to search for. + +target-expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that resolves to the array to search through. + +==== Return Values + +The `IN` operator evaluates to `TRUE` if the right-side value is an array and directly contains the left-side value. + +The `NOT IN` operator evaluates to `TRUE` if the right-side value is an array and does not directly contain the left-side value. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[InExA]] +.IN with simple array +==== +Search for all airlines from the United Kingdom or France. + +[source,sqlpp] +---- +SELECT * FROM airline AS t +WHERE country IN ["United Kingdom", "France"]; +---- + +This results in 60 documents: + +.Results +[source,json] +---- +[ + { + "t": { + "callsign": "CORSAIR", + "country": "France", + "iata": "SS", + "icao": "CRL", + "id": 1908, + "name": "Corsairfly", + "type": "airline" + } + }, +// ... +] +---- +==== + +[[InExB]] +.IN with array of objects +==== +Search for the author "Walton Wolf" in the hotel keyspace. + +[source,sqlpp] +---- +SELECT * FROM hotel AS t WHERE "Walton Wolf" IN t; +---- + +This results in an empty set because authors are not in the current level (the root level) of the hotel keyspace. + +.Results +[source,json] +---- +[] +---- + +The authors are listed inside the `reviews` array (a child element) and would need the `WITHIN` keyword to search all child elements along with the root level. +==== + +[#collection-op-within] +=== WITHIN + +The `WITHIN` operator specifies the search depth to include the current level of an array, and all of its child and descendant arrays. + +==== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=within-expr] +---- + +image::n1ql-language-reference/within-expr.png["Syntax diagram", align=left] + +==== Arguments + +search-expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that returns the value to search for. + +target-expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that resolves to the array to search through. + +==== Return Values + +The `WITHIN` operator evaluates to `TRUE` if the right-side value is an array and contains the left-side value as a child or descendant, that is, directly or indirectly. + +The `NOT WITHIN` operator evaluates to `TRUE` if the right-side value is an array and no child or descendant contains the left-side value. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[WithinEx]] +.WITHIN +==== +Search all elements for the author "Walton Wolf" in the hotel documents. + +[source,sqlpp] +---- +SELECT * FROM hotel AS t WHERE "Walton Wolf" WITHIN t; +---- + +This results in 1 document since his name appears inside the `reviews` array. + +.Results +[source,json] +---- +[ + { + "t": { + "address": "Gilsland, CA8 7DA", + "alias": null, + "checkin": null, + "checkout": null, + "city": null, + "country": "United Kingdom", + "description": "Tantallon House offers accommodation around 10 minutes walk from the National Trail. It also has a holiday cottage.", + "directions": null, + "email": null, + "fax": null, + "free_breakfast": true, + "free_internet": true, + "free_parking": false, + "geo": { + "accuracy": "ROOFTOP", + "lat": 54.99304, + "lon": -2.58142 + }, + "id": 10851, + "name": "Tantallon House B&B", + "pets_ok": true, + "phone": null, + "price": "From £44 (no cards)", + "public_likes": [ + "Victor Russel" + ], + "reviews": [ + { + "author": "Walton Wolf", +// ... + } + ], + "state": null, + "title": "Hadrian's Wall", + "tollfree": null, + "type": "hotel", + "url": "http://www.tantallonhouse.co.uk/", + "vacancy": false + } + } +] +---- +==== + +[#exists] +=== EXISTS + +The `EXISTS` operator enables you to test whether an array has any elements, or is empty. + +This operator may be used in a `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statement in combination with a subquery. +The condition is met if the subquery returns at least one result. + +==== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=exists-expr] +---- + +image::n1ql-language-reference/exists-expr.png["Syntax diagram", align=left] + +==== Arguments + +expr:: An xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expression] that returns an array. + +==== Return Values + +If the expression is an array which contains at least one element, the operator evaluates to `TRUE`; otherwise, it evaluates to `FALSE`. + +==== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ExistsEx]] +.EXISTS +==== +Of the 274 cities with a hotel, search for all cities that have hotels with reviews. + +[source,sqlpp] +---- +SELECT DISTINCT h.city +FROM hotel AS h +WHERE EXISTS h.reviews; +---- + +This results in 255 cities that contain hotels with reviews. + +.Results +[source,json] +---- +[ + { + "city": "Medway" + }, + { + "city": "Giverny" + }, + { + "city": "Glasgow" + }, + { + "city": "Highland" + }, +//... +] +---- +==== + +== Related Links + +Refer to xref:n1ql:n1ql-language-reference/constructionops.adoc[Construction Operators] for a simpler way to generate arrays and objects from a data source. diff --git a/modules/n1ql/pages/n1ql-language-reference/comma.adoc b/modules/n1ql/pages/n1ql-language-reference/comma.adoc new file mode 100644 index 000000000..8fa62d243 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/comma.adoc @@ -0,0 +1,534 @@ += Comma-Separated Join +:description: A comma-separated join enables you to produce new input objects by creating a Cartesian product of all the source objects. +:imagesdir: ../../assets/images +:page-topic-type: reference +:from-term: comma-separated join + +// Cross-references +:from: xref:n1ql-language-reference/from.adoc +:from-keyspace: {from}#from-keyspace-ref +:as-alias: {from}#section_ax5_2nx_1db +:from-subquery: {from}#select-expr-clause +:join: xref:n1ql-language-reference/join.adoc +:use-clause: {join}#ansi-join-hints +:where: xref:n1ql-language-reference/where.adoc +:hints: xref:n1ql-language-reference/optimizer-hints.adoc +:expr: xref:n1ql-language-reference/index.adoc#N1QL_Expressions +:authorization: xref:server:learn:security/authorization-overview.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +A comma-separated join is used within the {from}[FROM] clause. +Like the {join}[JOIN] clause, it creates an input object by combining two or more source objects. +A comma-separated join can combine arbitrary fields from the source documents, and you can chain several comma-separated joins together. + +(((join predicate,comma-separated join))) +The comma-separated join, by itself, does not specify a join predicate. +This means that, in its basic form, the comma-separated join would produce all the possible combinations of the combined source objects -- this is known as the _Cartesian product_. + +In practice, it is common to use the query's {where}[WHERE] clause to specify a condition for the comma-separated join. +Refer to the examples below for further details. + +== Prerequisites + +For you to select data from keyspace or expression, you must have the [.param]`query_select` privilege on that keyspace. +For more details about user roles, see {authorization}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=comma-separated-join] +---- + +image::n1ql-language-reference/comma-separated-join.png["Syntax diagram", align=left] + +[horizontal.compact] +rhs-keyspace:: <> icon:caret-down[] +rhs-subquery:: <> icon:caret-down[] +rhs-generic:: <> icon:caret-down[] + +[#from-term] +include::partial$n1ql-language-reference/from-term.adoc[] + +(((join type,comma-separated join))) +The comma-separated join is a type of inner join. +For each joined object produced, both the left-hand side and right-hand side source objects must be non-MISSING and non-NULL. + +(((right-hand side,comma-separated join))) +The _right-hand side_ of a comma-separated join may be a keyspace reference, a subquery, or a generic expression term. + +[#comma-join-lateral] +=== LATERAL Join + +When an expression on the right-hand side of a comma-separated join references a keyspace that is already specified in the same FROM clause, the expression is said to be correlated. +In relational databases, a join which contains correlated expressions is referred to as a lateral join. +In {sqlpp}, lateral correlations are detected automatically, and there is no need to specify that a join is lateral. + +In clusters using Couchbase Server 7.6 and later, you can use the LATERAL keyword as a visual reminder that a join contains correlated expressions. +The LATERAL keyword is not required -- the keyword is included solely for compatibility with queries from relational databases. + +If you use the LATERAL keyword in a join that has no lateral correlation, the keyword is ignored. + +You can use the optional LATERAL keyword in front of the right-hand side keyspace of a comma-separated join. + +NOTE: Using the LATERAL keyword in a comma-separated join implies that the right-hand side of the join must appear after the left-hand side of the join. This may prevent the cost-based optimizer from reordering joins in the query to give the optimal join order. For details, see xref:n1ql:n1ql-language-reference/cost-based-optimizer.adoc#join-enumeration[Join Enumeration]. + +[[rhs-keyspace]] +=== Right-Hand Side Keyspace + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=rhs-keyspace] +---- + +image::n1ql-language-reference/rhs-keyspace.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] +ansi-join-hints:: <> icon:caret-down[] + +[#rhs-keyspace-ref] +==== Keyspace Reference + +Keyspace reference for the right-hand side of the comma-separated join. +For details, see {from-keyspace}[Keyspace Reference]. + +[#rhs-keyspace-alias] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, see {as-alias}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#rhs-keyspace-hints] +==== USE Clause + +Enables you to specify that the join should use particular keys, a particular index, or a particular join method. +For details, see {use-clause}[ANSI JOIN Hints]. + +TIP: You can also supply a join hint within a specially-formatted {hints}[hint comment]. +Note that you cannot specify a join hint for the same keyspace using both the `USE` clause and a hint comment. +If you do this, the `USE` clause and the hint comment are both marked as erroneous and ignored by the optimizer. + +[[rhs-subquery]] +=== Right-Hand Side Subquery + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=rhs-subquery] +---- + +image::n1ql-language-reference/rhs-subquery.png["Syntax diagram", align=left] + +[horizontal.compact] +subquery-expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#ansi-subquery-expr] +==== Subquery Expression + +Use parentheses to specify a subquery for the right-hand side of the comma-separated join. +For details, see {from-subquery}[Subquery Expression]. + +NOTE: A subquery on the right-hand side of the comma-separated join cannot be *correlated*, i.e. it cannot refer to a keyspace in the outer query block. +This will lead to an error. + +[#ansi-subquery-alias] +==== AS Alias + +Assigns another name to the subquery. +For details, see {as-alias}[AS Clause]. + +You must assign an alias to a subquery on the right-hand side of the join. +However, when you assign an alias to the subquery, the `AS` keyword may be omitted. + +[[rhs-generic]] +=== Right-Hand Side Generic Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=rhs-generic] +---- + +image::n1ql-language-reference/rhs-generic.png["Syntax diagram", align=left] + +[horizontal.compact] +expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#ansi-generic-expr] +==== Expression Term + +A {sqlpp} {expr}[expression] generating JSON documents or objects for the right-hand side of the comma-separated join. + +NOTE: An expression on the right-hand side of the comma-separated join may be *correlated*, i.e. it may refer to a keyspace on the left-hand side of the join. +In this case, only a <> may be used. + +[#ansi-generic-alias] +==== AS Alias + +Assigns another name to the generic expression. +For details, see {as-alias}[AS Clause]. + +You must assign an alias to the generic expression if it is not an identifier; otherwise, assigning an alias is optional. +However, when you assign an alias to the generic expression, the `AS` keyword may be omitted. + +== Limitations + +* You can chain comma-separated joins with ANSI `JOIN` clauses, ANSI `NEST` clauses, and `UNNEST` clauses. +However, you cannot chain comma-separated joins with lookup `JOIN` and `NEST` clauses, or index `JOIN` and `NEST` clauses. + +* The right-hand side of a comma-separated join can only be a keyspace identifier, a subquery, or a generic expression. +This means that comma-separated joins must come _after_ any `JOIN`, `NEST`, or `UNNEST` clauses. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#example-cartesian] +.Cartesian product +==== +The following query lists every possible combination of the two input objects. + +.Comma-separated join +[source,sqlpp] +---- +SELECT * FROM [{"abc": 1}, {"abc": 2}, {"abc": 3}] AS a, + [{"xyz": 1}, {"xyz": 2}] AS b; +---- + +Compare the query above with the following query using an ANSI join. + +.ANSI join +[source,sqlpp] +---- +SELECT * FROM [{"abc": 1}, {"abc": 2}, {"abc": 3}] AS a + JOIN [{"xyz": 1}, {"xyz": 2}] AS b ON true; +---- + +The results of the two queries are the same. + +.Results +[source,json] +---- +[ + { + "a": { + "abc": 1 + }, + "b": { + "xyz": 1 + } + }, + { + "a": { + "abc": 1 + }, + "b": { + "xyz": 2 + } + }, + { + "a": { + "abc": 2 + }, + "b": { + "xyz": 1 + } + }, + { + "a": { + "abc": 2 + }, + "b": { + "xyz": 2 + } + }, + { + "a": { + "abc": 3 + }, + "b": { + "xyz": 1 + } + }, + { + "a": { + "abc": 3 + }, + "b": { + "xyz": 2 + } + } +] +---- +==== + +[#example-condition] +.Comma-separated join condition +==== +The following query uses the WHERE clause to define the condition for a comma-separated join. + +.Comma-separated join +[source,sqlpp] +---- +SELECT a.airportname AS airport, r.id AS route +FROM route AS r, + airport AS a +WHERE a.faa = r.sourceairport +LIMIT 4; +---- + +Compare the query above with the following query using an ANSI join. + +.ANSI join +[source,sqlpp] +---- +SELECT a.airportname AS airport, r.id AS route +FROM route AS r +JOIN airport AS a + ON a.faa = r.sourceairport +LIMIT 4; +---- + +The results of the two queries are the same. + +.Results +[source,json] +---- +[ + { + "airport": "Lehigh Valley Intl", + "route": 20010 + }, + { + "airport": "Lehigh Valley Intl", + "route": 20011 + }, + { + "airport": "Lehigh Valley Intl", + "route": 28856 + }, + { + "airport": "Lehigh Valley Intl", + "route": 28857 + } +] +---- +==== + +[#example-filters] +.Comma-separated join with filters +==== +The following query uses the WHERE clause to define a condition for a comma-separated join and to filter the query. + +.Comma-separated join +[source,sqlpp] +---- +SELECT a.airportname AS airport, r.id AS route +FROM route AS r, + airport AS a +WHERE a.faa = r.sourceairport + AND r.sourceairport = "SFO" +LIMIT 4; +---- + +Compare the query above with the following query using an ANSI join. + +.ANSI join +[source,sqlpp] +---- +SELECT a.airportname AS airport, r.id AS route +FROM route AS r +JOIN airport AS a + ON a.faa = r.sourceairport +WHERE r.sourceairport = "SFO" +LIMIT 4; +---- + +The results of the two queries are the same. + +.Results +[source,json] +---- +[ + { + "airport": "San Francisco Intl", + "route": 10624 + }, + { + "airport": "San Francisco Intl", + "route": 10625 + }, + { + "airport": "San Francisco Intl", + "route": 11212 + }, + { + "airport": "San Francisco Intl", + "route": 11213 + } +] +---- +==== + +[#example-hints] +.Comma-separated join with hints +==== +The following query uses the USE clause to specify hints for a comma-separated join. + +.Comma-separated join +[source,sqlpp] +---- +EXPLAIN SELECT a.airportname AS airport, r.id AS route +FROM route AS r, + airport AS a + USE INDEX(def_inventory_airport_faa) NL +WHERE a.faa = r.sourceairport + AND r.sourceairport = "SFO" +LIMIT 4; +---- + +Compare the query above with the following query using an ANSI join. + +.ANSI join +[source,sqlpp] +---- +EXPLAIN SELECT a.airportname AS airport, r.id AS route +FROM route AS r +JOIN airport AS a + USE INDEX(def_inventory_airport_faa) NL + ON a.faa = r.sourceairport +WHERE r.sourceairport = "SFO" +LIMIT 4; +---- + +The results of the two queries are the same. + +.Results +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "USE_NL(a)", + "INDEX(a def_inventory_airport_faa)" + ] + }, + // ... + } +] +---- +==== + +[#example-chain] +.Chaining ANSI joins with comma-separated joins +==== +The following query chains an ANSI join with a comma-separated join. + +.Query +[source,sqlpp] +---- +SELECT l.name AS airline, a.airportname AS airport, r.id AS route +FROM airline AS l +JOIN route AS r + ON META(l).id = r.airlineid, + airport AS a +WHERE a.faa = r.sourceairport + AND r.sourceairport = "SFO" +LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "airline": "AirTran Airways", + "airport": "San Francisco Intl", + "route": 25480 + }, + { + "airline": "AirTran Airways", + "airport": "San Francisco Intl", + "route": 25481 + }, + { + "airline": "AirTran Airways", + "airport": "San Francisco Intl", + "route": 25482 + }, + { + "airline": "AirTran Airways", + "airport": "San Francisco Intl", + "route": 25483 + } +] +---- +==== + +[#example-lateral] +.Lateral correlation +==== +The following query has a lateral correlation between the subquery and the `airport` keyspace. + +.Comma-separated join +[source,sqlpp] +---- +SELECT airport.airportname, t2.name +FROM airport, +(SELECT name FROM hotel WHERE hotel.city = airport.city) AS t2 +LIMIT 5; +---- + +Compare the query above with the following query using the LATERAL keyword. + +.Comma-separated join with LATERAL keyword +[source,sqlpp] +---- +SELECT airport.airportname, t2.name +FROM airport, +LATERAL (SELECT name FROM hotel WHERE hotel.city = airport.city) AS t2 +LIMIT 5; +---- + +The results of the two queries are the same. + +.Results +[source,json] +---- +[ + { + "airportname": "Mandelieu", + "name": "Hotel Cybelle" + }, + { + "airportname": "Cote D\\'Azur", + "name": "Best Western Hotel Riviera Nice" + }, + { + "airportname": "Cote D\\'Azur", + "name": "Hotel Anis" + }, + { + "airportname": "Cote D\\'Azur", + "name": "NH Nice" + }, + { + "airportname": "Cote D\\'Azur", + "name": "Hotel Suisse" + } +] +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/commit-transaction.adoc b/modules/n1ql/pages/n1ql-language-reference/commit-transaction.adoc new file mode 100644 index 000000000..e43df2e7c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/commit-transaction.adoc @@ -0,0 +1,115 @@ += COMMIT TRANSACTION +:description: The COMMIT TRANSACTION statement enables you to commit a transaction. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:durability: xref:server:learn:data/durability.adoc +:edit-bucket: xref:server:manage:manage-buckets/edit-bucket.adoc +:durability_level: xref:n1ql:n1ql-manage/query-settings.adoc#durability_level +:transactions: xref:n1ql:n1ql-language-reference/transactions.adoc +:preparation: xref:n1ql:n1ql-language-reference/transactions.adoc#preparation + +// Related links +:overview: xref:server:learn:data/transactions.adoc +:begin-transaction: xref:n1ql-language-reference/begin-transaction.adoc +:set-transaction: xref:n1ql-language-reference/set-transaction.adoc +:savepoint: xref:n1ql-language-reference/savepoint.adoc +:commit-transaction: xref:n1ql-language-reference/commit-transaction.adoc +:rollback-transaction: xref:n1ql-language-reference/rollback-transaction.adoc + +[abstract] +{description} + +== Purpose + +The `COMMIT TRANSACTION` statement enables you to commit an ACID transaction. +Refer to {transactions}[{sqlpp} Support for Couchbase Transactions] for further information. + +ifdef::flag-devex-rest-api[] +include::partial$n1ql-language-reference/transaction-id.adoc[] +endif::flag-devex-rest-api[] + +This statement removes all savepoints within the transaction. + +NOTE: If you are using the cbq shell, and a transaction fails for any reason, you must use the `ROLLBACK TRANSACTION` statement to remove the transaction context and reset the transaction ID. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/tcl.ebnf[tag=commit-transaction] +---- + +image::n1ql-language-reference/commit-transaction.png["Syntax diagram: refer to source code listing", align=left] + +The `WORK`, `TRAN`, and `TRANSACTION` keywords are synonyms. +These keywords are optional; you may include one of these keywords, or omit them entirely. + +== Usage + +The transaction can only be committed if the transactional {durability}[durability] requirements can be met. +The transaction durability level is set by the request-level {durability_level}[durability_level] parameter. + +If transaction durability requirements cannot be met, then a 161 error code is generated when you attempt to commit the transaction, with the message "Durability requirements are impossible to achieve". +For example: bucket replication is specified, but there are not enough Data nodes available on which to store the specified number of replicas at the requested durability level. + +To avoid this error, it is recommended that you add the correct number of Data nodes for the required durability level, and rebalance. +As a temporary measure, you can set the request-level {durability_level}[durability_level] parameter to `"none"` to turn off durability for this request, or {edit-bucket}[turn off bucket replication]. + +== Examples + +If you want to try these examples, first refer to {preparation}[Preparation] to set up your environment. + +[[ex-1]] +.Commit a transaction +==== +// Line highlighting doesn't work with highlight.js. +// Markup for future use [source,n1ql,highlight=90..92] + +.Transaction +[source,sqlpp,subs=macros] +---- +include::example$transactions/multiple.n1ql[tags=transaction;commit-mark;!begin-mark;!set-mark;!savepoint-mark;!rollback-mark;!commit-plain] +---- + +.Results +[source,json] +---- +include::example$transactions/results.jsonc[tags=!ellipsis] +---- + +<.> Beginning a transaction returns a transaction ID. +<.> Before setting the second savepoint, the booking document has user `"0"`, name `"Keon Hoppe"`. +<.> After setting the second savepoint and performing an update, the booking document has user `"1"`, name `"Rigoberto Bernier"`. +<.> After rolling back to the second savepoint, the booking document again has user `"0"`, name `"Keon Hoppe"`. +==== + +[[ex-2]] +.Check the result of <> +==== +Check the result of committing the transaction. + +.Query +[source,sqlpp] +---- +include::example$transactions/multiple.n1ql[tag=check-3] +---- + +.Results +[source,json,indent=0] +---- +include::example$transactions/results.jsonc[tag=check-3] +---- + +<.> The booking document has been added with the attributes that were present when the transaction was committed. +==== + +== Related Links + +* For an overview of Couchbase transactions, refer to {overview}[Transactions]. +* To begin a transaction, refer to {begin-transaction}[BEGIN TRANSACTION]. +* To specify transaction settings, refer to {set-transaction}[SET TRANSACTION]. +* To set a savepoint, refer to {savepoint}[SAVEPOINT]. +* To rollback a transaction, refer to {rollback-transaction}[ROLLBACK TRANSACTION]. +* Blog post: https://blog.couchbase.com/transactions-n1ql-couchbase-distributed-nosql/[Couchbase Transactions: Elastic, Scalable, and Distributed^]. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/comparisonfun.adoc b/modules/n1ql/pages/n1ql-language-reference/comparisonfun.adoc new file mode 100644 index 000000000..91715fade --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/comparisonfun.adoc @@ -0,0 +1,13 @@ += Comparison Functions +:description: Comparison functions determine the greatest or least value from a set of values. +:page-topic-type: reference + +{description} + +GREATEST(expression1, expression2, \...) + +Largest non-NULL, non-MISSING value if the values are of the same type; otherwise NULL. + +LEAST(expression1, expression2, \...) + +Returns smallest non-NULL, non-MISSING value if the values are of the same type, otherwise returns NULL. diff --git a/modules/n1ql/pages/n1ql-language-reference/comparisonops.adoc b/modules/n1ql/pages/n1ql-language-reference/comparisonops.adoc new file mode 100644 index 000000000..33504cc9c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/comparisonops.adoc @@ -0,0 +1,223 @@ += Comparison Operators +:description: Comparison operators enable you to compare expressions. +:page-topic-type: reference +:imagesdir: ../../assets/images + +{description} + +The following tables describe each comparison operator and its return values. + +== Relational Operators + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=relational-expr] +---- + +image::n1ql-language-reference/relational-expr.png["Syntax diagram", align=left] + +[cols="100,326,213"] +|=== +| Operator | Description | Returns + +| = +| Equal to. +Functionally equivalent to == for compatibility with other languages. +| TRUE or FALSE + +| == +| Equal to. +Functionally equivalent to = for compatibility with other languages. +| TRUE or FALSE + +| != +| Not equal to. +Functionally equivalent to <> for compatibility with other languages. +| TRUE or FALSE + +| <> +| Not equal to. +Functionally equivalent to != for compatibility with other languages. +| TRUE or FALSE + +| > +| Greater than. +| TRUE or FALSE + +| >= +| Greater than or equal to. +| TRUE or FALSE + +| < +| Less than. +| TRUE or FALSE + +| \<= +| Less than or equal to. +| TRUE or FALSE +|=== + +== BETWEEN + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=between-expr] +---- + +image::n1ql-language-reference/between-expr.png["Syntax diagram", align=left] + +[cols="100,326,213"] +|=== +| Operator | Description | Returns + +| BETWEEN +| Search criteria for a query where the value is between two values, including the end values specified in the range. +Values can be numbers, text, or dates. +| TRUE or FALSE + +| NOT BETWEEN +| Search criteria for a query where the value is outside the range of two values, including the end values specified in the range. +Values can be numbers, text, or dates. +| TRUE or FALSE +|=== + +== LIKE + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=like-expr] +---- + +image::n1ql-language-reference/like-expr.png["Syntax diagram", align=left] + +[cols="100,326,213"] +|=== +| Operator | Description | Returns + +| LIKE +| Match string with a wildcard expression. +Use % for zero or more wildcards and _ to match any character at this place in a string. + +The wildcard characters can be escaped by preceding them with a backslash (\). +Backslash itself can also be escaped by preceding it with another backslash. +| TRUE or FALSE + +| NOT LIKE +| Inverse of LIKE. +Return TRUE if string is not similar to given string. +| TRUE or FALSE +|=== + +== IS + +The IS family of operators lets you specify conditions based on the existence (or absence) of attributes in a data set. + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=is-expr] +---- + +image::n1ql-language-reference/is-expr.png["Syntax diagram", align=left] + +[cols="100,326,213"] +|=== +| Operator | Description | Returns + +| IS NULL +| Field has value of NULL. +| TRUE or FALSE + +| IS NOT NULL +| Field has value or is missing. +| TRUE or FALSE + +| IS MISSING +| No value for field found. +| TRUE or FALSE + +| IS NOT MISSING +| Value for field found or value is NULL. +| TRUE or FALSE + +| IS VALUED +| Value for field found. +Value is neither missing nor NULL +| TRUE or FALSE + +| IS NOT VALUED +| Value for field not found. +Value is NULL. +| TRUE or FALSE +|=== + +.IS NULL +==== +.Query +[source,sqlpp] +---- + SELECT fname, children + FROM tutorial + WHERE children IS NULL +---- + +.Returns +[source,json] +---- +{ + "results": [ + { + "children": null, + "fname": "Fred" + } + ] +} +---- +==== + +.IS MISSING +==== +.Query +[source,sqlpp] +---- + SELECT fname, children + FROM tutorial + WHERE children IS MISSING +---- + +.Returns +[source,json] +---- + { + "results": [ + { + "fname": "Harry" + }, + { + "fname": "Jane" + } + ] +} +---- +==== + +== Comparison of Data Types + +=== Strings + +String comparison is done using a raw-byte collation of UTF-8 encoded strings -- sometimes referred to as binary, C, or memcmp. +This collation is case sensitive. +Case-insensitive comparisons can be performed using the UPPER() or LOWER() functions. +See xref:n1ql-language-reference/stringfun.adoc[String Functions] for more information. + +=== Arrays and Objects + +Arrays are compared element-wise. +Objects are first compared by length; objects of equal length are compared pairwise, with the pairs sorted by name. + +=== NULL and MISSING + +Except when using the IS family of operators, comparison of the MISSING or NULL data types produces the following results. + +* If either operand in a comparison is MISSING, the result is MISSING. +* If either operand in a comparison is NULL, the result is NULL. +* If either operand is MISSING or NULL, the result is MISSING or NULL. diff --git a/modules/n1ql/pages/n1ql-language-reference/condfunnum.adoc b/modules/n1ql/pages/n1ql-language-reference/condfunnum.adoc new file mode 100644 index 000000000..8b3c9a4aa --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/condfunnum.adoc @@ -0,0 +1,35 @@ += Conditional Functions for Numbers +:description: Conditional functions evaluate expressions to determine if the values and formulas meet the specified condition. +:page-topic-type: reference + +{description} + +IFINF(expression1, expression2, \...) + +Returns first non-MISSING, non-Inf number. +Returns MISSING or NULL if a non-number input is encountered first. + +IFNAN(expression1, expression2, \...) + +Returns first non-MISSING, non-NaN number. +Returns MISSING or NULL if a non-number input is encountered first. + +IFNANORINF(expression1, expression2, \...) + +Returns first non-MISSING, non-Inf, or non-NaN number. +Returns MISSING or NULL if a non-number input is encountered first. + +NANIF(expression1, expression2) + +Returns NaN if expression1 = expression2, otherwise returns expression1. +Returns MISSING or NULL if either input is MISSING or NULL. + +NEGINFIF(expression1, expression2) + +Returns NegInf if expression1 = expression2, otherwise returns expression1. +Returns MISSING or NULL if either input is MISSING or NULL. + +POSINFIF(expression1, expression2) + +Returns PosInf if expression1 = expression2, otherwise returns expression1. +Returns MISSING or NULL if either input is MISSING or NULL. diff --git a/modules/n1ql/pages/n1ql-language-reference/condfununknown.adoc b/modules/n1ql/pages/n1ql-language-reference/condfununknown.adoc new file mode 100644 index 000000000..c2256f669 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/condfununknown.adoc @@ -0,0 +1,351 @@ += Conditional Functions for Unknowns +:page-topic-type: reference +:example-caption!: +:description: Conditional functions evaluate expressions to determine if the values and formulas meet the specified condition. + +{description} + +[[coalesce,COALESCE()]] +== COALESCE(`expression1`, `expression2`, \...) + +Alias for <>. + +[[decode,DECODE()]] +== DECODE(`expression`, `search1`, `result1` [, `search2`, `result2`, \...] [, `default`]) + +=== Arguments + +expression:: [Required] Any valid expression. +search1, search2, \...:: [At least 1 is required] Any values. +result1, result2, \...:: [At least 1 is required] Any values. +default:: [Optional] Any value. + +The function requires a minimum of three arguments. +The first argument is the _expression_. +This is followed by one or more pairs of _search_ and _result_ arguments. +If there is an even number of arguments, the last argument is the _default_ argument. +If there is an odd number of arguments, the _default_ is not specified. + +=== Return Value +Returns the _result_ corresponding to the first _search_ that matches the _expression_. +If none of the _search_ values match the _expression_, the function returns the value of _default_, or returns NULL if _default_ is not specified. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +Find the UTC offset of all airports in the United States whose altitude is greater than 1000: + +[source,sqlpp] +---- +SELECT a.airportname AS Airport, +DECODE(a.tz, "Pacific/Honolulu", "-10:00", + "America/Anchorage", "-09:00", + "America/Los_Angeles", "-08:00", + "America/Denver", "-07:00", + "America/Chicago", "-06:00", + "America/New_York", "-05:00", a.tz) AS UTCOffset +FROM airport a +WHERE a.country = "United States" AND a.geo.alt > 1000 +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "Airport": "Indian Mountain Lrrs", + "UTCOffset": "-09:00" + }, + { + "Airport": "Sparrevohn Lrrs", + "UTCOffset": "-09:00" + }, + { + "Airport": "Bicycle Lake Aaf", + "UTCOffset": "-08:00" + }, + { + "Airport": "Twentynine Palms Eaf", + "UTCOffset": "-0:800" + }, + { + "Airport": "Grants Milan Muni", + "UTCOffset": "-07:00" + } +] +---- +==== + +[[if_missing,IFMISSING()]] +== IFMISSING(`expression1`, `expression2`, \...) + +=== Arguments + +expression1, expression2, \...:: [At least 2 are required] Any valid expressions. + +=== Return Value +Returns the first non-MISSING value. +Returns NULL if all values are MISSING. + +=== Example +==== +[source,sqlpp] +---- +SELECT IFMISSING(null, missing, "abc", 123) AS Mix, -- <1> + IFMISSING(null, null, null) AS AllNull, -- <2> + IFMISSING(missing, missing, missing) AS AllMissing; +---- + +.Results +[source,json] +---- +[ + { + "AllMissing": null, + "AllNull": null, // <2> + "Mix": null // <1> + } +] +---- + +<1> The first non-MISSING value is NULL, so this function returns NULL. +<2> The first non-MISSING value is NULL, so this function returns NULL. +==== + +[[if_missing_or_null,IFMISSINGORNULL()]] +== IFMISSINGORNULL(`expression1`, `expression2`, \...) + +This function has an alias <>. + +=== Arguments + +expression1, expression2, \...:: [At least 2 are required] Any valid expressions. + +=== Return Value +Returns first non-NULL, non-MISSING value. +Returns NULL if all values are MISSING or NULL. + +=== Example +==== +[source,sqlpp] +---- +SELECT IFMISSINGORNULL(null, missing, "abc", 123) AS Mix, + IFMISSINGORNULL(null, null, null) AS AllNull, + IFMISSINGORNULL(missing, missing, missing) AS AllMissing; +---- + +.Results +[source,json] +---- +[ + { + "AllMissing": null, + "AllNull": null, + "Mix": "abc" + } +] +---- +==== + +[[if_null,IFNULL()]] +== IFNULL(`expression1`, `expression2`, \...) + +=== Arguments + +expression1, expression2, \...:: [At least 2 are required] Any valid expressions. + +=== Return Value +Returns first non-NULL value. +Returns NULL if all values are NULL. + +=== Example +==== +[source,sqlpp] +---- +SELECT IFNULL(null, missing, "abc", 123) AS Mix, -- <1> + IFNULL(null, null, null) AS AllNull, + IFNULL(missing, missing, missing) AS AllMissing; -- <2> +---- + +.Results +[source,json] +---- +[ + { + "AllNull": null + } +] +---- + +<1> The first non-NULL value is MISSING, so this function returns MISSING. +<2> The first non-NULL value is MISSING, so this function returns MISSING. +==== + +[[missing_if,MISSINGIF()]] +== MISSINGIF(`expression1`, `expression2`) + +=== Arguments + +expression1, expression2, \...:: [Exactly 2 are required] Any valid expressions. + +=== Return Value +Returns MISSING if `expression1` = `expression2`, otherwise returns `expression1`. +Returns MISSING if either input is MISSING or if both inputs are MISSING. +Returns NULL if either input is NULL or if both inputs are NULL. + +=== Example +==== +[source,sqlpp] +---- +SELECT MISSINGIF("abc", 123) AS Different, + MISSINGIF("abc", "abc") AS Same; +---- + +.Results +[source,json] +---- +[ + { + "Different": "abc" + } +] +---- +==== + +[[null_if,NULLIF()]] +== NULLIF(`expression1`, `expression2`) + +=== Arguments + +expression1, expression2, \...:: [Exactly 2 are required] Any valid expressions. + +=== Return Value +Returns NULL if `expression1` = `expression2`, otherwise returns `expression1`. +Returns MISSING if either input is MISSING or if both inputs are MISSING. +Returns NULL if either input is NULL or if both inputs are NULL. + +=== Example +==== +[source,sqlpp] +---- +SELECT NULLIF("abc", 123) AS Different, + NULLIF("abc", "abc") AS Same; +---- + +.Results +[source,json] +---- +[ + { + "Different": "abc", + "Same": null + } +] +---- +==== + +[[nvl,NVL()]] +== NVL(`expression1`, `expression2`) + +=== Arguments + +expression1, expression2, \...:: [Exactly 2 are required] Any valid expressions. + +=== Return Value +Returns `expression1` if `expression1` is not MISSING or NULL. +Returns `expression2` if `expression1` is MISSING or NULL. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +[source,sqlpp] +---- +SELECT name as Name, NVL(iata, "n/a") as IATA +FROM airline +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "IATA": "Q5", + "Name": "40-Mile Air" + }, + { + "IATA": "TQ", + "Name": "Texas Wings" + }, + { + "IATA": "A1", + "Name": "Atifly" + }, + { + "IATA": "n/a", + "Name": "Jc royal.britannica" + }, + { + "IATA": "ZQ", + "Name": "Locair" + } +] +---- +==== + +[[nvl2,NVL2()]] +== NVL2(`expression`, `value1`, `value2`) + +=== Arguments + +expression:: [Required] Any valid expression. +value1, value2, \...:: [Exactly 2 are required] Any values. + +=== Return Value +Returns `value1` if `expression` is not MISSING or NULL. +Returns `value2` if `expression` is MISSING or NULL. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +[source,sqlpp] +---- +SELECT name as Name, NVL2(directions, "Yes", "No") as DirectionsAvailable +FROM hotel +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "DirectionsAvailable": "No", + "Name": "Medway Youth Hostel" + }, + { + "DirectionsAvailable": "No", + "Name": "The Balmoral Guesthouse" + }, + { + "DirectionsAvailable": "Yes", + "Name": "The Robins" + }, + { + "DirectionsAvailable": "Yes", + "Name": "Le Clos Fleuri" + }, + { + "DirectionsAvailable": "Yes", + "Name": "Glasgow Grand Central" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/conditionalops.adoc b/modules/n1ql/pages/n1ql-language-reference/conditionalops.adoc new file mode 100644 index 000000000..33c0fd283 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/conditionalops.adoc @@ -0,0 +1,78 @@ += Conditional Operators +:description: Case expressions evaluate conditional logic in an expression. +:page-topic-type: reference +:imagesdir: ../../assets/images + +{description} + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=case-expr] +---- + +image::n1ql-language-reference/case-expr.png["Syntax diagram", align=left] + +== Simple Case Expressions + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=simple-case-expr] +---- + +image::n1ql-language-reference/simple-case-expr.png["Syntax diagram", align=left] + +Simple case expressions allow for conditional matching within an expression. +The evaluation process is as follows: + +* The first WHEN expression is evaluated. +If it is equal to the search expression, the result of this expression is the THEN expression. +* If it is not equal, subsequent WHEN clauses are evaluated in the same manner. +* If none of the WHEN expressions are equal to the search expression, then the result of the CASE expression is the ELSE expression. +* If no ELSE expression was provided, the result is NULL. + +== Searched Case Expressions + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=searched-case-expr] +---- + +image::n1ql-language-reference/searched-case-expr.png["Syntax diagram", align=left] + +Searched case expressions allow for conditional logic within an expression. +The evaluation process is as follows: + +* The first WHEN condition is evaluated. +* If TRUE, the result of this expression is the THEN expression. +* If not TRUE, subsequent WHEN clauses are evaluated in the same manner. +* If none of the WHEN clauses evaluate to TRUE, then the result of the expression is the ELSE expression. +* If no ELSE expression was provided, the result is NULL. + +=== Example + +The following example uses a CASE clause to handle documents that do not have a ship date. +This scans all orders. +If an order has a shipped-on date, it is provided in the result set. +If an order does not have a shipped-on date, default text appears. + +==== +.Query +[source,sqlpp] +---- +SELECT + CASE WHEN `shipped-on` + IS NOT NULL THEN `shipped-on` + ELSE "not-shipped-yet" + END + AS shipped + FROM orders +---- + +.Result +[source,json] +---- +{ "shipped": "2013/01/02" }, +{ "shipped": "2013/01/12" }, +{ "shipped": "not-shipped-yet" }, +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/constructionops.adoc b/modules/n1ql/pages/n1ql-language-reference/constructionops.adoc new file mode 100644 index 000000000..a926e2fdb --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/constructionops.adoc @@ -0,0 +1,200 @@ += Construction Operators +:description: {sqlpp} supports array and object construction operators. +:page-topic-type: reference +:imagesdir: ../../assets/images + +{description} + +[[array-construction]] +== Array Constructors + +Arrays are ordered lists with 0 or more values. +Arrays are enclosed in square brackets `[{nbsp}]`. +Commas separate each value. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=array] +---- + +image::n1ql-language-reference/array.png["Syntax diagram", align=left] + +=== Arguments + +expr:: An expression resolving to any supported JSON data type. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +.Simple array construction +==== +.Query +[source,sqlpp] +---- +SELECT ["one", "two", "three"], [1, 2, 3]; +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + "one", + "two", + "three" + ], + "$2": [ + 1, + 2, + 3 + ] + } +] +---- +==== + +.Dynamic array construction +==== +This example constructs a new array using the `address`, `city`, and `country` fields in the data source. + +.Query +[source,sqlpp] +---- +SELECT [ address, city, country ] AS location +FROM hotel LIMIT 3; +---- + +.Results +[source,json] +---- +[ + { + "location": [ + "Capstone Road, ME7 3JE", + "Medway", + "United Kingdom" + ] + }, + { + "location": [ + "57-59 Balmoral Road, ME7 4NT", + "Gillingham", + "United Kingdom" + ] + }, + { + "location": [ + "6 rue aux Juifs", + "Giverny", + "France" + ] + } +] +---- +==== + +[[object-construction]] +== Object Constructors + +Objects contain name-value pairs or attributes. +Objects are enclosed in curly braces ``{``{nbsp}``}``. +Commas separate each attribute. +The colon (`:`) character separates the key or name from its value within each attribute. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=object] +---- + +image::n1ql-language-reference/object.png["Syntax diagram", align=left] + +=== Arguments + +name-expr:: [Optional] An expression resolving to a string, which specifies the name of the attribute. +All names must be distinct from each other within the object. ++ +If a name does not evaluate to a string, the result of the object construction is NULL. + +expr:: An expression resolving to any supported JSON data type, which specifies the value of the attribute. + +.Dynamic names +NOTE: If the `expr` argument is an identifier referring to a named field in the data source, then you can omit the `name-expr` argument. +In this case, the name of the field in the data source will be used as the name of the attribute in the output object. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Simple object construction +==== +.Query +[source,sqlpp] +---- +SELECT { UPPER("foo") : 1, "foo" || "bar" : 2 }; +---- + +.Results +[source,json] +---- +[ + { + "$1": { + "FOO": 1, + "foobar": 2 + } + } +] +---- +==== + +.Dynamic object construction +==== +This example constructs a new object using the `address`, `city`, and `country` fields in the data source. + +.Query +[source,sqlpp] +---- +SELECT { "street": address, city, country } AS location +FROM hotel LIMIT 3; +---- + +Notice we have provided a new name for the `street` attribute, but the `city` and `country` attributes are named dynamically. + +.Results +[source,json] +---- +[ + { + "location": { + "city": "Medway", + "country": "United Kingdom", + "street": "Capstone Road, ME7 3JE" + } + }, + { + "location": { + "city": "Gillingham", + "country": "United Kingdom", + "street": "57-59 Balmoral Road, ME7 4NT" + } + }, + { + "location": { + "city": "Giverny", + "country": "France", + "street": "6 rue aux Juifs" + } + } +] +---- +==== + +== Related Links + +Refer to xref:n1ql:n1ql-language-reference/collectionops.adoc#range-xform[Range Transformations] for a more sophisticated way to generate arrays and objects from a data source. diff --git a/modules/n1ql/pages/n1ql-language-reference/conventions.adoc b/modules/n1ql/pages/n1ql-language-reference/conventions.adoc new file mode 100644 index 000000000..690bca138 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/conventions.adoc @@ -0,0 +1,58 @@ += Conventions +:description: The {sqlpp} syntax descriptions in the documentation use some notational conventions that you need to be familiar with. +:page-topic-type: reference +:imagesdir: ../../assets/images + +[abstract] +{description} + +The syntax descriptions are written using a https://www.w3.org/TR/REC-xml/#sec-notation[W3C dialect of EBNF] (Extended Backus-Naur Format). + +.Notational conventions for {sqlpp} syntax descriptions +[cols="1,1a,2a,2"] +|=== +| Convention | Notation | Example | Description + +| Upper case +|   +| `'SELECT'` +| Indicates keywords in the syntax description. +Delimited by quotes, to show that the keyword is required in the syntax. +Note that you can enter keywords in upper or lower case. + +| Single or double quotes +| `''` or `""` +| `'('` `')'` + +`','` +| Indicate that the text between the quotes is required in the syntax. + +| Pipe +| `{vbar}` +| `'AND' {vbar} 'OR'` +| Separates alternatives. + +| Parentheses +| `( )` +| `'USING' ( 'GSI' {vbar} 'FTS' )` +| Delimit alternatives, or group optional and repeated elements, where necessary. + +| Question mark +| `?` +| `element?` + +`(',' element)?` +| Indicates that the element or group preceding the question mark is optional. + +| Plus sign +| `+` +| `element+` + +`(',' element)+` +| Indicates that the element or group preceding the plus sign may appear one or many times. + +| Asterisk +| `*` +| `element*` + +`(',' element)*` +| Indicates that the element or group preceding the asterisk may appear zero, one, or many times. +|=== + +Syntax diagrams generated using https://www.bottlecaps.de/rr/ui[Railroad Diagram Generator^]. diff --git a/modules/n1ql/pages/n1ql-language-reference/correlated-subqueries.adoc b/modules/n1ql/pages/n1ql-language-reference/correlated-subqueries.adoc new file mode 100644 index 000000000..cfe145136 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/correlated-subqueries.adoc @@ -0,0 +1,169 @@ += Correlated Subqueries +:description: When a subquery refers to variables, aliases, attributes, or keyspaces in the outer statement, it is called a correlated subquery. +:page-topic-type: concept + +When a subquery is independent of its parent query, it is called a *non-correlated* subquery. +This means the subquery does not depend on any of the variables or aliases defined in the outer query, nor the specific document being processed by the outer query. +For instance, in examples xref:n1ql-language-reference/subqueries.adoc#Q1[Q1], xref:n1ql-language-reference/subqueries.adoc#Q2[Q2], and xref:n1ql-language-reference/subqueries.adoc#Q3[Q3] on the Subqueries page, the subquery has no correlation with its outer query. + +When a subquery refers to variables, aliases, attributes, or keyspace in the outer statement, it is called a *correlated* subquery. +These subqueries are special because their performance characteristics can be very different from non-correlated queries. +Typically, correlated queries are expensive, and query engines take special care in planning and executing such queries efficiently. + +.Examples on this Page +**** +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Performance + +For non-correlated queries, a subquery is evaluated once and resulting values are substituted in the parent query for all of the documents at the outer level queries. +However, when a query includes a correlated subquery, the evaluation of the subquery depends on the outer query document being processed, because the subquery refers to some values or attributes in the outer query. +It is similar to having variables in the subquery whose exact values are provided by the outer query, which might change for each of the documents considered at outer levels. +Therefore, the subquery is executed repeatedly, once for each document that is selected in the outer query. + +{sqlpp} query engine optimizes the correlated subquery processing in multiple ways. +For example: + +* Subqueries are prepared only once, though they are executed multiple times. +This avoids repetitive costs such as parsing and planning of the subquery. +* When a subquery is correlated through the FROM clause expression, fetching documents in the subquery is avoided. +The query engine smartly reuses the correlated document already fetched in the outer query. + +== Types of Correlation + +In {sqlpp}, the way in which a subquery is correlated with its parent queries is very important. +That dictates certain behaviors and limitations in writing nested subqueries, and impacts query performance. + +=== Correlation by Source (or FROM clause-Expression) + +The data source for a query or subquery is specified by its FROM clause. +When the FROM clause of a subquery refers to any variables (aliases, keyspace names, LET/LETTING variables, or document attributes) in the scope of parent queries, then the correlation is established using the source keyspace in the FROM expression. +Such subquery is called a *Source Correlated Subquery* and it offers the following benefits: + +Nested Paths in FROM clause:: +Couchbase Capella enables you to use correlated nested paths in a subquery FROM clause. +This provides powerful language expressibility, simplicity, and flexibility to {sqlpp} queries, especially when dealing with nested array attributes. +See xref:n1ql-language-reference/subqueries.adoc#nested-path-expr[Nested Paths in Subqueries] for more details. + +Better Performance:: +When correlation is established through the FROM clause in the subquery (with variables in scope), then the {sqlpp} engine knows that the subquery is referring to the same document that is being processed in one of the outer queries. +Therefore, the subquery avoids fetch of the documents used in the subquery. +This significantly improves the performance of such subqueries, as shown in example xref:n1ql-language-reference/subqueries.adoc#Q6[Q6] on the Subqueries page. +In contrast, example xref:n1ql-language-reference/subqueries.adoc#Q6A[Q6A] on the Subqueries page cannot take advantage of this optimization. + +=== Correlation by Reference (or non FROM clause-Expression) + +In this case the subquery refers to xref:n1ql-language-reference/subqueries.adoc#section_onz_3tj_mz[variables in the scope] of the outer level query, in clauses other than the FROM clause of the subquery. +In such case, the FROM clause will have an independent keyspace identifier that does not reference any variables in the scope. +This kind of subquery execution works like a JOIN query and requires the USE KEYS clause. +For more information, see <> and xref:n1ql-language-reference/subqueries.adoc#from-clause[FROM clause in Subqueries]. + +In the following example, the subquery in the LET clause of the parent query introduces correlation in the USE KEYS clause (referencing `t1` fields) and the WHERE clause (`t2.iata = t1.airline`). +This query finds the airline and route details of flights that have routes starting from SFO airport. + +[#Q10] +==== +.Q10 +[source,sqlpp] +---- +SELECT airline_details, t1.destinationairport, t1.stops +FROM route t1 +LET airline_details = (SELECT t2.name, t2.callsign + FROM airline t2 + USE KEYS t1.airlineid + WHERE t2.iata = t1.airline) +WHERE t1.sourceairport = "SFO" + AND ARRAY_LENGTH(airline_details) > 0 +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "airline_details": [ + { + "callsign": "JETBLUE", + "name": "JetBlue Airways" + } + ], + "destinationairport": "AUS", + "stops": 0 + }, + { + "airline_details": [ + { + "callsign": "JETBLUE", + "name": "JetBlue Airways" + } + ], + "destinationairport": "BOS", + "stops": 0 + } +] +---- +==== + +[#use-keys] +== FROM Clause and USE KEYS in Correlated Subqueries + +In example <>, notice the USE KEYS clause used to establish the correlation with the outer query documents. +Without this, it is not possible to identify the documents in the subquery that are related to the specific document being considered by the outer query. + +It is important to understand the reasoning to include the USE KEYS clause. +It is not always mandatory. +It entirely depends on how the FROM clause is formulated, which indicates the source of documents for the subquery and hence the correlation with the parent query. + +NOTE: When a keyspace name identifier is used in the FROM clause of a subquery, it refers to a collection of documents referenced by the keyspace identifier. +However, when an alias of the keyspace is used in the FROM clause (or any other clauses of the query), it refers to an individual document of the keyspace being considered in the outer query. + +=== FROM Clause with Keyspace Identifier + +The USE KEYS clause is mandatory for the primary keyspace of the subquery when the FROM clause has keyspace identifier that is independent of any of the aliases or variables in scope. +This is needed to establish correlation with the documents or keyspace used in the outer query. +For example: + +* The FROM clause of the subquery in <> is an independent keyspace identifier `airline`, and hence the correlation with the parent query is established explicitly using the USE KEYS clause through the referential attribute `t1.airlineid`. + +* Similarly, the subquery in xref:n1ql-language-reference/subqueries.adoc#Q9A[Q9A] on the Subqueries page has an independent keyspace identifier `airport` in the FROM clause, but the correlation is self-referencing to the same document. +Therefore, `USE KEYS meta(t).id` is used. + +This is exactly same as the Primary Key-Foreign Key relationship required to xref:n1ql-language-reference/join.adoc[join] two documents that are referenced in the outer and inner queries. +Note that in the `travel-sample` data model, the `"route"` documents refer the `"airline"` documents using the attribute `airlineid`. +Refer to the xref:server:learn:data/document-data-model.adoc[Data Model]. + +=== FROM Clause with Expression + +The USE KEYS clause is not required in the subquery when the FROM clause in the subquery has a generic expression as its data source, and not a keyspace name identifier. +The FROM clause expression can be: + +* An independent constant expression or subquery expression that does not refer to any variables in scope. +* A generic {sqlpp} expression or subquery that refers to any variables in scope. + +In example xref:n1ql-language-reference/subqueries.adoc#Q9[Q9] on the Subqueries page, the FROM clause is an expression referring to the variable alias `t` (in fact the nested path `t.reviews`) that already establishes correlation, and hence the subquery does not need an explicit USE KEYS clause. + +== Correlated Subquery versus JOINs + +Correlated subqueries can be alternatively formulated using JOINs, because conceptually, a correlated query execution involves the same steps as JOIN. +For instance, evaluating a nested subquery corresponding to each outer query document is equivalent to a nested-loop-join operation. +This is one reason for the above-mentioned mandatory requirement of the USE KEYS clause for certain correlated queries using a FROM clause. + +In general, {sqlpp} recommends the usage of JOIN queries when possible, instead of semantically equivalent correlated subqueries. +However, in some cases it may be easier or intuitive to formulate some queries using subqueries (instead of JOINs). +In such case, it is recommended to understand the EXPLAIN query plans and performance of both queries. + +[#Q10A] +==== +.Q10A: Earlier Q10 rewritten with JOIN +[source,sqlpp] +---- +SELECT DISTINCT airline.name, airline.callsign, route.destinationairport, route.stops, route.airline +FROM route + JOIN airline + ON KEYS route.airlineid +WHERE route.sourceairport = "SFO" +LIMIT 2; +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/cost-based-optimizer.adoc b/modules/n1ql/pages/n1ql-language-reference/cost-based-optimizer.adoc new file mode 100644 index 000000000..c7f42cb36 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/cost-based-optimizer.adoc @@ -0,0 +1,395 @@ += Understand the Cost-Based Optimizer for Queries +:page-topic-type: concept +:imagesdir: ../../assets/images +:description: The cost-based optimizer takes into account the cost of memory, CPU, network transport, and disk usage when choosing the optimal plan to execute a query. + +// Cross-references +:query-settings: xref:n1ql:n1ql-manage/query-settings.adoc +:queryUseCBO: {query-settings}#queryUseCBO +:use-cbo-srv: {query-settings}#use-cbo-srv +:use_cbo_req: {query-settings}#use_cbo_req +:n1ql: xref:n1ql-language-reference +:select: {n1ql}/selectintro.adoc +:update: {n1ql}/update.adoc +:delete: {n1ql}/delete.adoc +:merge: {n1ql}/merge.adoc +:insert: {n1ql}/insert.adoc +:explain: {n1ql}/explain.adoc +:updatestatistics: {n1ql}/updatestatistics.adoc +:optimizer-hints: {n1ql}/optimizer-hints.adoc +:query-hints: {n1ql}/query-hints.adoc +:ordered-hint: {query-hints}#ordered +:keyspace-hints: {n1ql}/keyspace-hints.adoc +:index-hint: {keyspace-hints}#index +:use-nl-hint: {keyspace-hints}#use_nl +:use-hash-hint: {keyspace-hints}#use_hash +:collation: {n1ql}/datatypes.adoc#collation +:query-service: xref:server:learn:services-and-indexes/services/query-service.adoc +:query-service-architecture: {query-service}#query-service-architecture +:query-execution: {query-service}#query-execution +:query-settings: xref:server:manage:manage-settings/general-settings.adoc#query-settings + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +[[overview]] +== Overview + +The _cost-based optimizer_ (CBO) enables the Query service to create the most efficient plan to execute a query. + +The execution of a query involves {query-execution}[many possible operations]: scan, fetch, join, filter, and so on. +When the query processor is planning the query execution, there may be several possible choices for each operation: for example, there may be different possible indexes, or a choice of join types. +With each of these operations, some of these choices are quicker and more efficient than others. +The query processor attempts to choose the most efficient options when creating the query execution plan. +The legacy {query-service-architecture}[rules-based optimizer] (RBO), as its name suggests, takes a rules-based approach; but this does not always lead to the optimum query plan. + +The cost-based optimizer uses metadata and statistics to estimate the amount of processing (memory, CPU, network traffic, and I/O) required for each operation. +It compares the cost of alternative routes, and then selects the query-execution plan with the least cost. + +.Query execution flow, showing the cost-based optimizer using statistics and metadata +[plantuml,cbo_query_execution_flow,svg,subs=attributes] +.... +@startuml + +skinparam defaultTextAlignment center +left to right direction + +queue "Statistics and\nMetadata" as E +artifact "{sqlpp}\nStatement" as A +agent "{sqlpp}\nParser" as B +queue "System\nMetadata" as C +agent "Semantic\nAnalyzer" as D + +rectangle Optimizer as F { + json "Plan A <&check>" as X{ + "Scan Cost": "12", + "Fetch Cost": "17", + "Join Cost": "7", + "Total": 23 + } + json "Plan B <&x>" as Y{ + "Scan Cost": 20, + "Fetch Cost": 25, + "Join Cost": 7, + "Total": 52 + } + json "Plan C <&x>" as Z{ + "Scan Cost": 18, + "Fetch Cost": 36, + "Join Cost": 14, + "Total": 68 + } +} + +file "Query Explain\nPlan" as G +file "Query Execution Tree\n(Query Plan)" as H +agent Executor as I +artifact "Debug Info\n(Query Profile)" as J +artifact "Query Results" as K + +A --> B +B --> D +C --> D +D --> X +E --> X +X --> G +X --> H +H --> I +I --> J +I --> K + +@enduml +.... + +The cost-based optimizer can generate a query plan for {select}[SELECT], {update}[UPDATE], {delete}[DELETE], {merge}[MERGE], and {insert}[INSERT INTO with SELECT] queries. + +**** +As an analogy, imagine that you need to travel from one side of a major city to the other by train. +There may be many options available to you: commuter rail, metro, or light rail. +You may also need to change from one service to another at an interchange station, perhaps more than once. +By combining the fastest services with the smallest number of changes and the shortest wait time at each interchange, you can get to your destination in the most efficient way. + +Of course, to plan your route, you need to have knowledge of the train frequencies, the size and accessibility of the interchange stations, and how busy the services are likely to be at the time when you travel. +Each of these factors imposes a cost on the options that are available to you. +If you have a greater knowledge and experience of the city's rail network, you will be better informed about these costs, and better able to plan the optimum journey. +**** + +[[advantages]] +== Advantages of the Cost-Based Optimizer + +The cost-based optimizer calculates a cost for a query plan that takes into consideration resource usages during query execution, thus can potentially generate an optimum query plan. + +[[index-selection]] +=== Index Selection + +The cost-based optimizer takes into consideration the characteristics of each qualified index, and thus can better differentiate between similar indexes. +The cost-based optimizer also reduces the need for intersect scans, since it can determine whether one index is better than another based on cost information. + +Refer to {index-hint}[INDEX] for an example. + +[[join-method]] +=== Join Method + +Two join methods are supported: nested-loop join and hash join. +With the legacy {query-service-architecture}[rules-based optimizer], nested-loop join is used by default, and hash join is only considered when a USE HASH hint is specified. +With the cost-based optimizer, both join methods are considered, and the optimizer chooses a join method based on cost information. + +Refer to {use-nl-hint}[USE_NL] and {use-hash-hint}[USE_HASH] for examples. + +[[join-enumeration]] +=== Join Enumeration + +With the legacy {query-service-architecture}[rules-based optimizer], joins are performed in the order in which they are specified in the query, and no reordering of joins is considered. +With the cost-based optimizer, different join orders can be considered, and the optimizer chooses the optimal join order based on cost information. + +Refer to {ordered-hint}[ORDERED] for an example. + +[[optimizer-stats]] +== Optimizer Statistics + +The cost-based optimizer uses keyspace statistics, index statistics, and distribution statistics. +Before you can use the cost-based optimizer with a query, you must first gather the statistics that it needs. + +In Couchbase Server 7.6 and later, the Query service automatically gathers statistics whenever an index is created or built. +You can use the {updatestatistics}[UPDATE STATISTICS] statement to gather statistics at any time. + +If the cost-based optimizer cannot properly calculate cost information for any step of a query plan, e.g. due to lack of the necessary optimizer statistics, the Query service falls back on the {query-service-architecture}[rules-based {sqlpp} optimizer] to generate a query plan. + +The cost-based optimizer uses the following statistics. + +For keyspaces: + +* The number of documents in the keyspace. +* The average document size. + +For indexes using standard index storage: + +* The number of items in the index. +* The number of index pages. +* The resident ratio. +* The average item size. +* The average page size. +* The number of documents indexed. + +For indexes using memory-optimized index storage: + +* The number of items in the index. +* The average item size. + +For data: + +* Distribution statistics -- refer to <>. + +[[distribution-stats]] +== Distribution Statistics + +The cost-based optimizer can collect distribution statistics on predicate expressions. +These predicate expressions may be fields, nested fields, array expressions, or any of the expressions supported as an index key. + +The distribution statistics enable the optimizer to estimate the cost for predicates like `c1 = 100`, `c1 >= 20`, or `c1 < 150`. +They also enable cost estimates for join predicates such as `t1.c1 = t2.c2`, assuming distribution statistics exist for both `t1.c1` and `t2.c2`. + +[[distribution-bins]] +=== Distribution Bins + +The optimizer takes a sample of the values returned by the expression across the keyspace. +These sample values are sorted into _distribution bins_ by data type and value. + +. Values with different data types are placed into separate distribution bins. +(A field may contain values of several different data types across documents.) + +. After being separated by data type, values are sorted further into separate bins depending on their value. + +The distribution bins are of approximately equal size, except for the last distribution bin for each data type, which could be a partial bin. + +[[overflow-bins]] +=== Overflow Bins + +For each distribution bin, the number of distinct values is calculated, as a fraction of the total number of documents. + +If a particular value is highly duplicated and represents more than 25% of a distribution bin, it is removed from the distribution bin and placed in an _overflow bin_. +MISSING, NULL, or boolean values are always placed in an overflow bin. + +[[boundary-bins]] +=== Boundary Bins + +Each distribution bin has a maximum value, which acts as the minimum value for the next bin. + +A _boundary bin_ containing no values is created before the first distribution bin of each different data type. +The boundary bin contains no values. +This provides the minimum value for the first bin of each type. + +[[histogram]] +=== Histogram + +The boundary bins, distribution bins, and overflow bins for each data type are chained together in the {collation}[default ascending collation order] used for {sqlpp} data types: + +* MISSING +* NULL +* FALSE +* TRUE +* number +* string +* array +* object +* binary (non-JSON) + +This forms a histogram of statistics for the index-key expression across multiple data types. + +.Distribution bins and boundary bins for integers, strings, and arrays +[plantuml,cbo_distribution_bins,svg] +.... +@startuml + +skinparam defaultTextAlignment center +skinparam linetype ortho + +rectangle "Integer Values" { + json " " as A { + "Size": "25%", + "Distinct": 23, + "Max": 300 + } + json " " as B { + "Size": "25%", + "Distinct": 49, + "Max": 2000 + } + json " " as C { + "Size": "25%", + "Distinct": 88, + "Max": 8000 + } + json " " as D { + "Size": "25%", + "Distinct": 3, + "Max": 10000 + } +} + +rectangle "String Values" { + card "Boundary" as E + json " " as F { + "Size": "25%", + "Distinct": 92, + "Max": "A232" + } + json " " as G { + "Size": "25%", + "Distinct": 23, + "Max": "F348" + } + json " " as H { + "Size": "25%", + "Distinct": 20, + "Max": "L283" + } + json " " as I { + "Size": "25%", + "Distinct": 3, + "Max": "Z82" + } +} + +rectangle "Array Values" { + card "Boundary" as J + json " " as K { + "Size": "25%", + "Distinct": 48, + "Max": "[234]" + } + json " " as L { + "Size": "25%", + "Distinct": 28, + "Max": "[948]" + } +} + + A . B + B . C + C . D + D . E + E . F + F . G + G . H + H . I + I . J + J . K + K . L + +@enduml +.... + +[[resolution]] +=== Resolution + +The number of distribution bins is determined by the _resolution_. + +The default resolution is `1.0`, meaning each distribution bin contains 1% of the documents, and therefore 100 bins are required. +The minimum resolution is `0.02` (5000 distribution bins) and the maximum is `5.0` (20 distribution bins). +The cost-based optimizer calculates the bin size based on the resolution and the number of documents in the collection. + +The resolution can be specified when you use the {updatestatistics}[UPDATE STATISTICS] statement. + +[[sample-size]] +=== Sample Size + +The size of the sample that is collected when gathering statistics is determined by the _sample size_. + +The cost-based optimizer calculates a default minimum sample size based on the resolution information. +You can optionally specify the sample size when you use the {updatestatistics}[UPDATE STATISTICS] statement. + +If you do not specify a sample size, or if the specified sample size is smaller than the default minimum sample size, the default minimum sample size is used instead. + +[[settings-and-parameters]] +== Settings and Parameters + +The cost-based optimizer is enabled by default. +You can enable or disable it as required. + +* The {use_cbo_req}[request-level] `use_cbo` parameter specifies whether the cost-based optimizer is enabled per request. +If a request does not include this parameter, the node-level setting is used. + +* The {use-cbo-srv}[node-level] `use-cbo` setting specifies whether the cost-based optimizer is enabled for a single query node. +It defaults to `true`. + +* The {queryUseCBO}[cluster-level] `queryUseCBO` setting enables you to specify the node-level setting for all the nodes in the cluster. + +You can also enable or disable the cost-based optimizer using the {query-settings}[Query Settings] in the Capella UI. + +If the cost-based optimizer is not enabled, the Query service falls back on the {query-service-architecture}[rules-based {sqlpp} optimizer]. + +=== Optimizer Hints + +In Couchbase Capella, you can supply hints to the optimizer within a specially-formatted hint comment. +For example, you can specify a particular index; specify a join method for a particular join; or request that the query should use the join order as written. +For further details, refer to {optimizer-hints}[Optimizer Hints]. + +[[operations]] +== Using the Cost-Based Optimizer + +When enabled, the optimizer performs the following tasks when a query is executed: + +. Rewrite the query if necessary, in the same manner as the previous rules-based optimizer. + +. Use the distribution histogram and index statistics to estimate the _selectivity_ of a predicate -- that is, the number of documents that the optimizer expects to retrieve which satisfy this predicate. + +. Use the selectivity to estimate the _cardinality_ -- that is, the number of documents remaining after all applicable predicates are applied. + +. Use the cardinality to estimate the cost of different access paths. + +. Compare the costs and generate a query execution plan with the lowest cost. + +As described above, the cost-based optimizer can choose the optimal join method for each join, and rewrites the query to use the optimal join ordering. + +The optimizer adds cost and cardinality estimates to every step in the query plan. +You can see these estimates using the {explain}[EXPLAIN] command. +Refer to the documentation for the {updatestatistics}[UPDATE STATISTICS] statement to see examples of how to generate optimizer statistics, and queries that use these optimizer statistics to calculate cost information in order to generate a query plan. + +== Related Links + +* {updatestatistics}[UPDATE STATISTICS] statement +* {optimizer-hints}[] overview +* Blog post: https://blog.couchbase.com/?p=7384&preview=true[Cost Based Optimizer for Couchbase N1QL^] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/covering-indexes.adoc b/modules/n1ql/pages/n1ql-language-reference/covering-indexes.adoc new file mode 100644 index 000000000..655a0cbec --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/covering-indexes.adoc @@ -0,0 +1,473 @@ += Covering Indexes +:description: When an index includes the actual values of all the fields specified in the query, the index covers the query and does not require an additional step to fetch the actual values from the data service. +:page-topic-type: concept +:page-aliases: indexes:covering-indexes.adoc +:imagesdir: ../../assets/images + +[abstract] +{description} +An index, in this case, is called a covering index and the query is called a covered query. +As a result, covered queries are faster and deliver better performance. + +.Examples on this Page +**** +The examples on this page use the `travel-sample` bucket, which needs to be installed before use. +See xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Overview + +The following diagram illustrates the query execution work flow without covering indexes: + +.Query execution workflow including fetch request from Data service +[plantuml,n1ql-query-workflow,svg] +.... +include::learn:partial$diagrams/query-execution.puml[tags=!example] +.... + +The following diagram illustrates the query execution work flow with covering indexes: + +.Query execution workflow with no fetch request from Data service +[plantuml,n1ql-query-workflow-cover-idx,svg] +.... +include::learn:partial$diagrams/query-execution.puml[tags=!example;!fetch] +.... + +As you can see in the second diagram, a well designed query that uses a covering index avoids the additional steps to fetch the data from the data service. +This results in a considerable performance improvement. + +== Details + +To see details of covering indexes at work, you can view the query execution plan using the EXPLAIN statement. +When a query uses a covering index, the EXPLAIN statement shows that a covering index is used for data access, thus avoiding the overhead associated with key-value document fetches. +Consider a simple index, [.in]`idx_state`, on the attribute [.param]`state` in the `hotel` keyspace: + +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx_state on hotel (state) USING GSI; +---- +==== + +If we select [.param]`state` from the `hotel` keyspace, the actual values of the field [.param]`state` that are to be returned are present in the index [.param]`idx_state`, and avoids an additional step to fetch the data. +In this case, the index [.param]`idx_state` is called a covering index and the query is a covered query. + +==== +.Query +[source,sqlpp] +---- +EXPLAIN SELECT state FROM hotel WHERE state = "CA"; +---- + +.Plan +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ // <.> + "cover ((`hotel`.`state`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`state`)) = \"CA\")", + "index": "idx_state", // <.> +// ... + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`hotel`.`state`))" // <.> + } + ] + } +// ... +]}}]}}] +---- + +<.> The `covers` object shows details of the data covered by the index. +<.> The index scan step uses the index we created ... +<.> And the projection step uses the data covered by the index. +==== + +If you modify the query to select the [.param]`state` and [.param]`city` from the `hotel` keyspace using the same index [.param]`idx_state`, the index does not contain the values of the [.param]`city` field to satisfy the query, and hence a key-value fetch is performed to retrieve this data. + +==== +.Query +[source,sqlpp] +---- +EXPLAIN SELECT state, city FROM hotel + USE INDEX (idx_state) + WHERE state = "CA"; +---- + +.Plan +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", // <.> + "bucket": "travel-sample", + "index": "idx_state", // <.> +// ... + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`hotel`.`state`) = \"CA\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`hotel`.`state`)" // <.> + }, + { + "expr": "(`hotel`.`city`)" + } + ] + } +// ... +]}}]}}] +---- + +<.> There is no `covers` object, showing that the data is not covered by the index. +<.> The index scan step uses the index we created ... +<.> But the projection step does not use the data covered by the index. +==== + +To use a covering index for the modified query, you must define an index with the [.param]`state` and [.param]`city` attributes before executing the query. + +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx_state_city on hotel (state, city) +USING GSI; +---- +==== + +[IMPORTANT] +==== +`MISSING` items are not indexed by indexers. +To take advantage of covering indexes and for the index to qualify, a query needs to exclude documents where the index key expression evaluates to `MISSING`. +For example, the index `index1` defined below covers the following query. + +[subs="quotes"] +---- +CREATE INDEX __index1__ ON __keyspace__(__attribute1__) WHERE __attribute2__ = "__value__"; +---- + +[subs="quotes"] +---- +SELECT __attribute1__ FROM __keyspace__ WHERE __attribute2__ = "__value__" AND __attribute1__ IS NOT MISSING; +---- +==== + +Covering indexes are applicable to secondary index scans and can be used with global secondary indexes (GSI). +Queries with expressions and aggregates benefit from covering indexes. + +NOTE: You cannot use multiple GSI indexes to cover a query. +You must create a composite index with all the required fields for the query engine to cover by GSI and not require reading the documents from the data nodes. + +xref:n1ql:n1ql-language-reference/prepare.adoc[Prepared statements] also benefit from using covering indexes. + +[#examples] +== Scenarios + +The following queries can benefit from covering indexes. +Try these statements using [.api]`cbq` or the Query tab to see the query execution plan. + +.Expressions and Aggregates +==== +For the first few examples, you must create the following covering index. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx_city_country on hotel (city, country); +---- + +.Aggregate Query +[source,sqlpp] +---- +EXPLAIN SELECT MAX(country) FROM hotel +WHERE city = "Paris"; +---- + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))", + "cover (max(cover ((`hotel`.`country`))))" + ], + "index": "idx_city_country", +// ... +---- + +.Expression Query +[source,sqlpp] +---- +EXPLAIN SELECT country || city FROM hotel +WHERE city = "Paris"; +---- + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"Paris\")", + "index": "idx_city_country", +// ... +---- +==== + +.UNION/INTERSECT/EXCEPT +==== +This example uses the index `idx_city_country` defined previously. + +.Query +[source,sqlpp] +---- +SELECT country FROM hotel WHERE city = "Paris" + UNION ALL +SELECT country FROM hotel WHERE city = "San Francisco"; +---- + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"Paris\")", + "index": "idx_city_country", +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"San Francisco\")", + "index": "idx_city_country", +// ... +---- +==== + +.Sub-queries +==== +This example uses the index `idx_city_country` defined previously. + +.Query +[source,sqlpp] +---- +SELECT * FROM ( + SELECT country FROM hotel WHERE city = "Paris" + UNION ALL + SELECT country FROM hotel WHERE city = "San Francisco" +) AS newtab; +---- + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"Paris\")", + "index": "idx_city_country", +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"San Francisco\")", + "index": "idx_city_country", +// ... +---- +==== + +.SELECT in INSERT statements +==== +This example uses the index `idx_city_country` defined previously. + +.Query +[source,sqlpp] +---- +INSERT INTO hotel (KEY UUID(), VALUE city) + SELECT country, city FROM hotel WHERE city = "Paris"; +---- + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover ((`hotel`.`city`))", + "cover ((`hotel`.`country`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "(cover ((`hotel`.`city`)) = \"Paris\")", + "index": "idx_city_country", +// ... +---- +==== + +.Arrays in WHERE clauses +==== +First, create a new index, [.in]`idx_array`. + +[source,sqlpp] +---- +CREATE INDEX idx_array ON hotel(public_likes, name); +---- + +Then, run the following query: + +[source,sqlpp] +---- +SELECT name FROM hotel + USE INDEX (idx_array) + WHERE ARRAY_CONTAINS(public_likes, "Jazmyn Harris"); +---- + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover ((`hotel`.`public_likes`))", + "cover ((`hotel`.`name`))", + "cover ((meta(`hotel`).`id`))" + ], + "filter": "array_contains(cover ((`hotel`.`public_likes`)), \"Jazmyn Harris\")", + "index": "idx_array", +// ... +---- +==== + +.Collection Operators: FIRST, ARRAY, ANY, EVERY, and ANY AND EVERY +==== +For this example, first insert the following documents into the default collection in the default scope in the `travel-sample` bucket: + +[source,sqlpp] +---- +INSERT INTO `travel-sample` VALUES ("account-customerXYZ-123456789", +{ "accountNumber": 123456789, + "docId": "account-customerXYZ-123456789", + "code": "001", + "transDate":"2016-07-02" } ); + +INSERT INTO `travel-sample` VALUES ("codes-version-9", +{ "version": 9, + "docId": "codes-version-9", + "codes": [ + { "code": "001", + "type": "P", + "title": "SYSTEM W MCC", + "weight": 26.2466 + }, + { "code": "166", + "type": "P", + "title": "SYSTEM W/O MCC", + "weight": 14.6448 } + ] +}); +---- + +Create an index, `idx_account_customer_xyz_transDate`: + +[source,sqlpp] +---- +CREATE INDEX idx_account_customer_xyz_transDate + ON `travel-sample` (SUBSTR(transDate,0,10),code) + WHERE code != "" AND meta().id LIKE "account-customerXYZ%"; +---- + +Then, run the following query: + +[source,sqlpp] +---- +SELECT SUBSTR(account.transDate,0,10) AS transDate, AVG(codes.weight) AS avgWeight +FROM `travel-sample` AS account +JOIN `travel-sample` AS codesDoc ON KEYS "codes-version-9" +LET codes = FIRST c FOR c IN codesDoc.codes WHEN c.code = account.code END +WHERE account.code != "" AND meta(account).id LIKE "account-customerXYZ-%" +AND SUBSTR(account.transDate,0,10) >= "2016-07-01" +AND SUBSTR(account.transDate,0,10) < "2016-07-03" +GROUP BY SUBSTR(account.transDate,0,10); +---- + +.Results +[source,json] +---- +[ + { + "avgWeight": 26.2466, + "transDate": "2016-07-02" + } +] +---- + +The query plan for the above query shows that the index covers the query. + +.Plan +[source,json] +---- +// ... + "covers": [ + "cover (substr0((`account`.`transDate`), 0, 10))", + "cover ((`account`.`code`))", + "cover ((meta(`account`).`id`))" + ], + "filter": "(cover ((not ((`account`.`code`) = \"\"))) and (cover ((meta(`account`).`id`)) like \"account-customerXYZ-%\") and (\"2016-07-01\" <= cover (substr0((`account`.`transDate`), 0, 10))) and (cover (substr0((`account`.`transDate`), 0, 10)) < \"2016-07-03\"))", + "filter_covers": { + "cover ((\"account-customerXYZ\" <= (meta(`account`).`id`)))": true, + "cover (((meta(`account`).`id`) < \"account-customerXY[\"))": true, + "cover (((meta(`account`).`id`) like \"account-customerXYZ%\"))": true, + "cover ((not ((`account`.`code`) = \"\")))": true + }, + "index": "idx_account_customer_xyz_transDate", +// ... +---- +==== + +== Related Links + +* xref:learn:services-and-indexes/indexes/index-scans.adoc#query-execution-details[Query Execution: Details] +* xref:learn:services-and-indexes/indexes/index_pushdowns.adoc[Index Pushdown Optimizations] +* xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[Grouping and Aggregate Pushdown] +* xref:learn:services-and-indexes/indexes/early-filters-and-pagination.adoc[Early Filters, Ordering and Pagination] diff --git a/modules/n1ql/pages/n1ql-language-reference/createcollection.adoc b/modules/n1ql/pages/n1ql-language-reference/createcollection.adoc new file mode 100644 index 000000000..08fb5fd32 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/createcollection.adoc @@ -0,0 +1,174 @@ += CREATE COLLECTION +:description: The CREATE COLLECTION statement enables you to create a named collection within a scope. +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +:identifier: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:naming-for-scopes-and-collections: xref:server:learn:data/scopes-and-collections.adoc#naming-for-scopes-and-collections +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:scopes-and-collections: xref:server:learn:data/scopes-and-collections.adoc +:bucket-expiration: xref:server:learn:data/expiration.adoc +:manage-scopes-and-collections: xref:server:manage:manage-scopes-and-collections/manage-scopes-and-collections.adoc +:scopes-and-collections-api: xref:server:rest-api:scopes-and-collections-api.adoc +:couchbase-cli-collection-manage: xref:server:cli:cbcli/couchbase-cli-collection-manage.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `CREATE COLLECTION` statement enables you to create a named collection within a scope. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-collection] +---- + +image::n1ql-language-reference/create-collection.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal] +namespace:: +(Optional) An {identifier}[identifier] that refers to the {logical-hierarchy}[namespace] of the bucket in which you want to create the collection. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Optional) An {identifier}[identifier] that refers to the bucket in which you want to create the collection. + +scope:: +(Optional) An {identifier}[identifier] that refers to the scope in which you want to create the collection. + +collection:: +(Required) An {identifier}[identifier] that refers to the name of the collection that you want to create. +Refer to {naming-for-scopes-and-collections}[Naming for Scopes and Collections] for restrictions on collection names. + +NOTE: If there is a hyphen (-) inside the bucket name, the scope name, or the collection name, you must wrap that part of the path in backticks ({backtick} {backtick}). +For example, `default:{backtick}travel-sample{backtick}` indicates the `travel-sample` keyspace in the `default` namespace. + +[[location]] +=== Specifying the Location + +To specify the location of the collection, you may do one of the following: + +* Include its [def]_full path_, containing the namespace, bucket, and scope, followed by the collection name; +* Include a [def]_relative path_, containing just the bucket and scope, followed by the connection name; +* Specify just the collection name without a path. + +When you specify a collection name without a path, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. +If you specify a collection name by itself without setting a valid query context, an error is generated. + +[[if-not-exists]] +=== IF NOT EXISTS Clause + +The optional `IF NOT EXISTS` clause enables the statement to complete successfully when the specified collection already exists. +If a collection with the same name already exists within the specified scope, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +[[with]] +=== WITH Clause + +In clusters using Couchbase Server 7.6 and later, you can use the optional `WITH` clause to specify additional options for the collection. + +[horizontal] +expr:: +An object representing the options to be set for the collection. +Only the `maxTTL` attribute is valid; any other attributes generate an error. + +.icon:brackets-curly[fw] Object +{blank} + +[options="header", cols="25a,55a,20a"] +|=== +|Name|Description|Schema + +|**maxTTL** + +__required__ +|The maximum time-to-live for any item in the collection. +May have any of the following values. + +`0` or unspecified: The collection inherits the maximum time-to-live setting from the bucket which contains it. + +Positive integer: By default, items in the collection expire after this many seconds. +Overrides the maximum time-to-live set by the bucket. + +`-1`: By default, items in the collection never expire. +Overrides the maximum time-to-live set by the bucket. + +|integer +|=== + +== Usage + +It is important to note that the scope must exist before you can create the collection, whether the scope is specified in the statement itself or implied by the query context. +If the scope does not exist, an error is generated. +You cannot create the scope and the collection in a single statement. + +== Examples + +.Create collection with full path +==== +This statement creates a collection called `city` in the `inventory` scope within the `travel-sample` bucket. + +[source,sqlpp] +---- +CREATE COLLECTION `travel-sample`.inventory.city +---- +==== + +.Create collection with query context +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Assuming that the query context is set, this statement creates a collection called `country` in the `inventory` scope within the `travel-sample` bucket. + +[source,sqlpp] +---- +CREATE COLLECTION country; +---- +==== + +.Create collection if it doesn't exist +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Assuming that the query context is set, this statement creates a collection called `country` in the `inventory` scope within the `travel-sample` bucket. + +If the `country` collection already exists, the statement does nothing and no error is generated. + +[source,sqlpp] +---- +CREATE COLLECTION country IF NOT EXISTS; +---- +==== + +.Create collection with maximum time-to-live +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Assuming that the query context is set, this statement creates a collection called `country` in the `inventory` scope within the `travel-sample` bucket. + +The maximum time-to-live for the collection is set to `123456` seconds, overriding the maximum time-to-live specified by the bucket. + +[source,sqlpp] +---- +CREATE COLLECTION country IF NOT EXISTS WITH {"maxTTL": 123456}; +---- +==== + +== Related Links + +* An overview of scopes and collections is provided in {scopes-and-collections}[Scopes and Collections]. + +* Step-by-step procedures for management are provided in {manage-scopes-and-collections}[Manage Scopes and Collections]. + +* Refer to {scopes-and-collections-api}[Scopes and Collections API] to manage scopes and collections with the REST API. + +* Refer to the reference page for the {couchbase-cli-collection-manage}[collection-manage] command to manage scopes and collections with the CLI. + +* Refer to {bucket-expiration}[Expiration] for information about bucket and collection time-to-live. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc new file mode 100644 index 000000000..0c0fab15f --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -0,0 +1,649 @@ += CREATE FUNCTION +:description: pass:q[The `CREATE FUNCTION` statement enables you to create a user-defined function.] +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: +:page-toclevels: 2 +:keywords: library namespacing + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +include::javascript-udfs:partial$javascript-udf-introduction.adoc[] + +External functions in {sqlpp} support most of the language constructs available in ECMAScript. +For more information about the restrictions and extensions that come with the Couchbase implementation, see xref:javascript-udfs:javascript-functions-with-couchbase.adoc[]. + +[[context]] +=== Global Functions and Scoped Functions + +You can create user-defined functions at two different levels of the {sqlpp} xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy[logical hierarchy]. + +* A [.term]#global function# is created within a namespace, at the same level as the buckets within the namespace. +When you call a global function, any partial keyspace references within the function definition are resolved against the function's namespace, regardless of the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. ++ +For example, when you call a global function `default:global()` which contains the keyspace reference `{backtick}travel-sample{backtick}`, the keyspace reference is always resolved within the context of the function to the `default:{backtick}travel-sample{backtick}` bucket. + +* A [.term]#scoped function# is created within a scope, at the same level as the collections within the scope. +When you call a scoped function, any partial keyspace references within the function definition are resolved against the function's scope, regardless of the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. ++ +For example, when you call a scoped function `default:{backtick}travel-sample{backtick}.inventory.scope()` which contains the keyspace reference `route`, the keyspace reference is always resolved within the context of the function to `default:{backtick}travel-sample{backtick}.inventory.route`. + +When you create a user-defined function, the current query context determines whether it is created as a global function or a scoped function. +If you want to create a user-defined function outside of the current query context, you must include the full path to the function when you specify the function name. + +Similarly, when you call a user-defined function, the current query context determines the path to the function. +If you want to call a user-defined function outside of the current query context, you must include the full path to the function when you specify the function name. + +Finally, it is important to note that a global function is _not_ the same as a scoped function stored in the default scope in a bucket. + +ifdef::flag-devex-javascript-udfs[] +include::javascript-udfs:partial$libraries-and-scopes.adoc[tags=extract] +endif::flag-devex-javascript-udfs[] + +include::javascript-udfs:partial$sqlpp-managed-udfs.adoc[] + +== Prerequisites + +[cols="2,3"] +|=== +| To manage ... | You must have ... + +| Global inline functions +| *Manage Global Functions* role. + +| Scoped inline functions +| *Manage Scope Functions* role, with permissions on the specified bucket and scope. + +| Global external functions +| *Manage Global External Functions* role. + +| Scoped external functions +| *Manage Scope External Functions* role, with permissions on the specified bucket and scope. +|=== + +Users with the *Manage Scope External Functions* role also have read-only access to any global external library. + +[cols="2,3"] +|=== +| To execute ... | You must have ... + +| Global inline functions +| *Execute Global Functions* role. + +| Scoped inline functions +| *Execute Scope Functions* role, with permissions on the specified bucket and scope. + +| Global external functions +| *Execute Global External Functions* role. + +| Scoped external functions +| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. +|=== + +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +The `CREATE FUNCTION` statement takes a different syntax depending on the type of function you are creating. +Refer to <> or <> below. + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-function] +---- + +image::n1ql-language-reference/create-function.png["Syntax diagram: refer to source code listing", align=left] + +[[create-function-inline]] +:section: inline +=== Inline Functions + +There are two alternative syntaxes for defining an inline function: a syntax with braces `{}` and a syntax using the `LANGUAGE` keyword. +The two syntaxes are synonymous. + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-function-inline] +---- + +image::n1ql-language-reference/create-function-inline.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal.compact] +function:: <> icon:caret-down[] +params:: <> icon:caret-down[] +body:: <> icon:caret-down[] + +// tag::replace[] +[id='{section}-replace'] +==== OR REPLACE / IF NOT EXISTS + +The optional `OR REPLACE` clause enables you to redefine a user-defined function if it already exists, whereas the optional `IF NOT EXISTS` clause enables the statement to complete successfully without replacing the function. + +When a function with the same name already exists within the same context: +footnote:context[That is, you are creating a global function, and a function with the same name already exists within the same namespace; or, you are creating a scoped function, and a function with the same name already exists within the same scope.] + +* If the `OR REPLACE` clause is present, the existing function is replaced. + +* If the `IF NOT EXISTS` clause is present, the statement does nothing and completes without error. + +* If neither of these two clauses is present, an error is generated. + +NOTE: These clauses are exclusive. +If the statement contains both the `OR REPLACE` clause and the `IF NOT EXISTS` clause, an error is generated. + +// end::replace[] + +// tag::arguments[] +[id='{section}-name'] +==== Function Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=function] +---- + +image::n1ql-language-reference/function.png["Syntax diagram: refer to source code listing", align=left] + +The function name specifies the name of the function to create. +It is recommended to use an unqualified identifier for the function name, such as `func1` or `{backtick}func-1{backtick}`. +In this case, the function is created as a global function or a scoped function, depending on the current query context. + +To create a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as `default:func1`. +Similarly, to create a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. + +If the function name is an unqualified identifier, it may not be the same as a reserved keyword. +A function name with a specified namespace or scope may have the same name as a reserved keyword. + +[id='{section}-parameter'] +==== Function Parameters + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=params] +---- + +image::n1ql-language-reference/params.png["Syntax diagram: refer to source code listing", align=left] + +[Optional] The function parameter list specifies parameters for the function. +If you specify named parameters for the function, then you must call the function with exactly the same number of arguments at execution time. +If you specify no parameters, then you must call the function with no arguments. +To create a variadic function, that is, a function which you can call with any number of arguments or none, specify `\...` as the only parameter. +// end::arguments[] + +[[inline-expression]] +==== Function Body + +The function body defines the function. +You can use any valid {sqlpp} expression. +If you specified named parameters for the function, you can use these in the expression to represent arguments passed to the function at execution time. +If you specified that the function is variadic, any arguments passed to the function at execution time are held in an array named `args`. + +[NOTE] +==== +* If the expression contains a parameter that has the same name as a field in the document, it will always refer to the parameter. +To distinguish between the field and the parameter, prefix the field with the keyspace name, for example `landmark.activity`. +To avoid this ambiguity, you should use unique parameter names that do not clash with document field names, such as `vActivity`. + +* Functions may return only one value, of any valid {sqlpp} type. +For inline functions, the result and type of the function are the result and type of the expression. +If you need to return multiple values, construct an array. +==== + +[[create-function-external]] +:section: external +=== External Functions + +ifdef::flag-devex-javascript-udfs[] +There are two alternative syntaxes for defining an external function: one where the function code is stored in an external library, and one for creating a {sqlpp} managed user-defined function. +endif::flag-devex-javascript-udfs[] + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-function-external] +---- + +image::n1ql-language-reference/create-function-external.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal.compact] +function:: <> icon:caret-down[] +params:: <> icon:caret-down[] +obj:: <> icon:caret-down[] +library:: <> icon:caret-down[] +javascript:: <> icon:caret-down[] + +include::createfunction.adoc[tag=replace] + +include::createfunction.adoc[tag=arguments] + +[[external-object]] +==== External Object + +[Optional] Use this parameter where the function code is stored in an external library. + +ifndef::flag-devex-javascript-udfs[] +Note that Capella does not currently support a way to create or manage an external library. +endif::flag-devex-javascript-udfs[] + +ifdef::flag-devex-javascript-udfs[] +The name of the JavaScript function that you want to use for the user-defined function. +This parameter is a string and must be wrapped in quotes. +endif::flag-devex-javascript-udfs[] + +[[external-library]] +==== External Library + +[Optional] Use this parameter where the function code is stored in an external library. + +ifndef::flag-devex-javascript-udfs[] +Note that Capella does not currently support a way to create or manage an external library. +endif::flag-devex-javascript-udfs[] + +ifdef::flag-devex-javascript-udfs[] +The name of the JavaScript library that contains the JavaScript function you want to use. +This parameter is a string and must be wrapped in quotes. + +The name of a scoped external library must include the bucket name, the scope name, and the library name, separated by slashes. +For example, to refer to a scoped library called `my-library` located in the `inventory` scope within the `travel-sample` bucket, you would specify the library name as `travel-sample/inventory/my-library`. +endif::flag-devex-javascript-udfs[] + +[[javascript]] +==== Function Body + +[Optional] Use this parameter to create a {sqlpp} managed user-defined function. + +The external JavaScript function code. +This must contain a function with the same name and the same number of parameters as the {sqlpp} user-defined function. +This parameter is a string and must be wrapped in quotes. + +The JavaScript code can contain multiple function definitions, but these functions can only be referenced within the JavaScript code for this {sqlpp} user-defined function, and cannot be shared. + +== Examples + +For simplicity, none of these examples implement any data validation or error checking. +If necessary, you can use xref:n1ql:n1ql-language-reference/conditionalops.adoc[conditional operators] to check the parameters of a user-defined function, and the xref:n1ql:n1ql-language-reference/metafun.adoc#abort[ABORT()] function to generate an error if something is wrong. + +[[ex-inline-language]] +.Inline function with the LANGUAGE syntax +==== +This statement creates a function called `celsius`, which converts Fahrenheit to Celsius. +The function is variadic. + +For purposes of illustration, this expression converts just the first argument supplied at execution time, which is stored in the first member in the `args` array. +A more realistic variadic function would make use of all the supplied arguments. + +[source,sqlpp] +---- +CREATE FUNCTION celsius(...) LANGUAGE INLINE AS (args[0] - 32) * 5/9; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION celsius(100); +---- + +.Result +[source,json] +---- +[ + 37.77777777777778 +] +---- +==== + +[[ex-inline-braces]] +.Inline function with the braces syntax +==== +This statement creates a function called `fahrenheit`, which converts Celsius to Fahrenheit. +The function is variadic. + +For purposes of illustration, this expression converts just the first argument supplied at execution time, which is stored in the first member in the `args` array. +A more realistic variadic function would make use of all the supplied arguments. + +[source,sqlpp] +---- +CREATE FUNCTION fahrenheit(...) { (args[0] * 9/5) + 32 }; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION fahrenheit(100, "ignore this"); +---- + +.Result +[source,json] +---- +[ + 212 +] +---- + +As the function is variadic, you can use any number of arguments when you call the function. +Arguments which are not used by the function expression are ignored. +==== + +[[ex-params-incorrect]] +.Inline function with named parameters +==== +The following statement creates a function called `lstr`, which returns the specified number of characters from the left of a string. +The expression expects two named arguments: `vString`, which is the string to work with, and `vLen`, which is the number of characters to return. + +[source,sqlpp] +---- +CREATE FUNCTION lstr(vString, vLen) LANGUAGE INLINE AS SUBSTR(vString, 0, vLen); +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION lstr("Couchbase", 5, "ignore this"); +---- + +.Result +[source,json] +---- +[ + { + "code": 10104, + "msg": "Incorrect number of arguments supplied to function lstr - cause: lstr" + } +] +---- + +As the arguments were specified by the function definition, you must use the same number of arguments when you call the function. +If you supply the wrong number of arguments, an error is generated. +==== + +[[ex-params-correct]] +.Inline function with named parameters +==== +The following statement creates a function called `rstr`, which returns the specified number of characters from the right of a string. +The expression expects two named arguments: `vString`, which is the string to work with, and `vLen`, which is the number of characters to return. + +[source,sqlpp] +---- +CREATE FUNCTION rstr(vString, vLen) { SUBSTR(vString, LENGTH(vString) - vLen, vLen) }; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION rstr("Couchbase", 4); +---- + +.Result +[source,json] +---- +[ + "base" +] +---- +==== + +[[ex-inline-subquery]] +.Inline function with subquery +==== +The following statement creates a function called `locations`, which selects name and address information from all documents with the specified activity in the `landmark` keyspace. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/udf-locations-define.n1ql[] +---- + +.Test +[source,sqlpp] +---- +include::example$n1ql-language-reference/udf-locations-test.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/udf-locations-test.jsonc[tag=excerpt] +... +---- +==== + +[[ex-replace]] +.Replace a function +==== +This statement creates a function which returns the mathematical constant φ. +The function takes no arguments. + +[source,sqlpp] +---- +CREATE FUNCTION phi() { 2 * SIN(RADIANS(54)) }; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION phi(); +---- + +.Result +[source,json] +---- +[ + 1.618033988749895 +] +---- + +The following statement redefines the function so that it calculates φ using a different method. + +.Replace +[source,sqlpp] +---- +CREATE OR REPLACE FUNCTION phi() { (1 + SQRT(5)) / 2 }; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION phi(); +---- + +.Result +[source,json] +---- +[ + 1.618033988749895 +] +---- +==== + +[[ex-managed]] +.{sqlpp} managed user-defined function +==== +The following statement creates external JavaScript function code and the corresponding {sqlpp} user-defined function in one operation. + +[source,sqlpp] +---- +CREATE FUNCTION add100(num) LANGUAGE JAVASCRIPT AS +"function add100(param1) {return param1+100;}"; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION add100(100); +---- + +.Result +[source,json] +---- +[ + 200 +] +---- +==== + +ifdef::flag-devex-javascript-udfs[] +[[ex-external]] +.External functions +==== +The following command registers two JavaScript functions called `encodeGeoHash` and `calculateAdjacent` in a library called `geohash-js`. +footnote:[Credit: https://github.com/davetroy/geohash-js] + +* The function `encodeGeoHash` takes two arguments, a latitude and a longitude, and returns the 12-character https://en.wikipedia.org/wiki/Geohash[geohash^] for the specified location. +* The function `calculateAdjacent` takes two arguments, a geohash and a direction -- `"top"`, `"bottom"`, `"left"`, or `"right"` -- and returns the geohash of the location next to the original geohash in the specified direction. + +[source,sh] +---- +curl -v -X POST \ +http://localhost:8093/evaluator/v1/libraries/geohash-js \ +-u Administrator:password \ +-H 'content-type: application/json' \ +-d 'function encodeGeoHash(latitude, longitude) { + + var BITS = [16, 8, 4, 2, 1]; + var BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz"; + + var is_even = 1; + var i = 0, mid; + var lat = []; var lon = []; + var bit = 0; + var ch = 0; + var precision = 12; + var geohash = ""; + + lat[0] = -90.0; lat[1] = 90.0; + lon[0] = -180.0; lon[1] = 180.0; + + while (geohash.length < precision) { + if (is_even) { + mid = (lon[0] + lon[1]) / 2; + if (longitude > mid) { + ch |= BITS[bit]; + lon[0] = mid; + } else + lon[1] = mid; + } else { + mid = (lat[0] + lat[1]) / 2; + if (latitude > mid) { + ch |= BITS[bit]; + lat[0] = mid; + } else + lat[1] = mid; + } + + is_even = !is_even; + if (bit < 4) + bit++; + else { + geohash += BASE32[ch]; + bit = 0; + ch = 0; + } + } + + return geohash; +} + +function calculateAdjacent(srcHash, dir) { + + var BITS = [16, 8, 4, 2, 1]; + var BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz"; + + var NEIGHBORS = { right : { even : "bc01fg45238967deuvhjyznpkmstqrwx" }, + left : { even : "238967debc01fg45kmstqrwxuvhjyznp" }, + top : { even : "p0r21436x8zb9dcf5h7kjnmqesgutwvy" }, + bottom : { even : "14365h7k9dcfesgujnmqp0r2twvyx8zb" } }; + + var BORDERS = { right : { even : "bcfguvyz" }, + left : { even : "0145hjnp" }, + top : { even : "prxz" }, + bottom : { even : "028b" } }; + + NEIGHBORS.bottom.odd = NEIGHBORS.left.even; + NEIGHBORS.top.odd = NEIGHBORS.right.even; + NEIGHBORS.left.odd = NEIGHBORS.bottom.even; + NEIGHBORS.right.odd = NEIGHBORS.top.even; + + BORDERS.bottom.odd = BORDERS.left.even; + BORDERS.top.odd = BORDERS.right.even; + BORDERS.left.odd = BORDERS.bottom.even; + BORDERS.right.odd = BORDERS.top.even; + + srcHash = srcHash.toLowerCase(); + var lastChr = srcHash.charAt(srcHash.length - 1); + var type = (srcHash.length % 2) ? "odd" : "even"; + var base = srcHash.substring(0, srcHash.length - 1); + if (BORDERS[dir][type].indexOf(lastChr) != -1) + base = calculateAdjacent(base, dir); + return base + BASE32[NEIGHBORS[dir][type].indexOf(lastChr)]; +}' +---- + +The following statements create two functions: + +. A function called `geohash`, which calls the JavaScript `encodeGeoHash` function from the `geohash-js` library; +. A function called `adjacent`, which calls the JavaScript `calculateAdjacent` function from the `geohash-js` library. + +[source,sqlpp] +---- +CREATE FUNCTION geohash(lat, lon) + LANGUAGE JAVASCRIPT AS "encodeGeoHash" AT "geohash-js"; + +CREATE FUNCTION adjacent(src, dir) + LANGUAGE JAVASCRIPT AS "calculateAdjacent" AT "geohash-js"; +---- + +.Test `geohash` +[source,sqlpp] +---- +EXECUTE FUNCTION geohash(53.353744, -2.27495); +---- + +.Result +[source,json] +---- +[ + "gcqrs0z2jfdr" +] +---- + +To view the geohash on a map, go to http://geohash.org/gcqrs0z2jfdr and follow one of the links provided. +At the specified latitude, the geohash represents an area of approximately 11 𐄂 19 millimeters. + +.Test `adjacent` +[source,sqlpp] +---- +EXECUTE FUNCTION adjacent(geohash(53.353744, -2.27495), "top"); +---- + +.Result +[source,json] +---- +[ + "gcqrs0z2jff2" +] +---- + +To view the geohash on a map, go to http://geohash.org/gcqrs0z2jff2 and follow one of the links provided. +At this level of precision, the geohash should appear to be in almost exactly the same location as the previous one. +==== +endif::flag-devex-javascript-udfs[] + +== Related Links + +ifdef::flag-devex-javascript-udfs[] +* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. +endif::flag-devex-javascript-udfs[] +* To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. +* To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. +* To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. +* To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/createindex.adoc b/modules/n1ql/pages/n1ql-language-reference/createindex.adoc new file mode 100644 index 000000000..08434b512 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/createindex.adoc @@ -0,0 +1,559 @@ += CREATE INDEX +:page-topic-type: reference +:imagesdir: ../../assets/images +:keywords: secondary, index, placement +:description: The CREATE INDEX statement allows you to create a secondary index. \ +Secondary indexes contain a filtered or a full set of keys in a given keyspace. + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:index-replication: xref:learn:services-and-indexes/indexes/index-replication.adoc#index-replication +:console-indexes: xref:server:manage:manage-ui/manage-ui.adoc#console-indexes +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:build-index: xref:n1ql-language-reference/build-index.adoc +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:expression: xref:n1ql-language-reference/index.adoc +:aggregatefun: xref:n1ql:n1ql-language-reference/aggregatefun.adoc +:indexing-arrays: xref:n1ql-language-reference/indexing-arrays.adoc +:index-partitioning: xref:n1ql-language-reference/index-partitioning.adoc +:indexing-meta-info: xref:n1ql-language-reference/indexing-meta-info.adoc +:operator-pushdowns: xref:learn:services-and-indexes/indexes/index_pushdowns.adoc#operator-pushdowns +:logical-hierarchy: xref:n1ql:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:querying-indexes: xref:n1ql-intro/sysinfo.adoc#querying-indexes + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +The `CREATE INDEX` statement allows you to create a secondary index. +Secondary indexes contain a filtered or a full set of keys in a given keyspace. +Secondary indexes are optional but increase query efficiency on a keyspace. + +== Purpose + +`CREATE INDEX` allows you to make multiple concurrent index creation requests. +The command starts a task to create the index definition in the background. +If there is an index creation task already running, the Index Service queues the incoming index creation request. +`CREATE INDEX` returns as soon as the index creation phase is complete. + +By default, when the index creation phase is complete, the Index Service triggers the index build phase. +If you lose connectivity, the index build operation continues in the background. +You can defer the index build phase using the `defer_build` clause. +In deferred build mode, `CREATE INDEX` creates the index definition, but does not trigger the index build phase. +You can then build the index using the {build-index}[BUILD INDEX] command. + +You can create multiple identical secondary indexes on a keyspace and place them on separate nodes for better index availability. +The recommended way to do this is using the `num_replica` option. + +== Prerequisites + +[discrete] +===== RBAC Privileges + +User executing the CREATE INDEX statement must have the _Query Manage Index_ privilege granted on the keyspace. +For more details about user roles, see +{authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-index] +---- + +image::n1ql-language-reference/create-index.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal#index-name, reftext="index-name"] +index-name:: (Required) A unique name that identifies the index. ++ +Valid GSI index names can contain any of the following characters: `A-Z` `a-z` `0-9` `#` `_`, and must start with a letter, [`A-Z` `a-z`]. +The minimum length of an index name is 1 character and there is no maximum length set for an index name. +When querying, if the index name contains a `#` or `_` character, you must enclose the index name within backticks. + +keyspace-ref:: (Required) Specifies the keyspace where the index is created. +Refer to <> below. + +index-key:: (Required) Specifies an index key. +Refer to <> below. + +lead-key-attribs:: (Optional) Specifies attributes for the leading index key. +Refer to <> below. + +key-attribs:: (Optional) Specifies attributes for a non-leading index key. +Refer to <> below. + +index-partition:: (Optional) Specifies index partitions. +Refer to <> below. + +where-clause:: (Optional) Specifies filters for a partial index. +Refer to <> below. + +index-using:: (Optional) Specifies the index type. +Refer to <> below. + +index-with:: (Optional) Specifies options for the index. +Refer to <> below. + +[[if-not-exists]] +=== IF NOT EXISTS Clause + +The optional `IF NOT EXISTS` clause enables the statement to complete successfully when the specified index already exists. +If an index with the same name already exists within the specified keyspace, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the keyspace for which the index needs to be created. +The keyspace reference may be a <> or a <>. + +NOTE: If there is a hyphen (-) inside any part of the keyspace reference, you must wrap that part of the keyspace reference in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-path,keyspace path]] +==== Keyspace Path + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +If the keyspace is a named collection, or the default collection in the default scope within a bucket, the keyspace reference may be a keyspace path. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. +If omitted, the bucket's default scope is used. + +collection:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. +If omitted, the default collection in the bucket's default scope is used. + +==== +For example, `default:{backtick}travel-sample{backtick}` indicates the default collection in the default scope in the `travel-sample` bucket in the `default` namespace. + +Similarly, `default:{backtick}travel-sample{backtick}.inventory.airline` indicates the `airline` collection in the `inventory` scope in the `travel-sample` bucket in the `default` namespace. +==== + +[[keyspace-partial,keyspace partial]] +==== Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the keyspace reference may be just the collection name with no path. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `airline` indicates the `airline` collection, assuming the query context is set. +==== + +[[index-key]] +=== Index Key + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-key] +---- + +image::n1ql-language-reference/index-key.png["Syntax diagram: refer to source code listing", align=left] + +Refers to an attribute name or a scalar function or an ARRAY expression on the attribute. +This constitutes an index-key for the index. + +[horizontal#index-key-args] +expr:: +A {sqlpp} {expression}[expression] over any fields in the document. +This cannot use constant expressions, aggregate functions, or sub-queries. + +array-expr:: +An array expression. +Array indexing enables you to create global indexes on array elements and optimize the execution of queries involving array elements. +For details, refer to {indexing-arrays}[Array Indexing]. + +[[index-key-attrib]] +=== Index Key Attributes + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=lead-key-attribs] +---- + +image::n1ql-language-reference/lead-key-attribs.png["Syntax diagram: refer to source code listing", align=left] + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=key-attribs] +---- + +image::n1ql-language-reference/key-attribs.png["Syntax diagram: refer to source code listing", align=left] + +Specifies attributes for the index key. + +[horizontal] +index-order:: (Optional) All index keys may include an index order clause. +Refer to <> below. + +include-missing:: (Optional) The leading index key may also include `INCLUDE MISSING` clause. +Refer to <> below. + +[[index-order]] +==== Index Order + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-order] +---- + +image::n1ql-language-reference/index-order.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the sort order of the index key. + +[horizontal] +`ASC`:: +The index key is sorted in ascending order. + +`DESC`:: +The index key is sorted in descending order. + +This clause is optional; if omitted, the default is `ASC`. + +[[include-missing]] +==== INCLUDE MISSING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=include-missing] +---- + +image::n1ql-language-reference/include-missing.png["Syntax diagram: refer to source code listing", align=left] + +The optional `INCLUDE MISSING` clause ensures that documents which do not include the index key field are indexed regardless. +If this clause is not present, then documents without the index key field are not indexed. + +The `INCLUDE MISSING` clause can only be applied to the leading index key. +The `INCLUDE MISSING` clause may be included before or after the `ASC` or `DESC` keyword. + +[[index-partition]] +=== PARTITION BY HASH Clause + +Used to partition the index. +Index partitioning helps increase the query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. +For details, refer to {index-partitioning}[Index Partitioning]. + +[[where-clause]] +=== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal#where-clause-args] +cond:: +Specifies WHERE clause predicates to qualify the subset of documents to include in the index. + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +The index type for a secondary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +[[index-with]] +=== WITH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-with] +---- + +image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] + +Use the WITH clause to specify additional options. + +[horizontal#index-with-args] +expr:: +An object with the following properties. + +[options="header", cols="1a,4a,1a"] +|=== +|Name|Description|Schema + +|**nodes** + +__optional__ +| An array of strings, each of which represents a node name. + +include::partial$n1ql-language-reference/file-based-index-rebalance-note.adoc[] + +You can specify multiple nodes to distribute replicas of an index across nodes running the indexing service: for example, `WITH {"nodes": ["node1:8091", "node2:8091", "node3:8091"]}`. +For details and examples, refer to {index-replication}[Index Replication]. + +If specifying both [.var]`nodes` and [.var]`num_replica`, the number of nodes in the array must be one greater than the specified number of replicas otherwise the index creation will fail. + +(((default index placement)))If [.var]`nodes` is not specified, then the system chooses nodes on which to place the new index and any replicas, in order to achieve the best resource utilization across nodes running the indexing service. +This is done by taking into account the current resource usage statistics of index nodes. + +''' +A node name passed to the `nodes` property must include the cluster administration port, by default 8091. + +**Example:** `["192.0.2.0:8091"]` +|String array + +|**defer_build** + +__optional__ +| Whether the index should be created in deferred build mode. + +When set to `true`, the `CREATE INDEX` operation queues the task for building the GSI index but immediately pauses the building of the index. +Index building requires an expensive scan operation. +Deferring building of the index with multiple indexes can optimize the expensive scan operation. +Admins can defer building multiple indexes and, using the `BUILD INDEX` statement, build multiple indexes efficiently with one efficient scan of bucket data. + +When set to `false`, the `CREATE INDEX` operation queues the task for building the GSI index and immediately kicks off the building of the index. + +**Default:** `false` +|Boolean + +|**num_replica** + +__optional__ +| The number of {index-replication}[replicas] of the index to create. + +The indexer will automatically distribute these replicas amongst index nodes in the cluster for load-balancing and high availability purposes. +The indexer will attempt to distribute the replicas based on the server groups in use in the cluster where possible. + +If the value of this property is not less than the number of index nodes in the cluster, then the index creation will fail. + +**Default:** `1` +|Integer +|=== + +== Usage + +NOTE: It is not recommended to create (or drop) secondary indexes when any node with a secondary index role is down, as this may result in duplicate index names. + +=== Monitoring Indexes + +Index metadata provides a state field. +This state field and other index metadata can be queried using {querying-indexes}[system:indexes]. +The index state may be `scheduled for creation`, `deferred`, `building`, `pending`, `online`, `offline`, or `abridged`. +You can also monitor the index state using the Couchbase Web Console. + +[IMPORTANT] +==== +If you kick off multiple index creation operations concurrently, you may sometimes see transient errors similar to the following. +If this error occurs, the Index Service tries to run the failed operation again in the background until it succeeds, up to a maximum of 1000 retries. + +[source,json] +---- +include::example$n1ql-language-reference/build-idx-error.jsonc[] +---- + +If the Index Service still cannot create the index after the maximum number of retries, the index state is marked as `offline`. +You must drop the failed index using the `DROP INDEX` command. +==== + +[[indexing-metadata]] +=== Using the `meta().id` Function + +You can create indexes on metadata information. +For details, refer to {indexing-meta-info}[Indexing Meta Info]. + +[[index-aggregates]] +=== Using Indexes for Aggregates + +If you have an index on a simple expression, such as `geo.alt`, you can use that index to satisfy a query on an {aggregatefun}[aggregate] of that expression, such as `MIN(geo.alt)` or `MAX(geo.alt)`. +For details and examples, refer to {operator-pushdowns}[Operator Pushdowns]. + +[[index-replicas]] +=== Index Replicas + +In the {console-indexes}[Indexes screen in the Couchbase Web Console], index replicas are marked with their replica ID. + +image::create-index-replica-id.png["The Indexes screen showing an index and index replica with replica ID"] + +If you select `view by server node` from the drop-down menu, you can see the server node where each index and index replica is placed. + +You can also query the {querying-indexes}[system:indexes] catalog to find the ID of an index replica and see which node it is placed on. + +[NOTE] +==== +By default, index replicas are used to serve index scans. +The system automatically load-balances an index scan across the index and all its replicas. +Adding index replicas enables you to scale scan throughput, in addition to providing high availability. +==== + +ifdef::flag-devex-rest-api[] +=== Defer Index Builds by Default + +[.status]#Couchbase Server 7.6.2# + +Usually, the default setting for the `defer_build` option is `false`. +In Couchbase Server 7.6.2 and later, you can change the default setting for the `defer_build` option. + +If you change the default setting for `defer_build` to `true`, index creation operates in deferred build mode by default. + +To change the default setting for deferred builds, use the REST API to set the `indexer.settings.defer_build` property. +For example, + +[source,sh] +---- +curl http://$BASEURL:9102/settings -u $USER:$PASSWORD \ +-d '{"indexer.settings.defer_build": true}' +---- + +Use the following command to retrieve the indexer settings: + +[source,sh] +---- +curl -X GET http://$BASEURL:9102/settings -u $USER:$PASSWORD +---- + +* `$BASEURL` is the base URL for the API call, for example: `localhost`. +* `$USER` is the username, for example: `Administrator`. +* `$PASSWORD` is the password. +endif::flag-devex-rest-api[] + +== Examples + +To try the examples in this section, you must set the query context as described in each example. + +[[ex-create-idx]] +.Create an index in the default scope and collection +==== +include::ROOT:partial$query-context.adoc[tag=unset] + +Create a secondary index that contains airports with an `alt` value greater than 1000 on the node `127.0.0.1`. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-default.n1ql[tag=query] +---- +==== + +[[ex-create-idx-collection]] +.Create an index in a named scope and collection +==== +For this example, the path to the required keyspace is specified by the query, so you do not need to set the query context. + +Create a secondary index that contains airports with an `alt` value greater than 1000 on the node `127.0.0.1`. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-collection.n1ql[tag=query] +---- +==== + +[[ex-create-idx-defer]] +.Create a deferred index +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Create a secondary index with the `defer_build` option. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-defer-1.n1ql[] +---- + +Query `system:indexes` for the status of the index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/check-idx-defer.n1ql[] +---- + +.Results +[source,json] +---- +include::example$n1ql-language-reference/check-idx-defer.jsonc[] +---- + +<1> Note that the index is in the deferred state. +==== + +[[ex-build-idx-defer]] +.Build a deferred index +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Kick off a deferred build using the index name. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/build-idx-single.n1ql[] +---- + +Query `system:indexes` for the status of the index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/check-idx-online.n1ql[] +---- + +.Results +[source,json] +---- +include::example$n1ql-language-reference/check-idx-online.jsonc[] +---- + +<1> Note that the index has now been created. +==== + +[[ex-create-idx-missing]] +.Create index with missing leading key +==== +include::ROOT:partial$query-context.adoc[tag=example] + +The following statement will not index airports where the `district` field is missing. + +[source, n1ql] +---- +include::example$n1ql-language-reference/create-idx-missing.n1ql[] +---- + +The following statement will index all airports, even if the `district` field is not included in the document. + +[source, n1ql] +---- +include::example$n1ql-language-reference/create-idx-include.n1ql[] +---- +==== + +For more examples of indexes where the leading key may be missing, see xref:n1ql:n1ql-language-reference/selectintro.adoc#index-selection[Index Selection]. diff --git a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc new file mode 100644 index 000000000..408460b0e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc @@ -0,0 +1,352 @@ += CREATE PRIMARY INDEX +:page-topic-type: reference +:imagesdir: ../../assets/images +:keywords: primary, index, placement +:description: The CREATE PRIMARY INDEX statement allows you to create a primary index. \ +Primary indexes contain a full set of keys in a given keyspace. + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:build-index: xref:n1ql-language-reference/build-index.adoc +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:querying-indexes: xref:n1ql-intro/sysinfo.adoc#querying-indexes +:index-replication: xref:learn:services-and-indexes/indexes/index-replication.adoc#index-replication +:query-settings: xref:server:manage:manage-settings/query-settings.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +The `CREATE PRIMARY INDEX` statement allows you to create a primary index. +Primary indexes contain a full set of keys in a given keyspace. +Primary indexes are optional and are only required for running ad hoc queries on a keyspace that is not supported by a secondary index. + +== Purpose + +`CREATE PRIMARY INDEX` allows you to make multiple concurrent index creation requests. +The command starts a task to create the primary index definition in the background. +If there is an index creation task already running, the Index Service queues the incoming index creation request. +`CREATE PRIMARY INDEX` returns as soon as the index creation phase is complete. + +By default, when the index creation phase is complete, the Index Service triggers the index build phase. +If you lose connectivity, the index build operation continues in the background. +You can defer the index build phase using the `defer_build` clause. +In deferred build mode, `CREATE PRIMARY INDEX` creates the index definition, but does not trigger the index build phase. +You can then build the index using the {build-index}[BUILD INDEX] command. + +You can create multiple identical primary indexes on a keyspace and place them on separate nodes for better index availability. +The recommended way to do this is using the `num_replicas` option. +Refer to <> below for more details. + +== Prerequisites + +[discrete] +===== RBAC Privileges + +Users executing the `CREATE PRIMARY INDEX` statement must have the _Query Manage Index_ privilege granted on the keyspace. +For more details about user roles, see +{authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-primary-index] +---- + +image::n1ql-language-reference/create-primary-index.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal] +index-name:: +(Optional) A unique name that identifies the index. +If a name is not specified, the default name of `#primary` is applied. [small]##[<>]## ++ +Valid GSI index names can contain any of the following characters: `A-Z` `a-z` `0-9` `#` `_`, and must start with a letter, [`A-Z` `a-z`]. +The minimum length of an index name is 1 character and there is no maximum length set for an index name. +When querying, if the index name contains a `#` or `_` character, you must enclose the index name within backticks. + +keyspace-ref:: [Required] Specifies the keyspace where the index is created. +Refer to <> below. + +index-using:: (Optional) Specifies the index type. +Refer to <> below. + +index-with:: (Optional) Specifies options for the index. +Refer to <> below. + +[[note-index-name,note]] +NOTE: You can drop unnamed primary indexes using the `DROP PRIMARY INDEX` statement, and named primary indexes using the `DROP INDEX` statement. + +[[if-not-exists]] +=== IF NOT EXISTS Clause + +The optional `IF NOT EXISTS` clause enables the statement to complete successfully when the specified primary index already exists. +If a primary index with the same name already exists within the specified keyspace, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the keyspace for which the index needs to be created. +The keyspace reference may be a <> or a <>. + +NOTE: If there is a hyphen (-) inside any part of the keyspace reference, you must wrap that part of the keyspace reference in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-path,keyspace path]] +==== Keyspace Path + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +If the keyspace is a named collection, or the default collection in the default scope within a bucket, the keyspace reference may be a keyspace path. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. +If omitted, the bucket's default scope is used. + +collection:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. +If omitted, the default collection in the bucket's default scope is used. + +==== +For example, `default:{backtick}travel-sample{backtick}` indicates the default collection in the default scope in the `travel-sample` bucket in the `default` namespace. + +Similarly, `default:{backtick}travel-sample{backtick}.inventory.airline` indicates the `airline` collection in the `inventory` scope in the `travel-sample` bucket in the `default` namespace. +==== + +[[keyspace-partial,keyspace partial]] +==== Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the keyspace reference may be just the collection name with no path. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `airline` indicates the `airline` collection, assuming the query context is set. +==== + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +The index type for a primary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +[[index-with]] +=== WITH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-with] +---- + +image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] + +Use the WITH clause to specify additional options. + +[horizontal#index-with-args] +expr:: +An object with the following properties. + +[options="header", cols="1a,4a,1a"] +|=== +|Name|Description|Schema + +|**nodes** + +__optional__ +| An array of strings, each of which represents a node name. + +include::partial$n1ql-language-reference/file-based-index-rebalance-note.adoc[] + +''' + +You can specify multiple nodes to distribute replicas of an index across nodes running the indexing service: for example, `WITH {"nodes": ["node1:8091", "node2:8091", "node3:8091"]}`. +For details and examples, refer to {index-replication}[Index Replication]. + +If specifying both [.var]`nodes` and [.var]`num_replica`, the number of nodes in the array must be one greater than the specified number of replicas otherwise the index creation will fail. + +(((default index placement)))If [.var]`nodes` is not specified, then the system chooses nodes on which to place the new index and any replicas, in order to achieve the best resource utilization across nodes running the indexing service. +This is done by taking into account the current resource usage statistics of index nodes. + +''' +A node name passed to the `nodes` property must include the cluster administration port, by default 8091. + +**Example:** `["192.0.2.0:8091"]` +|String array + +|**defer_build** + +__optional__ +| Whether the index should be created in deferred build mode. + +When set to `true`, the `CREATE PRIMARY INDEX` operation queues the task for building the GSI index but immediately pauses the building of the index. +Index building requires an expensive scan operation. +Deferring building of the index with multiple indexes can optimize the expensive scan operation. +Admins can defer building multiple indexes and, using the `BUILD INDEX` statement, build multiple indexes efficiently with one efficient scan of keyspace data. + +When set to `false`, the `CREATE PRIMARY INDEX` operation queues the task for building the GSI index and immediately kicks off the building of the index. + +**Default:** `false` +|Boolean + +|**num_replica** + +__optional__ +| The number of {index-replication}[replicas] of the index to create. + +The indexer will automatically distribute these replicas amongst index nodes in the cluster for load-balancing and high availability purposes. +The indexer will attempt to distribute the replicas based on the server groups in use in the cluster where possible. + +If the value of this property is not less than the number of index nodes in the cluster, then the index creation will fail. + +**Default:** `1` +|Integer +|=== + +== Usage + +=== Monitoring Primary Indexes + +Index metadata provides a state field. +This state field and other index metadata can be queried using {querying-indexes}[system:indexes]. +The index state may be `scheduled for creation`, `deferred`, `building`, `pending`, `online`, `offline`, or `abridged`. +You can also monitor the index state using the Couchbase Web Console. + +[IMPORTANT] +==== +If you kick off multiple index creation operations concurrently, you may sometimes see transient errors similar to the following. +If this error occurs, the Index Service tries to run the failed operation again in the background until it succeeds, up to a maximum of 1000 retries. + +[source,json] +---- +include::example$n1ql-language-reference/build-idx-error.jsonc[] +---- + +If the Index Service still cannot create the index after the maximum number of retries, the index state is marked as `offline`. +You must drop the failed index using the `DROP INDEX` command. +==== + +=== Primary Scan Timeout + +For a primary index scan on any keyspace size, the query engine guarantees that the client is not exposed to scan timeout if the indexer throws a scan timeout after it has returned a greater than zero sized subset of primary keys. +To complete the scan, the query engine performs successive scans of the primary index until all the primary keys have been returned. +It is possible that the indexer throws scan timeout without returning any primary keys, and in this event the query engine returns scan timeout to the client. + +For example, if the indexer cannot find a snapshot that satisfies the consistency guarantee of the query within the timeout limit, it will timeout without returning any primary keys. + +For secondary index scans, the query engine does not handle scan timeout, and returns index scan timeout error to the client. +You can handle scan timeout on a secondary index by increasing the indexer timeout setting (see +{query-settings}[Query Settings]) or preferably by defining and using a more selective index. + +== Examples + +To try the examples in this section, you must set the query context as described in each example. + +[[ex-create-primary]] +.Create a primary index in the default scope and collection +==== +include::ROOT:partial$query-context.adoc[tag=unset] + +Create a named primary index on the default collection in the default scope within the `travel-sample` bucket. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-pri-default.n1ql[tag=query] +---- +==== + +[[ex-create-primary-name]] +.Create a primary index in a named scope and collection +==== +For this example, the path to the required keyspace is specified by the query, so you do not need to set the query context. + +This example is similar to <>, but creates a named primary index on the `airport` collection. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-pri-collection.n1ql[tag=query] +---- +==== + +.Create a deferred primary index +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Create a named primary index using the `defer_build` option. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-pri-defer.n1ql[] +---- + +Query `system:indexes` for the status of the index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/check-pri-defer.n1ql[] +---- + +The output from `system:indexes` shows the `idx_hotel_primary` in the deferred state. +==== + +.Build a deferred primary index +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Kick off the deferred build on the named primary index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/build-pri-single.n1ql[] +---- + +Query `system:indexes` for the status of the index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/check-pri-online.n1ql[] +---- + +The output from `system:indexes` shows that the index has now been created. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/createscope.adoc b/modules/n1ql/pages/n1ql-language-reference/createscope.adoc new file mode 100644 index 000000000..6b13be527 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/createscope.adoc @@ -0,0 +1,75 @@ += CREATE SCOPE +:description: pass:q[The `CREATE SCOPE` statement enables you to create a scope.] +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +:identifier: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:naming-for-scopes-and-collections: xref:server:learn:data/scopes-and-collections.adoc#naming-for-scopes-and-collections +:scopes-and-collections: xref:clusters:data-service/about-buckets-scopes-collections.adoc +:manage-scopes-and-collections: xref:clusters:data-service/scopes-collections.adoc +:scopes-and-collections-api: xref:server:rest-api:scopes-and-collections-api.adoc +:couchbase-cli-collection-manage: xref:server:cli:cbcli/couchbase-cli-collection-manage.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=create-scope] +---- + +image::n1ql-language-reference/create-scope.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal] +namespace:: +(Optional) An {identifier}[identifier] that refers to the {logical-hierarchy}[namespace] of the bucket in which you want to create the scope. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifier}[identifier] that refers to the bucket in which you want to create the scope. + +scope:: +(Required) An {identifier}[identifier] that refers to the name of the scope that you want to create. +Refer to {naming-for-scopes-and-collections}[Naming for Scopes and Collections] for restrictions on scope names. + +NOTE: If there is a hyphen (-) inside the bucket name or the scope name, you must wrap that part of the path in backticks ({backtick} {backtick}). +For example, `default:{backtick}travel-sample{backtick}` indicates the `travel-sample` keyspace in the `default` namespace. + +[[if-not-exists]] +=== IF NOT EXISTS Clause + +The optional `IF NOT EXISTS` clause enables the statement to complete successfully when the specified scope already exists. +If a scope with the same name already exists within the specified bucket, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +== Example + +==== +This statement creates a scope called `events` in the `travel-sample` bucket. + +[source,sqlpp] +---- +CREATE SCOPE `travel-sample`.events +---- +==== + +== Related Links + +* An overview of scopes and collections is provided in {scopes-and-collections}[Scopes and Collections]. + +* Step-by-step procedures for management are provided in {manage-scopes-and-collections}[Manage Scopes and Collections]. + +* Refer to {scopes-and-collections-api}[Scopes and Collections API] to manage scopes and collections with the REST API. + +* Refer to the reference page for the {couchbase-cli-collection-manage}[collection-manage] command to manage scopes and collections with the CLI. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/createsequence.adoc b/modules/n1ql/pages/n1ql-language-reference/createsequence.adoc new file mode 100644 index 000000000..a70aace8d --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/createsequence.adoc @@ -0,0 +1,414 @@ += CREATE SEQUENCE +:page-topic-type: reference +:imagesdir: ../../assets/images +:description: The CREATE SEQUENCE statement enables you to create a sequence in a given scope. + +// Cross-references +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +include::./sequenceops.adoc[tags=overview;attributes] + +=== Cache + +Sequences operate most efficiently with an in-memory cache of values. +You can specify the size of this cache when you create the sequence. +A block of values is reserved by a node, and requests for values are satisfied from this cache. +When exhausted, a new block of values is reserved. +Reserving a cached block offers a performance boost, as it enables the Query service to return values directly from memory. + +Note however that if a Query node shuts down, or if you alter the sequence, the unused values in the cached block are lost: a new block is reserved when you restart the node, or request the next value. +You should choose a cache size with this in mind, along with the expected usage patterns for the sequence. + +=== Storage + +Sequences are stored in the bucket's hidden `_system` scope. +When you back up a bucket, sequences are included automatically, in accordance with the backup filters. +Similarly, when you restore a bucket, sequences are restored in accordance with the restore command -- if you select to restore specific scopes, the sequences associated with those scopes are restored, and no others. + +== Prerequisites + +.RBAC Privileges +To execute the CREATE SEQUENCE statement, you must have the _Query Manage Sequences_ privilege granted on the scope. +For more details about user roles, see {authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=create-sequence] +---- + +image::n1ql-language-reference/create-sequence.png["Syntax diagram: refer to source code listing", align=left] + +The CREATE SCOPE statement provides two possible syntaxes for specifying options for a sequence. + +// TODO: Automatic links in EBNF. + +[horizontal] +sequence:: (Required) A name that identifies the sequence within a namespace, bucket, and scope. +See <> below. + +create-sequence-options:: (Optional) One possible syntax for specifying options for the sequence. +See <> below. + +sequence-with:: (Optional) The other possible syntax for specifying options for the sequence. +See <> below. + +[[sequence]] +=== Sequence Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=sequence] +---- + +image::n1ql-language-reference/sequence.png["Syntax diagram: refer to source code listing", align=left] + +The sequence name specifies the name of the sequence to create. + +Each sequence is associated with a given namespace, bucket, and scope. +You must specify the namespace, bucket, and scope to name the sequence correctly. + +[horizontal] +namespace:: +(Optional) The {logical-hierarchy}[namespace] of the bucket in which you want to create the sequence. + +bucket:: +(Optional) The bucket in which you want to create the sequence. + +scope:: +(Optional) The scope in which you want to create the sequence. + +identifier:: +(Required) The name of the sequence. +The sequence name must be unique within the scope. + +Currently, only the `default` namespace is available. +If you omit the namespace, the default namespace in the current session is used. + +If the {query-context}[query context] is set, you can omit the bucket and scope from the statement. +In this case, the bucket and scope for the sequence are taken from the query context. + +The namespace, bucket, scope, and sequence name must follow the rules for {identifiers}[identifiers]. +If the namespace, bucket, scope, or sequence name contain any special characters such as hyphens (-), you must wrap that part of the expression in backticks ({backtick} {backtick}). + +[[if-not-exists]] +=== IF NOT EXISTS Clause + +The optional `IF NOT EXISTS` clause enables the statement to complete successfully when the specified sequence already exists. +If a sequence with the same name already exists within the specified scope, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +[[create-sequence-options]] +=== Sequence Options + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=create-sequence-options] +---- + +image::n1ql-language-reference/create-sequence-options.png["Syntax diagram: refer to source code listing", align=left] + +You can use the following optional clauses to specify individual attributes for the sequence. +These clauses can occur in any order, but none of them can occur more than once in the statement. + +[horizontal.compact] +start-with:: <> icon:caret-down[] +increment-by:: <> icon:caret-down[] +maxvalue:: <> icon:caret-down[] +minvalue:: <> icon:caret-down[] +cycle:: <> icon:caret-down[] +cache:: <> icon:caret-down[] + +[[start-with]] +==== START WITH Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=start-with] +---- + +image::n1ql-language-reference/start-with.png["Syntax diagram: refer to source code listing", align=left] + +Use the START WITH clause to specify the starting value for the sequence. + +If this clause is omitted, the default start value is `0`. + +[horizontal#start-with-args] +integer:: +(Required) The starting value for the sequence. + +[[increment-by]] +==== INCREMENT BY Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=increment-by] +---- + +image::n1ql-language-reference/increment-by.png["Syntax diagram: refer to source code listing", align=left] + +Use the INCREMENT BY clause to specify the increment value of each step in the sequence. + +If this clause is omitted, the increment value is `1` -- that is, at each step in the sequence, the value goes up by `1`. + +[horizontal#increment-by-args] +integer:: +(Required) The step size for the sequence. +Use a negative value for a descending sequence. + +[[maxvalue]] +==== MAXVALUE Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=maxvalue] +---- + +image::n1ql-language-reference/maxvalue.png["Syntax diagram: refer to source code listing", align=left] + +Use the MAXVALUE clause to specify the maximum value for the sequence. + +Use NO MAXVALUE to specify that the maximum value is the highest signed 64-bit integer, `2^63^-1`. + +If this clause is omitted, the default is NO MAXVALUE. + +[horizontal#maxvalue-args] +integer:: +(Optional) The maximum value for the sequence. + +[[minvalue]] +==== MINVALUE Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=minvalue] +---- + +image::n1ql-language-reference/minvalue.png["Syntax diagram: refer to source code listing", align=left] + +Use the MINVALUE clause to specify the minimum value for the sequence. + +Use NO MINVALUE to specify that the minimum value is the lowest signed 64-bit integer, `-2^63^`. + +If this clause is omitted, the default is NO MINVALUE. + +[horizontal#minvalue-args] +integer:: +(Optional) The minimum value for the sequence. + +[[cycle]] +==== CYCLE Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=cycle] +---- + +image::n1ql-language-reference/cycle.png["Syntax diagram: refer to source code listing", align=left] + +Use the CYCLE clause to specify the whether the sequence should begin again when it reaches the maximum or minimum value. + +Use NO CYCLE to specify that the sequence should stop when it reaches the maximum or minimum value. + +If this clause is omitted, the default is NO CYCLE. + +[[cache]] +==== CACHE Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=cache] +---- + +image::n1ql-language-reference/cache.png["Syntax diagram: refer to source code listing", align=left] + +Use the CACHE clause to specify the cache size for the sequence. + +Use NO CACHE to specify a cache size of `1`. + +If this clause is omitted, the default is NO CACHE. + +[horizontal#cache-args] +integer:: +(Optional) The cache size for the sequence. +The value must be greater than `0`. + +[[sequence-with]] +=== WITH Clause + +[source,ebnf] +---- +include::{partialsdir}/grammar/ddl.ebnf[tag=sequence-with] +---- + +image::n1ql-language-reference/sequence-with.png["Syntax diagram: refer to source code listing", align=left] + +You can use the WITH clause to specify options for the sequence using a JSON object. + +[horizontal#sequence-with-args] +expr:: +(Required) An object with the following properties. + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**start** + +__optional__ +|The starting value for the sequence. + +**Default:** `0` +|Integer + +|**increment** + +__optional__ +|The step size for the sequence. +Use a negative value for a descending sequence. + +**Default:** `1` +|Integer + +|**max** + +__optional__ +|The maximum value for the sequence. +If unspecified, the maximum is the highest signed 64-bit integer. + + +**Default:** `2^63^-1` +|Integer (int64) + +|**min** + +__optional__ +|The minimum value for the sequence. +If unspecified, the minimum is the lowest signed 64-bit integer. + +**Default:** `-2^63^` +|Integer (int64) + +|**cycle** + +__optional__ +|Whether the sequence should begin again when it reaches the maximum or minimum value. + +**Default:** `false` +|Boolean + +|**cache** + +__optional__ +|The cache size for the sequence. +The value must be greater than `0`. + +[%hardbreaks] +**Default:** `50` +**Minimum:** `1` +|Integer +|=== + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-create-seq1]] +.Create a sequence in a specified scope +==== +This statement creates a sequence with default attributes in the specified scope. + +[source,sqlpp] +---- +CREATE SEQUENCE `travel-sample`.inventory.seq1; +---- +==== + +[[ex-create-seq2]] +.Create a sequence in the current query context +==== +This statement creates a sequence with default attributes in the current query context, as long as a sequence of the same name does not already exist. + +[source,sqlpp] +---- +CREATE SEQUENCE seq2 IF NOT EXISTS; +---- +==== + +[[ex-create-seq3]] +.Create a sequence which cycles +==== +This statement creates a sequence starting at 5 and incrementing by 5 each time. +When the sequence reaches the maximum value of 1000, it starts again at 0. + +[source,sqlpp] +---- +CREATE SEQUENCE seq3 IF NOT EXISTS START WITH 5 INCREMENT BY 5 MAXVALUE 1000 MINVALUE 0 CYCLE; +---- + +The following query tests the sequence. + +[source,sqlpp] +---- +SELECT NEXT VALUE FOR seq3; +---- + +The query returns the specified starting value, 5. + +[source,json] +---- +[ + { + "$1": 5 + } +] +---- +==== + +[[ex-create-seq4]] +.Create a descending sequence +==== +This statement creates a sequence that starts at 10 and counts down to 0. +When it reaches the minimum value, the sequence stops. + +[source,sqlpp] +---- +CREATE SEQUENCE seq4 IF NOT EXISTS WITH {"start": 10, "increment": -1, "min": 0}; +---- + +The following query tests the sequence. + +[source,sqlpp] +---- +SELECT NEXT VALUE FOR seq4; +---- + +The query returns the specified starting value, 10. + +[source,json] +---- +[ + { + "$1": 10 + } +] +---- +==== + +See xref:n1ql-language-reference/sequenceops.adoc[] for detailed examples using sequences. + +== Related Links + +* To alter a sequence, see xref:n1ql-language-reference/altersequence.adoc[]. +* To drop a sequence, see xref:n1ql-language-reference/dropsequence.adoc[]. +* To use a sequence in an expression, see xref:n1ql-language-reference/sequenceops.adoc[]. +* To monitor sequences, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-sequences[Monitor Sequences]. diff --git a/modules/n1ql/pages/n1ql-language-reference/datatypes.adoc b/modules/n1ql/pages/n1ql-language-reference/datatypes.adoc new file mode 100644 index 000000000..35351f2c6 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/datatypes.adoc @@ -0,0 +1,104 @@ += Data Types +:description: {sqlpp} supports many data types: MISSING, NULL, Boolean values, numeric values, string values, arrays, objects, and binary. +:page-topic-type: reference + +[abstract] +{description} + +These types are described in detail in their respective sections. +While {sqlpp} does not support the Date data type, it does provide a robust set of functions to work with dates. + +[#datatype-missing] +== MISSING + +Missing represents a missing name-value pair in a JSON document. +If the referenced field does not exist, an empty result value is returned by the query. +Missing is added as a literal expression, although it is not returned in the final results. +It is omitted from objects, and is converted to null in result arrays. + +Because {sqlpp} is not constrained by a fixed schema, some objects and documents can contain fields that others do not contain; so a field can be present in one document and MISSING in another. +(MISSING is not present in SQL, because every record in a table follows an identical schema.) + +[#datatype-null] +== NULL + +Nulls represent empty values using the keyword NULL. +For example, a developer might initially set a field value to null by default until a user enters a value. + +Null values are also generated by certain operations, for example, when dividing by zero or passing arguments of the wrong type. + +Note that NULL is case insensitive. +For example, null, NULL, Null, and nUll are all equivalent. + +[#datatype-boolean] +== Boolean + +This type can have a value of TRUE and FALSE. +The values are case insensitive. + +== Numbers + +Numbers can be a signed decimal number that can contain a fractional part. +Numbers can also use E-notation. + +== String values + +Strings include all Unicode characters and backslash escape characters. +They are delimited by single quotation marks ('') or double quotation marks (""). + +== Arrays + +Arrays are an ordered list of zero or more values. +The values can be of any type. +Arrays are enclosed in square brackets ( [ ] ). +Commas separate each value. + +Here are some array examples: ["one", "two", "three"] and [1, 2, 3], and ["one", 2, "three"]. + +== Objects + +Objects consist of name-value pairs. +The name must be a string, and the value can be any supported JSON data type. + +Objects are enclosed in curly braces ( { } ). +Commas separate each pair. +The colon (:) character separates the name from its value within each pair. + +Here are some object examples: {"age": 17}, {"fname": "Jane", "lname": "Doe"} + +All names must be strings and should be distinct from each other within that object. + +[#datatype-binary] +== Binary + +When Couchbase Capella is used as a key-value store and the value is a non-JSON value, the value is exposed as binary. +{sqlpp} does not parse the binary data. +The returned value only signifies that the value is a binary value. +For example, "[.out]``\u003cbinary (size_in_bytes b)\u003e``", where [.var]`size_in_bytes` signifies the size of the binary data in bytes. +You can use the [.api]`TYPE()` function to retrieve the type of the value as binary. +Functions that return metadata such as [.api]`META()` still operate as expected. +However, operations on binary data are limited. + +== Collation + +Collation defines the sort order for data types. +Here is the default ascending collation order used for {sqlpp} data types: + +* MISSING +* NULL +* FALSE +* TRUE +* number +* string +* array +* object +* binary (non-JSON) + +It is possible to specify a different order, and set the ordering of NULL and MISSING values. +See xref:n1ql-language-reference/orderby.adoc[ORDER BY clause] for more information. + +[#datatype-date] +== Date + +{sqlpp} does not support the Date data type; however {sqlpp} does provide a full range of functions which you can use to manipulate dates. +See xref:n1ql-language-reference/datefun.adoc[Date Functions] for more information. diff --git a/modules/n1ql/pages/n1ql-language-reference/datefun.adoc b/modules/n1ql/pages/n1ql-language-reference/datefun.adoc new file mode 100644 index 000000000..b0b57b213 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/datefun.adoc @@ -0,0 +1,2699 @@ += Date Functions +:description: {sqlpp} date functions return the system clock value or manipulate the datetime values, which are represented as a string or an integer. +:page-topic-type: reference +:example-caption!: +:imagesdir: ../../assets/images +:other-characters: pass:q[Characters which are not part of the format specification are matched literally and produced unaltered, with the exception of Unicode U+0020, i.e. space `" "`, which matches any single character when parsing, and is produced unaltered on output.] + +[abstract] +{description} +These functions are very useful for manipulating dates in datasets with various date formats and timezones. + +[#date-timezone] +== Timezones + +Datetime values are always tied to a specific timezone, either explicitly in the date value, or implicitly in the application. +The date functions in {sqlpp} therefore support multiple different timezones. + +=== UTC + +UTC, The Coordinated Universal Time is the primary time standard by which the world regulates clocks and time. +It is defined as the time at 0° longitude and is consistent, as it does not take into account daylight savings time. +You can read further about UTC at https://www.timeanddate.com/time/aboututc.html[^]. + +All {sqlpp} functions which accept a timezone as an argument also accept `UTC`. + +=== IANA Timezones + +Many applications operate across multiple different time zones and may not necessarily use `UTC`. +Therefore, it is important for the database to be able to handle and manipulate dates in these time zones in a consistent manner. +Many date functions take the time zone as an additional argument. + +NOTE: Timezones are case sensitive, `Europe/London` is not the same as `europe/london`. + +It is important to note that many time zones change their UTC offset based on daylight savings time, as a result the UTC offset of times may change based on the time of year. +{sqlpp} take this into account when converting dates. + +Below are a few examples of commonly used timezones and their offsets: + +.Common Timezones +|==== +| Timezone | UTC Offset (without daylight savings time) | UTC Offset (during daylight savings time) + +| America/New_York +| -05:00 +| -04:00 + +| America/Tijuana +| -08:00 +| -07:00 + +| Europe/Paris +| +01:00 +| +02:00 + +| Europe/London +| +00:00 +| +01:00 + +| Asia/Tel_Aviv +| +02:00 +| +03:00 + +| Asia/Kolkata +| +05:30 +| +05:30 +|==== + +=== Local System Timezone + +Many functions default to using the local timezone of the system, which will be one of the IANA timezones. + +[#date-formats] +== Date Formats + +{sqlpp} date functions accept dates in either Epoch/UNIX timestamp format or string date format. +{sqlpp} is then able to represent the passed date as a standardized date object internally. +In general, functions whose name contains the word `STR` are designed to use string formats while `MILLIS` functions are designed to use Epoch/UNIX timestamps. + +[[unix-time]] +=== Epoch/UNIX Timestamps + +Epoch/UNIX time is the number of seconds (or milliseconds) that have elapsed since `1970-01-01T00:00:00.000Z` (Thursday, 1 January 1970 at midnight), not including leap seconds. +This can be useful for numeric and timezone agnostic representations of dates. +While Epoch/UNIX time can be represented in either seconds or milliseconds, _all {sqlpp} date functions specifically treat Epoch/UNIX timestamps as milliseconds_. +For example, the date `2017-01-31T10:02:07Z` would equate to an Epoch/UNIX timestamp of `1485856927000`. + +[[date-string]] +=== Date String Formats + +In many cases, dates are not stored as Epoch/UNIX timestamp but instead as more human-readable formats, such as `2006-01-02T15:04:05.567+08:00`. +Therefore, {sqlpp} also provides convenience methods to allow you to manipulate and convert dates in string format. + +{sqlpp} accepts format strings following several conventions: + +* *ISO-8601 example dates*, e.g. `1111-11-11`. +* *Date string component codes*, e.g. `YYYY-MM-DD`. +* *Go language native dates*, e.g. specifically `2006-01-02` for year, month, and day. +* *Percent-style date format specifiers*, e.g. `%Y-%m-%d`. + +Only a single style can be used at a time in a specified format string. + +[tabs] +==== +ISO-8601 Dates:: ++ +-- +https://www.w3.org/TR/NOTE-datetime[ISO-8601^] example dates are composed of the following date components. + +[cols="2,1,2"] +|==== +| Component | Code | Value + +| Year +| YYYY +| Any four-digit integer from `1111` to `9999` + +| Month (of the year) +| MM +| Any two digit integer from `01` to `12` + +| Day (of the month) +| DD +| Any two digit integer from `01` to `31` + +| Hour (of the day) +| hh +| Any two-digit integer from `00` to `23` + +| Minute (of the hour) +| mm +| Any two-digit integer from `00` to `59` + +| Second (of the minute) +| ss +| Any two-digit integer from `00` to `59` + +| Millisecond (of the second) -- output only +| s +| Any three-digit integer from `000` to `999` + +| Time Zone (as UTC offset) +| TZD +| UTC offset in the format ±hh:mm + +3+a|NOTE: A UTC offset of 0 (+00:00) can just be specified as `Z`. +|==== + +To specify a date format, you must put together example component values, as specified above, to create one of the following date formats. +ISO-8601 date formats are very specific; they must contain the correct components in the correct order, with punctuation exactly as shown. + +[cols="1,2a"] +|==== +| Format | Example + +| YYYY-MM-DDThh:mm:ss.sTZD +| `1111-12-31T23:00:59.999+00:00` or `1111-12-31T23:00:59.999Z` + +| YYYY-MM-DDThh:mm:ssTZD +| `1111-12-31T23:00:59+00:00` or `1111-12-31T23:00:59Z` + +| YYYY-MM-DDThh:mm:ss.s +| `1111-12-31T23:00:59.999` + +| YYYY-MM-DDThh:mm:ss +| `1111-12-31T23:00:59` + +| YYYY-MM-DD hh:mm:ss.sTZD +| `1111-12-31 23:00:59.999+00:00` or `1111-12-31 23:00:59.999Z` + +| YYYY-MM-DD hh:mm:ssTZD +| `1111-12-31 23:00:59+00:00` or `1111-12-31 23:00:59Z` + +| YYYY-MM-DD hh:mm:ss.s +| `1111-12-31 23:00:59.999` + +| YYYY-MM-DD hh:mm:ss +| `1111-12-31 23:00:59` + +| YYYY-MM-DD +| `1111-12-31` + +| hh:mm:ss.sTZD +| `23:00:59.999+00:00` or `23:00:59.999Z` + +| hh:mm:ssTZD +| `23:00:59+00:00` or `23:00:59Z` + +| hh:mm:ss.s +| `23:00:59.999` + +| hh:mm:ss +| `23:00:59` +|==== + +The examples above use arbitrary values for the date components. +You can use any valid values in your date components, as long as the date format contains the correct combination of components and punctuation. + +Note, however, that if you use Go reference date values as the date components, the example date is interpreted as a <>, rather than an ISO-8601 example date. +This may cause some date formats to be interpreted differently to what you expect. +For example, the date format `2006-02-01` is interpreted as a Go reference date, where `02` is the day and `01` is the month. +-- + +Date String Codes:: ++ +-- +For greater flexibility, you can specify a date format using date string codes. +These are based on the alphabetic format codes from the https://www.w3.org/TR/NOTE-datetime[ISO-8601^] standard, with some extensions. +The date string codes are given below. + +[cols="1,2"] +|==== +| Code | Component + +| `CC` +| 2-digit century + +| `YYYY` +| 4-digit century and year + +| `YY` +| 2-digit year ^[<>]^ + +| `MM` +| 2-digit month + +| `DD` +| 2-digit day + +| `hh` +| 2-digit hour, 00-23 + +| `HH` +| 2-digit hour, 00-23 + +| `mm` +| 2-digit minute, 00-59 + +| `ss` +| 2-digit second, 00-59 + +| `s` +| Fraction of a second (down to millisecond) -- output only + +| `TZD` +| Time Zone (as UTC offset) +|==== + +To specify a date format, you can put the date string components together in any order, along with any other characters as required. + +{other-characters} +For example, `YYYY MM DD` parses `2021-06-28`, `2021/06/28`, `2021.06.28`, etc. +-- + +Go Reference Dates:: ++ +-- +You can specify a date format using https://golang.org/pkg/time/#pkg-constants[Go language date components^]. +The available reference date components are given below. + +[cols="1,1,2"] +|==== +| Component | Reference Date | Meaning + +.2+| Year +| `2006` +| 4-digit century and year + +| `06` +| 2-digit year ^[<>]^ + +.4+|Month +| `1` +| Unpadded month + +| `01` +| Zero-padded 2-digit month + +| `January` +| Full English month name + +| `Jan` +| Abbreviated English month name + +.7+|Day +| `2` +| Unpadded day of the month + +| `_2` +| Space-padded 2-digit day of the month + +| `02` +| Zero-padded 2-digit day of the month + +| `Monday` +| Full English day name + +| `Mon` +| Abbreviated English day name + +| `__2` +| Space-padded 3-digit day of the year + +| `002` +| Zero-padded 3-digit day of the year + +.3+|Hour +| `3` +| Unpadded hour, 1-12 + +| `03` +| Zero-padded 2-digit hour, 01-12 + +| `15` +| Zero-padded 2-digit hour, 00-23 + +.2+|AM or PM +| `PM` +| AM or PM (upper case) + +| `pm` +| am or pm (lower case) + +.2+|Minute +| `4` +| Unpadded minute, 0-59 + +| `04` +| Zero-padded minute, 00-59 + +.2+|Second +| `5` +| Unpadded second, 0-59 + +| `05` +| Zero-padded second, 00-59 + +.2+|Fraction of a second +| `,000` (one or + +`.000` more zeros) +| Fraction of a second, to the given number of decimal places + +| `,999` (one or + +`.999` more nines) +| Fraction of a second, to the given number of decimal places, with trailing zeros removed + +.2+|Time zone +| `-07` + +`-0700` + +`-07:00` +| Time Zone (as UTC offset) + +| `Z07` + +`Z0700` + +`Z07:00` +| Time Zone (as UTC offset); + +a UTC offset of 0 (+00:00) is output as `Z` +|==== + +To specify a date format, you can put the reference date components together in any order, along with any other characters as required. + +{other-characters} +For example, `2006 01 02` parses `2021-06-28`, `2021/06/28`, `2021.06.28`, etc. +-- + +Percent-Style Dates:: ++ +-- +Date and time functions also accept `printf`-style format specifiers for date formats, based on the Unix https://man7.org/linux/man-pages/man1/date.1.html[date^] command. +Format specifiers begin with a percent character `%` and take the following form: + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=format-specifier] +---- + +image::n1ql-language-reference/format-specifier.png["Syntax diagram: refer to source code listing", align=left] + +The optional hyphen (`-`), underscore (`_`), or zero (`0`) characters specify the padding for number fields. + +[horizontal] +hyphen `-`;; No padding for numeric date components. +underscore `_`;; Padding with spaces for numeric date components. +zero `0`;; Padding with zeros for numeric date components -- the default. + +The optional circumflex (`^`) character specifies case insensitivity when parsing text date components, or a preference for upper case when outputting text date components. + +The _width_ is accepted but ignored for parsing, and is used for output. +However, it should rarely be needed, as elements have common or expected default widths. + +The _element_ is a single character which specifies a date component or an entire date format. +The elements are given in the table below. + +[cols="1,2,2"] +|==== +| Element | Meaning | Example + +| `D` +| Short form date, YYYY-MM-DD +| `2021-06-28` + +| `F` +| Long form date, YYYY-MM-DDThh:mm:ss.sTZD +| `2021-06-28T19:22:59.123+01:00` + +| `Y` +| 4-digit century and year +| `2021` + +| `C` +| 2-digit century +| `20` + +| `y` +| 2-digit year ^[<>]^ +| `21` + +| `m` +| 2-digit month +| `01` + +| `B` +| Full English month name +| `January` + +| `b` +| Abbreviated English month name +| `Jan` + +| `d` +| 2-digit day +| `28` + +| `A` +| Full English day name +| `Monday` + +| `a` +| Abbreviated English day name +| `Mon` + +| `f` +| English ordinal number suffix +| `st` (as in `1st`) + +| `H` +| 2-digit hour, 00-23 +| `19` + +| `I` +| 2-digit hour, 01-12 +| `07` + +| `p` +| AM or PM (upper case) +| `PM` + +| `P` +| am or pm (lower case) +| `pm` + +| `M` +| 2-digit minute, 00-59 +| `22` + +| `S` +| 2-digit second, 00-59 +| `59` + +| `R` +| 24-hour hour and minute (same as `%H:%M`) +| `19:22` + +| `T` +| 24-hour time (same as `%H:%M:%S`) +| `19:22:59` + +| `N` +| Fraction of a second (down to nanosecond) +| `123` + +.2+| `z` +| When parsing, matches a time zone in any supported format -- ±hh, ±hhmm, +±hh:mm, zone name +| `+01` + + `+0100` + + `+01:00` + + `Europe/Paris` + +| For output, produces time zone in ±hh:mm format +| `+01:00` + +.2+| `Z` +| When parsing, matches a time zone in any supported format -- ±hh, ±hhmm, +±hh:mm, zone name +| `+01` + + `+0100` + + `+01:00` + + `Europe/Paris` + +| For output, produces time zone name +| `Europe/Paris` + +| `s` +| Seconds since 1970-01-01 00:00:00 UTC +| `1624904579` + +|==== + +To specify a date format, you can put the format specifiers together in any order, along with any other characters as required. +If you need to include a literal percent symbol in the date format, use the special format specifier `%%`. + +{other-characters} +For example, `%Y %m %d` parses `2021-06-28`, `2021/06/28`, `2021.06.28`, and so on. +-- +==== + +[NOTE#default-values] +.Default Values +==== +If the date string does not explicitly declare the value of a component, then the following default values are assumed: + +* The month and day default to 1. +* The century (when not specified by year) defaults to 19 if year is greater than or equal to 69, or 20 otherwise. +* All other numeric components default to 0. +* The time zone defaults to the local local system time zone. + +In cases where the timezone is not specified, the local system time is assumed. + +For example, `2016-02-07` is equivalent to `2016-02-07T00:00:00` and parsing just `16` as the year is equivalent to `2016-01-01T00:00:00` in the local system time zone. +==== + +[#manipulating-components] +== Manipulating Date Components + +Dates are composed of multiple different components such as the day, year, month, etc. +It is important for applications to be able to extract and manipulate particular components of a date, so that these can be used in {sqlpp} queries. +Functions such as <> accept a `part` argument, which is the component to adjust. + +The following are the supported date parts that can be passed to date manipulation functions. +These date parts are expressed as strings and are not case-sensitive, so `year` is regarded the same as `YeAr`. +For all examples, the date being used is `2006-01-02T15:04:05.999Z`. + +.Date and Time Components +[cols="3,5,1,1,1"] +|==== +| Component | Description | Lower Bound | Upper Bound | Example + +| `millennium` +| The millennium (1000 year period), counting from the start of year 0, which is equivalent to 1 BCE. +| - +| - +| 3 + +| `century` +| The century (100 year period), counting from the start of year 0, which is equivalent to 1 BCE. +| - +| - +| 21 + +| `decade` +| The decade (10 year period), counting from the start of year 0, which is equivalent to 1 BCE. +This is calculated as `floor(year / 10)`. +| - +| - +| 200 + +| `year` +| The proleptic Gregorian year. +The year 0 is equivalent to 1 BCE. +| - +| - +| 2006 + +| `iso_year` +| The ISO-8601 year. +Each ISO-8601 year begins with the Monday of the week containing the 4th of January, so in early January and late December the ISO year may differ from the Gregorian year. +Should be used in conjunction with `iso_week` to get consistent results. +| - +| - +| 2006 + +| `quarter` +| The number of the quarter (3 month period) of the year. +January-March (inclusive) is 1 while October-December (inclusive) is 4. +| 1 +| 4 +| 1 + +| `month` +| The number of the month of the year. +January is 1 and December is 12. +| 1 +| 12 +| 1 + +| `week` +| The number of the week of the year. +This is the ceiling value of the day of the year divided by 7. +| 1 +| 53 +| 1 + +| `iso_week` +| The number of the week of the year, based on the ISO definition. +ISO weeks start on Mondays and the first week of a year contains January 4 of that year. +In other words, the first Thursday of a year will always be in week 1 of that year. +This results in some different results between `week` and `iso_week`, based on the input date. + +For example the `iso_week` of `2006-01-08T15:04:05.999Z` is 1, while the `week` is 2. +Should be used in conjunction with `iso_year` to get consistent results. +| 1 +| 53 +| 1 + +| `day` +| The day of the month. +| 1 +| 31 +| 2 + +| `day_of_year` or `doy` +| The day of the year. +| 1 +| 366 +| 2 + +| `day_of_week` or `dow` +| The day of the week. +| 0 +| 6 +| 1 + +| `hour` +| The hour of the day. +| 0 +| 23 +| 5 + +| `minute` +| The minute of the hour. +| 0 +| 59 +| 4 + +| `second` +| The second of the minute. +| 0 +| 59 +| 5 + +| `millisecond` +| The millisecond of the second. +| 0 +| 999 +| 999 + +| `timezone` +| The offset from UTC in seconds. +| -43200 +| 43200 +| 0 + +| `timezone_hour` +| The hour component of the offset from UTC. +| -12 +| 12 +| 0 + +| `timezone_minute` +| The minute component of the offset from UTC. +| -59 +| 59 +| 0 +|==== + +== Date Functions + +Below is a list of all date functions that {sqlpp} provides. + +NOTE: If any arguments to any of the following functions are `MISSING` then the result is also `MISSING` (i.e. +no result is returned). +Similarly, if any of the arguments are `NULL` then `NULL` is returned. + +[#fn-date-clock-local] +== CLOCK_LOCAL([fmt]) + +=== Description + +The current time (at function evaluation time) of the machine that the query service is running on, in the specified string format. + +=== Arguments + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If no format or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string in the format specified representing the local system time. + +=== Limitations + +`CLOCK_LOCAL()` cannot be used as part of an index definition, this includes the indexed fields and the `WHERE` clause of the index. + +If this function is called multiple times within the same query then the values returned may differ, particularly if the query takes a long time to run. +To avoid inconsistencies between multiple calls to `CLOCK_LOCAL()` within a single query, use <> instead. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT CLOCK_LOCAL() as full_date, + CLOCK_LOCAL('invalid date') as invalid_date, + CLOCK_LOCAL('1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2018-01-23T13:57:29.847-08:00", + "invalid_date": "2018-01-23T13:57:29.847-08:00", + "short_date": "2018-01-23" + } +] +---- +==== + +[#fn-date-clock-millis] +== CLOCK_MILLIS() + +=== Description + +The current time as an Epoch/UNIX timestamp. +Its fractional part represents nanoseconds, but the additional precision beyond milliseconds may not be consistent or guaranteed on all platforms. + +=== Arguments + +This function accepts no arguments. + +=== Return Value + +A single float value (with 3 decimal places) representing the system time as Epoch/UNIX time. + +=== Limitations + +`CLOCK_MILLIS()` cannot be used as part of an index definition, this includes the indexed fields and the `WHERE` clause of the index. + +If this function is called multiple times within the same query then the values returned may differ, particularly if the query takes a long time to run. +To avoid inconsistencies between multiple calls to `CLOCK_MILLIS()` within a single query, use <> instead. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT CLOCK_MILLIS() AS CurrentTime; +---- + +.Results +[source,json] +---- +[ + { + "CurrentTime": 1516744600430.677 + } +] +---- +==== + +[#fn-date-clock-str] +== CLOCK_STR([fmt]) + +=== Description + +The current time (at function evaluation time) of the machine that the query service is running on, in the specified string format. + +=== Arguments + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. +. ++ +*Optional argument*. +If no format or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string in the format specified representing the system time. + +=== Limitations + +`CLOCK_STR()` cannot be used as part of an index definition, this includes the indexed fields and the `WHERE` clause of the index. + +If this function is called multiple times within the same query then the values returned may differ, particularly if the query takes a long time to run. +To avoid inconsistencies between multiple calls to `CLOCK_STR()` within a single query, use <> instead. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT CLOCK_STR() as full_date, + CLOCK_STR('invalid date') as invalid_date, + CLOCK_STR('1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2018-01-23T13:55:10.798-08:00", + "invalid_date": "2018-01-23T13:55:10.798-08:00", + "short_date": "2018-01-23" + } +] +---- +==== + +[#fn-date-clock-tz] +== CLOCK_TZ(tz [, fmt]) + +=== Description + +The current time (at function evaluation time) in the timezone given by the timezone argument passed to the function. +This time is the local system time converted to the specified timezone. + +=== Arguments + +tz:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to convert the local time to. ++ +If this argument is not a valid timezone then `null` is returned as the result. + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If no format or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +An date string in the format specified representing the system time in the specified timezone. + +=== Limitations + +As this function converts the local time, it may not accurately represent the true time in that timezone. + +`CLOCK_TZ()` cannot be used as part of an index definition, this includes the indexed fields and the `WHERE` clause of the index. + +If this function is called multiple times within the same query then the values returned may differ, particularly if the query takes a long time to run. +To avoid inconsistencies between multiple calls to `CLOCK_TZ()` within a single query, use <> instead. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT CLOCK_TZ('UTC') as UTC_full_date, + CLOCK_TZ('UTC', '1111-11-11') as UTC_short_date, + CLOCK_TZ('invalid timezone') as invalid_timezone, + CLOCK_TZ('US/Eastern') as us_east, + CLOCK_TZ('US/Pacific') as us_west; +---- + +.Results +[source,json] +---- +[ + { + "UTC_full_date": "2018-01-23T21:54:37.178Z", + "UTC_short_date": "2018-01-23", + "invalid_timezone": null, + "us_east": "2018-01-23T16:54:37.18-05:00", + "us_west": "2018-01-23T13:54:37.181-08:00" + } +] +---- +==== + +[#fn-date-clock-utc] +== CLOCK_UTC([fmt]) + +=== Description + +The current time in UTC. +This time is the local system time converted to UTC. +This function is provided for convenience and is the same as `CLOCK_TZ('UTC')`. + +=== Arguments + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If no format or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +An date string in the format specified representing the system time in UTC. + +=== Limitations + +As this function converts the local time, it may not accurately represent the true time in UTC. + +`CLOCK_UTC()` cannot be used as part of an index definition, this includes the indexed fields and the `WHERE` clause of the index. + +If this function is called multiple times within the same query then the values returned may differ, particularly if the query takes a long time to run. +To avoid inconsistencies between multiple calls to `CLOCK_UTC()` within a single query, use <> instead. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT CLOCK_UTC() as full_date, CLOCK_UTC('1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2018-01-23T21:54:03.593Z", + "short_date": "2018-01-23" + } +] +---- +==== + +[#fn-date-add-millis] +== DATE_ADD_MILLIS(date1, n, part) + +=== Description + +Performs date arithmetic on a particular component of an Epoch/UNIX timestamp value. +This calculation is specified by the arguments `n` and `part`. ++ +For example, a value of 3 for `n` and a value of `day` for `part` would add 3 days to the date specified by `date1`. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing an Epoch/UNIX timestamp in milliseconds. ++ +If this argument is not an integer then `null` is returned. + +n:: +The value to increment the date component by. +This value must be an integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, and may be negative to perform date subtraction. ++ +If a non-integer is passed to the function then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function then `null` is returned. + +=== Return Value + +An integer, representing the result of the calculation as an Epoch/UNIX timestamp in milliseconds. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_ADD_MILLIS(1463284740000, 3, 'day') as add_3_days, + DATE_ADD_MILLIS(1463284740000, 3, 'year') as add_3_years, + DATE_ADD_MILLIS(1463284740000, -3, 'day') as sub_3_days, + DATE_ADD_MILLIS(1463284740000, -3, 'year') as sub_3_years; +---- + +.Results +[source,json] +---- +[ + { + "add_3_days": 1463543940000, + "add_3_years": 1557892740000, + "sub_3_days": 1463025540000, + "sub_3_years": 1368590340000 + } +] +---- +==== + +[#fn-date-add-str] +== DATE_ADD_STR(date1, n, part) + +=== Description + +Performs date arithmetic on a date string. +This calculation is specified by the arguments `n` and `part`. +For example a value of 3 for `n` and a value of `day` for `part` would add 3 days to the date specified by `date1`. + +=== Arguments + +date1:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the date in a <>. + +n:: +The value to increment the date component by. +This value must be an integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, and may be negative to perform date subtraction. ++ +If a non-integer is passed to the function then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function then `null` is returned. + +=== Return Value + +An integer representing the result of the calculation as an Epoch/UNIX timestamp in milliseconds. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_ADD_STR('2016-05-15 03:59:00Z', 3, 'day') as add_3_days, + DATE_ADD_STR('2016-05-15 03:59:00Z', 3, 'year') as add_3_years, + DATE_ADD_STR('2016-05-15 03:59:00Z', -3, 'day') as sub_3_days, + DATE_ADD_STR('2016-05-15 03:59:00Z', -3, 'year') as sub_3_years; +---- + +.Results +[source,json] +---- +[ + { + "add_3_days": "2016-05-18T03:59:00Z", + "add_3_years": "2019-05-15T03:59:00Z", + "sub_3_days": "2016-05-12T03:59:00Z", + "sub_3_years": "2013-05-15T03:59:00Z" + } +] +---- +==== + +[#fn-date-diff-millis] +== DATE_DIFF_MILLIS(date1, date2, part) + +=== Description + +Finds the elapsed time between two Epoch/UNIX timestamps. +This elapsed time is measured from the date specified by `date2` to the date specified by `date1`. +If `date1` is greater than `date2`, then the value returned will be positive, otherwise the value returned will be negative. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +date2:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. ++ +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function, then `null` is returned. + +=== Return Value + +An integer representing the elapsed time (based on the specified `part`) between both dates. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_DIFF_MILLIS(1463543940000, 1463284740000, 'day') as add_3_days, + DATE_DIFF_MILLIS(1557892740000, 1463284740000, 'year') as add_3_years, + DATE_DIFF_MILLIS(1463025540000, 1463284740000, 'day') as sub_3_days, + DATE_DIFF_MILLIS(1368590340000, 1463284740000, 'year') as sub_3_years; +---- + +.Results +[source,json] +---- +[ + { + "add_3_days": 3, + "add_3_years": 3, + "sub_3_days": -3, + "sub_3_years": -3 + } +] +---- +==== + +[#fn-date-diff-str] +== DATE_DIFF_STR(date1, date2, part) + +=== Description + +Finds the elapsed time between two dates specified as formatted strings. +This elapsed time is measured from the date specified by `date2` to the date specified by `date1`. +If `date1` is greater than `date2` then the value returned will be positive, otherwise the value returned will be negative. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +date2:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. ++ +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function, then `null` is returned. + +=== Return Value + +An integer representing the elapsed time (based on the specified `part`) between both dates. + +=== Examples + +.Example 1 +==== +Find the day difference and year difference between two strings. + +[source,sqlpp] +---- +SELECT DATE_DIFF_STR('2016-05-18T03:59:00Z', '2016-05-15 03:59:00Z', 'day') as add_3_days, + DATE_DIFF_STR('2019-05-15T03:59:00Z', '2016-05-15 03:59:00Z', 'year') as add_3_years, + DATE_DIFF_STR('2016-05-12T03:59:00Z', '2016-05-15 03:59:00Z', 'day') as sub_3_days, + DATE_DIFF_STR('2013-05-15T03:59:00Z', '2016-05-15 03:59:00Z', 'year') as sub_3_years; +---- + +.Results +[source,json] +---- +[ + { + "add_3_days": 3, + "add_3_years": 3, + "sub_3_days": -3, + "sub_3_years": -3 + } +] +---- +==== + +.Example 2 +==== +include::ROOT:partial$query-context.adoc[tag=example] + +To list all hotel documents that were reviewed between two dates: + +[source,sqlpp] +---- +SELECT name, reviews[0].date +FROM hotel +WHERE reviews[0].date BETWEEN "2013-01-01 00:00:00 +0100" AND "2014-01-01 00:00:00 +0100"; +---- + +The query can also be entered as: + +[source,sqlpp] +---- +SELECT name, reviews[0].date +FROM hotel +WHERE reviews[0].date BETWEEN "2013-01-01 %" AND "2014-01-01 %"; +---- + +.Results +[source,json] +---- +[ + { + "date": "2013-06-22 18:33:50 +0300", + "name": "Medway Youth Hostel" + }, + { + "date": "2013-06-13 01:39:18 +0300", + "name": "Le Clos Fleuri" + }, + { + "date": "2013-07-12 12:18:02 +0300", + "name": "Glasgow Grand Central" + }, + { + "date": "2013-07-02 14:32:55 +0300", + "name": "The George Hotel" + }, + { + "date": "2013-12-05 09:27:07 +0300", + "name": "Bacara Resort & Spa" + }, + { + "date": "2013-01-10 12:48:39 +0300", + "name": "Once Brewed YHA Hostel" + }, + { + "date": "2013-09-12 02:57:37 +0300", + "name": "Sandy Patch" + }, + { + "date": "2013-12-18 22:36:14 +0300", + "name": "The Granary at Roch Mill" + }, + { + "date": "2013-05-08 17:54:41 +0300", + "name": "Alberta House B&B" + }, + // ... +] +---- +==== + +NOTE: When querying between two dates, you must specify the full date (with time and time zone) or use the wildcard character (%). + +[#fn-date-format-str] +== DATE_FORMAT_STR(date1, fmt) + +=== Description + +Converts datetime strings from one supported date string format to a different supported date string format. + +=== Arguments + +date1:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. ++ +If this argument is not a valid date string then `null` is returned. + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +If an incorrect format is specified then this defaults to the combined full date and time. + +=== Return Value + +A date string in the format specified. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_FORMAT_STR('2016-05-15T00:00:23+00:00', '1111-11-11') as full_to_short, + DATE_FORMAT_STR('2016-05-15', '1111-11-11T00:00:00+00:00') as short_to_full, + DATE_FORMAT_STR('01:10:05', '1111-11-11T01:01:01Z') as time_to_full; +---- + +.Results +[source,json] +---- +[ + { + "full_to_short": "2016-05-15", + "short_to_full": "2016-05-15T00:00:00-07:00", + "time_to_full": "0000-01-01T01:10:05-08:00" + } +] +---- +==== + +[#fn-date-part-millis] +== DATE_PART_MILLIS(date1, part [, tz]) + +=== Description + +Extracts the value of a given date component from an Epoch/UNIX timestamp value. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function, then `null` is returned. + +tz:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to convert the local time to. ++ +*Optional argument*. +Defaults to the system timezone if not specified. +If an incorrect time zone is provided, then `null` is returned. + +=== Return Value + +An integer representing the value of the component extracted from the timestamp. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_PART_MILLIS(1463284740000, 'day') as day_local, + DATE_PART_MILLIS(1463284740000, 'day', 'America/Tijuana') as day_pst, + DATE_PART_MILLIS(1463284740000, 'day', 'UTC') as day_utc, + DATE_PART_MILLIS(1463284740000, 'month') as month, + DATE_PART_MILLIS(1463284740000, 'week') as week, + DATE_PART_MILLIS(1463284740000, 'year') as year; +---- + +.Results +[source,json] +---- +[ + { + "day_local": 14, + "day_pst": 14, + "day_utc": 15, + "month": 5, + "week": 20, + "year": 2016 + } +] +---- +==== + +[#fn-date-part-str] +== DATE_PART_STR(date1, part) + +=== Description + +Extracts the value of a given date component from a date string. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function, then `null` is returned. + +=== Return Value + +An integer representing the value of the component extracted from the timestamp. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_PART_STR('2016-05-15T03:59:00Z', 'day') as day, + DATE_PART_STR('2016-05-15T03:59:00Z', 'millisecond') as millisecond, + DATE_PART_STR('2016-05-15T03:59:00Z', 'month') as month, + DATE_PART_STR('2016-05-15T03:59:00Z', 'week') as week, + DATE_PART_STR('2016-05-15T03:59:00Z', 'year') as year; +---- + +.Results +[source,json] +---- +[ + { + "day": 15, + "millisecond": 0, + "month": 5, + "week": 20, + "year": 2016 + } +] +---- +==== + +[#fn-date-range-millis] +== DATE_RANGE_MILLIS(date1, date2, part [,n]) + +=== Description + +Generates an array of dates from the start date specified by `date1` and the end date specified by `date2`, as Epoch/UNIX timestamps. +The difference between each subsequent generated date can be adjusted. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +date2:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. ++ +This is the value that is subtracted from `date1`. ++ +If this argument is not an integer, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function, then `null` is returned. + +n:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing the value by which to increment the part component for each generated date. ++ +*Optional argument*. +If not specified, this defaults to 1. +If a value which is not an integer is specified, then `null` is returned. + +=== Return Value + +An array of integers representing the generated dates, as Epoch/UNIX timestamps, between `date1` and `date2`. + +=== Limitations + +It is possible to generate very large arrays using this function. +In some cases the query engine may be unable to process all of these and cause excessive resource consumption. +It is therefore recommended that you first validate the inputs to this function to ensure that the generated result is a reasonable size. + +If the start date is greater than the end date passed to the function then an error will not be thrown, but the result array will be empty. +An array of descending dates can be generated by setting the start date greater than the end date and specifying a negative value for `n`. + +=== Examples + +.Example 1 +==== +Range of milliseconds by month. + +[source,sqlpp] +---- +SELECT DATE_RANGE_MILLIS(1480752000000, 1475478000000, 'month', -1) as Milliseconds; +---- + +.Results +[source,json] +---- +[ + { + "Milliseconds": [ + 1480752000000, + 1478156400000 + ] + } +] +---- +==== + +.Example 2 +==== +Range of milliseconds by previous month. + +[source,sqlpp] +---- +SELECT DATE_RANGE_MILLIS(1480752000000, 1449129600000, 'month', -1) as Months; +---- + +.Results +[source,json] +---- +[ + { + "Months": [ + 1480752000000, + 1478156400000, + 1475478000000, + 1472886000000, + 1470207600000, + 1467529200000, + 1464937200000, + 1462258800000, + 1459666800000, + 1456992000000, + 1454486400000, + 1451808000000 + ] + } +] +---- +==== + +[#fn-date-range-str] +== DATE_RANGE_STR(start_date, end_date, date_interval [, quantity_int ]) + +=== Description + +Generates an array of date strings between the start date and end date, calculated by the interval and quantity values. +The input dates can be in any of the <>. + +=== Arguments + +start_date:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date used as the start date of the array generation. ++ +If this argument is not an integer, then `null` is returned. + +end_date:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date used as the end date of the array generation, and this value is exclusive, that is, the end date will not be included in the result. ++ +If this argument is not an integer, then `null` is returned. + +date_interval:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> of the date to increment. ++ +If an invalid part is passed to the function, then `null` is returned. + +quantity_int:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing the value by which to increment the interval component for each generated date. ++ +*Optional argument*. +If not specified, this defaults to 1. +If a value which is not an integer is specified, then `null` is returned. + +=== Return Value + +An array of strings representing the generated dates, as date strings, between `start_date` and `end_date`. + +=== Limitations + +* It is possible to generate very large arrays using this function. +In some cases the query engine may be unable to process all of these and cause excessive resource consumption. +It is therefore recommended that you first validate the inputs of this function to ensure that the generated result is a reasonable size. + +* If the `start_date` is greater than the `end_date`, then an error will not be thrown, but the result array will be empty. +An array of descending dates can be generated by setting the `start_date` greater than the `end_date` and specifying a negative value for `quantity_number`. + +* From 4.6.2, both specified dates can be different acceptable date formats; but prior to 4.6.2, both specified dates must have the same string format, otherwise `null` will be returned. +To ensure that both dates have the same format, you should use <>. + +=== Examples + +.Example 1 +==== +Ranges by quarters. + +[source,sqlpp] +---- +SELECT DATE_RANGE_STR('2015-11-30T15:04:05.999', '2017-04-14T15:04:06.998', 'quarter') +AS Quarters; +---- + +.Results +[source,json] +---- +[ + { + "Quarters": [ + "2015-11-30T15:04:05.999", + "2016-03-01T15:04:05.999", + "2016-06-01T15:04:05.999", + "2016-09-01T15:04:05.999", + "2016-12-01T15:04:05.999", + "2017-03-01T15:04:05.999" + ] + } +] +---- +==== + +.Example 2 +==== +Ranges by a single day. + +[source,sqlpp] +---- +SELECT DATE_RANGE_STR('2016-01-01T15:04:05.999', '2016-01-05T15:04:05.998', 'day', 1) +AS Days; +---- + +.Results +[source,json] +---- +[ + { + "Days": [ + "2016-01-01T15:04:05.999", + "2016-01-02T15:04:05.999", + "2016-01-03T15:04:05.999", + "2016-01-04T15:04:05.999" + ] + } +] +---- +==== + +.Example 3 +==== +Ranges by four months. + +[source,sqlpp] +---- +SELECT DATE_RANGE_STR('2018-01-01','2019-01-01', 'month', 4) +AS Months; +---- + +.Results +[source,json] +---- +[ + { + "Months": [ + "2018-01-01", + "2018-05-01", + "2018-09-01" + ] + } +] +---- +==== + +.Example 4 +==== +Ranges by previous days. + +[source,sqlpp] +---- +SELECT DATE_RANGE_STR('2016-01-05T15:04:05.999', '2016-01-01T15:04:06.998', 'day', -1) +AS Previous; +---- + +.Results +[source,json] +---- +[ + { + "Previous": [ + "2016-01-05T15:04:05.999", + "2016-01-04T15:04:05.999", + "2016-01-03T15:04:05.999", + "2016-01-02T15:04:05.999" + ] + } +] +---- +==== + +.Example 5 +==== +Ranges by month. + +[source,sqlpp] +---- +SELECT DATE_RANGE_STR('2015-01-01T01:01:01', '2015-12-11T00:00:00', 'month', 1) +AS Months; +---- + +.Results +[source,json] +---- +[ + { + "Months": [ + "2015-01-01T01:01:01", + "2015-02-01T01:01:01", + "2015-03-01T01:01:01", + "2015-04-01T01:01:01", + "2015-05-01T01:01:01", + "2015-06-01T01:01:01", + "2015-07-01T01:01:01", + "2015-08-01T01:01:01", + "2015-09-01T01:01:01", + "2015-10-01T01:01:01", + "2015-11-01T01:01:01", + "2015-12-01T01:01:01" + ] + } +] +---- +==== + +[#fn-date-trunc-millis] +== DATE_TRUNC_MILLIS(date1, part) + +=== Description + +Truncates an Epoch/UNIX timestamp up to the specified date component. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the date used as the date to truncate. ++ +If this argument is not an integer, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to truncate to. +This function accepts the components `millennium`, `century`, `decade`, `year`, `quarter`, `month`, `week`, and `iso_week`. ++ +If an invalid part is specified, then `null` is returned. + +=== Return Value + +An integer representing the truncated timestamp in Epoch/UNIX time. + +=== Limitations + +In some cases, where the timestamp is smaller than the duration of the provided part, this function returns the incorrect result. +It is recommended that you do not use this function for very small Epoch/UNIX timestamps. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_TRUNC_MILLIS(1463284740000, 'day') as day, + DATE_TRUNC_MILLIS(1463284740000, 'month') as month, + DATE_TRUNC_MILLIS(1463284740000, 'year') as year; +---- + +.Results +[source,json] +---- +[ + { + "day": 1463270400000, + "month": 1462147200000, + "year": 1451696400000 + } +] +---- +==== + +[#fn-date-trunc-str] +== DATE_TRUNC_STR(date1, part) + +=== Description + +Truncates a date string up to the specified date component. + +=== Arguments + +date1:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date that is truncated. ++ +If this argument is not a valid date format, then `null` is returned. + +part:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to truncate to. +This function accepts the components `millennium`, `century`, `decade`, `year`, `quarter`, `month`, `week`, and `iso_week`. ++ +If an invalid part is specified, then `null` is returned. + +=== Return Value + +A date string representing the truncated date. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DATE_TRUNC_STR('2016-05-18T03:59:00Z', 'day') as day, + DATE_TRUNC_STR('2016-05-18T03:59:00Z', 'month') as month, + DATE_TRUNC_STR('2016-05-18T03:59:00Z', 'year') as year; +---- + +.Results +[source,json] +---- +[ + { + "day": "2016-05-18T00:00:00Z", + "month": "2016-05-01T00:00:00Z", + "year": "2016-01-01T00:00:00Z" + } +] +---- +==== + +[#fn-date-duration-to-str] +== DURATION_TO_STR(duration) + +=== Description + +Converts a number into a human-readable time duration with units. + +=== Arguments + +duration:: +A number, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a number, which represents the duration to convert to a string. +This value is specified in nanoseconds (1×10^-9^ seconds). ++ +If a value which is not a number is specified, then `null` is returned. + +=== Return Value + +A string representing the human-readable duration. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT DURATION_TO_STR(2000) as microsecs, + DURATION_TO_STR(2000000) as millisecs, + DURATION_TO_STR(2000000000) as secs; +---- + +.Results +[source,json] +---- +[ + { + "microsecs": "2µs", + "millisecs": "2ms", + "secs": "2s" + } +] +---- +==== + +[#fn-date-millis] +== MILLIS(date1) + +=== Description + +Converts a date string to Epoch/UNIX milliseconds. + +=== Arguments + +date1:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date to convert to Epoch/UNIX milliseconds. ++ +If this argument is not a valid date format, then `null` is returned. + +=== Return Value + +An integer representing the date string converted to Epoch/UNIX milliseconds. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT MILLIS("2016-05-15T03:59:00Z") as DateStringInMilliseconds; +---- + +.Results +[source,json] +---- +[ + { + "DateStringInMilliseconds": 1463284740000 + } +] +---- +==== + +[#fn-date-millis-to-local] +== MILLIS_TO_LOCAL(date1 [, fmt]) + +Alias for <>. + +[#fn-date-millis-to-str] +== MILLIS_TO_STR(date1 [, fmt ]) + +=== Description + +Converts an Epoch/UNIX timestamp into the specified date string format. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the date to convert. ++ +If this argument is not an integer, then `null` is returned. + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If unspecified or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string representing the local date in the specified format. + +=== Limitations + +In some cases, where the timestamp is smaller than the duration of the provided part, this function returns the incorrect result. +It is recommended that you do not use this function for very small Epoch/UNIX timestamps. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT MILLIS_TO_STR(1463284740000) as full_date, + MILLIS_TO_STR(1463284740000, 'invalid format') as invalid_format, + MILLIS_TO_STR(1463284740000, '1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2016-05-14T20:59:00-07:00", + "invalid_format": "2016-05-14T20:59:00-07:00", + "short_date": "2016-05-14" + } +] +---- +==== + +[#fn-date-millis-to-tz] +== MILLIS_TO_TZ(date1, tz [, fmt]) + +=== Description + +Converts an Epoch/UNIX timestamp into the specified time zone in the specified date string format. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the date to convert. ++ +If this argument is not an integer, then `null` is returned. + +tz:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to convert the local time to. +*Optional argument*. +Defaults to the system timezone if not specified. ++ +If an incorrect time zone is provided, then `null` is returned. + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If no format or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string representing the date in the specified timezone in the specified format.. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT MILLIS_TO_TZ(1463284740000, 'America/New_York') as est, + MILLIS_TO_TZ(1463284740000, 'Asia/Kolkata') as ist, + MILLIS_TO_TZ(1463284740000, 'UTC') as utc; +---- + +.Results +[source,json] +---- +[ + { + "est": "2016-05-14T23:59:00-04:00", + "ist": "2016-05-15T09:29:00+05:30", + "utc": "2016-05-15T03:59:00Z" + } +] +---- +==== + +[#fn-date-millis-to-utc] +== MILLIS_TO_UTC(date1 [, fmt]) + +=== Description + +Converts an Epoch/UNIX timestamp into local time in the specified date string format. + +=== Arguments + +date1:: +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing a Epoch/UNIX timestamp in milliseconds. +This is the date to convert to UTC. ++ +If this argument is not an integer, then `null` is returned. + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If unspecified or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string representing the date in UTC in the specified format. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT MILLIS_TO_UTC(1463284740000) as full_date, + MILLIS_TO_UTC(1463284740000, 'invalid format') as invalid_format, + MILLIS_TO_UTC(1463284740000, '1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2016-05-15T03:59:00Z", + "invalid_format": "2016-05-15T03:59:00Z", + "short_date": "2016-05-15" + } +] +---- +==== + +[#fn-date-millis-to-zone-name] +== MILLIS_TO_ZONE_NAME(date1, tz [, fmt]) + +Alias for <> + +[#fn-date-now-local] +== NOW_LOCAL([fmt]) + +=== Description + +The timestamp of the query as date string in the system timezone. +Will not vary during a query. + +=== Arguments + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If no format or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date time string in the format specified. + +=== Limitations + +If this function is called multiple times within the same query it will always return the same time. +If you wish to use the system time when the function is evaluated, use <> instead. + +=== Examples + +.Example 1 +==== +Various arguments of NOW_LOCAL(). + +[source,sqlpp] +---- +SELECT NOW_LOCAL() as full_date, + NOW_LOCAL('invalid date') as invalid_date, + NOW_LOCAL('1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2018-01-23T14:03:40.26-08:00", + "invalid_date": "2018-01-23T14:03:40.26-08:00", + "short_date": "2018-01-23" + } +] +---- +==== + +.Example 2 +==== +Difference between NOW_LOCAL() and CLOCK_LOCAL(). + +[source,sqlpp] +---- +SELECT NOW_LOCAL(), NOW_LOCAL(), NOW_LOCAL(), NOW_LOCAL(), NOW_LOCAL(), CLOCK_LOCAL(); +---- + +.Results +[source,json] +---- +[ + { + "$1": "2018-01-23T14:06:20.254-08:00", + "$2": "2018-01-23T14:06:20.254-08:00", + "$3": "2018-01-23T14:06:20.254-08:00", + "$4": "2018-01-23T14:06:20.254-08:00", + "$5": "2018-01-23T14:06:20.254-08:00", + "$6": "2018-01-23T14:06:20.256-08:00" + } +] +---- +==== + +[#fn-date-now-millis] +== NOW_MILLIS() + +=== Description + +The timestamp of the query as an Epoch/UNIX timestamp. +Will not vary during a query. + +=== Arguments + +This function accepts no arguments. + +=== Return Value + +A floating point number representing the Epoch/UNIX timestamp of the query. + +=== Limitations + +If this function is called multiple times within the same query it will always return the same time. +If you wish to use the system time when the function is evaluated, use <> instead. + +=== Examples + +.Example 1 +==== +The time now in milliseconds. + +[source,sqlpp] +---- +SELECT NOW_MILLIS() as NowInMilliseconds; +---- + +.Results +[source,json] +---- +[ + { + "NowInMilliseconds": 1516745378065.12 + } +] +---- +==== + +.Example 2 +==== +Difference between NOW_MILLIS() and CLOCK_MILLIS(). + +[source,sqlpp] +---- +SELECT NOW_MILLIS(), NOW_MILLIS(), NOW_MILLIS(), NOW_MILLIS(), CLOCK_MILLIS(); +---- + +.Results +[source,json] +---- +[ + { + "$1": 1516745528579.607, + "$2": 1516745528579.607, + "$3": 1516745528579.607, + "$4": 1516745528580.29 + } +] +---- +==== + +[#fn-date-now-tz] +== NOW_TZ(tz [, fmt]) + +=== Description + +The timestamp of the query as date string in the specified timezone. +Will not vary during a query. + +=== Arguments + +tz:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to convert the query timestamp to. ++ +If an incorrect time zone is provided then `null` is returned. + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If unspecified or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string in the format specified representing the timestamp of the query in the specified timezone. + +=== Limitations + +If this function is called multiple times within the same query it will always return the same time. +If you wish to use the system time when the function is evaluated, use <> instead. + +=== Examples + +.Example 1 +==== +Various arguments for NOW_TZ(). + +[source,sqlpp] +---- +SELECT NOW_TZ('invalid tz') as invalid_tz, + NOW_TZ('Asia/Kolkata') as ist, + NOW_TZ('UTC') as utc, + NOW_TZ('UTC', '1111-11-11') as utc_short_date; +---- + +.Results +[source,json] +---- +[ + { + "invalid_tz": null, + "ist": "2018-01-24T03:43:36.457+05:30", + "utc": "2018-01-23T22:13:36.457Z", + "utc_short_date": "2018-01-23" + } +] +---- +==== + +.Example 2 +==== +Difference between NOW_TZ() and CLOCK_TZ(). + +[source,sqlpp] +---- +SELECT NOW_TZ('UTC'), NOW_TZ('UTC'), NOW_TZ('UTC'), CLOCK_TZ('UTC'); +---- + +.Results +[source,json] +---- +[ + { + "$1": "2018-01-23T22:15:59.551Z", + "$2": "2018-01-23T22:15:59.551Z", + "$3": "2018-01-23T22:15:59.551Z", + "$4": "2018-01-23T22:15:59.552Z" + } +] +---- +==== + +[#fn-date-now-str] +== NOW_STR([fmt]) + +=== Description + +The timestamp of the query as date string in the system timezone. +Will not vary during a query. + +=== Arguments + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If unspecified or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string in the format specified representing the timestamp of the query. + +=== Limitations + +If this function is called multiple times within the same query it will always return the same time. +If you wish to use the system time when the function is evaluated, use <> instead. + +=== Examples + +.Example 1 +==== +Various arguments for NOW_STR(). + +[source,sqlpp] +---- +SELECT NOW_STR() as full_date, + NOW_STR('invalid date') as invalid_date, + NOW_STR('1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "2018-01-23T14:16:58.075-08:00", + "invalid_date": "2018-01-23T14:16:58.075-08:00", + "short_date": "2018-01-23" + } +] +---- +==== + +.Example 2 +==== +Difference between NOW_STR() and CLOCK_STR(). + +[source,sqlpp] +---- +SELECT NOW_STR(), NOW_STR(), NOW_STR(), NOW_STR(), NOW_STR(), NOW_STR(), CLOCK_STR(); +---- + +.Results +[source,json] +---- +[ + { + "$1": "2018-01-23T14:18:37.605-08:00", + "$2": "2018-01-23T14:18:37.605-08:00", + "$3": "2018-01-23T14:18:37.605-08:00", + "$4": "2018-01-23T14:18:37.605-08:00", + "$5": "2018-01-23T14:18:37.605-08:00", + "$6": "2018-01-23T14:18:37.605-08:00", + "$7": "2018-01-23T14:18:37.607-08:00" + } +] +---- +==== + +[#fn-date-now-utc] +== NOW_UTC([fmt]) + +=== Description + +The timestamp of the query as date string in UTC. +Will not vary during a query. + +=== Arguments + +fmt:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a <> to output the result as. ++ +*Optional argument*. +If unspecified or an incorrect format is specified, then this defaults to the combined full date and time. + +=== Return Value + +A date string in the format specified representing the timestamp of the query in UTC. + +=== Limitations + +If this function is called multiple times within the same query it will always return the same time. +If you wish to use the system time when the function is evaluated, use <> instead. + +=== Examples + +.Example 1 +==== +The current UTC time. + +[source,sqlpp] +---- +SELECT NOW_UTC() as CurrentUTC; +---- + +.Results +[source,json] +---- +[ + { + "CurrentUTC": "2018-01-23T22:20:43.971Z" + } +] +---- +==== + +.Example 2 +==== +Difference between NOW_UTC() and CLOCK_UTC(). + +[source,sqlpp] +---- +SELECT NOW_UTC(), NOW_UTC(), NOW_UTC(), NOW_UTC(), NOW_UTC(), NOW_UTC(), NOW_UTC(), CLOCK_UTC(); +---- + +.Results +[source,json] +---- +[ + { + "$1": "2018-01-23T22:21:46.769Z", + "$2": "2018-01-23T22:21:46.769Z", + "$3": "2018-01-23T22:21:46.769Z", + "$4": "2018-01-23T22:21:46.769Z", + "$5": "2018-01-23T22:21:46.769Z", + "$6": "2018-01-23T22:21:46.769Z", + "$7": "2018-01-23T22:21:46.769Z", + "$8": "2018-01-23T22:21:46.77Z" + } +] +---- +==== + +[#fn-date-str-to-duration] +== STR_TO_DURATION(duration) + +=== Description + +Converts a string representation of a time duration into nanoseconds. +This accepts the following units: + +* nanoseconds (`ns`) +* microseconds (`us` or `µs`) +* milliseconds (`ms`) +* seconds (`s`) +* minutes (`m`) +* hours (`h`) + +=== Arguments + +duration:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the duration to convert. ++ +If an invalid duration string is specified, then `null` is returned. + +=== Return Value + +A single integer representing the duration in nanoseconds. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT STR_TO_DURATION('1h') as hour, +STR_TO_DURATION('1us') as microsecond, +STR_TO_DURATION('1ms') as millisecond, +STR_TO_DURATION('1m') as minute, +STR_TO_DURATION('1ns') as nanosecond, +STR_TO_DURATION('1s') as second; +---- + +.Results +[source,json] +---- +[ + { + "hour": 3600000000000, + "microsecond": 1000, + "millisecond": 1000000, + "minute": 60000000000, + "nanosecond": 1, + "second": 1000000000 + } +] +---- +==== + +[#fn-date-str-to-millis] +== STR_TO_MILLIS(date1 [, format]) + +=== Description + +Converts a date string to Epoch/UNIX milliseconds. + +=== Arguments + +date1:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the date to convert to Epoch/UNIX milliseconds. ++ +If this argument is not a valid date format, then `null` is returned. + +format:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the expected format of the input date string, using the https://golang.org/pkg/time/#pkg-constants[Go language reference date^]. ++ +*Optional argument*. +If not specified, the input date string must be in a <>. +If an incorrect format is provided, then `null` is returned. + +=== Return Value + +An integer representing the date string converted to Epoch/UNIX milliseconds. + +=== Examples + +.Example 1 +==== +[source,sqlpp] +---- +SELECT STR_TO_MILLIS("2016-05-15T03:59:00Z") AS Milliseconds; +---- + +.Results +[source,json] +---- +[ + { + "Milliseconds": 1463284740000 + } +] +---- +==== + +.Example 2 +==== +[source,sqlpp] +---- +SELECT STR_TO_MILLIS("19/08/2011 6:33:23+0000", "02/01/2006 15:04:05Z0700") +AS Milliseconds; +---- + +.Results +[source,json] +---- +[ + { + "Milliseconds": 1313735603000 + } +] +---- +==== + +[#fn-date-str-to-utc] +== STR_TO_UTC(date1) + +=== Description + +Converts a date string into the equivalent date in UTC. +The output date format follows the date format of the date passed as input. + +=== Arguments + +date1:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date to convert to UTC. ++ +If this argument is not a valid date format, then `null` is returned. + +=== Return Value + +A single date string representing the date string converted to UTC. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT STR_TO_UTC('1111-11-11T00:00:00+08:00') as full_date, +STR_TO_UTC('1111-11-11') as short_date; +---- + +.Results +[source,json] +---- +[ + { + "full_date": "1111-11-10T16:00:00Z", + "short_date": "1111-11-11" + } +] +---- +==== + +[#fn-date-str-to-tz] +== STR_TO_TZ(date1, tz) + +=== Description + +Converts a date string to its equivalent in the specified timezone. +The output date format follows the date format of the date passed as input. + +=== Arguments + +date1:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date to convert to UTC. ++ +If this argument is not a valid date format then `null` is returned. + +tz:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to convert the local time to. ++ +If this argument is not a valid timezone, then `null` is returned. + +=== Return Value + +A single date string representing the date string converted to the specified timezone. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT STR_TO_TZ('1111-11-11T00:00:00+08:00', 'America/New_York') as est, + STR_TO_TZ('1111-11-11T00:00:00+08:00', 'UTC') as utc, + STR_TO_TZ('1111-11-11', 'UTC') as utc_short; +---- + +.Results +[source,json] +---- +[ + { + "est": "1111-11-10T11:00:00-05:00", + "utc": "1111-11-10T16:00:00Z", + "utc_short": "1111-11-11" + } +] +---- +==== + +[#fn-date-str-to-zone-name] +== STR_TO_ZONE_NAME(date1, tz) + +Alias for <>. + +== WEEKDAY_MILLIS(expr [, tz ]) + +=== Description + +Converts a date string to its equivalent in the specified timezone. +The output date format follows the date format of the date passed as input. + +=== Arguments + +expr:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, representing an Epoch/UNIX timestamp in milliseconds. + +tz:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the <> to for the expr argument. ++ +*Optional argument*. +Defaults to the system timezone if not specified. +If an incorrect time zone is provided then `null` is returned. + +=== Return Value + +A single date string representing the date string converted to the specified timezone. + +=== Examples + +==== +[source,sqlpp] +---- +SELECT WEEKDAY_MILLIS(1486237655742, 'America/Tijuana') as Day; +---- + +.Results +[source,json] +---- +[ + { + "Day": "Saturday" + } +] +---- +==== +== WEEKDAY_STR(date) + +=== Description + +Returns the day of the week string value from the input date string. +Returns the weekday name from the input date in Unix timestamp. +Note that his function returns the string value of the day of the week, where <> with part = "dow" returns an integer value of the weekday (0-6). + +=== Arguments + +date:: +A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing a date in a <>. +This is the date to convert to UTC. ++ +If this argument is not a valid date format then `null` is returned. + +=== Return Value + +The text string name of the day of the week, such as "Monday" or "Friday". + +=== Examples + +==== +[source,sqlpp] +---- +SELECT WEEKDAY_STR('2017-02-05') as Day; +---- + +.Results +[source,json] +---- +[ + { + "Day": "Sunday" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/delete.adoc b/modules/n1ql/pages/n1ql-language-reference/delete.adoc new file mode 100644 index 000000000..58f15fd41 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/delete.adoc @@ -0,0 +1,311 @@ += DELETE +:description: DELETE immediately removes the specified document from your keyspace. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:clusters:manage-database-users.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:returning-clause: xref:n1ql-language-reference/insert.adoc#returning-clause +:use-keys-clause: xref:n1ql-language-reference/hints.adoc#use-keys-clause + +:from: xref:n1ql-language-reference/from.adoc +:from-keyspace-ref: {from}#from-keyspace-ref +:as-clause: {from}#section_ax5_2nx_1db + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +{description} + +== Prerequisites + +=== RBAC Privileges + +To execute the DELETE statement, you must have the _Query Delete_ privilege granted on the target keyspace. +If the statement has any RETURNING clauses that need data read, then the _Query Select_ privilege is also required on the keyspaces referred in the respective clauses. +For more details about user roles, see {authorization-overview}[]. + +.RBAC Examples +[%collapsible] +==== +[cols="^25,^25,^25,^25"] +|=== +| Delete Query Contains | Query Delete Permissions Needed | Query Select Permissions Needed | Example + +| WHERE clause +| Yes +| No +| <> + +| Subquery +| Yes +| Yes +| <> + +| RETURNING clause +| Yes +| Yes +| <> +|=== +==== + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=delete] +---- + +image::n1ql-language-reference/delete.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links from EBNF + +[horizontal.compact] +target-keyspace:: <> icon:caret-down[] +use-keys-clause:: <> icon:caret-down[] +where-clause:: <> icon:caret-down[] +limit-clause:: <> icon:caret-down[] +offset-clause:: <> icon:caret-down[] +returning-clause:: <> icon:caret-down[] + +[[delete-target]] +=== Delete Target + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=target-keyspace] +---- + +image::n1ql-language-reference/target-keyspace.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the data source from which to delete the document. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[keyspace-ref]] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Keyspace reference for the delete target. +For more details, refer to {from-keyspace-ref}[Keyspace Reference]. + +[[delete-alias]] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[[delete-hint]] +=== Delete Hint + +You can use a `USE KEYS` hint on the delete target to specify the keys of the data items to be deleted. +For details, refer to {use-keys-clause}[USE KEYS Clause]. + +[[where-clause]] +=== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the condition that needs to be met for data to be deleted. +Optional. + +[[limit-clause]] +=== LIMIT Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=limit-clause] +---- + +image::n1ql-language-reference/limit-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the greatest number of objects that can be deleted. +This clause must have a non-negative integer as its upper bound. +Optional. + +[[offset-clause]] +=== OFFSET Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=offset-clause] +---- + +image::n1ql-language-reference/offset-clause.png["Syntax diagram: refer to source code listing", align=left] + +Like the xref:n1ql-language-reference/offset.adoc[OFFSET clause] for a SELECT query, you can include an OFFSET clause in a DELETE statement to specify a number of objects to skip before beginning the deletion. +This option can be useful for parallelizing a large delete operation. + +You can include the OFFSET clause either before or after the optional LIMIT clause. +The position has no effect on the result. + +The expression for this clause must be a non-negative integer. +Optional. + +[[returning-clause]] +=== RETURNING Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=returning-clause] +---- + +image::n1ql-language-reference/returning-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the information to be returned by the operation as a query result. +For more details, refer to {returning-clause}[RETURNING Clause]. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +WARNING: Be aware that running the following examples will permanently delete your sample data. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +[[Q1]] +.Delete query containing a WHERE clause +==== +This example requires the _Query Delete_ privilege on `hotel`. + +[source,sqlpp] +---- +include::example$dml/delete-all.n1ql[] +---- +==== + +[[Q2]] +.Delete queries containing a subquery +==== +This example requires the _Query Delete_ privilege on `airport` and the _Query Select_ privilege on `pass:c[`beer-sample`]`. + +[source,sqlpp] +---- +include::example$dml/delete-sub-other.n1ql[] +---- + +This example requires the _Query Delete_ and _Query Select_ privileges on `airport`. + +[source,sqlpp] +---- +include::example$dml/delete-sub-same.n1ql[] +---- +==== + +[[Q3]] +.Delete queries containing a RETURNING clause +==== +These examples require the _Query Delete_ and _Query Select_ privileges on `hotel`. + +[source,sqlpp] +---- +include::example$dml/delete-all-return.n1ql[] +---- + +[source,sqlpp] +---- +include::example$dml/delete-filter-return.n1ql[] +---- +==== + +.Delete by key +==== +This example deletes the document `airline_4444`. + +[source,sqlpp] +---- +include::example$dml/delete-key.n1ql[] +---- + +.Results +[source,json] +---- +include::example$dml/delete-key.jsonc[] +---- +==== + +.Delete by filter +==== +This example deletes the airline with the callsign "AIR-X". + +[source,sqlpp] +---- +include::example$dml/delete-filter.n1ql[] +---- + +.Results +[source,json] +---- +include::example$dml/delete-filter.jsonc[] +---- +==== + +.Delete with LIMIT and OFFSET +==== +This example deletes a subset of the airlines with a country of "France'. +First, you query to get a list of the airlines in France. + +[source,sqlpp] +---- +include::example$dml/delete-offset-before.n1ql[] +---- + +There are 21 documents in this collection with `country="France"`. + +.Results +[source,text] +---- +include::example$dml/delete-offset-before.jsonc[] +---- + +<.> The 10th document's id. +<.> The 20th document's id. + +Next, you specify that you want to delete up to 10 documents, after skipping the first 10. + +[source,sqlpp] +---- +include::example$dml/delete-offset.n1ql[] +---- + +Now there are 11 documents in this collection with `country="France"`. + +.Results +[source,text] +---- +include::example$dml/delete-offset.jsonc[] +---- + +<.> Documents with the first 10 ids--the offset--remain in the airline collection. +<.> After deleting 10 documents--the limit--1 more document remains in the collection. +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/dropcollection.adoc b/modules/n1ql/pages/n1ql-language-reference/dropcollection.adoc new file mode 100644 index 000000000..c0c8e7395 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/dropcollection.adoc @@ -0,0 +1,102 @@ += DROP COLLECTION +:description: The DROP COLLECTION statement enables you to delete a named collection from a scope. +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +:identifier: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:scopes-and-collections: xref:server:learn:data/scopes-and-collections.adoc +:manage-scopes-and-collections: xref:server:manage:manage-scopes-and-collections/manage-scopes-and-collections.adoc +:scopes-and-collections-api: xref:server:rest-api:scopes-and-collections-api.adoc +:couchbase-cli-collection-manage: xref:server:cli:cbcli/couchbase-cli-collection-manage.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `DROP COLLECTION` statement enables you to delete a named collection from a scope. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=drop-collection] +---- + +image::n1ql-language-reference/drop-collection.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal] +namespace:: +(Optional) An {identifier}[identifier] that refers to the {logical-hierarchy}[namespace] of the bucket which contains the collection you want to delete. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Optional) An {identifier}[identifier] that refers to the bucket which contains the collection you want to delete. + +scope:: +(Optional) An {identifier}[identifier] that refers to the scope which contains the collection you want to delete. + +collection:: +(Required) An {identifier}[identifier] that refers to the name of the collection that you want to delete. + +NOTE: If there is a hyphen (-) inside the bucket name, the scope name, or the collection name, you must wrap that part of the path in backticks ({backtick} {backtick}). +For example, `default:{backtick}travel-sample{backtick}` indicates the `travel-sample` keyspace in the `default` namespace. + +[[location]] +=== Specifying the Location + +To specify the location of the collection, you may do one of the following: + +* Include its [def]_full path_, containing the namespace, bucket, and scope, followed by the collection name; +* Include a [def]_relative path_, containing just the bucket and scope, followed by the connection name; +* Specify just the collection name without a path. + +When you specify a collection name without a path, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. +If you specify a collection name by itself without setting a valid query context, an error is generated. + +[[if-exists]] +=== IF EXISTS Clause + +The optional `IF EXISTS` clause enables the statement to complete successfully when the specified collection doesn't exist. +If the collection does not exist within the specified scope, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +== Examples + +.Delete collection with full path +==== +This statement deletes a collection called `city` in the `inventory` scope within the `travel-sample` bucket. + +[source,sqlpp] +---- +DROP COLLECTION `travel-sample`.inventory.city +---- +==== + +.Delete collection with query context +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Assuming that the query context is set, this statement deletes a collection called `country` in the `inventory` scope within the `travel-sample` bucket. + +[source,sqlpp] +---- +DROP COLLECTION country; +---- +==== + +== Related Links + +* An overview of scopes and collections is provided in {scopes-and-collections}[Scopes and Collections]. + +* Step-by-step procedures for management are provided in {manage-scopes-and-collections}[Manage Scopes and Collections]. + +* Refer to {scopes-and-collections-api}[Scopes and Collections API] to manage scopes and collections with the REST API. + +* Refer to the reference page for the {couchbase-cli-collection-manage}[collection-manage] command to manage scopes and collections with the CLI. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc new file mode 100644 index 000000000..685b28972 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -0,0 +1,163 @@ += DROP FUNCTION +:description: pass:q[The `DROP FUNCTION` statement enables you to delete a user-defined function.] +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Prerequisites + +[cols="2,3"] +|=== +| To manage ... | You must have ... + +| Global inline functions +| *Manage Global Functions* role. + +| Scoped inline functions +| *Manage Scope Functions* role, with permissions on the specified bucket and scope. + +| Global external functions +| *Manage Global External Functions* role. + +| Scoped external functions +| *Manage Scope External Functions* role, with permissions on the specified bucket and scope. +|=== + +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=drop-function] +---- + +image::n1ql-language-reference/drop-function.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal.compact] +function:: <> icon:caret-down[] + +[[name]] +=== Function Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=function] +---- + +image::n1ql-language-reference/function.png["Syntax diagram: refer to source code listing", align=left] + +The name of the function. +This is usually an unqualified identifier, such as `func1` or `{backtick}func-1{backtick}`. +In this case, the path to the function is determined by the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +To delete a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as `default:func1`. +Similarly, to delete a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. +Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more information. + +NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. +You must delete the user-defined function using the same case that was used when it was created. + +=== IF EXISTS Clause + +The optional `IF EXISTS` clause enables the statement to complete successfully when the specified function doesn't exist. + +When the function does not exist within the specified context: +footnote:context[That is, you are dropping a global function, and the function does not exist within the specified namespace; or, you are dropping a scoped function, and the function does not exist within the specified scope.] + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +== Usage + +ifdef::flag-devex-javascript-udfs[] +When you drop a user-defined function whose definition is stored in an external library, the external library and function on which the user-defined function depended are not deleted. +This enables you to create a new user-defined function with a different name, or a different number of parameters, using the same JavaScript library and function. + +To change or delete an external library or the external function code, you must use the {sqlpp} xref:n1ql-rest-functions:index.adoc[Functions REST API]. +endif::flag-devex-javascript-udfs[] + +When you drop a {sqlpp} managed user-defined function, the associated external function code is deleted also. + +== Examples + +.Drop an inline function +==== +This statement deletes an inline function called `celsius`. + +[source,sqlpp] +---- +DROP FUNCTION celsius; +---- + +You can run the following query to check that the function is no longer available. + +[source,sqlpp] +---- +SELECT * FROM system:functions; +---- +==== + +.Drop a {sqlpp} managed user-defined function +==== +This statement deletes a {sqlpp} managed user-defined function called `add100`. + +[source,sqlpp] +---- +DROP FUNCTION add100 IF EXISTS; +---- + +You can run the following query to check that the function is no longer available. + +[source,sqlpp] +---- +SELECT * FROM system:functions; +---- +==== + +ifdef::flag-devex-javascript-udfs[] +.Drop an external function +==== +These statements delete two external functions: + +. A function called `geohash`, which depends on the JavaScript `encodeGeoHash` function in the `geohash-js` library; +. A function called `adjacent`, which depends on the JavaScript `calculateAdjacent` function in the `geohash-js` library. + +[source,sqlpp] +---- +DROP FUNCTION geohash; + +DROP FUNCTION adjacent; +---- + +You can run the following command to check that the JavaScript `geohash-js` library and the `encodeGeoHash` and `calculateAdjacent` functions are still available. + +[source,sh] +---- +curl -v -X GET \ +http://localhost:8093/evaluator/v1/libraries/geohash-js \ +-u Administrator:password +---- +==== +endif::flag-devex-javascript-udfs[] + +== Related Links + +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +ifdef::flag-devex-javascript-udfs[] +* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. +endif::flag-devex-javascript-udfs[] +* To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. +* To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. +* To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. +* To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. diff --git a/modules/n1ql/pages/n1ql-language-reference/dropindex.adoc b/modules/n1ql/pages/n1ql-language-reference/dropindex.adoc new file mode 100644 index 000000000..aee6c4260 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/dropindex.adoc @@ -0,0 +1,337 @@ += DROP INDEX +:description: The DROP INDEX statement allows you to drop a named primary index or a secondary index. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:drop-primary-index: xref:n1ql-language-reference/dropprimaryindex.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +{description} +Dropping an index that has replicas will also drop all of the replica indexes too. +You can drop unnamed primary indexes using the {drop-primary-index}[DROP PRIMARY INDEX] statement. + +== Prerequisites + +[discrete] +===== RBAC Privileges + +User executing the DROP INDEX statement must have the _Query Manage Index_ privilege granted on the keyspace/bucket. +For more details about user roles, see +{authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=drop-index] +---- + +image::n1ql-language-reference/drop-index.png["Syntax diagram: refer to source code listing", align=left] + +The DROP INDEX statement provides two possible syntaxes for specifying the index and the keyspace where the index is located. + +// TODO: Automatic links in EBNF. + +[horizontal] +index-name:: (Required) A unique name that identifies the index. + +index-path:: (Optional) One possible syntax for specifying the the keyspace. +Refer to <> below. + +keyspace-ref:: (Optional) The other possible syntax for specifying the keyspace. +Refer to <> below. + +index-using:: Specifies the index type. +(Optional) Refer to <> below. + +[[if-exists]] +=== IF EXISTS Clause + +The optional `IF EXISTS` clause enables the statement to complete successfully when the specified index doesn't exist. +If the index does not exist within the specified keyspace, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +[[index-path]] +=== Index Path + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-path] +---- + +image::n1ql-language-reference/index-path.png["Syntax diagram: refer to source code listing", align=left] + +You can use a dotted notation to specify the index and the keyspace on which the index is built. +This syntax provides compatibility with legacy versions of Couchbase Server. +The index path may be a <>, a <>, or a <>. + +NOTE: If there is a hyphen (-) inside the index name or any part of the index path, you must wrap the index name or that part of the index path in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-full-index,full keyspace path]] +==== Index Path: Full Keyspace + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=keyspace-full] +---- + +image::n1ql-language-reference/keyspace-full.png["Syntax diagram: refer to source code listing", align=left] + +If the index is built on a named collection, the index path may be a full keyspace path, including namespace, bucket, scope, and collection, followed by the index name. +In this case, the {query-context}[query context] is ignored. + +[horizontal] +namespace:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. + +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `default:{backtick}travel-sample{backtick}.inventory.airline.{backtick}idx-name{backtick}` indicates the `idx-name` index on the `airline` collection in the `inventory` scope in the `default:{backtick}travel-sample{backtick}` bucket. +==== + +[[keyspace-prefix-index,keyspace prefix]] +==== Index Path: Keyspace Prefix + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=keyspace-prefix] +---- + +image::n1ql-language-reference/keyspace-prefix.png["Syntax diagram: refer to source code listing", align=left] + +If the index is built on the default collection in the default scope within a bucket, the index path may be just an optional namespace and the bucket name, followed by the index name. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +==== +For example, `default:{backtick}travel-sample{backtick}.def_type` indicates the `def_type` index on the default collection in the default scope in the `default:{backtick}travel-sample{backtick}` bucket. +==== + +[[keyspace-partial-index,keyspace partial]] +==== Index Path: Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the index path may be just the collection name, followed by the index name. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `airline.{backtick}idx-name{backtick}` indicates the `idx-name` index on the `airline` collection, assuming that the query context is set. +==== + +[[keyspace-ref]] +=== Index Name ON Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +You can use the index name with the `ON` keyword and a keyspace reference to specify the keyspace on which the index is built. +The keyspace reference may be a <> or a <>. + +NOTE: If there is a hyphen (-) inside the index name or any part of the keyspace reference, you must wrap the index name or that part of the keyspace reference in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-path,keyspace path]] +==== Keyspace Reference: Keyspace Path + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +If the keyspace is a named collection, or the default collection in the default scope within a bucket, the keyspace reference may be a keyspace path. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. +If omitted, the bucket's default scope is used. + +collection:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. +If omitted, the default collection in the bucket's default scope is used. + +==== +For example, `def_type ON default:{backtick}travel-sample{backtick}` indicates the `def_type` index on the default collection in the default scope in the `default:{backtick}travel-sample{backtick}` bucket. + +Similarly, `{backtick}idx-name{backtick} ON default:{backtick}travel-sample{backtick}.inventory.airline` indicates the `idx-name` index on the `airline` collection in the `inventory` scope in the `default:{backtick}travel-sample{backtick}` bucket. +==== + +[[keyspace-partial,keyspace partial]] +==== Keyspace Reference: Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the keyspace reference may be just the collection name. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `{backtick}idx-name{backtick} ON airline` indicates the `idx-name` index on the `airline` collection, assuming the query context is set. +==== + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +The index type for a secondary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +== Usage + +When using memory-optimized indexes, DROP INDEX is an expensive operation and may take a few minutes to complete. + +If you drop an index with replicas while one of the index nodes is failed over, then only the replicas in the active index nodes are dropped. +If the failed-over index node is recovered, then the orphan replica will be dropped when this failed-over indexer is added back to cluster. + +If you drop an index with replicas when one of the index nodes is unavailable but not failed over, the drop index operation may fail. + +If you drop an index which is scheduled for background creation, a warning message is generated, but the drop index operation succeeds. + +[caption=Attention] +IMPORTANT: We recommend that you do not drop (or create) secondary indexes when any node with a secondary index role is down as this may result in duplicate index names. + +== Examples + +To try the examples in this section, you must set the query context as described in each example. + +[[ex-1]] +.Drop index from the default collection in the default scope +==== +This example drops an index from the default collection in the default scope within the `travel-sample` bucket. +include::ROOT:partial$query-context.adoc[tag=unset] + +First create a secondary index on the default collection in the default scope in the `travel-sample` bucket. +Once the index creation statement comes back, query `system:indexes` for the status of the index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-default.n1ql[tag=tmp] +---- + +Subsequently, drop the index and check that it is no longer reported in the `system:indexes` output. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-default.n1ql[tag=query] +---- + +The following command would drop the index in exactly the same way, but uses alternative syntax. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-default.n1ql[tag=alt] +---- +==== + +[[ex-2]] +.Drop index from a named collection with path +==== +This example drops an index from the `airline` collection. +For this example, the path to the required keyspace is specified by the query, so you do not need to set the query context. + +First create an index called `idx-name` in the `airline` collection. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-collection.n1ql[tag=tmp] +---- + +Drop the index `idx-name` from the `airline` collection. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-collection.n1ql[tag=alt] +---- +==== + +[[ex-3]] +.Drop index from a named collection with query context +==== +include::ROOT:partial$query-context.adoc[tag=example] + +Create an index called `idx-name` in the `airline` collection. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-name.n1ql[] +---- + +Drop the index `idx-name` from the `airline` collection. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-name.n1ql[] +---- + +The following command would drop the index in exactly the same way, but uses alternative syntax. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-idx-alt.n1ql[] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/dropprimaryindex.adoc b/modules/n1ql/pages/n1ql-language-reference/dropprimaryindex.adoc new file mode 100644 index 000000000..dbb226962 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/dropprimaryindex.adoc @@ -0,0 +1,160 @@ += DROP PRIMARY INDEX +:description: The DROP PRIMARY INDEX statement allows you to drop an unnamed primary index. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:roles: xref:server:learn:security/roles.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +{description} + +IMPORTANT: Named primary indexes that are created using CREATE PRIMARY INDEX can only be dropped using the DROP INDEX command. + +== Prerequisites + +[discrete] +===== RBAC Privileges + +User executing the DROP PRIMARY INDEX statement must have the _Query Manage Index_ privilege granted on the keyspace. +For more details about user roles, see {roles}[Roles]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=drop-primary-index] +---- + +image::n1ql-language-reference/drop-primary-index.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal] +keyspace-ref:: (Required) Specifies the keyspace where the index is located. +Refer to <> below. + +index-using:: (Optional) Specifies the index type. +Refer to <> below. + +[[if-exists]] +=== IF EXISTS Clause + +The optional `IF EXISTS` clause enables the statement to complete successfully when the specified primary index doesn't exist. +If the primary index does not exist within the specified keyspace, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the keyspace for the primary index to drop. +The keyspace reference may be a <> or a <>. + +NOTE: If there is a hyphen (-) inside any part of the keyspace reference, you must wrap that part of the keyspace reference in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-path,keyspace path]] +==== Keyspace Path + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +If the keyspace is a named collection, or the default collection in the default scope within a bucket, the keyspace reference may be a keyspace path. +In this case, the {query-context}[query context] should not be set. + +[horizontal] +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. +If omitted, the bucket's default scope is used. + +collection:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. +If omitted, the default collection in the bucket's default scope is used. + +==== +For example, `default:{backtick}travel-sample{backtick}` indicates the default collection in the default scope in the `travel-sample` bucket in the `default` namespace. + +Similarly, `default:{backtick}travel-sample{backtick}.inventory.airline` indicates the `airline` collection in the `inventory` scope in the `travel-sample` bucket in the `default` namespace. +==== + +[[keyspace-partial,keyspace partial]] +==== Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, if the keyspace is a named collection, the keyspace reference may be just the collection name with no path. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +[horizontal] +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `airline` indicates the `airline` collection, assuming the query context is set. +==== + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +The index type for a primary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +.Drop unnamed primary index +==== +Create an unnamed primary index on the `airline` keyspace. +Once the index creation statement comes back, query `system:indexes` for status of the index. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-pri-nameless.n1ql[tags=**] +---- + +Subsequently, drop the unnamed primary index with the following statement so that it is no longer reported in the `system:indexes` output. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/drop-pri-nameless.n1ql[tags=**] +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/dropscope.adoc b/modules/n1ql/pages/n1ql-language-reference/dropscope.adoc new file mode 100644 index 000000000..a2cb4b261 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/dropscope.adoc @@ -0,0 +1,77 @@ += DROP SCOPE +:description: pass:q[The `DROP SCOPE` statement enables you to delete a scope.] +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +:identifier: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:scopes-and-collections: xref:clusters:data-service/about-buckets-scopes-collections.adoc +:manage-scopes-and-collections: xref:clusters:data-service/scopes-collections.adoc +:scopes-and-collections-api: xref:server:rest-api:scopes-and-collections-api.adoc +:couchbase-cli-collection-manage: xref:server:cli:cbcli/couchbase-cli-collection-manage.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=drop-scope] +---- + +image::n1ql-language-reference/drop-scope.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal] +namespace:: +(Optional) An {identifier}[identifier] that refers to the {logical-hierarchy}[namespace] of the bucket which contains the scope you want to delete. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifier}[identifier] that refers to the bucket which contains the scope you want to delete. + +scope:: +(Required) An {identifier}[identifier] that refers to the name of the scope that you want to delete. + +NOTE: If there is a hyphen (-) inside the bucket name or the scope name, you must wrap that part of the path in backticks ({backtick} {backtick}). +For example, `default:{backtick}travel-sample{backtick}` indicates the `travel-sample` keyspace in the `default` namespace. + +[[if-exists]] +=== IF EXISTS Clause + +The optional `IF EXISTS` clause enables the statement to complete successfully when the specified scope doesn't exist. +If the scope does not exist within the specified bucket, then: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +== Usage + +When you delete a scope, any collections within that scope are deleted also. + +== Example + +==== +This statement deletes a scope called `events` in the `travel-sample` bucket. + +[source,sqlpp] +---- +DROP SCOPE `travel-sample`.events +---- +==== + +== Related Links + +* An overview of scopes and collections is provided in {scopes-and-collections}[Scopes and Collections]. + +* Step-by-step procedures for management are provided in {manage-scopes-and-collections}[Manage Scopes and Collections]. + +* Refer to {scopes-and-collections-api}[Scopes and Collections API] to manage scopes and collections with the REST API. + +* Refer to the reference page for the {couchbase-cli-collection-manage}[collection-manage] command to manage scopes and collections with the CLI. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/dropsequence.adoc b/modules/n1ql/pages/n1ql-language-reference/dropsequence.adoc new file mode 100644 index 000000000..4da496e21 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/dropsequence.adoc @@ -0,0 +1,122 @@ += DROP SEQUENCE +:page-topic-type: reference +:imagesdir: ../../assets/images +:description: The DROP SEQUENCE statement enables you to drop a sequence in a given scope. + +// Cross-references +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +include::./sequenceops.adoc[tags=overview] + +== Prerequisites + +.RBAC Privileges +To execute the DROP SEQUENCE statement, you must have the _Query Manage Sequences_ privilege granted on the scope. +For more details about user roles, see {authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=drop-sequence] +---- + +image::n1ql-language-reference/drop-sequence.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links in EBNF. + +[horizontal] +sequence:: (Required) A name that identifies the sequence within a namespace, bucket, and scope. +See <> below. + +[[sequence]] +=== Sequence Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=sequence] +---- + +image::n1ql-language-reference/sequence.png["Syntax diagram: refer to source code listing", align=left] + +The sequence name specifies the name of the sequence to drop. + +Each sequence is associated with a given namespace, bucket, and scope. +You must specify the namespace, bucket, and scope to refer to the sequence correctly. + +[horizontal] +namespace:: +(Optional) The {logical-hierarchy}[namespace] of the bucket which contains the sequence you want to drop. + +bucket:: +(Optional) The bucket which contains the sequence you want to drop. + +scope:: +(Optional) The scope which contains the sequence you want to drop. + +identifier:: +(Required) The name of the sequence. +The sequence name is case-sensitive. + +Currently, only the `default` namespace is available. +If you omit the namespace, the default namespace in the current session is used. + +If the {query-context}[query context] is set, you can omit the bucket and scope from the statement. +In this case, the bucket and scope for the sequence are taken from the query context. + +The namespace, bucket, scope, and sequence name must follow the rules for {identifiers}[identifiers]. +If the namespace, bucket, scope, or sequence name contain any special characters such as hyphens (-), you must wrap that part of the expression in backticks ({backtick} {backtick}). + +=== IF EXISTS Clause + +The optional `IF EXISTS` clause enables the statement to complete successfully when the specified sequence doesn't exist. + +When the sequence does not exist within the specified context: + +* If this clause is not present, an error is generated. + +* If this clause is present, the statement does nothing and completes without error. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-drop-seq1]] +.Drop a sequence in a specified scope +==== +This statement drops a sequence in the specified scope. + +[source,sqlpp] +---- +DROP SEQUENCE `travel-sample`.inventory.seq1; +---- +==== + +[[ex-drop-seq2]] +.Drop a sequence in the current query context +==== +This statement drops a sequence in the current query context, if a sequence of that name exists. + +[source,sqlpp] +---- +DROP SEQUENCE seq2 IF EXISTS; +---- +==== + +== Related Links + +* To create a sequence, see xref:n1ql-language-reference/createsequence.adoc[]. +* To alter a sequence, see xref:n1ql-language-reference/altersequence.adoc[]. +* To use a sequence in an expression, see xref:n1ql-language-reference/sequenceops.adoc[]. +* To monitor sequences, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-sequences[Monitor Sequences]. diff --git a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc new file mode 100644 index 000000000..eef2abdd2 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc @@ -0,0 +1,101 @@ += EXECUTE FUNCTION +:description: The EXECUTE FUNCTION statement enables you to execute a user-defined function. +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `EXECUTE FUNCTION` statement enables you to execute a user-defined function. + +== Purpose + +The `EXECUTE FUNCTION` statement enables you to execute a user-defined function. +It is useful for testing user-defined functions outside the context of a query. +It also enables you to execute functions which have side effects, such as performing mutations, which is not possible when calling a user-defined function in an expression. + +You cannot use the `EXECUTE FUNCTION` statement to execute a built-in {sqlpp} function. +If you do this, error `10101: Function not found` is generated. + +== Prerequisites + +[cols="2,3"] +|=== +| To execute ... | You must have ... + +| Global inline functions +| *Execute Global Functions* role. + +| Scoped inline functions +| *Execute Scope Functions* role, with permissions on the specified bucket and scope. + +| Global external functions +| *Execute Global External Functions* role. + +| Scoped external functions +| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. +|=== + +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=execute-function] +---- + +image::n1ql-language-reference/execute-function.png["Syntax diagram", align=left] + +[horizontal.compact] +function:: <> icon:caret-down[] +expr:: <> icon:caret-down[] + +[[name]] +=== Function Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=function] +---- + +image::n1ql-language-reference/function.png["Syntax diagram", align=left] + +The name of the function. +This is usually an unqualified identifier, such as `func1` or `{backtick}func-1{backtick}`. +In this case, the path to the function is determined by the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +To execute a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as `default:func1`. +Similarly, to execute a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. +Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more information. + +NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. +You must execute the user-defined function using the same case that was used when it was created. + +[[expression]] +=== Arguments + +[Optional] Comma-separated expressions specify arguments for the function. +If the function was created with named parameters, you must supply all the arguments that were specified when the function was created. +If the function was created without named parameters, you cannot supply an argument. +If the function is variadic, you can supply as many arguments as needed, or none. + +include::partial$n1ql-language-reference/udf-output.adoc[] + +== Examples + +For examples, refer to xref:n1ql-language-reference/createfunction.adoc#examples[CREATE FUNCTION]. + +== Related Links + +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +ifdef::flag-devex-rest-api[] +* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. +endif::flag-devex-rest-api[] +* To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. +* To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. +* To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/execute.adoc b/modules/n1ql/pages/n1ql-language-reference/execute.adoc new file mode 100644 index 000000000..476c6b422 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/execute.adoc @@ -0,0 +1,278 @@ += EXECUTE +:description: The EXECUTE statement executes a prepared statement. +:page-topic-type: reference +:imagesdir: ../../assets/images + +[abstract] +{description} + +== Prerequisites + +[[query-context]] +=== Query Context + +A prepared statement is created and stored relative to the current _query context_. +You can create multiple prepared statements with the same name, each stored relative to a different query context. +This enables you to run multiple instances of the same application against different datasets. + +To execute a prepared statement, the query context must be the same as it was when the prepared statement was created; otherwise the prepared statement will not be found. + +You must therefore set the required query context, or unset the query context if necessary, before executing the prepared statement. +If you do not set the query context, it defaults to the empty string. + +For further information, refer to xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +[[syntax]] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=execute] +---- + +image::n1ql-language-reference/execute.png["Syntax diagram: refer to source code listing", align=left] + +name:: +The name of the prepared statement. +This has the format `[host:port]local-name-or-UUID`, and may consist of: ++ +* Optionally, the host and port of the node where the prepared statement was created, in square brackets, followed by +* The local name that you specified for the prepared statement, or a UUID that was assigned automatically. + ++ +If present, the host and port are used for <>. + +TIP: If the name of the prepared statement contains hyphens, wrap the entire name in backticks (`{backtick}`) or double quotation marks (`"`). + +=== USING Clause + +[Optional] The USING clause enables you to specify parameter values to use in the prepared statement. + +parameters:: +The parameter values to use in the prepared statement. +This may be: ++ +* An array of values, for positional parameters, or +* An object containing name / value properties, for named parameters. + +For more details, refer to <> below. + +[[statement-retrieval]] +== Statement Retrieval + +The query engine first looks for the prepared statement on the currently connected node, using the local name or UUID. +If the prepared statement is not found on the currently connected node, the query engine attempts to retrieve it from the node specified in the prepared statement name. +Once retrieved, the query engine creates a local cached copy of the prepared statement, and executes it. + +An error is returned if the name does not identify a prepared statement. + +[[auto-reprepare]] +== Auto-Reprepare + +Before execution, the query engine checks whether the statement plan is still valid -- i.e. that all the indexes and keyspaces to which the plan refers are unchanged. +If any indexes or keyspaces have changed, the statement is automatically prepared again, so that the plan matches the new set of resources. + +If this automatic reprepare succeeds, the statement simply executes as expected. +However, if any required resources are found to be missing, execution of the affected prepared statement fails until those resources are created again. +Once the resources are available again, execution proceeds without any further intervention. + +[[parameters]] +== Parameters + +A prepared statement may contain parameters. +These are replaced by a supplied value when the statement is executed. +Parameters may be _named parameters_ or _positional parameters_. + +Named parameters are specified by name when the prepared statement is executed. +In {sqlpp}, named parameters are specified using an object containing name / value properties. + +==== +[source.no-callouts,sqlpp] +---- +include::example$utility/execute-names.n1ql[] +---- +==== + +Positional parameters are specified by the position of each supplied parameter when the statement is executed. +In {sqlpp}, positional parameters are specified using an array of values. + +==== +[source.no-callouts,sqlpp] +---- +include::example$utility/execute-numbers.n1ql[] +---- +==== + +[IMPORTANT] +==== +Alternatively, you can specify named parameters and positional parameters using the {sqlpp} REST API (`/query/service` endpoint), the `cbq` command line tool, or a software development kit (SDK). +Named parameters can be specified as request-level parameters, and positional parameters can be specified using the `args` parameter. +See xref:n1ql:n1ql-manage/query-settings.adoc[] for more information. + +When you specify parameters with the USING clause, you cannot also specify parameters at the same time using the {sqlpp} REST API, the `cbq` command line tool, or an SDK. +When you do this, the query service returns error `5003`: "cannot have both USING clause and request parameters". +==== + +[[examples]] +== Examples + +.Executing a prepared statement in {sqlpp} +==== +The following example shows how to execute a prepared statement in {sqlpp}. + +.Request +[source,sqlpp] +---- +EXECUTE `[127.0.0.1:8091]24734829-c793-4b90-b8bd-74ff788be493`; +---- +==== + +.Executing a prepared statement without a name using the REST API +==== +The following example shows how to prepare the statement without specifying a name. + +.Request +[source,sh] +---- +curl -v http://localhost:8093/query/service \ + -d 'statement=PREPARE SELECT text FROM tweets + WHERE rating > $r AND created_at > $date' +---- + +.Response +[source,json] +---- +{ + "requestID": "a339a496-7ed5-4625-9c64-0d7bf584a1bd", + "signature": "json", + "results": [ + { "encoded_plan": "H4sIAAAJbogA/5yRQU/6QBDFvwpZ/gdIIAAA==", + "name": "a1355198-2576-4e3d-af04-5acc77d8a681", + "operator": { + "#operator": "Sequence", + "~children": [ + // Content redacted + ] + }, + "signature": { + "text": "json" + }, + "text": "PREPARE SELECT text FROM tweets WHERE rating > $r AND created_at > $date" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "1.970679ms", + "executionTime": "1.889351ms", + "resultCount": 1, + "resultSize": 2261 + } +} +---- + +The following example uses the server-generated name of the prepared statement to execute the statement. + +.Request: +[source,sh] +---- +curl -v http://localhost:8093/query/service \ + -d 'prepared="a1355198-2576-4e3d-af04-5acc77d8a681"&$r=9.5&$date="1-1-2014"' +---- + +.Response: +[source,json] +---- +{ + "requestID": "1bd9956b-bc8e-478a-bd84-3955fe2db047", + "signature": { + "text": "json" + }, + "results": [ + { + "text": "Couchbase is my favorite database" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "1.527795ms", + "executionTime": "1.443748ms", + "resultCount": 0, + "resultSize": 0 + } +} +---- +==== + +.Executing a prepared statement with a name using the REST API +==== +The following example specifies a [.param]`name` for the prepared statement. + +.Request: +[source,sh] +---- +curl -v http://localhost:8093/query/service \ + -d 'statement=PREPARE fave_tweets FROM SELECT text FROM tweets WHERE rating >= $r' +---- + +.Response: +[source,json] +---- +{ + "requestID": "a339a496-7ed5-4625-9c64-0d7bf584a1bd", + "signature": "json", + "results": [ + { + "encoded_plan": "H4sIAAAJbogA/5yRQU/6QBDFvwpZ/gdIIAAA==", + "name": "fave_tweets", + "operator": { + // ... + } + } + ] +} +---- + +The following example uses the [.param]`name` specified in the example above to run the prepared statement. + +.Request: +[source,sh] +---- +curl -v http://localhost:8093/query/service -d 'prepared="fave_tweets"&$r=9.5' +---- + +.Response +[source,json] +---- +{ + "requestID": "1bd9956b-bc8e-478a-bd84-3955fe2db047", + "signature": { + "text": "json" + }, + "results": [ + { + "text": "Couchbase is my favorite database" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "1.527795ms", + "executionTime": "1.443748ms", + "resultCount": 0, + "resultSize": 0 + } + } +---- +==== + +[[related]] +== Related + +* For information on preparing a statement for execution, refer to xref:n1ql-language-reference/prepare.adoc[PREPARE]. + +* For information on using prepared statements with the `cbq` command line shell, refer to xref:n1ql:n1ql-intro/cbq.adoc[]. + +ifdef::flag-devex-rest-api[] +* For information on using prepared statements with the Query REST API (`/query/service` endpoint), refer to xref:n1ql-rest-query:index.adoc[]. +endif::flag-devex-rest-api[] + +* For information on using prepared statements with an SDK, refer to xref:java-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Prepared Statements for Query Optimization] and xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc#parameterized-queries[Parameterized Queries]. diff --git a/modules/n1ql/pages/n1ql-language-reference/explain.adoc b/modules/n1ql/pages/n1ql-language-reference/explain.adoc new file mode 100644 index 000000000..b564c23f4 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/explain.adoc @@ -0,0 +1,133 @@ += EXPLAIN +:description: The EXPLAIN statement when used before any {sqlpp} statement, provides information about the execution plan for the statement. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// TEMP +include::partial$n1ql-language-reference/collapsible-style.adoc[] + +[abstract] +{description} + +== Prerequisites + +To execute the EXPLAIN statement, you must have the privileges required for the {sqlpp} statement that is being explained. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +.RBAC Examples +[%collapsible] +==== +====== +include::ROOT:partial$query-context.adoc[tag=example] + +To execute the following statement, you must have the _Query Insert_ privilege on the `landmark` keyspace and the _Query Select_ privilege on the `pass:c[`beer-sample`]` keyspace. + +[source,sqlpp] +---- +EXPLAIN INSERT INTO landmark (KEY foo, VALUE bar) + SELECT META(doc).id AS foo, doc AS bar + FROM `beer-sample` AS doc WHERE type = "brewery"; +---- + +To execute the following statement, you must have the _Query Insert_, _Query Update_, and _Query Select_ privileges on the `testbucket` keyspace. + +[source,sqlpp] +---- +EXPLAIN UPSERT INTO testbucket VALUES ("key1", { "a" : "b" }) RETURNING meta().cas; +---- +====== +==== + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=explain] +---- + +image::n1ql-language-reference/explain.png["Syntax diagram: refer to source code listing", align=left] + +The statement consists of the `EXPLAIN` keyword, followed by the query whose execution plan you want to see. + +== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +[source,sqlpp] +---- +EXPLAIN SELECT title, activity, hours +FROM landmark +ORDER BY title; +---- + +.Results +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_landmark_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "(`landmark`.`title`)" + }, + { + "expr": "(`landmark`.`activity`)" + }, + { + "expr": "(`landmark`.`hours`)" + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Order", + "sort_terms": [ + { + "expr": "(`landmark`.`title`)" + } + ] + } + ] + }, + "text": "SELECT title, activity, hours FROM landmark ORDER BY title;" + } +] +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc new file mode 100644 index 000000000..8ce6cdbe8 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc @@ -0,0 +1,146 @@ += EXPLAIN FUNCTION +:description: For a specified user-defined function, you use EXPLAIN FUNCTION to expose the execution plan for the {sqlpp} subqueries or embedded statements that it contains. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +You can request the execution plan for an inline or external user-defined function. + +* For an inline function, EXPLAIN FUNCTION returns the query plans for all of the subqueries present in the function body. ++ +For more information about inline functions, see xref:n1ql-language-reference/userfun.adoc[]. + +* For an external function, EXPLAIN FUNCTION returns the query plans for all embedded {sqlpp} queries inside the referenced JavaScript body, or the line number on which a N1QL() call appears. +Line numbers are calculated from the beginning of the JavaScript function definition. ++ +For more information about user-defined functions with JavaScript, see xref:guides:javascript-udfs.adoc[]. + +The following constraints apply: + +* If a user-defined function itself contains other, nested user-defined function executions, EXPLAIN FUNCTION generates the query plan for the specified function only, and not for its nested {sqlpp} queries. + +* If an external function defines an alias for a N1QL() call, EXPLAIN FUNCTION cannot return its line number. + +== Prerequisites + +[cols="2,3"] +|=== +| To execute EXPLAIN FUNCTION on ... | You must have ... + +| Global inline functions +| *Execute Global Functions* role. + +| Scoped inline functions +| *Execute Scope Functions* role, with permissions on the specified bucket and scope. + +| Global external functions +| *Execute Global External Functions* role. + +| Scoped external functions +| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. +|=== + +You must also have the necessary privileges required for the {sqlpp} statements inside the function. + +For more information about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=explain-function] +---- + +image::n1ql-language-reference/explain-function.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal.compact] +function:: <> icon:caret-down[] + +[[name]] +=== Function Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=function] +---- + +image::n1ql-language-reference/function.png["Syntax diagram", align=left] + +The name of the function. +This is usually an unqualified identifier, such as `func1` or `{backtick}func-1{backtick}`. +In this case, the path to the function is determined by the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +To get the plan for a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as `default:func1`. +Similarly, to get the plan for a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. +Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more information. + +NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. +You must get the plan for the user-defined function using the same case that was used when it was created. + +== Examples + +.Inline Function Example +==== +In this example, you create an inline function named `func1` and then request the plan for its subquery. + +[source,sqlpp] +---- +include::n1ql:example$utility/explainfunction.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$utility/explainfunction.jsonc[] +---- +==== + +.External Function Example +==== +This example assumes that you have defined a JavaScript library named `lib1`. + +You then add a JavaScript function named `function1` to that library as follows: + +[source,javascript] +---- +include::n1ql:example$utility/explainfunctionjs.js[] +---- + +<.> An embedded {sqlpp} statement. +<.> A N1QL() call that executes a {sqlpp} statement. + +You then create the corresponding {sqlpp} user-defined function for that JavaScript function, named `jsfunction1`, and request the plan information for the statements within the function definition: + +[source,SQL++] +---- +include::n1ql:example$utility/explainfunctionjs.n1ql[] +---- + +.Results +[source,json] +---- +include::n1ql:example$utility/explainfunctionjs.jsonc[] +---- + +<.> The line number in the JavaScript function that includes a N1QL() call. +<.> The query plan for the embedded {sqlpp} statement. +==== + +== Related Links + +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +ifdef::flag-devex-rest-api[] +* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. +endif::flag-devex-rest-api[] +* To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. +* To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. +* To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/flex-indexes.adoc b/modules/n1ql/pages/n1ql-language-reference/flex-indexes.adoc new file mode 100644 index 000000000..0121a2f9f --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/flex-indexes.adoc @@ -0,0 +1,793 @@ += Use Search Indexes with a Query +:description: The Flex Index feature enables you run a {sqlpp} query as a full-text search query, using a full-text index. +:page-topic-type: concept +:imagesdir: ../../assets/images +:keywords: flex +:no-escape-hatch: + +// Cross-references +:searchfun: xref:n1ql-language-reference/searchfun.adoc +:build-index: xref:n1ql-language-reference/build-index.adoc +:collation: xref:n1ql-language-reference/datatypes.adoc#collation +:index-type: xref:n1ql-language-reference/hints.adoc#index-type +:isstring: xref:n1ql-language-reference/typefun.adoc#isstring +:isnumber: xref:n1ql-language-reference/typefun.adoc#isnumber +:covering-indexes: xref:n1ql:n1ql-language-reference/covering-indexes.adoc +:query-settings: xref:n1ql:n1ql-manage/query-settings.adoc +:fts-creating-indexes: xref:clusters:search-service/create-full-text-indexes.adoc +:inserting-a-child-field: clusters:search-service/create-full-text-indexes.adoc#inserting-a-child-field +:pre-constructed-analyzers: xref:server:fts:fts-using-analyzers.adoc#pre-constructed-analyzers +:simple-queries: xref:server:fts:fts-query-types.adoc#simple-queries +:index_pushdowns: xref:learn:services-and-indexes/indexes/index_pushdowns.adoc + +[abstract] +{description} +This means that you can write queries in {sqlpp} to leverage the Search service's keyword search capabilities. + +include::ROOT:partial$component-signpost.adoc[] + +In Couchbase Capella, a global secondary index (GSI) uses a B-tree structure for fast exact search, whereas full-text search (FTS) uses an inverted index to provide efficient term search. +It is possible to perform a full-text search within a {sqlpp} query using {searchfun}[search functions]. +However this requires you to write the full-text search using the FTS syntax. + +The _Flex Index_ feature provides the ability for a {sqlpp} query to leverage either a global secondary index or full-text index transparently with standard {sqlpp} syntax, simplifying the application development process. + +The full-text index must be defined in a certain way to be usable by a {sqlpp} query; similarly, the {sqlpp} query must have certain characteristics to be able to use the full-text index. +If these requirements are met, the query is transformed into an FTS query, and run against the full-text index. + +Using a Flex Index query may offer advantages in the following situations: + +* When the search conditions are not predetermined. +* When the search predicate involves a large number of fields combined using AND or OR. +* When the search predicate involves multiple arrays. +* When an application requires a full-text search combined with {sqlpp} aggregation or joins. + +For a general introduction to creating full-text indexes, refer to {fts-creating-indexes}[Creating Indexes]. + +[[overview]] +== Overview + +To understand how a {sqlpp} query can make use of a full-text index, it's important to understand the differences between the semantics of {sqlpp} queries and full-text indexes, and the restrictions that arise from these differences. + +[[semantic-differences]] +=== Semantic Differences + +Full-text indexes have different semantics from {sqlpp} queries. +Some of the main differences are described here. + +* {sqlpp} uses escaped path names, whereas full-text indexes flatten the field names. + +* {sqlpp} uses array subscripts to identify array objects, for example `f1.arr1[0].b`; whereas full-text indexes ignore subscripts, for example `f1.arr1.b`. +This means full-text indexes cannot uniquely identify the path. + +* In {sqlpp}, data can be compared across data types. +This is not possible with a full-text index. + +* {sqlpp} handles MISSING fields, whereas these are not handled by a full-text index. + +[[restrictions]] +=== Restrictions + +Because of the semantic differences described above, there are several restrictions to the way a Flex Index query can use a full-text index. + +* A Flex Index query cannot use a full-text index as a {covering-indexes}[covering index]. +* A Flex Index query cannot use a full-text index with a query on fields whose names contain special characters. +* A Flex Index query may include LIMIT and OFFSET clauses, but they cannot be {index_pushdowns}[pushed down to the full-text index]. +* A Flex Index query may include Aggregate functions and Window functions, but they cannot be {index_pushdowns}[pushed down to the full-text index]. + +Flex Index queries only make use of full-text indexes to find the access path to the required data. +The query engine then fetches the data from the data service. + +Flex Index queries may use full-text indexes to do an intersect scan with other indexes. +For further details, refer to <> below. + +[[index-availability]] +=== Index Availability + +Full-text indexes are online and searchable as soon as they are created. +GSI indexes are online and searchable after they have been built. +For further details, refer to {build-index}[BUILD INDEX]. + +[[usage]] +== Usage + +Assuming that there is no search function in the query predicate, there are two ways to specify that you would like to use a full-text index with a {sqlpp} query: + +* Use the `USING FTS` hint in the {sqlpp} query. +For full details, refer to {index-type}[USE Clause]. + +* Set the `use_fts` request-level parameter to `true`. +For full details, refer to {query-settings}[]. + +When using an index hint, you may specify preferred indexes by name, or simply specify the preferred index type -- `FTS` or `GSI`. +It is possible to specify mixed index types. + +[[ex-usage-1]] +.Use FTS, no index specified +==== +[source,sqlpp] +---- +SELECT META(d).id +FROM default AS d +USE INDEX (USING FTS) +WHERE d.f1 = "xyz" AND d.f2 = 100; +---- +==== + +In this case: + +. The query engine considers all available full-text indexes. +. If any full-text index qualifies, the full-text index is used. +. If none of the full-text indexes qualify, the query engine considers other available GSI and primary indexes, following existing rules. + +[[ex-usage-2]] +.Use FTS or GSI, no index specified +==== +[source,sqlpp] +---- +SELECT META(d).id +FROM default AS d +USE INDEX (USING FTS, USING GSI) +WHERE d.f1 = "xyz" AND d.f2 = 100; +---- +==== + +In this case: + +. If any GSI index covers the query, the covering index is used and all other indexes are ignored. +. If the query is not covered, the query engine considers all available full-text indexes and GSI indexes. +. If any full-text indexes qualify, the query engine does an intersect scan of all the qualified full-text indexes and GSI indexes. +. If none of the full-text indexes qualify, the query engine considers other available GSI and primary indexes, following existing rules. + +[[ex-usage-3]] +.Prefer the specified FTS and GSI indexes +==== +[source,sqlpp] +---- +SELECT META(d).id +FROM default AS d +USE INDEX (fix1 USING FTS, gix1 USING GSI) +WHERE d.f1 = "xyz" AND d.f2 = 100; +---- +==== + +In this case: + +. If the specified GSI index covers the query, the covering index is used and all other indexes are ignored. +. If the query is not covered, the query engine considers the specified full-text indexes and all available GSI indexes. +. If the specified full-text index qualifies, the query engine does an intersect scan of the full-text index and all qualified GSI indexes. +. If the specified full-text index does not qualify, the query engine considers other available GSI and primary indexes, following existing rules. + +In all cases, if the query meets the requirements to use a full-text index, and a qualified full-text index is selected, the query is transformed into an FTS {simple-queries}[simple query] (_not_ a query string query), and the simple query is run against the qualified full-text index. + +[IMPORTANT] +If the query predicate contains a search function, none of this applies -- instead, an index is selected for the query according to the method described on the {searchfun}[Search Functions] page. + +[[fts-requirements]] +== Full-Text Index Requirements + +In order to use a full-text index with a {sqlpp} query, the full-text index must meet certain requirements. + +[[analyzer]] +=== Analyzer + +The full-text index _must_ use the {pre-constructed-analyzers}[keyword analyzer]. + +To specify that a full-text index should use the keyword analyzer: + +. In the *Add Index*, *Edit Index*, or *Clone Index* screen, click the *Advanced* heading to display the Advanced settings panel. +. Open the *Default Analyzer* pull-down menu and select `keyword`. ++ +image::flex-fts-keyword-analyzer.png["FTS Settings Advanced Panel with Default Analyzer set to keyword",498,552] + +[[type-mappings]] +=== Type Mappings + +The full-text index _must_ use one of the following type mappings: + +* The default type mapping +* A single custom type mapping +* Multiple custom type mappings + +The full-text index may _not_ use the default type mapping along with one or more custom type mappings. + +[[indexed-fields]] +=== Indexed Fields + +If the full-text index uses the default type mapping, only child mappings and fields mapped under the default type mapping can be used in a query. +In case of dynamic mapping or dynamic child mappings, any field within the mapping can be used within a query. + +If the full-text index has multiple custom type mappings, all the fields that you want to query must be indexed within all the requested type mappings. + +Child mappings and fields mapped under top level type mappings can all be used within a query, provided they are enabled. + +When {inserting-a-child-field}[creating a full-text definition in the Couchbase Capella UI], the child fields listed by field name or by *searchable as* may be used within a {sqlpp} query. + +NOTE: The type field in a custom type mapped index is _not_ searchable. + +[[ex-indexed-fields]] +.Child fields that may be used in a query +==== +A full-text index definition contains the following child fields: + +[source,json] +---- +{ + "reviews": { + "enabled": true, + "dynamic": false, + "properties": { + "review": { + "enabled": true, + "dynamic": false, + "properties": { + "author": { + "enabled": true, + "dynamic": false, + "fields": [{ + "name": "author", // <.> + "type": "text", + "index": true, + "analyzer": "keyword" + }] + } + } + } + } + }, + "id": { + "enabled": true, + "dynamic": false, + "fields": [{ + "name": "id", // <.> + "type": "number", + "index": true + }] + } +} +---- + +A query may search the following fields with this full-text index: + +<.> The `reviews.review.author` field +<.> The `id` field +==== + +[[query-requirements]] +== Query Requirements + +In order to use a full-text index with a {sqlpp} query, the query must also meet certain requirements. + +[[conditional-expression]] +=== Conditional Expression for Custom Type Mappings + +If the full-text index has a single custom type mapping, the query predicate _must_ contain an expression matching the type, independent of the rest of the predicate. + +[[ex-conditional-1]] +.Conditional expression for a custom type mapping with a simple predicate +==== +A full-text index definition contains the following custom type mapping: + +[source,json] +---- +"doc_config.mode": "type_field", +"doc_config.type_field": "type" +---- + +The following query can be used with this full-text index: + +[source,sqlpp] +---- +SELECT meta().id +FROM `keyspace` USE INDEX (USING FTS) +WHERE type = "hotel" -- <.> +AND country = "US"; +---- +<.> Conditional expression matching the type mapping +==== + +If you have several expressions within the WHERE clause, the query engine needs to be able to resolve the conditional expression without any ambiguity, to avoid the possibility of false negatives. + +[[ex-conditional-2]] +.Conditional expression for a custom type mapping with a complex predicate +==== +The following query is ambiguous, and cannot be used with the full-text index defined in <>: + +[source,sqlpp] +---- +SELECT meta().id +FROM `keyspace` USE INDEX (USING FTS) +WHERE type = "hotel" AND country = "US" OR country = "CAN"; +---- + +With brackets setting the priority of the AND and OR operators, the following queries are unambiguous, and can be used with the full-text index defined in <>: + +[source,sqlpp] +---- +SELECT meta().id +FROM `keyspace` USE INDEX (USING FTS) +WHERE type = "hotel" AND (country = "US" OR country = "CAN"); +---- + +[source,sqlpp] +---- +SELECT meta().id +FROM default USE INDEX (USING FTS) +WHERE type = "hotel" +AND ( + country = "US" OR country = "CAN" + AND id >= 0 AND id <= 10 + OR id >= 20 AND id <= 30 +); +---- + +[source,sqlpp] +---- +SELECT meta().id +FROM default USE INDEX (USING FTS) +WHERE type = "hotel" +AND (country = "US" OR country = "CAN") +AND (id >= 0 AND id <= 10 OR id >= 20 AND id <= 30); +---- +==== + +Similarly, if the full-text index contains multiple custom type mappings, the query engine needs to be able to resolve the conditional expression without any ambiguity, to avoid the possibility of false negatives. + +[[ex-conditional-3]] +.Conditional expression for multiple custom type mappings +==== +The following predicates can be used with a full-text index with multiple custom type mappings: + +[source,sqlpp] +---- +WHERE type = "xyz" +WHERE (type = "xyz" OR type = "abc") +---- + +The following predicate cannot be used with a full-text index with multiple custom type mappings: + +[source,sqlpp] +---- +WHERE type = "xyz" OR type = "abc" +---- +==== + +[[n1ql-predicates]] +=== {sqlpp} Predicates + +{sqlpp} predicates can be used with a Flex Index query, as long as they meet certain requirements, as detailed below. + +[[equality]] +==== Equality Expressions + +You can use an equality expression with a full-text index, as long as the field is either explicitly indexed, or if the indexing is dynamic within the keyword analyzer. + +[[ex-equality-1]] +.Equality expressions with a dynamic keyword index +==== +The following predicates can be used with a dynamic keyword index: + +[source,sqlpp] +---- +WHERE a = "12" +WHERE b = true +WHERE c = 13 +---- +==== + +[[ex-equality-2]] +.Equality expressions with explicitly indexed fields +==== +A full-text index has the following explicitly indexed fields: `a` (text), `b` (boolean), `c` (numeric). + +The following predicates can be used with this full-text index: + +[source,sqlpp] +---- +WHERE a = "12" +WHERE b = true +---- + +The following predicates cannot be used with this full-text index: + +[source,sqlpp] +---- +WHERE c = "13" -- <.> +WHERE d = "N/A" -- <.> +---- + +<.> `c` is indexed as numeric +<.> `d` is not indexed +==== + +The left-hand side of an equality expression must be a field name or a fully-qualified path. +It may not be an expression. +Conversely, the right-hand side of an equality expression may not depend on the keyspace. + +[[ex-equality-3]] +.Equality expression with field name +==== +The following predicate can be used with a full-text index: + +[source,sqlpp] +---- +WHERE state = LOWER("CALIFORNIA") +---- + +The following predicate cannot be used with a full-text index: + +[source,sqlpp] +---- +WHERE LOWER(state) = "california" -- <.> +---- +<.> Left-hand side is an expression +==== + +[[and]] +==== AND Expressions + +You can use an `AND` expression with a full-text index. +Partial sargability is supported: this means that one or both of the requested child expressions must be indexed for the query to use a full-text index. +If there's a possibility of false positives, the query engine filters the results using KV fetches. + +[[ex-and]] +.AND expressions +==== +In a full-text index, the fields `a` and `b` are indexed. + +The following expressions can be used with this full-text index: + +[source,sqlpp] +---- +WHERE a = "12" AND b = "34" -- <.> +WHERE a = "12" AND d = "56" -- <.> +---- + +<.> Searches for `a` and `b` using the full-text index +<.> Searches for `a` using the full-text index, and uses KV fetch to filter results for `d` + +The following expressions cannot be used with this full-text index: + +[source,sqlpp] +---- +WHERE d = "56" AND e = "78" -- <.> +---- + +[start=3] +<.> Neither `d` nor `e` are indexed +==== + +[[or]] +==== OR Expressions + +You can use an `OR` expression with a full-text index. +Partial sargability is not supported: all the requested child expressions must be indexed. +This is to avoid false negatives. + +[[ex-or]] +.OR expressions +==== +In a full-text index, the fields `a` and `b` are indexed. + +The following expressions can be used with this full-text index: + +[source,sqlpp] +---- +WHERE a = "12" OR b = "34" -- <.> +WHERE a = "12" OR a = "98" -- <.> +---- + +<.> Searches for `a` and `b` using the full-text index +<.> Searches for `a` using the full-text index + +The following expressions cannot be used with this full-text index: + +[source,sqlpp] +---- +WHERE a = "12" OR d = "56" -- <.> +---- + +<.> `d` is not indexed (false negatives) +==== + +[[compound-expressions]] +==== Compound Expressions + +You can use compound expressions with a full-text index, as long as they respect the rules of <> and <> expressions described above, and do not return false negatives. + +[[ex-compound]] +.Compound expressions +==== +A full-text index definition has a type mapping `X` with 2 child fields -- `name` (text), `age` (numeric). + +The following predicate can be used with this full-text index: + +[source,sqlpp] +---- +WHERE type = "X" AND name = "abc" AND age = 10 -- <.> +---- +<.> No chance of false negatives, all fields are sargable + +The following predicates cannot be used with this full-text index: + +[source,sqlpp] +---- +WHERE type = "X" OR name = "abc" AND age = 10 -- <.> +WHERE type = "X" AND name = "abc" OR age = 10 -- <.> +---- +<.> This is treated as an OR expression: `(type = "X") OR (name = "abc" AND age = 10)` +<.> This is treated as an OR expression: `(type = "X" AND name = "abc") OR (age = 10)` + +AND takes precedence over OR, so these predicates are treated as OR expressions. +Both child expressions of an OR expression must be indexed. +Therefore these predicates cannot be used with a full-text index. + +However, the following predicate can be used with this full-text index: + +[source,sqlpp] +---- +WHERE type = "X" AND (name = "abc" OR age = 10) -- <.> +---- +<.> Brackets alter the order of precedence so there is no chance of false negatives +==== + +[[ranges]] +==== Range Expressions + +You can use range expressions with a full-text index, as long as the range expressions meet the following criteria: + +. Ranges must be deterministic: that is, they should have a clear start and finish. +. Range boundaries must be of the same data type. +. The maximum range boundary expression must always come after the minimum range boundary expression. +. If there are several range expressions, or there is a mixture of range expressions and other expressions, the range expressions need to be contiguous. + +[[ex-ranges]] +.Range expressions +==== +The following range expressions can be used with a full-text index: + +[source,sqlpp] +---- +WHERE a >= 10 AND a <= 20 +WHERE b >= "hot" AND b <= "hotel" +WHERE c >= "2020-03-01" AND c <= "2020-04-01" -- <.> + +WHERE type = "xyz" AND a >= 10 AND a <= 20 +WHERE a >= 10 AND a <= 20 AND type = "xyz" +WHERE type = "xyz" AND (a >= 10 AND a <= 20) -- <.> +---- + +<.> Ranges are deterministic, range boundaries are of similar type, and maximum range boundary comes after minimum range boundary +<.> Range expressions are contiguous + +The following range expressions cannot be used with a full-text index: + +[source,sqlpp] +---- +WHERE a >= 10 +WHERE b < "hotel" +WHERE c > "2020-03-01" +WHERE a >= 10 OR a <= 20 -- <.> + +WHERE a <= 20 AND a >= 10 +WHERE a >= 20 AND a <= 10 -- <.> + +WHERE a >= 10 AND a <= "hot" -- <.> + +WHERE a >= 10 AND type = "xyz" AND a <= 20 -- <.> +---- + +<.> Ranges are open-ended (non-deterministic) +<.> Maximum range boundary comes before minimum range boundary +<.> Range boundaries are of different data types +<.> Range expression is not contiguous +==== + +[[isstring-and-issnumber]] +==== ISSTRING() and ISNUMBER() + +You can use the {isstring}[ISSTRING()] and {isnumber}[ISNUMBER()] functions as a workaround to support open-ended ranges with a full-text index. + +* The query engine translates `ISSTRING(x)` to a range establishing the data type of the object as a string, i.e. greater than or equal to an empty string, and less than an empty array: `+++"" <= x AND x < []+++`. + +* The query engine translates `ISNUMBER(y)` to a range establishing the data type of the object as numeric, i.e. greater than the boolean value `true`, and less than an empty string: `+++true < y AND y < ""+++`. + +Refer to {collation}[Collation] for more information. + +[[ex-isstring-and-issnumber]] +.Workarounds for open-ended ranges +==== +The following open-ended ranges can be used with a full-text index: + +[source,sqlpp] +---- +WHERE ISSTRING(name) AND name >= "abhi" -- <.> +WHERE ISNUMBER(age) AND age > 30 -- <.> +---- + +<.> An open-ended range specifying any string later than "abhi". +<.> An open-ended range specifying any number greater than 30. +==== + +[[like]] +==== LIKE Expressions + +You can use a `LIKE` expression with a full-text index, as long as the `LIKE` expression contains a simple string, or a string followed by the `%` wildcard. + +If the `LIKE` expression contains a simple string, it must respect the rules outlined in the <> section above. +A string followed by the `%` wildcard, such as `a LIKE bc%`, will be treated as a range expression. +Other `LIKE` expressions cannot be used with a full-text index. + +[[ex-like]] +.LIKE expressions +==== +The following predicates may be used with a full-text index: + +[source,sqlpp] +---- +WHERE a LIKE "hotel" -- <.> +WHERE a LIKE "hote%" -- <.> +---- +<.> The query engine treats this expression as the equality expression `a = "hotel"` +<.> The query engine treats this expression as the range `+++a >= "hote" AND a <= "hotf"+++` +==== + +[[between]] +==== BETWEEN Expressions + +You can use a `BETWEEN` expression with a full-text index. +The range specified by the `BETWEEN` expression must respect the rules outlined in the <> section above. +`BETWEEN` expressions that mix data type boundaries cannot be used with a full-text index. + +[[ex-between]] +.BETWEEN expressions +==== +The following predicate may be used with a full-text index: + +[source,sqlpp] +---- +WHERE a BETWEEN 10 AND 20 -- <.> +---- +<.> The query engine treats this expression as the range `+++a >= 10 AND a <= 20+++` +==== + +[[any-in-satisfies]] +==== ANY ... IN ... SATISFIES Expressions + +:any-in-satisfies: pass:q[`ANY` ... `IN` ... `SATISFIES`] + +You can use an {any-in-satisfies} expression with a full-text index. +The {any-in-satisfies} expression must operate over an array, which may be an array of objects or any supported data types. + +[[ex-any-in-satisfies]] +.ANY ... IN ... SATISFIES expressions +==== +A full-text index definition contains the following type mapping over documents of type `"hotel"`. + +[source,json] +---- +{ + "hotel": { + "default_analyzer": "keyword", + "enabled": true, + "properties": { + "reviews": { + "enabled": true, + "properties": { + "ratings": { + "enabled": true, + "properties": { + "Cleanliness": { + "enabled": true, + "fields": [ + { + "index": true, + "name": "Cleanliness", + "type": "number" + } + ] + }, + "Overall": { + "enabled": true, + "fields": [ + { + "index": true, + "name": "Overall", + "type": "number" + } + ] + } + } + }, + "author": { + "enabled": true, + "fields": [ + { + "index": true, + "name": "author", + "type": "text" + } + ] + } + } + }, + "public_likes": { + "enabled": true, + "fields": [ + { + "index": true, + "name": "public_likes", + "type": "text" + } + ] + } + } + } +} +---- + +The following predicates may be used with this full-text index: + +// no source language because hl.js highlights this snippet incorrectly +---- +WHERE type = "hotel" AND ANY r in reviews SATISFIES r.author = "xyz" END + +WHERE type = "hotel" AND ANY r in reviews SATISFIES r.ratings.Cleanliness = 5 OR r.ratings.Overall = 4 END + +WHERE type = "hotel" AND ANY r in reviews SATISFIES r.ratings.Cleanliness = 5 OR r.ratings.Overall = 4 END AND ANY p in public_likes SATISFIES p LIKE "xyz" END +---- +==== + +[[every-in-satisfies]] +==== EVERY ... IN ... SATISFIES Expressions + +:every-in-satisfies: pass:q[`EVERY` ... `IN` ... `SATISFIES`] + +You can use an {every-in-satisfies} expression with a full-text index. +The {every-in-satisfies} expression must operate over an array, which may be an array of objects or any supported data types. + +[[ex-every-in-satisfies]] +.EVERY ... IN ... SATISFIES expressions +==== +The following predicate may be used with the full-text index defined in <>: + +// no source language because hl.js highlights this snippet incorrectly +---- +WHERE EVERY r IN reviews SATISFIES r.ratings.Cleanliness = 5 END +---- +==== + +[[any-and-every-in-satisfies]] +==== ANY AND EVERY ... IN ... SATISFIES Expressions + +:any-and-every-in-satisfies: pass:q[`ANY AND EVERY` ... `IN` ... `SATISFIES`] + +You can use an {any-and-every-in-satisfies} expression with a full-text index. +The {any-and-every-in-satisfies} expression must operate over an array, which may be an array of objects or any supported data types. + +[[ex-any-and-every-in-satisfies]] +.ANY AND EVERY ... IN ... SATISFIES expressions +==== +The following predicate may be used with the full-text index defined in <>: + +// no source language because hl.js highlights this snippet incorrectly +---- +WHERE ANY AND EVERY r IN reviews SATISFIES r.ratings.Cleanliness = 5 END +---- +==== + +[[not]] +==== NOT Expressions + +You cannot use a complex `NOT` expression with a full-text index. + +[[joins]] +=== JOINs + +JOINs may be used with a full-text index, as long as the JOIN predicate meets the requirements to be used with a full-text index. +Refer to <> above. + +[[pagination]] +=== ORDER, LIMIT, and OFFSET + +The LIMIT, OFFSET, and ORDER clauses can be used with a full-text index when the index uses the default type mapping or a single custom type mapping. diff --git a/modules/n1ql/pages/n1ql-language-reference/from.adoc b/modules/n1ql/pages/n1ql-language-reference/from.adoc new file mode 100644 index 000000000..ec85641e5 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/from.adoc @@ -0,0 +1,529 @@ += FROM Clause +:description: The FROM clause specifies the documents to be used as the input for a query. +:imagesdir: ../../assets/images +:page-topic-type: reference + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:selectclause: xref:n1ql-language-reference/selectclause.adoc +:join: xref:n1ql-language-reference/join.adoc +:nest: xref:n1ql-language-reference/nest.adoc +:unnest: xref:n1ql-language-reference/unnest.adoc +:comma: xref:n1ql-language-reference/comma.adoc +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:hints: xref:n1ql-language-reference/hints.adoc +:expressions: xref:n1ql-language-reference/index.adoc +:curl: xref:n1ql-language-reference/curl.adoc + +:subqueries: xref:n1ql-language-reference/subqueries.adoc +:variables-in-scope: {subqueries}#section_onz_3tj_mz + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `FROM` clause specifies the documents to be used as the input for a query. + +== Purpose + +The `FROM` clause is used within a {selectclause}[SELECT] query or {subqueries}[subquery]. +It specifies the documents to be used as the input for a query. + +== Prerequisites + +For you to select data from keyspace or expression, you must have the [.param]`query_select` privilege on that keyspace. +For more details about user roles, see +{authorization-overview}[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=from-clause] +---- + +// <> +image::n1ql-language-reference/from-clause.png["Syntax diagram", align=left] + +[#section_nkd_3nx_1db] +=== FROM Terms + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=from-terms] +---- + +image::n1ql-language-reference/from-terms.png["Syntax diagram", align=left] + +The first FROM term may be any of the following: + +* A <> +* A <> (such as derived tables) +* A <> (nested paths, `CURL()`, or other expressions) + +This may be followed by further FROM terms, each of which may be one of the following: + +* A {join}[JOIN] clause and conditions +* A {nest}[NEST] clause and conditions +* An {unnest}[UNNEST] clause and conditions + +You may additionally include one or more {comma}[comma-separated joins]. + +[IMPORTANT] +==== +`JOIN` clauses, `NEST` clauses, `UNNEST` clauses, and comma-separated joins each have a _left-hand side_ and a _right-hand side_. +The left-hand side is defined by the preceding FROM term; the right-hand side is defined by the FROM term itself. + +When you chain multiple FROM terms together, the right-hand side of one FROM term acts as the left-hand side of the following FROM term. +==== + +=== Limitations + +* When the FROM term is an expression, `USE KEYS` or `USE INDEX` clauses are not allowed. + +* When using a lookup `JOIN` clause, an index `JOIN` clause, a `NEST` clause, or an `UNNEST` clause, the left-hand side of the join may be a keyspace identifier, an expression, or a subquery; but the right-hand side may only be a keyspace identifier. + +* When using an ANSI `JOIN` clause, the right-hand side of the join may also be a keyspace identifier, an expression, or a subquery, similar to the left-hand side. + +* You can chain comma-separated joins with ANSI `JOIN` clauses, ANSI `NEST` clauses, and `UNNEST` clauses. +However, you cannot chain comma-separated joins with lookup `JOIN` and `NEST` clauses, or index `JOIN` and `NEST` clauses. + +* The right-hand side of a comma-separated join can only be a keyspace identifier, a subquery, or a generic expression. +This means that comma-separated joins must come _after_ any `JOIN`, `NEST`, or `UNNEST` clauses. + +[#sec_from-keyspace] +== FROM Keyspace + +The FROM keyspace specifies a keyspace to query from: either a specific keyspace or a constant expression. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=from-keyspace] +---- + +image::n1ql-language-reference/from-keyspace.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] +use-clause:: <> icon:caret-down[] + +[#from-keyspace-ref] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-path:: <> icon:caret-down[] +keyspace-partial:: <> icon:caret-down[] + +Keyspace reference of the data source. +The identifiers that make up the keyspace reference are not available as {variables-in-scope}[variables in scope of a subquery]. + +NOTE: If there is a hyphen (-) inside any part of the keyspace reference, you must wrap that part of the keyspace reference in backticks ({backtick}{nbsp}{backtick}). +Refer to the examples below. + +[[keyspace-path]] +==== Keyspace Path + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram", align=left] + +If the keyspace is a named collection, or the default collection in the default scope within a bucket, the keyspace reference may be a keyspace path. +In this case, the {query-context}[query context] should not be set. + +namespace:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[namespace] of the keyspace. +Currently, only the `default` namespace is available. +If the namespace name is omitted, the default namespace in the current session is used. + +bucket:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[bucket name] of the keyspace. + +scope:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[scope name] of the keyspace. +If omitted, the bucket's default scope is used. + +collection:: +(Optional) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. +If omitted, the default collection in the bucket's default scope is used. + +==== +For example, `default:{backtick}travel-sample{backtick}` indicates the default collection in the default scope in the `travel-sample` bucket in the `default` namespace. + +Similarly, `default:{backtick}travel-sample{backtick}.inventory.airline` indicates the `airline` collection in the `inventory` scope in the `travel-sample` bucket in the `default` namespace. +==== + +[[keyspace-partial]] +==== Keyspace Partial + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram", align=left] + +Alternatively, if the keyspace is a named collection, the keyspace reference may be just the collection name with no path. +In this case, you must set the {query-context}[query context] to indicate the required namespace, bucket, and scope. + +collection:: +(Required) An {identifiers}[identifier] that refers to the {logical-hierarchy}[collection name] of the keyspace. + +==== +For example, `airline` indicates the `airline` collection, assuming the query context is set. +==== + +[#from-keyspace-alias] +==== AS Alias + +Assigns another name to the FROM keyspace. +For details, see <>. + +Assigning an alias is optional for the FROM keyspace. +If you assign an alias to the FROM keyspace, the `AS` keyword may be omitted. + +[#from-keyspace-hints] +==== USE Clause + +Enables you to specify that the query should use particular keys, or a particular index. +For details, see {hints}[USE clause]. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +The simplest type of FROM keyspace clause specifies a single keyspace. + +[[ex-single-keyspace]] +.Use a single keyspace +==== +Select four unique landmarks from the `landmark` keyspace. + +[source,sqlpp] +---- +SELECT DISTINCT name +FROM landmark +LIMIT 4; +---- + +.Results +[source,JSON] +---- +[ + { + "name": "Royal Engineers Museum" + }, + { + "name": "Hollywood Bowl" + }, + { + "name": "Thai Won Mien" + }, + { + "name": "Spice Court" + } +] +---- +==== + +[#select-expr] +== FROM Subquery + +Specifies a {sqlpp} `SELECT` expression of input objects. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=from-subquery] +---- + +image::n1ql-language-reference/from-subquery.png["Syntax diagram", align=left] + +[horizontal.compact] +subquery-expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#select-expr-clause] +==== Subquery Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=subquery-expr] +---- + +// {selectclause}[select] +image::n1ql-language-reference/subquery-expr.png["Syntax diagram", align=left] + +Use parentheses to specify a subquery. + +For more details and examples, see {selectclause}[SELECT Clause] and {subqueries}[Subqueries]. + +[#select-expr-alias] +==== AS Alias + +Assigns another name to the subquery. +For details, see <>. + +Assigning an alias is required for subqueries in the FROM term. +However, when you assign an alias to the subquery, the `AS` keyword may be omitted. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-subquery-1]] +.A `SELECT` clause inside a `FROM` clause. +==== +List all `Gillingham` landmark names from a subset of all landmark eating places. + +[source,sqlpp] +---- +SELECT name, city +FROM (SELECT id, name, address, city + FROM landmark + WHERE activity = "eat") AS l +WHERE city = "Gillingham"; +---- + +.Results +[source,JSON] +---- +[ + { + "city": "Gillingham", + "name": "Hollywood Bowl" + }, + { + "city": "Gillingham", + "name": "Thai Won Mien" + }, + { + "city": "Gillingham", + "name": "Spice Court" + }, + { + "city": "Gillingham", + "name": "Beijing Inn" + }, + { + "city": "Gillingham", + "name": "Ossie's Fish and Chips" + } +] +---- +==== + +[[ex-subquery-2]] +.Subquery Example +==== +For each country, find the number of airports at different altitudes and their corresponding cities. + +In this case, the inner query finds the first level of grouping of different altitudes by country and corresponding number of cities. +Then the outer query builds on the inner query results to count the number of different altitude groups for each country and the total number of cities. + +[source,sqlpp] +---- +SELECT t1.country, num_alts, total_cities +FROM (SELECT country, geo.alt AS alt, + count(city) AS num_cities + FROM airport + GROUP BY country, geo.alt) t1 +GROUP BY t1.country +LETTING num_alts = count(t1.alt), total_cities = sum(t1.num_cities); +---- + +.Results +[source,JSON] +---- +[ + { + "country": "United States", + "num_alts": 946, + "total_cities": 1560 + }, + { + "country": "United Kingdom", + "num_alts": 128, + "total_cities": 187 + }, + { + "country": "France", + "num_alts": 196, + "total_cities": 221 + } +] +---- +==== + +This is equivalent to blending the results of the following two queries by country, but the subquery in the `from-term` above simplified it. + +==== +[source,sqlpp] +---- +SELECT country,count(city) AS num_cities +FROM airport +GROUP BY country; +---- + +[source,sqlpp] +---- +SELECT country, count(distinct geo.alt) AS num_alts +FROM airport +GROUP BY country; +---- +==== + +[#generic-expr] +== FROM Generic Expression + +Generic {expressions}[expressions] in the FROM term may include {sqlpp} functions, operators, path expressions, language constructs on constant expressions, variables, and subqueries. +This adds huge flexibility by enabling just about any FROM clause imaginable. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=from-generic] +---- + +image::n1ql-language-reference/from-generic.png["Syntax diagram", align=left] + +[horizontal.compact] +expr:: A {sqlpp} expression generating JSON documents or objects. +alias:: <> icon:caret-down[] + +[#generic-expr-alias] +==== AS Alias + +Assigns another name to the generic expression. +For details, see <>. + +Assigning an alias is optional for generic expressions in the FROM term. +However, when you assign an alias to the expression, the `AS` keyword is required. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-constant-expr]] +.Independent Constant Expression +==== +The expression may include JSON scalar values, static JSON literals, objects, or {sqlpp} functions. + +[source,sqlpp] +---- +SELECT * FROM [1, 2, "name", { "type" : "airport", "id" : "SFO"}] AS ks1; +---- + +[source,sqlpp] +---- +SELECT CURL("https://maps.googleapis.com/maps/api/geocode/json", + {"data":"address=Half+Moon+Bay" , "request":"GET"} ); +---- +==== + +Note that functions such as {curl}[CURL()] can independently produce input data objects for the query. +Similarly, other {sqlpp} functions can also be used in the expressions. + +[[ex-var-expr]] +.Variable {sqlpp} Expression +==== +The expression may refer to any {variables-in-scope}[variables in scope] for the query. + +[source,sqlpp] +---- +SELECT count(*) +FROM airport t +LET x = t.geo +WHERE (SELECT RAW y.alt FROM x y)[0] > 6000; +---- +==== + +The `FROM x` clause is an expression that refers to the outer query. +This is applicable to only subqueries because the outermost level query cannot use any variables in its own `FROM` clause. +This makes the subquery correlated with outer queries, as explained in the {subqueries}[Subqueries] section. + +[#section_ax5_2nx_1db] +== AS Clause + +To use a shorter or clearer name anywhere in the query, like SQL, {sqlpp} allows you to assign an alias to any FROM term in the `FROM` clause. + +=== Syntax + +The `AS` keyword is required when assigning an alias to a generic expression. + +The `AS` keyword is optional when assigning an alias to the FROM keyspace, a subquery, the JOIN clause, the NEST clause, or the UNNEST clause. + +=== Arguments + +alias:: +String to assign an alias. + +[NOTE] +==== +Since the original name may lead to referencing wrong data and wrong results, you must use the alias name throughout the query instead of the original keyspace name. + +In the FROM clause, the renaming appears only in the projection and not the fields themselves. + +When no alias is used, the keyspace or last field name of an expression is given as the implicit alias. + +When an alias conflicts with a keyspace or field name in the same scope, the identifier always refers to the alias. +This allows for consistent behavior in scenarios where an identifier only conflicts in some documents. +For more information on aliases, see {identifiers}[Identifiers]. +==== + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +The following `FROM` clauses are equivalent, with and without the `AS` keyword. + +[cols=2*] +|=== +a| +[source,sqlpp] +---- +FROM airport AS t +---- +a| +[source,sqlpp] +---- +FROM airport t +---- +a| +[source,sqlpp] +---- +FROM hotel AS h +INNER JOIN landmark AS l +ON (h.city = l.city) +---- +a| +[source,sqlpp] +---- +FROM hotel h +INNER JOIN landmark l +ON (h.city = l.city) +---- +|=== + +== Related Links + +* {hints}[USE Clause] +* {join}[JOIN Clause] +* {nest}[NEST Clause] +* {unnest}[UNNEST Clause] +* {comma}[Comma-Separated Join] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/functions.adoc b/modules/n1ql/pages/n1ql-language-reference/functions.adoc new file mode 100644 index 000000000..e5f8e9985 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/functions.adoc @@ -0,0 +1,32 @@ += Functions Overview +:description: Function names are used to apply a function to values, to values at a specified path, or to values derived from a DISTINCT clause. +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/column-style.adoc[] + +[abstract] +{description} +Function names are case insensitive. + +Here are the categories of {sqlpp} functions: + +[.two-columns] +* xref:n1ql-language-reference/aggregatefun.adoc[Aggregate Functions] +* xref:n1ql-language-reference/arrayfun.adoc[Array Functions] +* xref:n1ql-language-reference/bitwisefun.adoc[Bitwise Functions] +* xref:n1ql-language-reference/comparisonfun.adoc[Comparison Functions] +* xref:n1ql-language-reference/condfununknown.adoc[Conditional Functions for Unknowns] +* xref:n1ql-language-reference/condfunnum.adoc[Conditional Functions for Numbers] +* xref:n1ql-language-reference/datefun.adoc[Date Functions] +* xref:n1ql-language-reference/jsonfun.adoc[JSON Functions] +* xref:n1ql-language-reference/metafun.adoc[Miscellaneous Utility Functions] +* xref:n1ql-language-reference/numericfun.adoc[Number Functions] +* xref:n1ql-language-reference/objectfun.adoc[Object Functions] +* xref:n1ql-language-reference/patternmatchingfun.adoc[Pattern-Matching Functions] +* xref:n1ql-language-reference/searchfun.adoc[Search Functions] +* xref:n1ql-language-reference/stringfun.adoc[String Functions] +* xref:n1ql-language-reference/tokenfun.adoc[Token Functions] +* xref:n1ql-language-reference/typefun.adoc[Type Functions] +* xref:n1ql-language-reference/userfun.adoc[User-Defined Functions] +* xref:n1ql-language-reference/windowfun.adoc[Window Functions] diff --git a/modules/n1ql/pages/n1ql-language-reference/grant.adoc b/modules/n1ql/pages/n1ql-language-reference/grant.adoc new file mode 100644 index 000000000..3064c39f0 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/grant.adoc @@ -0,0 +1,123 @@ += GRANT +:description: The GRANT statement allows granting any RBAC roles to a specific user. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:clusters:manage-database-users.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:keyspace-ref: xref:n1ql-language-reference/createindex.adoc#keyspace-ref + +[abstract] +{description} + +Roles can be of the following two types: + +simple:: +Roles which apply generically to all keyspaces or resources in the cluster. ++ +For example: `ClusterAdmin` or `BucketAdmin` + +parameterized by a keyspace:: +Roles which are defined for the scope of the specified keyspace only. +The keyspace name is specified after ON. ++ +For example: `pass:c[DataReader ON `travel-sample`]` + +or `pass:c[Query_Select ON `travel-sample`]` + +NOTE: Only Full Administrators can run the GRANT statement. +For more details about user roles, see {authorization-overview}[]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dcl.ebnf[tag=grant] +---- + +image::n1ql-language-reference/grant.png["Syntax diagram: refer to source code listing", align=left] + +role:: +One of the {authorization-overview}[RBAC role names predefined] by Couchbase Capella. ++ +The following roles have short forms that can be used as well: + +* `query_select` → `select` +* `query_insert` → `insert` +* `query_update` → `update` +* `query_delete` → `delete` + +user:: +A user name created by the Couchbase Capella RBAC system. + +[[keyspace-ref,keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of a keyspace. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +== Usage + +GRANT statements support legacy systems and have two forms: + +.{counter:form}. Unparameterized Roles +[source,sqlpp] +---- +GRANT Replication Admin, Query External Access + TO cchaplan, jgleason; + +GRANT replication_admin, query_external_access + TO cchaplan, jgleason; +---- + +.{counter:form}. Parameterized Roles +[source,sqlpp] +---- +GRANT Query Select, Views Admin + ON orders, customers + TO bill, linda; + +GRANT query_select, views_admin + ON orders, customers + TO bill, linda; +---- + +NOTE: Mixing of parameterized and unparameterized roles or syntax is not allowed and will create an error. + +== Examples + +.Grant the role of Cluster Administrator to three people +==== +[source,sqlpp] +---- +GRANT ClusterAdmin TO david, michael, robin; +---- +==== + +.Grant the roles of Cluster Administrator and Data Reader in the travel-sample keyspace to Debby +==== +[source,sqlpp] +---- +GRANT ClusterAdmin, DataReader ON `travel-sample` TO debby; +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/groupby-aggregate-performance.adoc b/modules/n1ql/pages/n1ql-language-reference/groupby-aggregate-performance.adoc new file mode 100644 index 000000000..4810e543a --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/groupby-aggregate-performance.adoc @@ -0,0 +1,2631 @@ += Grouping and Aggregate Pushdowns +:description: {sqlpp} Pushdowns optimize the performance of {sqlpp} queries by supporting grouping and aggregate expressions. +:imagesdir: ../../assets/images + +[abstract] +{description} + +.Examples on this Page +**** +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +[#Overview] +== Overview + +Grouping and aggregate pushdown improves the performance of {sqlpp} queries with groupings and aggregations. + +After the optimizer selects an index for a query block, it attempts the two optimizations below: + +* Pagination optimization, by pushing the OFFSET and LIMIT parameters to the index scan. +* Grouping and aggregate pushdown to the indexer (introduced in Couchbase 5.5). + +The query intelligently requests the indexer to perform grouping and aggregation in addition to range scan. +The Indexer has been enhanced to perform grouping, COUNT(), SUM(), MIN(), MAX(), AVG(), and related operations. + +You do not need to make any changes to the query to use this feature, but a good index design is required to cover the query and order the keys. +Not every query will benefit from this optimization, and not every index can accelerate every grouping and aggregation. +Understanding the right patterns will help you to design your indexes and queries. +Grouping and aggregate pushdown is supported on both storage engines: Standard GSI and Memory Optimized GSI (MOI). + +This reduction step reduces the amount of data transfer and disk I/O, resulting in: + +* Improved query response time +* Improved resource utilization +* Low latency +* High scalability +* Low TCO + +Let's compare query performance with and without grouping and aggregate pushdown. +Consider the following generic example index and query: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __keyspace_ref__ (__a__); + +SELECT __a__, __aggregate_function__(__a__) +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__; +---- + +Without grouping and aggregate pushdown, the query engine fetches relevant data from the indexer, and then the query engine groups and aggregates the data, as shown in the typical query execution plan below. + +image::GBAP_Ex0_QP_before55.png["Execution plan with 6 steps: Authorize, IndexScan3, Filter, Group, Project with 2 terms, and Stream"] + +With grouping and aggregate pushdown, the query uses the same index, but the indexer does the grouping and aggregation as well. +In the typical query execution plan below, you can see fewer steps, and note the lack of the grouping step after the index scan. + +image::GBAP_Ex0_QP_after55.png["Execution plan with 4 items: Authorize, IndexScan3, Project with 2 terms, and Stream"] + +With grouping and aggregate pushdown, this simple generic query typically executes in less than a third of the time. +As the data and query complexity grows, the performance benefit (both latency and throughput) will grow as well. + +The query plan shows the accelerated aggregation details. +For details, see <>. + +Here's how a query executes when the indexer handles the grouping and aggregation. +Note that the query engine does not fetch any data from the data service (KV service). + +.Query execution process, showing grouping and aggregation pushed down to the indexer +[plantuml,GBAP_55execution,svg] +.... +@startuml + +skinparam maxMessageSize 150 +skinparam responseMessageBelowArrow true +skinparam sequenceMessageAlign direction + +' title Query Execution with Grouping and Aggregation Pushdown + +participant Application + +collections "Query Engine" as Query +collections "Indexer" as Index + +Application -> Query: SELECT\nstatement +activate Query #teal + +Query -[#transparent]> Query: Analyze query; send scan, grouping and aggregation request +Query -> Index: Scan, grouping and aggregate request +activate Index #deepskyblue + +Index -[#transparent]> Index: Execute scan, grouping and aggregation +Index -> Query: Projection of results from scan, grouping and aggregation +deactivate Index + +Query -[#transparent]> Query: Perform group merge, if required; project the results +Query -> Application: Result projection +deactivate Query +@enduml +.... + +For reference, this is how the same query would be executed without grouping and aggregate pushdown. + +.Query execution process, showing grouping and aggregation performed by the query engine +[plantuml,GBAP_pre55execution,svg] +.... +@startuml + +skinparam maxMessageSize 150 +skinparam responseMessageBelowArrow true +skinparam sequenceMessageAlign direction + +' title Query Execution without Grouping and Aggregation Pushdown + +participant Application + +collections "Query Engine" as Query +collections "Indexer" as Index + +Application -> Query: SELECT\nstatement +activate Query #teal + +Query -[#transparent]> Query: Analyze query; send scan request +Query -> Index: Scan request +activate Index #deepskyblue + +Index -[#transparent]> Index: Execute scan +Index -> Query: Projection of results from scan +deactivate Index + +Query -[#transparent]> Query: Perform sub-group, grouping and aggregation; project the results +Query -> Application: Result projection +deactivate Query +@enduml +.... + +== Examples for Grouping and Aggregation + +Consider a composite index: + +.Example A +[source,sqlpp] +---- +CREATE INDEX idx_grp_add ON airport +(geo.alt, geo.lat, geo.lon, id); +---- + +This section considers sample queries that can benefit from this optimization, and queries that cannot. + +Positive Case examples of queries that use indexing grouping and aggregation:: + +[source,sqlpp] +---- +SELECT COUNT(*) FROM airport WHERE geo.alt > 10; + +SELECT COUNT(geo.alt) FROM airport +WHERE geo.alt BETWEEN 10 AND 30; + +SELECT COUNT(geo.lat) FROM airport +WHERE geo.alt BETWEEN 10 AND 30 AND geo.lat = 40; + +SELECT geo.alt, AVG(id), SUM(id), COUNT(geo.alt), MIN (geo.lon), MAX(ABS(geo.lon)) +FROM airport WHERE geo.alt > 100 GROUP BY geo.alt; + +SELECT lat_count, SUM(id) FROM airport +WHERE geo.alt > 100 GROUP BY geo.alt +LETTING lat_count = COUNT(geo.lat) HAVING lat_count > 1; + +SELECT AVG(DISTINCT geo.lat) FROM airport +WHERE geo.alt > 100 GROUP BY geo.alt; + +SELECT ARRAY_AGG(geo.alt) FROM airport +WHERE geo.alt > 10; +---- + +Negative Case examples:: + +[source,sqlpp] +---- +SELECT COUNT(*) FROM airport WHERE geo.lat > 20; +---- + +This query has no predicate on the leading key `geo.alt`. +The index `idx_grp_add` cannot be used. + +[source,sqlpp] +---- +SELECT COUNT(*) FROM airport; +---- + +This query has no predicate at all. + +[source,sqlpp] +---- +SELECT COUNT(v1) FROM airport +LET v1 = ROUND(geo.lat) WHERE geo.lat > 10; +---- + +The aggregate depends on `LET` variable. + +=== Positive query examples with GROUP BY on leading index keys + +The following example uses the `idx_grp_add` index defined previously: + +.Example B +[source,sqlpp] +---- +CREATE INDEX idx_grp_add ON airport +(geo.alt, geo.lat, geo.lon, id); +---- + +In the following query, the GROUP BY keys `(geo.alt, geo.lat)` are the leading keys of the index, so the index is naturally ordered and grouped by the order of the index key definition. +Therefore, the query below is suitable for indexer to handle grouping and aggregation. + +[source,sqlpp] +---- +SELECT geo.alt, geo.lat, SUM(geo.lon), AVG(id), COUNT(DISTINCT geo.lon) +FROM airport +WHERE geo.alt BETWEEN 10 AND 30 +GROUP BY geo.alt, geo.lat +HAVING SUM(geo.lon) > 1000; +---- + +The query plan shows that the index scan handles grouping and aggregation: + +image::GBAP_ExB_Plan.png["Visual plan with three steps: IndexScan3 using idx_grp_add, Filter, and Project with 5 terms"] + +=== Positive query examples with GROUP BY on non-leading index keys + +The following example uses the `idx_grp_add` index defined previously: + +.Example C +[source,sqlpp] +---- +CREATE INDEX idx_grp_add ON airport +(geo.alt, geo.lat, geo.lon, id); + +SELECT geo.lat, id, SUM(geo.lon) +FROM airport +WHERE geo.alt BETWEEN 10 AND 30 +GROUP BY geo.lat, id +HAVING SUM(geo.lon) > 1000; +---- + +In this case, the indexer sends partial group aggregation, which the query merges to create the final group and aggregation. +In this scenario (when the grouping is on non-leading keys), any query with aggregation and DISTINCT modifier cannot be accelerated by the indexer, such as `COUNT(DISTINCT id)`. + +image::GBAP_ExC_Plan.png["Visual plan with 4 steps: IndexScan3 using idx_grp_add, Group, Filter, and Project with 3 terms"] + +=== Positive query examples on array indexes with GROUP BY on leading index keys + +Consider the following index and query: + +.Example D +[source,sqlpp] +---- +CREATE INDEX idx_grp_add_distinct ON hotel +(geo.lat, geo.lon, DISTINCT public_likes, id); + +SELECT geo.lat, geo.lon, SUM(id), AVG(id) +FROM hotel +WHERE geo.lat BETWEEN 10 AND 30 + AND geo.lon > 50 + AND ANY v IN public_likes SATISFIES v = "%a%" END +GROUP BY geo.lat, geo.lon +HAVING SUM(id) > 100; +---- + +In this case, the predicates are on the leading keys up to and including the array key. +Therefore, indexer can efficiently do the grouping as seen by the optimal plan below. +It’s important to note the array index key is created with a `DISTINCT` modifier (not the `ALL` modifier) to get this optimization and that the `SATISFIES` clause in the `ANY` predicate must be that of equality (that is, `v = "%a%"`). + +image::GBAP_ExD_Plan.png["Visual plan with 3 steps: IndexScan3 using idx_grp_add_distinct, Filter, and Project with 4 terms"] + +Consider the index and query: + +.Example E +[source,sqlpp] +---- +CREATE INDEX idx_grp_add_all ON hotel +(ALL public_likes, geo.lat, geo.lon, id); + +SELECT un, t.geo.lat, COUNT(un), AVG(t.geo.lat) +FROM hotel AS t + UNNEST t.public_likes AS un +WHERE un > "J" +GROUP BY un, t.geo.lat; +---- + +In this case, the `UNNEST` operation can use the index because the leading `ALL` array key is the array being unwound. +Note, the unwound operation repeats the parent document (`hotel`) and the `t.geo.lat` reference would have duplicates compared to the original `hotel` documents. + +image::GBAP_ExE_Plan.png["Visual plan with two steps: IndexScan3 using idx_grp_add_all, and Project with 4 terms"] + +== Query Qualification and Pushdown + +Not every GROUP BY and aggregate query can be handled by the indexer. +Following are some simple rules that will help you to write the proper queries and design the required indexes to get the most of this feature. + +The following are necessary in order for an indexer to execute GROUP BY and aggregates: + +* All the query predicates are able to convert into ranges and able to push to indexer. +* The whole query must be covered by an index. + ** For a query to be covered by an index, every attribute referenced in the query should be in one index. + ** Query should not have operations such as joins, subquery, or derived table queries. +* GROUP BY keys and Aggregate expressions must be one of the following: + ** Index keys or document key + ** An expression based on index keys or document key +* GROUP BY and aggregate expressions must be simple. + +== Scenarios for Grouping and Aggregation + +Like any feature in a query language, there are subtle variations between each query and index that affects this optimization. +We use the travel sample dataset to illustrate both positive and negative use cases. + +The following table lists the scenarios and requirements for queries to request the indexer to do the grouping and acceleration. +When the requirements are unmet, the query will fetch the relevant data and then do the grouping and acceleration as usual. +No application changes are necessary. +The query plan generated reflects this decision. + +GROUP BY Scenarios:: + +. <> +. <> +. <> +. <> +. <> +. <> +. <> +. <> + +Aggregate Scenarios:: + +. <> +. <> +. <> +. <> +. <> +. <> + +[[group-by-on-leading-keys]] +=== GROUP BY on leading keys + +One of the common cases is to have both predicates and GROUP BY on leading keys of the index. +First create the index so that the query is covered by the index. +You can then think about the order of the keys. + +The query requires a predicate on leading keys to consider an index. +The simplest predicate is `IS NOT MISSING`. + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __keyspace_ref__ (__a__, __b__, __c__); + +SELECT __a__, __b__, __aggregate_function__(__c__) -- <1> +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING -- <2> +GROUP BY __a__, __b__; +---- + +<1> Where `__aggregate_function__(__c__)` is `MIN(__c__)`, `MAX(__c__)`, `COUNT(__c__)`, or `SUM(__c__)` +<2> 1st index field must be in a WHERE clause + +[[ex1]] +.List the cities with the landmarks with the highest latitude +==== +Use the `MAX()` aggregate to find the highest landmark latitude in each state, group the results by `country` and `state`, and then sort in reverse order by the highest latitudes per `state`. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx1 ON landmark +(country, state, geo.lat); +---- + +.Query +[source,sqlpp] +---- +SELECT country, state, MAX(ROUND(geo.lat)) AS Max_Latitude +FROM landmark +WHERE country IS NOT MISSING +GROUP BY country, state +ORDER BY Max_Latitude DESC; +---- + +In this query, we need to give the predicate `country IS NOT MISSING` (or any WHERE clause) to ensure this index is selected for the query. +Without a matching predicate, the query will use the primary index. + +.Results +[source,json] +---- +[ + { + "Max_Latitude": 60, + "country": "United Kingdom", + "state": null + }, + { + "Max_Latitude": 51, + "country": "United Kingdom", + "state": "England" + }, + { + "Max_Latitude": 50, + "country": "France", + "state": "Picardie" + }, +... +] +---- + +.Plan +[source,json] +---- +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`country`))", + "cover ((`landmark`.`state`))", + "cover (((`landmark`.`geo`).`lat`))", + "cover ((meta(`landmark`).`id`))", + "cover (max(round(cover (((`landmark`.`geo`).`lat`)))))" + ], + "index": "idx1", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "MAX", + "depends": [ + 2 + ], + "expr": "round(cover (((`landmark`.`geo`).`lat`)))", + "id": 4, + "keypos": -1 + } + ], + "depends": [ + 0, + 1, + 2 + ], + "group": [ + { + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`country`))", + "id": 0, + "keypos": 0 + }, + { + "depends": [ + 1 + ], + "expr": "cover ((`landmark`.`state`))", + "id": 1, + "keypos": 1 + } + ] + }, +... + } + ] + } + ] + } +} +---- + +The query plan shows that grouping is executed by the indexer. +This is detailed in <>. +==== + +[[group-by-on-non-leading-keys]] +=== GROUP BY on non-leading keys + +When using GROUP BY on a non-leading key: + +* The indexer will return _pre-aggregated_ results. +* Results can have duplicate or out-of-order groups. +The {sqlpp} indexer will do 2nd level of aggregation and compute the final result. +* The {sqlpp} indexer can pushdown only if the leading key has a predicate. + +To use Aggregate Pushdown, use the following syntax for the index and query statements: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __keyspace_ref__ (__a__, __b__, __c__); +---- + +.Syntax A +[subs="verbatim,quotes"] +---- +SELECT __aggregate_function__(__a__), __b__, __aggregate_function__(__c__) +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __b__; +---- + +.Syntax B +[subs="verbatim,quotes"] +---- +SELECT __aggregate_function__(__a__), __aggregate_function__(__b__), __c__ +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __c__; +---- + +[[ex2-a]] +.List the states with their total number of landmarks and the lowest latitude of any landmark +==== +Use the `COUNT()` operator to find the total number of landmarks and use the `MIN()` operator to find the lowest landmark latitude in each state, group the results by `state`, and then sort in order by the lowest latitudes per `state`. +This example uses the `idx1` index defined previously: + +.Index +[source,sqlpp] +---- +CREATE INDEX idx1 ON landmark +(country, state, geo.lat); +---- + +.Query +[source,sqlpp] +---- +SELECT COUNT(country) AS Total_landmarks, state, MIN(ROUND(geo.lat)) AS Min_Latitude +FROM landmark +WHERE country IN ["France", "United States", "United Kingdom"] +GROUP BY state +ORDER BY Min_Latitude; +---- + +// FIXME: Non-deterministic + +.Plan +[source,json] +---- +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`country`))", + "cover ((`landmark`.`state`))", + "cover (((`landmark`.`geo`).`lat`))", + "cover ((meta(`landmark`).`id`))", + "cover (count(cover ((`landmark`.`country`))))", + "cover (min(round(cover (((`landmark`.`geo`).`lat`)))))" + ], + "index": "idx1", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`country`))", + "id": 4, + "keypos": 0 + }, + { + "aggregate": "MIN", + "depends": [ + 2 + ], + "expr": "round(cover (((`landmark`.`geo`).`lat`)))", + "id": 5, + "keypos": -1 + } + ], + "depends": [ + 0, + 1, + 2 + ], + "group": [ + { + "depends": [ + 1 + ], + "expr": "cover ((`landmark`.`state`))", + "id": 1, + "keypos": 1 + } + ], + "partial": true // <1> + }, +... + } + ] + } + ] + } +} +---- + +image::GBAP_Ex2A_EP.png["Query plan with 4 steps: IndexScan3 using idx1, Group, Project with 3 terms, and Order by Min Latitude"] + +.Results +[source,json] +---- +[ + { + "Min_Latitude": 33, + "Total_landmarks": 1900, + "state": "California" + }, + { + "Min_Latitude": 41, + "Total_landmarks": 8, + "state": "Corse" + }, + { + "Min_Latitude": 43, + "Total_landmarks": 2208, + "state": null + }, +... +] +---- +==== + +<1> The `"partial": true` line means it was pre-aggregated. + +[[ex2-b]] +.List the number of landmarks by latitude and the state it's in +==== +Use `COUNT(country)` for the total number of landmarks at each latitude. +At a particular latitude, the `state` will be the same; but an aggregate function on it is needed, so `MIN()` or `MAX()` is used to return the original value. + +.Query +[source,sqlpp] +---- +SELECT COUNT(country) Num_Landmarks, MIN(state) State_Name, ROUND(geo.lat) Latitude +FROM landmark +WHERE country IS NOT MISSING +GROUP BY ROUND(geo.lat) +ORDER BY ROUND(geo.lat); +---- + +.Results +[source,json] +---- +[ + { + "Latitude": 33, + "Num_Landmarks": 227, + "State_Name": "California" + }, + { + "Latitude": 34, + "Num_Landmarks": 608, + "State_Name": "California" + }, + { + "Latitude": 35, + "Num_Landmarks": 27, + "State_Name": "California" + }, +... +] +---- +==== + +[[group-by-keys-in-different-order]] +=== GROUP BY keys in different CREATE INDEX order + +When using GROUP BY on keys in a different order than they appear in the CREATE INDEX statement, use the following syntax: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __keyspace_ref__(__a__, __b__, __c__); + +SELECT __aggregate_function__(__c__) +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __b__, __a__; +---- + +[[ex3]] +.List the landmarks with the lowest longitude +==== +Like <> with the GROUP BY fields swapped. + +Use the `MIN()` operator to find the lowest landmark longitude in each city, group the results by `activity` and `city`, and then sort in reverse order by the lowest longitudes per `activity`. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx3 ON landmark +(activity, city, geo.lon); +---- + +.Query +[source,sqlpp] +---- +SELECT activity, city, MIN(ROUND(geo.lon)) AS Min_Longitude +FROM landmark +WHERE country IS NOT MISSING +GROUP BY activity, city +ORDER BY Min_Longitude, activity; +---- + +// FIXME: Non-deterministic + +.Results +[source,json] +---- +[ + { + "Min_Longitude": -124, + "activity": "buy", + "city": "Eureka" + }, + { + "Min_Longitude": -123, + "activity": "eat", + "city": "Santa Rosa" + }, + { + "Min_Longitude": -123, + "activity": "eat", + "city": "Sebastopol" + }, + { + "Min_Longitude": -123, + "activity": "see", + "city": "Sebastopol" + }, +... +] +---- +==== + +[[group-by-on-expression]] +=== GROUP BY on expression + +When grouping on an expression or operation, the indexer will return pre-aggregated results whenever the GROUP BY and leading index keys are not an exact match. + +To use Aggregate Pushdown and avoid pre-aggregated results, use one of the two following syntaxes for the index and query statements: + +.Syntax A: Field with an expression -- GROUP BY and Index keys match +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __keyspace_ref__(__a__+__b__, __b__, __c__); + +SELECT __aggregate_function__(__c__) +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__+__b__; +---- + +.Syntax B: Operation on a field -- GROUP BY and Index keys match +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_operation__ ON __keyspace_ref__ (LOWER(__a__), __b__, __c__); + +SELECT __aggregate_function__(__c__) +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY LOWER(__a__); +---- + +For comparison, the below index and query combination will yield pre-aggregated results. + +.Pre-aggregated Syntax -- the GROUP BY and Index keys don't match +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_operation__ ON __keyspace_ref__ (__a__, __b__, __c__); + +SELECT __aggregate_function__(__c__) +FROM __keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY UPPER(__a__); +---- + +[[ex4-a]] +.A field with an expression +==== +Let's say the distance of a flight feels like "nothing" when it's direct, but feels like the true distance when there is one layover. +Then we can list and group by flight distances by calculating the distance multiplied by the stops it makes. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx4_expr ON route +(ROUND(distance*stops), ROUND(distance), sourceairport); +---- + +.Query +[source,sqlpp] +---- +SELECT ROUND(distance*stops) AS Distance_Feels_Like, + MAX(ROUND(distance)) AS Distance_True, + COUNT(sourceairport) Number_of_Airports +FROM route +WHERE ROUND(distance*stops) IS NOT MISSING +GROUP BY ROUND(distance*stops); +---- + +// FIXME: Non-deterministic + +.Plan +[source,json] +---- +... + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 2 + ], + "expr": "cover ((`route`.`sourceairport`))", + "id": 4, + "keypos": 2 + }, + { + "aggregate": "MAX", + "depends": [ + 1 + ], + "expr": "cover (round((`route`.`distance`)))", + "id": 5, + "keypos": 1 + } + ], + "depends": [ + 0, + 1, + 2 + ], + "group": [ + { + "depends": [ + 0 + ], + "expr": "cover (round(((`route`.`distance`) * (`route`.`stops`))))", + "id": 0, + "keypos": 0 + } + ] + }, +... +---- + +image::GBAP_Ex4A_VP.png["Query plan with 2 steps: IndexScan3 using idx4_expr, and Project with 3 terms"] + +.Results +[source,json] +---- +[ + { + "Distance_Feels_Like": 0, + "Distance_True": 13808, + "Number_of_Airports": 24018 + }, + { + "Distance_Feels_Like": 309, + "Distance_True": 309, + "Number_of_Airports": 1 + }, + { + "Distance_Feels_Like": 1055, + "Distance_True": 1055, + "Number_of_Airports": 1 + }, +... +] +---- +==== + +[[ex4-b]] +.An operation on a field +==== +Let's say the distance of a flight feels like "nothing" when it's direct, but feels like the true distance when there is one layover. +Then we can list and group by the uppercase of the airport codes and listing the flight distances by calculating the distance multiplied by the stops it makes along with the total distance. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx4_oper ON route +(sourceairport, ROUND(distance*stops), distance); +---- + +.Query +[source,sqlpp] +---- +SELECT UPPER(sourceairport) AS Airport_Code, + MIN(ROUND(distance*stops)) AS Distance_Feels_Like, + SUM(ROUND(distance)) AS Total_Distance +FROM route +WHERE sourceairport IS NOT MISSING +GROUP BY UPPER(sourceairport); +---- + +// FIXME: Non-deterministic + +.Results +[source,json] +---- +[ + { + "Airport_Code": "ITO", + "Distance_Feels_Like": 0, + "Total_Distance": 4828 + }, + { + "Airport_Code": "GJT", + "Distance_Feels_Like": 0, + "Total_Distance": 6832 + }, + { + "Airport_Code": "HYA", + "Distance_Feels_Like": 0, + "Total_Distance": 148 + }, +... +] +---- +==== + +[[heterogeneous-data-types]] +=== Heterogeneous data types for GROUP BY key + +When a field has a mix of data types for the GROUP BY key: + +* `NULLS` and `MISSING` are two separate groups. + +[[ex5]] +.Heterogeneous data types +==== +To see a separate grouping of `MISSING` and `NULL`, we need to `GROUP BY` a field we know exists in one document but not in another document while both documents have another field in common. + +.Create Documents +[source,sqlpp] +---- +INSERT INTO landmark + VALUES("01",{"type":1, "email":"abc","xx":3}); + +INSERT INTO landmark + VALUES("02",{"type":1, "email":"abc","xx":null}); + +INSERT INTO landmark + VALUES("03",{"type":1, "email":"abcd"}); +---- + +.Query +[source,sqlpp] +---- +SELECT type, xx, MIN(email) AS Min_Email +FROM landmark +WHERE type IS NOT NULL +GROUP BY type, xx; +---- + +.Results +[source,json] +---- +[ + { + "Min_Email": "abc", + "type": 1, + "xx": 3 + }, + { + "Min_Email": "abc", + "type": 1, + "xx": null + }, + { + "Min_Email": "abcd", + "type": 1 // <1> + }, + { + "Min_Email": "2willowroad@nationaltrust.org.uk", + "type": "landmark" + } +] +---- +==== + +<1> This is a separate result since field `xx` is MISSING + +[[group-by-meta-id]] +=== GROUP BY META().ID Primary Index + +If there is no filter, then pushdown is supported for an expression on the Document ID `META().id` in the `GROUP BY` clause. + +To use Aggregate Pushdown, use the following syntax for the index and query statement: + +[subs="verbatim,quotes"] +---- +CREATE PRIMARY INDEX __idx_expr__ ON __named_keyspace_ref__; + +SELECT COUNT(1) +FROM __named_keyspace_ref__ +GROUP BY SUBSTR(META().id, __start__, __finish__); +---- + +NOTE: If there is a filter on the Document ID, then the primary index can be used as a secondary scan. + +[[ex6]] +.List the number of airports that are in each decile of the `META().id` field +==== +.Index +[source,sqlpp] +---- +CREATE PRIMARY INDEX idx6 ON airport; +---- + +.Query +[source,sqlpp] +---- +SELECT COUNT(1) AS Count, SUBSTR(META().id,0,9) AS Meta_Group +FROM airport +GROUP BY SUBSTR(META().id,0,9); +---- + +// FIXME: Non-deterministic + +.Results +[source,json] +---- +[ + { + "Count": 168, + "Meta_Group": "airport_4" + }, + { + "Count": 175, + "Meta_Group": "airport_5" + }, + { + "Count": 125, + "Meta_Group": "airport_6" + }, +... +] +---- +==== + +[[limit-with-group-by]] +=== LIMIT with GROUP BY on leading keys + +To use Aggregate Pushdown when there is a LIMIT clause and a GROUP BY clause on one or more leading keys, use the following example of the index and query statement: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__k0__, __k1__); + +SELECT __k0__, COUNT(__k1__) +FROM __named_keyspace_ref__ +WHERE __k0__ IS NOT MISSING +GROUP BY __k0__ +LIMIT __n__; +---- + +[[ex7]] +.LIMIT with GROUP BY on the leading key +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx7 ON landmark +(city, name); +---- + +.Query +[source,sqlpp] +---- +SELECT city AS City, COUNT(DISTINCT name) AS Landmark_Count +FROM landmark +WHERE city IS NOT MISSING +GROUP BY city +LIMIT 4; +---- + +.Plan +[source,json] +---- +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((`landmark`.`name`))", + "cover ((meta(`landmark`).`id`))", + "cover (count(DISTINCT cover ((`landmark`.`name`))))" + ], + "index": "idx7", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 1 + ], + "distinct": true, + "expr": "cover ((`landmark`.`name`))", + "id": 3, + "keypos": 1 + } + ], + "depends": [ + 0, + 1 + ], + "group": [ + { + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`city`))", + "id": 0, + "keypos": 0 + } + ] + }, + "index_id": "7fe5ede3626e6d29", + "index_projection": { + "entry_keys": [ + 0, + 3 + ] + }, + "keyspace": "landmark", + "limit": "4", // <1> + "namespace": "default", +... + } + ] + } + ] + } +} +---- + +.Results +[source,json] +---- +[ + { + "City": null, + "Landmark_Count": 15 + }, + { + "City": "Abbeville", + "Landmark_Count": 1 + }, + { + "City": "Abbots Langley", + "Landmark_Count": 19 + }, + { + "City": "Aberdeenshire", + "Landmark_Count": 6 + } +] +---- +==== + +<1> The `limit` is pushed to the indexer because the GROUP BY key matched with the leading index key. + +[[offset-with-group-by]] +=== OFFSET with GROUP BY on leading keys + +To use Aggregate Pushdown when there is an OFFSET clause and a GROUP BY clause on one or more leading keys, use the following example of the index and query statement. + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__k0__, __k1__); + +SELECT __k0__, COUNT(k1) +FROM __named_keyspace_ref__ +WHERE __k0__ IS NOT MISSING +GROUP BY __k0__ +OFFSET __n__; +---- + +[[ex8]] +.OFFSET with GROUP BY on a leading key +==== +This example uses the `idx7` index defined previously: + +.Index +[source,sqlpp] +---- +CREATE INDEX idx7 ON landmark +(city, name); +---- + +.Query +[source,sqlpp] +---- +SELECT city AS City, COUNT(DISTINCT name) AS Landmark_Count +FROM landmark +WHERE city IS NOT MISSING +GROUP BY city +OFFSET 4; +---- + +.Plan +[source,json] +---- +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`city`))", + "cover ((`landmark`.`name`))", + "cover ((meta(`landmark`).`id`))", + "cover (count(DISTINCT cover ((`landmark`.`name`))))" + ], + "index": "idx7", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 1 + ], + "distinct": true, + "expr": "cover ((`landmark`.`name`))", + "id": 3, + "keypos": 1 + } + ], + "depends": [ + 0, + 1 + ], + "group": [ + { + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`city`))", + "id": 0, + "keypos": 0 + } + ] + }, + "index_id": "7fe5ede3626e6d29", + "index_projection": { + "entry_keys": [ + 0, + 3 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "offset": "4", // <1> + "scope": "inventory", + "spans": [ +... + ] + } + ] + } + ] + } +} +---- + +.Results +[source,json] +---- +[ + { + "City": "Aberdour", + "Landmark_Count": 4 + }, + { + "City": "Aberdulais", + "Landmark_Count": 1 + }, + { + "City": "Abereiddy", + "Landmark_Count": 1 + }, + { + "City": "Aberfeldy", + "Landmark_Count": 2 + }, +... +] +---- +==== + +<1> The `offset` is pushed to the indexer because the GROUP BY key matched with the leading index key. + +[[aggregate-without-group-by]] +=== Aggregate without GROUP BY key + +This is a case of aggregation over a range without groups. +If the index can be used for computing the aggregate, the indexer will return a single aggregate value. +To use Aggregate Pushdown, use the following syntax for index and queries: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__); +---- + +.Q1 +[subs="verbatim,quotes"] +---- +SELECT __aggregate_function__(__c__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING; +---- + +.Q2 +[subs="verbatim,quotes"] +---- +SELECT SUM(__a__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING; +---- + +.Q3 +[subs="verbatim,quotes"] +---- +SELECT SUM(__a__), COUNT(__a__), MIN(__a__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING; +---- + +.Q4 +[subs="verbatim,quotes"] +---- +SELECT SUM(__a__), COUNT(__b__), MIN(__c__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING; +---- + +[[ex9-q1]] +.Multiple Aggregate without GROUP BY key -- Q1 +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx9 ON route +(distance, stops, sourceairport); +---- + +.Query +[source,sqlpp] +---- +SELECT SUM(ROUND(distance)) AS Total_Distance, + SUM(stops) AS Total_Stops, + COUNT(sourceairport) AS Total_Airports +FROM route +WHERE distance IS NOT MISSING; +---- + +.Results +[source,json] +---- +[ + { + "Total_Airports": 24024, + "Total_Distance": 53538071, + "Total_Stops": 6 + } +] +---- +==== + +[[ex9-q2]] +.Aggregate without GROUP BY key -- Q2 +==== +.Query +[source,sqlpp] +---- +SELECT SUM(ROUND(distance)) AS Total_Distance +FROM route; +---- + +.Results +[source,json] +---- +[ + { + "Total_Distance": 53538071 + } +] +---- +==== + +[[ex9-q3]] +.Multiple Aggregate without GROUP BY key -- Q3 +==== +.Query +[source,sqlpp] +---- +SELECT SUM(ROUND(distance)) AS Total_Distance, + COUNT(ROUND(distance)) AS Count_of_Distance, + MIN(ROUND(distance)) AS Min_of_Distance +FROM route +WHERE distance IS NOT MISSING; +---- + +.Results +[source,json] +---- +[ + { + "Count_of_Distance": 24024, + "Min_of_Distance": 3, + "Total_Distance": 53538071 + } +] +---- +==== + +[[ex9-q4]] +.Multiple Aggregate without GROUP BY key -- Q4 +==== +.Query +[source,sqlpp] +---- +SELECT SUM(ROUND(distance)) AS Total_Distance, + COUNT(stops) AS Count_of_Stops, + MIN(sourceairport) AS Min_of_Airport +FROM route +WHERE distance IS NOT MISSING; +---- + +.Results +[source,json] +---- +[ + { + "Count_of_Stops": 24024, + "Min_of_Airport": "AAE", + "Total_Distance": 53538071 + } +] +---- +==== + +[[expression-in-aggregate-function]] +=== Expression in Aggregate function + +Aggregations with scalar expressions can be speeded up even if the index key does not have the matching expression on the key. +To use Aggregate Pushdown, use the following syntax for the index and query statement: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__); + +SELECT __aggregate_function1__(__expression__(c)) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__, __b__; +---- + +[[ex10]] +.List the landmarks with the highest latitude +==== +Use the `MAX()` operator to find the highest landmark latitude in each state, group the results by `country` and `state`, and then sort in reverse order by the highest latitudes. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx10 ON landmark +(country, state, ABS(ROUND(geo.lat))); +---- + +.Query +[source,sqlpp] +---- +SELECT country, state, SUM(ABS(ROUND(geo.lat))) AS SumAbs_Latitude +FROM landmark +USE INDEX (idx10) -- <1> +WHERE country IS NOT MISSING +GROUP BY country, state +ORDER BY SumAbs_Latitude DESC; +---- + +<1> Specifies that the query must use `idx10` rather than the similar `idx1` + +.Plan +[source,json] +---- +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`country`))", + "cover ((`landmark`.`state`))", + "cover (abs(round(((`landmark`.`geo`).`lat`))))", + "cover ((meta(`landmark`).`id`))", + "cover (sum(cover (abs(round(((`landmark`.`geo`).`lat`))))))" + ], + "index": "idx10", + "index_group_aggs": { + "aggregates": [ + { + "aggregate": "SUM", + "depends": [ + 2 + ], + "expr": "cover (abs(round(((`landmark`.`geo`).`lat`))))", + "id": 4, + "keypos": 2 + } + ], + "depends": [ + 0, + 1, + 2 + ], + "group": [ + { + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`country`))", + "id": 0, + "keypos": 0 + }, + { + "depends": [ + 1 + ], + "expr": "cover ((`landmark`.`state`))", + "id": 1, + "keypos": 1 + } +... + ] + } + } + ] + } + ] + } +} +---- + +The query plan shows that aggregates are executed by the indexer. +This is detailed in <>. + +image::GBAP_Ex10_VP.png["Query plan with 3 steps: IndexScan3 using idx10, Project with 3 terms, and Order by SumAbs_Latitude"] + +.Results +[source,json] +---- +[ + { + "SumAbs_Latitude": 117513, + "country": "United Kingdom", + "state": null + }, + { + "SumAbs_Latitude": 68503, + "country": "United States", + "state": "California" + }, + { + "SumAbs_Latitude": 10333, + "country": "France", + "state": "Île-de-France" + }, +... +] +---- +==== + +[[sum-count-min-max-avg]] +=== SUM, COUNT, MIN, MAX, or AVG Aggregate functions + +Currently, the only aggregate functions that are supported are SUM(), COUNT(), MIN(), MAX(), and AVG() with or without the DISTINCT modifier. + +To use Aggregate Pushdown, use the below syntax for the index and query statement: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__, __d__); + +SELECT __aggregate_function__(__a__), __aggregate_function__(__b__), + __aggregate_function__(__c__), __aggregate_function__(__d__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__; +---- + +.Aggregate functions +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx11 ON airport +(geo.lat, geo.alt, city, geo.lon); +---- + +.Query +[source,sqlpp] +---- +SELECT MIN(ROUND(geo.lat)) AS Min_Lat, + SUM(geo.alt) AS Sum_Alt, + COUNT(city) AS Count_City, + MAX(ROUND(geo.lon)) AS Max_Lon +FROM airport +WHERE geo.lat IS NOT MISSING +GROUP BY (ROUND(geo.lat)) +ORDER BY (ROUND(geo.lat)) DESC; +---- + +.Results +[source,json] +---- +[ + { + "Count_City": 1, + "Max_Lon": 43, + "Min_Lat": 72, + "Sum_Alt": 149 + }, + { + "Count_City": 3, + "Max_Lon": -157, + "Min_Lat": 71, + "Sum_Alt": 120 + }, + { + "Count_City": 6, + "Max_Lon": -144, + "Min_Lat": 70, + "Sum_Alt": 292 + }, +... +] +---- +==== + +[[distinct-aggregates]] +=== DISTINCT aggregates + +There are four cases when DISTINCT aggregates can use this feature: + +. If the DISTINCT aggregate is on the leading GROUP BY key(s). +. If the DISTINCT aggregate is on the leading GROUP By key(s) + 1 (the immediate next key). +. If the DISTINCT aggregate is on a constant expression (GROUP BY can be on any key). +. If there is no GROUP BY and the DISTINCT aggregate is on the first key only or in a constant expression. + +To use Aggregate Pushdown, use one of the following syntaxes of the index and query statements: + +==== Case 1 + +If the DISTINCT aggregate is on the leading GROUP BY key(s). + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__); +---- + +.Syntax A +[subs="verbatim,quotes"] +---- +SELECT SUM(DISTINCT __a__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__; +---- + +.Syntax B +[subs="verbatim,quotes"] +---- +SELECT COUNT(DISTINCT __a__), SUM(DISTINCT __b__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__, __b__; +---- + +[[ex12-1-a]] +.DISTINCT aggregate -- Case 1, Syntax A +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx12_1 ON airport +(geo.lat, geo.lon, country); +---- + +.Query +[source,sqlpp] +---- +SELECT SUM(DISTINCT ROUND(geo.lat)) AS Sum_Lat +FROM airport +WHERE geo.lat IS NOT MISSING +GROUP BY ROUND(geo.lat); +---- + +.Results +[source,json] +---- +[ + { + "Sum_Lat": 27 + }, + { + "Sum_Lat": 36 + }, + { + "Sum_Lat": 71 + }, +... +] +---- +==== + +// FIXME: Non-deterministic + +[[ex12-1-b]] +.DISTINCT aggregate -- Case 1, Syntax B +==== +.Query +[source,sqlpp] +---- +SELECT COUNT(DISTINCT ROUND(geo.lat)) AS Count_Lat, + SUM(DISTINCT ROUND(geo.lon)) AS Sum_Lon +FROM airport +WHERE geo.lat IS NOT MISSING +GROUP BY ROUND(geo.lat), ROUND(geo.lon); +---- + +.Results +[source,json] +---- +[ + { + "Count_Lat": 1, + "Sum_Lon": -166 + }, + { + "Count_Lat": 1, + "Sum_Lon": -107 + }, + { + "Count_Lat": 1, + "Sum_Lon": -159 + }, +... +] +---- +==== + +// FIXME: Non-deterministic + +==== Case 2 + +If the DISTINCT aggregate is on the leading GROUP BY key(s) + 1 (the next key). + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__); +---- + +.Syntax A +[subs="verbatim,quotes"] +---- +SELECT SUM(DISTINCT __b__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__; +---- + +.Syntax B +[subs="verbatim,quotes"] +---- +SELECT COUNT(DISTINCT __c__) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __a__, __b__; +---- + +[[ex12-2-a]] +.DISTINCT aggregate -- Case 2, Syntax A +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx12_2 ON airport +(country, ROUND(geo.lat), ROUND(geo.lon)); +---- + +.Query +[source,sqlpp] +---- +SELECT COUNT(DISTINCT country) AS Count_Country, + SUM(DISTINCT ROUND(geo.lat)) AS Sum_Lat +FROM airport +WHERE country IS NOT MISSING +GROUP BY country; +---- + +.Results +[source,json] +---- +[ + { + "Count_Country": 1, + "Sum_Lat": 483 + }, + { + "Count_Country": 1, + "Sum_Lat": 591 + }, + { + "Count_Country": 1, + "Sum_Lat": 2290 + } +] +---- +==== + +[[ex12-2-b]] +.DISTINCT aggregate -- Case 2, Syntax B +==== +.Query +[source,sqlpp] +---- +SELECT COUNT(DISTINCT country) AS Count_Country, + SUM(DISTINCT ROUND(geo.lat)) AS Sum_Lat, + COUNT(DISTINCT ROUND(geo.lon)) AS Count_Lon +FROM airport +WHERE country IS NOT MISSING +GROUP BY country, ROUND(geo.lat); +---- + +.Results +[source,json] +---- +[ + { + "Count_Country": 1, + "Count_Lon": 1, + "Sum_Lat": 18 + }, + { + "Count_Country": 1, + "Count_Lon": 1, + "Sum_Lat": 42 + }, + { + "Count_Country": 1, + "Count_Lon": 9, + "Sum_Lat": 43 + }, +... +] +---- +==== + +==== Case 3 + +If the DISTINCT aggregate is on a constant expression -- GROUP BY can be on any key. + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__); + +SELECT __a__, COUNT(DISTINCT 1) +FROM __named_keyspace_ref__ +WHERE __a__ IS NOT MISSING +GROUP BY __b__; +---- + +NOTE: The results will be pre-aggregated if the `GROUP BY` key is non-leading, as in this case and example. + +[[ex12-3]] +.DISTINCT aggregate -- Case 3 +==== +.Index +[source,sqlpp] +---- +CREATE INDEX idx12_3 ON airport +(country, geo.lat, geo.lon); +---- + +.Query +[source,sqlpp] +---- +SELECT MIN(country) AS Min_Country, + COUNT(DISTINCT 1) AS Constant_Value, + MIN(ROUND(geo.lon)) AS Min_Longitude +FROM airport +WHERE country IS NOT MISSING +GROUP BY geo.lat; +---- + +// FIXME: Non-deterministic + +.Results +[source,json] +---- +[ + { + "Constant_Value": 1, + "Min_Country": "United States", + "Min_Longitude": -103 + }, + { + "Constant_Value": 1, + "Min_Country": "France", + "Min_Longitude": 3 + }, + { + "Constant_Value": 1, + "Min_Country": "United States", + "Min_Longitude": -105 + }, +... +] +---- +==== + +==== Case 4 + +If the DISTINCT aggregate is on the first key only or in a constant expression, and there is no GROUP BY clause. + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__a__, __b__, __c__); +---- + +.Q1 +[subs="verbatim,quotes"] +---- +SELECT __aggregate_function__(DISTINCT __a__) +FROM __named_keyspace_ref__; -- <1> +---- + +.Q2 +[subs="verbatim,quotes"] +---- +SELECT __aggregate_function__(DISTINCT 1) +FROM __named_keyspace_ref__; -- <2> +---- + +.Q3 +[subs="verbatim,quotes"] +---- +SELECT __aggregate_function__(DISTINCT __c__) +FROM __named_keyspace_ref__; -- <3> +---- + +<1> OK +<2> OK +<3> Not OK + +All other cases of DISTINCT pushdown will return an error. + +[[ex12-4-q1]] +.DISTINCT aggregate -- Case 4, Q1 +==== +A DISTINCT aggregate on the first key only, where there is no GROUP BY clause. + +.Index +[source,sqlpp] +---- +CREATE INDEX idx12_4 ON airport +(geo.alt, geo.lat, geo.lon); +---- + +.Query +[source,sqlpp] +---- +SELECT SUM(DISTINCT ROUND(geo.alt)) AS Sum_Alt +FROM airport +WHERE geo.alt IS NOT MISSING; +---- + +.Results +[source,json] +---- +[ + { + "Sum_Alt": 1463241 + } +] +---- +==== + +[[ex12-4-q2]] +.DISTINCT aggregate -- Case 4, Q2 +==== +A DISTINCT aggregate on a constant expression, where there is no GROUP BY clause. +This query pushes the aggregation down to the indexer, but does not necessarily use the index `idx12_4`. + +.Query +[source,sqlpp] +---- +SELECT COUNT(DISTINCT 1) AS Const_expr +FROM airport; +---- + +.Results +[source,json] +---- +[ + { + "Const_expr": 1 + } +] +---- +==== + +[[ex12-4-q3]] +.DISTINCT aggregate -- Case 4, Q3 +==== +A DISTINCT aggregate on a non-leading key, where there is no GROUP BY clause. +This query uses the index `idx12_4`, but does not push the aggregation down to the indexer. + +.Query +[source,sqlpp] +---- +SELECT SUM(DISTINCT ROUND(geo.lon)) AS Sum_Lon +FROM airport +WHERE geo.alt IS NOT MISSING; +---- + +.Results +[source,json] +---- +[ + { + "Sum_Lon": -11412 + } +] +---- +==== + +[[having-with-aggregate-function]] +=== HAVING with an aggregate function inside + +To use Aggregate Pushdown when a HAVING clause has an aggregate function inside, use the following syntax of index and query statement: + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__k0__, __k1__); + +SELECT __k0__, COUNT(__k1__) +FROM __named_keyspace_ref__ +WHERE __k0__ IS NOT MISSING +GROUP BY __k0__ +HAVING __aggregate_function__(__k1__); +---- + +[[ex13]] +.HAVING with an aggregate function inside +==== +List the cities that have more than 180 landmarks. +This example uses the `idx7` index defined previously: + +.Index +[source,sqlpp] +---- +CREATE INDEX idx7 ON landmark +(city, name); +---- + +.Query +[source,sqlpp] +---- +SELECT city AS City, COUNT(DISTINCT name) AS Landmark_Count +FROM landmark +WHERE city IS NOT MISSING +GROUP BY city +HAVING COUNT(DISTINCT name) > 180; +---- + +.Results +[source,json] +---- +[ + { + "City": "London", + "Landmark_Count": 443 + }, + { + "City": "Los Angeles", + "Landmark_Count": 284 + }, + { + "City": "San Diego", + "Landmark_Count": 197 + }, + { + "City": "San Francisco", + "Landmark_Count": 797 + } +] +---- +==== + +[[letting-with-aggregate-function]] +=== LETTING with an aggregate function inside + +To use Aggregate Pushdown when a LETTING clause has an aggregate function inside, use the following syntax of the index and query statement. + +[subs="verbatim,quotes"] +---- +CREATE INDEX __idx_expr__ ON __named_keyspace_ref__ (__k0__, __k1__); + +SELECT __k0__, COUNT(__k1__) +FROM __named_keyspace_ref__ +WHERE __k0__ IS NOT MISSING +GROUP BY __k0__ +LETTING var_expr = __aggregate_function__(__k1__) +HAVING var_expr; +---- + +[[ex14]] +.LETTING with an aggregate function inside +==== +List cities that have more than half of all landmarks. +This example uses the `idx7` index defined previously: + +.Index +[source,sqlpp] +---- +CREATE INDEX idx7 ON landmark +(city, name); +---- + +.Query +[source,sqlpp] +---- +SELECT city AS City, COUNT(DISTINCT name) AS Landmark_Count +FROM landmark +WHERE city IS NOT MISSING +GROUP BY city +LETTING MinimumThingsToSee = COUNT(DISTINCT name) +HAVING MinimumThingsToSee > 180; +---- + +.Results +[source,json] +---- +[ + { + "City": "London", + "Landmark_Count": 443 + }, + { + "City": "Los Angeles", + "Landmark_Count": 284 + }, + { + "City": "San Diego", + "Landmark_Count": 197 + }, + { + "City": "San Francisco", + "Landmark_Count": 797 + } +] +---- +==== + +== Limitations + +The following are currently not supported and not pushed to the indexer: + +* `HAVING` or `LETTING` clauses, unless there is an aggregate function inside. +* `ORDER BY` clauses. +* `ARRAY_AGG()` or any facility to add new Aggregate function, such as Median. +* `LIMIT` pushdown with `GROUP BY` on non-leading keys. +* `OFFSET` pushdown with `GROUP BY` on non-leading keys. +* A subquery in a `GROUP BY` or Aggregate pushdown. +* `FILTER` clauses on aggregate functions. + +.Aggregate Comparison +[cols="^3,^2,^2,^2,^2"] +|=== +| Item | Aggregate on Non-Array Index Field | Aggregate on Array Index Field | DISTINCT Aggregate on Non-Array Index Field | DISTINCT Aggregate on Array Index Field + +| Supports `MIN()` and `MAX()` +| *✓* +| *✓* +| - +| - + +| Supports `SUM()` and `COUNT()` +| - +| *✓* +| *✓* +| *✓* + +| Supports `AVG()` +| *✓* +| *✓* +| *✓* +| *✓* + +| Supports `ARRAY_AGG()` +| - +| - +| - +| - +|=== + +[[filter-clause]] +=== FILTER Clause + +If the query block contains an aggregate function which uses the FILTER clause, the aggregation is not pushed down to the indexer. +As a workaround, if you require aggregation pushdown, you can use a comparison operator as the argument for the aggregate function. +For example: + +.Aggregate functions with FILTER clause +[source,sqlpp] +---- +SELECT + SUM(d.c3) FILTER (WHERE d.c2 IN ['X']), + COUNT(1) FILTER (WHERE d.c2 IN ['Y']) + ... +---- + +.Workaround using comparison operators +[source,sqlpp] +---- +SELECT + SUM (CASE WHEN d.c2 IN ['X'] THEN d.c3 ELSE 0 END), + COUNT (CASE WHEN d.c2 IN ['Y'] THEN 1 ELSE NULL END) + ... +---- + +[#section_bpf_wjf_ycb] +== Appendix: Query Plan Fields + +Consider the example: + +[source,sqlpp] +---- +CREATE INDEX idx_landmark_activity +ON landmark(activity); + +EXPLAIN SELECT activity, COUNT(activity) +FROM landmark +WHERE activity IS NOT MISSING +GROUP BY activity; +---- + +In the query plan: + +* `pass:c[plan.`~children`[0].covers]` shows that the index covers the query. +* `pass:c[plan.`~children`[0].index_group_aggs]` shows the aggregation and groupings done by the indexer. +* `index_group_aggs` object has details on the aggregate, index key position, expression dependency, and group expressions handled by the indexer. +This object is present in the plan only when the indexer handles the grouping and aggregation. + +[cols="2,5,5"] +|=== +| Item Name | Description | Explain Text in This Example + +| `aggregates` +| Array of Aggregate objects, and each object represents one aggregate function. +The absence of this item means there is no Aggregate function. +| `aggregates` + +| `+... aggregate+` +| Aggregate operation. +| `COUNT` + +| `+... depends+` +| List of index key positions the GROUP BY expression depends on, starting with 0. +| `0` + +(because it's the 1st item) + +| `+... expr+` +| Group expression or an aggregate expression. +| `pass:c["cover ((`landmark`.`activity`))"]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection` +| `2` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `0` + +(because it matches the 1st index key) + +| `depends` +| List of index key positions the GROUP BY expression depends on, starting with 0. +| `0` + +(because it's the 1st item) + +| `group` +| Array of GROUP BY objects, and each object represents one group key. +The absence of this item means there is no GROUP BY clause. +| `group` + +| `+... depends+` +| Index key position of a single GROUP BY expression +| `0` + +(because it's the 1st GROUP BY key) + +| `+... expr+` +| Single GROUP BY expression. +| `pass:c["cover ((`landmark`.`activity`))"]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection` +| `0` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `0` + +(because it matches the 1st key in the index expression) +|=== + +[source,json] +---- +{ + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((`landmark`.`activity`))", + "cover ((meta(`landmark`).`id`))", + "cover (count(cover ((`landmark`.`activity`))))" + ], + "index": "idx_landmark_activity", + "index_group_aggs": { // <1> + "aggregates": [ + { + "aggregate": "COUNT", + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`activity`))", + "id": 2, + "keypos": 0 + } + ], + "depends": [ + 0 + ], + "group": [ + { + "depends": [ + 0 + ], + "expr": "cover ((`landmark`.`activity`))", + "id": 0, + "keypos": 0 + } + ] + }, + "index_id": "ba98a2af8f4e0f4d", + "index_projection": { + "entry_keys": [ + 0, + 2 + ] + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "inclusion": 1, + "low": "null" + } + ] + } + ], + "using": "gsi" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "cover ((`landmark`.`activity`))" + }, + { + "expr": "cover (count(cover ((`landmark`.`activity`))))" + } + ] + } + ] + } + } + ] + }, + "text": "SELECT activity, COUNT(activity)\nFROM landmark\nWHERE activity IS NOT MISSING\nGROUP BY activity;" +} +---- + +<1> When the `index_group_aggs` section is present, it means that the query is using Index Aggregations. + +.GROUP BY Query Plan +[#table_bw2_nrf_ycb,cols="2,5,5"] +|=== +| Item Name | Description | EXPLAIN Text in <> (GROUP BY) + +| `aggregates` +| Array of Aggregate objects, and each object represents one aggregate function. +The absence of this item means there is no Aggregate function. +| `aggregates` + +| `+... aggregate+` +| Aggregate operation. +| `MAX` + +| `+... depends+` +| List of index key positions the GROUP BY expression depends on, starting with 0. +| `2` + +(because it's the 3rd item) + +| `+... expr+` +| Group expression or an aggregate expression. +| `pass:c[round(cover (((`landmark`. +`geo`).`lat`)))]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection` +| `4` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `-1` + +(because the index has the field `geo.lat` but the query adds the `ROUND()` function to `geo.lat`) + +| `depends` +| List of index key positions the GROUP BY expression depends on, starting with 0. +| `0, 1, 2` + +| `group` +| Array of GROUP BY objects, and each object represents one group key. +The absence of this item means there is no GROUP BY clause. +| `group` + +| `+... depends+` +| Index key position of a single GROUP BY expression, starting with 0. +| `0` + +(because it's the 1st GROUP BY key) + +| `+... expr+` +| Single GROUP BY expression. +| `pass:c[`landmark`.`country`]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection.` +| `0` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `0` + +(because it matches the first key in the index expression) +|=== + +The Query Plan sections of an Aggregate pushdown are slightly different than those used in a GROUP BY. + +.Aggregate Query Plan +[#docs-internal-guid-facfdbc0-bb3d-b00f-2ec0-6bee4921dabc,cols="2,5,5"] +|=== +| Item Name | Description | EXPLAIN Text in <> (Aggregate) + +| `aggregates` +| Array of Aggregate objects, and each object represents one aggregate function. +The absence of this item means there is no Aggregate function. +| `aggregates` + +| `+... aggregate+` +| Aggregate operation. +| `SUM` + +| `+... depends+` +| List of index key positions the GROUP BY expression depends on, starting with 0. +| `2` + +(because it's the 3rd item) + +| `+... expr+` +| Group expression or an aggregate expression. +| `pass:c["abs(round(cover (((`landmark`.`geo`).`lat`))))"]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection` +| `4` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `2` + +(because the query's 3rd key exactly matches the index's 3rd key) + +| `depends` +| List of index key positions the GROUP BY expression depends on, starting with 0. +| `0, 1, 2` + +| `group` +| Array of GROUP BY objects, and each object represents one group key. +The absence of this item means there is no GROUP BY clause. +| `group` + +| `+... depends+` +| Index key position of a single GROUP BY expression, starting with 0. +| `0` + +(because it's the 1st GROUP BY key) + +| `+... expr+` +| Single GROUP BY expression. +| `pass:c["cover ((`landmark`.`country`))"]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection.` +| `0` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `0` + +(because it matches the 1st key in the index expression) + +| `+... depends+` +| Index key position of a single GROUP BY expression, starting with 0. +| `1` + +(because it's the 2nd GROUP BY key) + +| `+... expr+` +| Single GROUP BY expression. +| `pass:c["cover ((`landmark`.`state`))"]` + +| `+... id+` +| Unique ID given internally and will be used in `index_projection.` +| `1` + +| `+... keypos+` +a| +Key Position to use the Index expr or the query expr. + +* A value > -1 means the group key exactly matches the corresponding index keys, where 0 is the 1st index key. +* A value of -1 means the group key does not match the index key and uses the query expression instead. +| `1` + +(because it matches the 2nd key in the index expression) +|=== + +== Related Links + +* xref:learn:services-and-indexes/indexes/index-scans.adoc#query-execution-details[Query Execution: Details] +* xref:n1ql:n1ql-language-reference/covering-indexes.adoc[Covering Indexes] +* xref:learn:services-and-indexes/indexes/index_pushdowns.adoc[Index Pushdown Optimizations] +* xref:learn:services-and-indexes/indexes/early-filters-and-pagination.adoc[Early Filters, Ordering and Pagination] diff --git a/modules/n1ql/pages/n1ql-language-reference/groupby.adoc b/modules/n1ql/pages/n1ql-language-reference/groupby.adoc new file mode 100644 index 000000000..82828b54f --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/groupby.adoc @@ -0,0 +1,268 @@ += GROUP BY Clause +:description: The GROUP BY clause arranges aggregate values into groups, based on one or more fields. +:imagesdir: ../../assets/images +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +Use the GROUP BY clause to arrange aggregate values into groups of one or more fields. +This `GROUP BY` clause follows the `WHERE` clause and can contain the optional `GROUP AS`, `LETTING`, and `HAVING` clauses. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=group-by-clause] +---- + +image::n1ql-language-reference/group-by-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +group-term:: <> icon:caret-down[] +group-as-clause:: <> icon:caret-down[] +letting-clause:: <> icon:caret-down[] +having-clause:: <> icon:caret-down[] + +[[group-term]] +=== Group Term + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=group-term] +---- + +image::n1ql-language-reference/group-term.png["Syntax diagram", align=left] + +At least one group term is required. + +[#group-term-args] +expr:: String or expression representing an xref:n1ql-language-reference/aggregatefun.adoc[aggregate function] or field to group together. + +alias:: Assigns another name to the group term. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the group term is optional. +If you assign an alias, the `AS` keyword may be omitted. + +[[group-as]] +=== GROUP AS Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=group-as-clause] +---- + +image::n1ql-language-reference/group-as-clause.png["Syntax diagram", align=left] + +JSON is a hierarchical format, and a fully featured JSON query language needs to be able to produce hierarchies of its own, with computed data at every level of the hierarchy. +The key feature of SQL{pp} that makes this possible is the `GROUP AS` clause. + +A query can include a `GROUP AS` clause only if it has a `GROUP BY` clause. +The effect of a `GROUP BY` clause is to hide the original objects in each group, exposing only the grouping expressions and special aggregation functions on the non-grouping fields. +The purpose of the `GROUP AS` clause is to make the original objects in the group visible to subsequent clauses. +As a result, the query can generate output data both for the group as a whole and for the individual objects inside the group. + +For each group, `GROUP AS` preserves all of the objects in the group, as they were before grouping, in an array. +The name of the array is the alias in the GROUP AS clause. +You can then use the array name in the `FROM` clause of a subquery to process and return the individual objects in the group. + +In the `GROUP AS` array, each object is wrapped in an outer object that gives it the name of the alias specified in the `FROM` clause, or its implicit alias if no alias was specified. +Identifying the objects with their aliases in this way helps avoid ambiguity. + +For example, a query has a `FROM` clause of `FROM airline as a, route as r`, and a `GROUP AS` clause of `GROUP AS g`. +The result of the `GROUP AS` clause is an array of objects, each of which contains both an airline object and a route object. +These objects might contain field names that are the same, such as `"id"`. +The resulting array `g` identifies each of the objects it contains separately with its alias, as follows: + +[source,json] +---- +[ + { + "a": { an original airline object }, + "r": { an original route object } + }, + { + "a": { an original airline object }, + "r": { an original route object } + }, + ... +] +---- + +[[letting-clause]] +=== LETTING Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=letting-clause] +---- + +image::n1ql-language-reference/letting-clause.png["Syntax diagram", align=left] + +[Optional] Stores the result of a sub-expression in order to use it in subsequent clauses. + +[#letting-clause-args] +alias:: String or expression representing the name of the clause to be referred to. + +expr:: String or expression representing the value of the `LETTING` [.var]`alias` variable. + +[[having-clause]] +=== HAVING Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=having-clause] +---- + +image::n1ql-language-reference/having-clause.png["Syntax diagram", align=left] + +[Optional] To return items where xref:n1ql-language-reference/aggregatefun.adoc[aggregate] values meet the specified conditions. + +[#having-clause-args] +cond:: String or expression representing the clause of aggregate values. + +== Limitations + +`GROUP BY` works only on a group key or xref:n1ql-language-reference/aggregatefun.adoc[aggregate function]. + +A query needs a predicate on a leading index key to ensure that the optimizer can select a secondary index for the query. +Without a matching predicate, the query will use the primary index. +The simplest predicate is `WHERE _leading-index-key_ IS NOT MISSING`. +This is usually only necessary in queries which do not otherwise have a WHERE clause; for example, some GROUP BY and aggregate queries. +For more details, refer to xref:n1ql:n1ql-language-reference/selectintro.adoc#index-selection[Index Selection]. + +== Examples + +.Group the unique landmarks by city and list the top 4 cities with the most landmarks in descending order +==== +[source,sqlpp] +---- +include::example$select/group-by.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-by.jsonc[] +---- +==== + +.Group airlines by country and also list all airlines for each country +==== +[source,sqlpp] +---- +include::example$select/group-as.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-as.jsonc[] +---- +==== + +.Group airlines by country and also list the name and id of two airlines from each country +==== +[source,sqlpp] +---- +include::example$select/group-as-subclause.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-as-subclause.jsonc[] +---- +==== + +.Use LETTING to find cities that have a minimum number of things to see +==== +[source,sqlpp] +---- +include::example$select/group-by-letting.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-by-letting.jsonc[] +---- +==== + +.Use HAVING to specify cities that have more than 180 landmarks +==== +[source,sqlpp] +---- +include::example$select/group-by-having.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-by-having.jsonc[] +---- +==== + +NOTE: The above `HAVING` clause must use the xref:n1ql-language-reference/aggregatefun.adoc[aggregate function] `COUNT` instead of its alias `LandmarkCount`. + +.Use HAVING to specify landmarks that begin with an "S" or higher +==== +[source,sqlpp] +---- +include::example$select/group-by-compare-having.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-by-compare.jsonc[tags=excerpt;ellipsis] +---- + +(execution: 1s docs: 138) +==== + +.Using WHERE yields the same results as HAVING, however, WHERE is faster +==== +[source,sqlpp] +---- +include::example$select/group-by-compare-where.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-by-compare.jsonc[tags=excerpt;ellipsis] +---- + +(execution: 480.2ms docs: 138) +==== + +NOTE: The `WHERE` clause is faster because `WHERE` gets processed _before_ any `GROUP BY` and doesn't have access to aggregated values. +`HAVING` gets processed _after_ `GROUP BY` and is used to constrain the resultset to only those with aggregated values. + +.Using an alias for a group term +==== +[source,sqlpp] +---- +include::example$select/group-by-alias.n1ql[] +---- + +.Results +[source,json] +---- +include::example$select/group-by-alias.jsonc[] +---- +==== + +NOTE: The `CASE` expression categorizes each landmark into the Western hemisphere if its longitude is negative, or the Eastern hemisphere otherwise. +The alias in the `GROUP BY` clause enables you to refer to the `CASE` expression in the `SELECT` clause. + +== Related Links + +* For further examples, refer to xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[Group By and Aggregate Performance]. diff --git a/modules/n1ql/pages/n1ql-language-reference/hints.adoc b/modules/n1ql/pages/n1ql-language-reference/hints.adoc new file mode 100644 index 000000000..de6000f71 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/hints.adoc @@ -0,0 +1,264 @@ += USE Clause +:description: The USE clause enables you to specify that the query should use particular keys, or a particular index. +:page-toclevels: 2 +:imagesdir: ../../assets/images +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `USE` clause enables you to specify that the query should use particular keys, or a particular index. + +== Purpose + +The `USE` clause is used within the xref:n1ql-language-reference/from.adoc[FROM] clause. +It enables you to provide a hint to the query service, specifying that the query should use particular keys, or a particular index. + +TIP: You can also supply an index hint within a specially-formatted xref:n1ql-language-reference/optimizer-hints.adoc[hint comment]. +Note that you cannot specify an index hint for the same keyspace using both the `USE` clause and a hint comment. +If you do this, the `USE` clause and the hint comment are both marked as erroneous and ignored by the optimizer. + +== Prerequisites + +For you to select data from a document or keyspace, you must have the [.param]`query_select` privilege on the document or keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-clause] +---- + +image::n1ql-language-reference/use-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +use-keys-clause:: <> icon:caret-down[] +use-index-clause:: <> icon:caret-down[] + +[#use-keys-clause] +== USE KEYS Clause + +=== Purpose + +You can refer to a document's unique document key by using the `USE KEYS` clause. +Only documents having those document keys will be included as inputs to a query. + +There is no optimizer hint equivalent to this clause. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-keys-clause] +---- + +image::n1ql-language-reference/use-keys-clause.png["Syntax diagram", align=left] + +[source#use-keys-term,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-keys-term] +---- + +image::n1ql-language-reference/use-keys-term.png["Syntax diagram", align=left] + +Synonym: `USE KEYS` and `USE PRIMARY KEYS` are synonyms. + +[horizontal.compact#use-keys-args] +expr:: String of a document key or an array of comma-separated document keys. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Select a single document by its document key +==== +[source,sqlpp] +---- +SELECT * +FROM airport +USE KEYS "airport_1254"; +---- + +.Results +[source,JSON] +---- +[ + { + "travel-sample": { + "airportname": "Calais Dunkerque", + "city": "Calais", + "country": "France", + "faa": "CQF", + "geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + }, + "icao": "LFAC", + "id": 1254, + "type": "airport", + "tz": "Europe/Paris" + } + } +] +---- +==== + +.Select multiple documents by their document keys +==== +[source,sqlpp] +---- +SELECT * +FROM airport +USE KEYS ["airport_1254","airport_1255"]; +---- + +.Results +[source,JSON] +---- +[ + { + "travel-sample": { + "airportname": "Calais Dunkerque", + "city": "Calais", + "country": "France", + "faa": "CQF", + "geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + }, + "icao": "LFAC", + "id": 1254, + "type": "airport", + "tz": "Europe/Paris" + } + }, + { + "travel-sample": { + "airportname": "Peronne St Quentin", + "city": "Peronne", + "country": "France", + "faa": null, + "geo": { + "alt": 295, + "lat": 49.868547, + "lon": 3.029578 + }, + "icao": "LFAG", + "id": 1255, + "type": "airport", + "tz": "Europe/Paris" + } + } +] +---- +==== + +[#use-index-clause] +== USE INDEX clause + +=== Purpose + +Use the `USE INDEX` clause to specify the index or indexes to be used as part of the query execution. +The query engine attempts to use a specified index if the index is applicable for the query. + +If necessary, you can omit the index name and just specify the index type. +In this case, the query service considers all the available indexes of the specified type. + +This clause is equivalent to the `INDEX` and `INDEX_FTS` optimizer hints. +For more details, refer to xref:n1ql-language-reference/keyspace-hints.adoc[Keyspace Hints]. + +If you attempt to use an index which is still scheduled for background creation, the request fails. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-index-clause] +---- + +image::n1ql-language-reference/use-index-clause.png["Syntax diagram", align=left] + +[source#use-index-term,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-index-term] +---- + +image::n1ql-language-reference/use-index-term.png["Syntax diagram", align=left] + +[source#index-ref,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-ref] +---- + +image::n1ql-language-reference/index-ref.png["Syntax diagram", align=left] + +[horizontal.compact#use-index-args] +index-name:: [Optional] String or expression representing an index to be used for the query. ++ +This argument is optional; if omitted, the query engine considers all available indexes of the specified index type. + +index-type:: <> icon:caret-down[] + +[#index-type] +==== USING clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-type] +---- + +image::n1ql-language-reference/index-type.png["Syntax diagram", align=left] + +Specifies which index form to use. + +`USING GSI`:: A Global Secondary Index, which lives on an index node and can possibly be separate from a data node. + +`USING FTS`:: A Full Text Search index, for use with queries containing xref:n1ql-language-reference/searchfun.adoc[Search functions]. +You can use this hint to specify that the query is a xref:n1ql:n1ql-language-reference/flex-indexes.adoc[Flex Index] query using a Full Text Search index. + +This clause is optional; if omitted, the default is `USING GSI`. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Use a specified Global Secondary Index +==== +This example uses the index `def_inventory_route_route_src_dst_day`, which is installed with the `travel-sample` bucket. + +The following query hints that the optimizer should select the specified index for the keyspace `route`. + +.INDEX hint +[source,sqlpp] +---- +include::example$select/index-legacy.n1ql[tag=query] +---- +==== + +.Use any suitable Full Text Search index +==== +Specify that the query service should prefer an FTS index, without specifying the index by name. +To qualify for this query, there must be an FTS index on state and type, using the keyword analyzer. +(Or alternatively, an FTS index on state, with a custom type mapping on "hotel".) + +[source,sqlpp] +---- +SELECT META().id +FROM hotel USE INDEX (USING FTS) +WHERE state = "Corse" OR state = "California"; +---- + +All FTS indexes are considered. +If a qualified FTS index is available, it is selected for the query. +If none of the available FTS indexes are qualified, the available GSI indexes are considered instead. +==== + +== Related Links + +* xref:n1ql-language-reference/join.adoc#ansi-join-hints[ANSI JOIN Hints] +* xref:n1ql-language-reference/optimizer-hints.adoc[Optimizer Hints] diff --git a/modules/n1ql/pages/n1ql-language-reference/identifiers.adoc b/modules/n1ql/pages/n1ql-language-reference/identifiers.adoc new file mode 100644 index 000000000..2d9cf266e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/identifiers.adoc @@ -0,0 +1,82 @@ += Identifiers +:description: An identifier is a symbolic reference to a value in the current context of a query. +:page-topic-type: reference +:imagesdir: ../../assets/images + +[abstract] +{description} +Identifiers can include keyspace names, fields within documents, and aliases. +{sqlpp} identifiers are case-sensitive. + +An identifier can either be escaped or unescaped. + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=identifier] +---- + +image::n1ql-language-reference/identifier.png["Syntax diagram", align=left] + +For example, if the current context is the document `{"name": "n1ql"}`, then the identifier `name` would evaluate to the value `n1ql`. + +== Unescaped Identifiers + +Unescaped identifiers cannot support the full range of identifiers allowed in a JSON document, but do support the most common ones with a simpler syntax. + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=unescaped-identifier] +---- + +image::n1ql-language-reference/unescaped-identifier.png["Syntax diagram", align=left] + +== Escaped Identifiers + +Escaped identifiers are surrounded by backticks `{backtick}` and support all identifiers in JSON. +You can use the backtick character within an escaped identifier by specifying two consecutive backtick characters. +Keywords cannot be escaped; therefore, escaped identifiers can overlap with keywords. + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=escaped-identifier] +---- + +image::n1ql-language-reference/escaped-identifier.png["Syntax diagram", align=left] + +For example, if you have a hyphen in an attribute name, it can be referred to as `{backtick}first-name{backtick}`. + +Identifiers can be expressed using the dot notation, where the left-most portion of a dotted identifier refers to the name of the data source. +For example, in the query `SELECT {backtick}beer-sample{backtick}.name FROM {backtick}beer-sample{backtick}`, `{backtick}beer-sample{backtick}.name` is a more formal way of expressing the identifier name. + +[#identifier-alias] +== Aliases + +Aliases give a temporary name to identifiers. + +When an alias collides with a keyspace or field name in the same scope, the identifier always refers to the alias. +This enables consistent behavior in scenarios where an identifier only collides in some documents. + +The following table describes some rules that apply when referring to the new names created by aliases: + +[cols="~,~"] +|=== +| Aliases in \... Clause | Create New Names That May be Referred to \... + +| WITH +| Anywhere within the scope of the given query block + +| FROM +| Anywhere within the scope of the given query block + +| LET +| Anywhere within the scope of the given query block + +| LETTING +| HAVING, SELECT, and ORDER BY clauses + +| SELECT +| SELECT and ORDER BY clauses + +| FOR +| The local collection expression +|=== diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc new file mode 100644 index 000000000..926aef492 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -0,0 +1,639 @@ += Index Partitioning +:imagesdir: ../../assets/images +:description: Index Partitioning enables you to increase aggregate query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. +:page-topic-type: reference + +:createindex: xref:n1ql-language-reference/createindex.adoc +:gbap: xref:n1ql-language-reference/groupby-aggregate-performance.adoc +:index-with: {createindex}#index-with +:rebalancing-the-index-service: xref:clusters:scale-database.adoc#rebalance + +{description} +The system partitions the index across a number of index nodes using a hash partitioning strategy in a way that is transparent to queries. + +[#idx-partition-intro] +-- +Benefits of a partitioned index include: + +* The ability to scale out horizontally as the index size increases. +* Transparency to queries, requiring no change to existing queries. +* Reduction of query latency for large aggregated queries since each partition can be scanned in parallel. +* Provides a low-latency range query while allowing indexes to be scaled out as needed. +-- +//// +Partitioned indexes are displayed in the Couchbase Web Console with a `partitioned` indicator: + +image::manage:manage-indexes/index-indicators.png[] +//// + +For further details, refer to xref:server:manage:manage-indexes/manage-indexes.adoc[Manage Indexes]. + +== Syntax + +To create a partitioned index, the overall syntax is the same as for a global secondary index. +The distinguishing feature is the use of the PARTITION BY HASH clause to specify the partitions. + +Refer to the {createindex}[CREATE INDEX] statement for details of the syntax. + + +[[index-partition,index-partition]] +=== PARTITION BY HASH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-partition] +---- + +image::n1ql-language-reference/index-partition.png["Syntax diagram: refer to source code listing", align=left] + +_partition-key-expr_:: +A field or an expression over a field representing a partition key. +For details and examples, refer to <>. + +[[index-with,index-with]] +=== WITH Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-with] +---- + +image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] + +When creating a partitioned index, you can use the WITH clause to specify additional options for the partitions. + +_expr_:: +An object with the following properties: + +num_partition;; +[Optional] An integer that defines the number of partitions to divide into. +The default value is 8. +For more details and examples, refer to <>. + +nodes;; +[Optional] An array of strings, specifying a list of nodes. +The node list to restrict the set of nodes available for placement. +Refer to the {index-with}[CREATE INDEX] statement for details of the syntax. +For more details and examples, refer to <>. + +defer_build;; +[Optional] Boolean. +When set to true, the index creation operation queues the task for building the index, but immediately pauses the building of the index. +Refer to the {index-with}[CREATE INDEX] statement for more details. + +num_replica;; +[Optional] An integer specifying the number of replicas of the partitioned index to create. +If this integer is greater than or equal to the number of index nodes in the cluster, then the index creation will fail. +Refer to the {index-with}[CREATE INDEX] statement for more details. + +secKeySize;; +[Optional] An integer, specifying the average length of the combined index keys. +For more details and examples, refer to <>. + +docKeySize;; +[Optional] An integer, specifying the average length of the document key. +For more details and examples, refer to <>. + +arrSize;; +[Optional] An integer, specifying the average length of the array fields. +For more details and examples, refer to <>. + +numDoc;; +[Optional] An integer, specifying the number of documents in the index. +For more details and examples, refer to <>. + +residentRatio;; +[Optional] An integer, specifying the resident ratio of the index. +For more details and examples, refer to <>. + +[[partition-keys]] +== Partition Keys + +Partition keys are made up of one or more terms, with each term being the document key, a document field, or an expression of document key or field. +The partition keys are hashed to generate a partition ID for each document. +The partition ID is then used to identify the partition in which the document's index keys would reside. + +The partition keys should be immutable, that is, its values shouldn't change once the document is created. +For example, in the `landmark` keyspace, the field named `activity` almost never changes, and is therefore a good candidate for partition key. +If the partition keys have changed, then the corresponding document should be deleted and recreated with the new partition keys. + +Each term in the partition keys can be any JSON data type: number, string, boolean, array, object, or NULL. +If a term in the partition keys is missing in the document, the term will have a {sqlpp} MISSING value. +Partition keys do not support {sqlpp} array expressions, e.g. `ARRAY` \... `FOR` \... `IN`. + +The following table lists some examples of partition keys. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +[cols="1,2"] +|=== +| Partition Type | Example + +.^| The document key. +a| +[source,sqlpp] +---- +include::example$n1ql-language-reference/partition-idx.n1ql[] +---- + +.^| Any single or multiple immutable field in the defined index. +a| +[source,sqlpp] +---- +CREATE INDEX idx ON route +(sourceairport, destinationairport, stops, airline, id) + PARTITION BY HASH(sourceairport,destinationairport); +---- + +.^| Any single or multiple immutable non-leading field in the defined index. +a| +[source,sqlpp] +---- +CREATE INDEX idx ON route +(airline, sourceairport, destinationairport, stops, id) + PARTITION BY HASH(sourceairport, destinationairport); +---- + +.^| Any single or multiple immutable document field not defined in the index. +a| +[source,sqlpp] +---- +CREATE INDEX idx ON route +(sourceairport, stops, airline, id) + PARTITION BY HASH (sourceairport, destinationairport); +---- + +.^| A function on the index fields, such as `LOWER(), LEAST(), GREATEST(), SUBSTR()`, etc. +a| +[source,sqlpp] +---- +CREATE INDEX idx ON route +(LOWER(sourceairport), LOWER(destinationairport), + stops, airline, id) + PARTITION BY HASH (LOWER(sourceairport), + LOWER(destinationairport)); +---- + +.^| A complex expression on the index fields combining functions and operators. +a| +[source,sqlpp] +---- +CREATE INDEX idx ON route +(POSITION(meta().id,'__')+2, destinationairport, + sourceairport, stops, airline, id) + PARTITION BY HASH(POSITION(meta().id,'__')+2)); +---- +|=== + +// Each partition key can have a different data type: +// +// [#ul_ewd_ydg_ndb] +// * Scalar +// * Array (whole array as a partition key, not as individual elements within an array) +// * JSON Object (whole JSON object as partition key, not as individual elements within the object) +// * [[ul_yrx_lhg_ndb]]MISSING value +// ** If the partition key is the leading index key, the document will not be indexed; +// ** Otherwise, a MISSING value is used as the partition value. +// * NULL value + +[#doc-keys-as-partition-key] +== Using Document Keys as Partition Key + +The simplest way to create a partitioned index is to use the document key as the partition key. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create a partitioned index with partition key being the document key +==== +[source,sqlpp] +---- +CREATE INDEX idx_pe1 ON airline (country, name, id) + PARTITION BY HASH(META().id); + +SELECT name, id +FROM airline +WHERE country="United States" +ORDER BY name; +---- +==== + +With [.cmd]`meta().id` as the partition key, the index keys are evenly distributed among all the partitions. +Every query will gather the qualifying index keys from all the partitions. + +[#partition-keys-range-query] +== Choosing Partition Keys for Range Query + +An application has the option to choose the partition key that can minimize latency on a range query for a partitioned index. +For example, let's say a query has an equality predicate based on the field `sourceairport` and `destinationairport`. +If the index is also partitioned by the index keys on `sourceairport` and `destinationairport`, then the query will only need to read a single partition for the given pair of `sourceairport` and `destinationairport`. +In this case, the application can maintain a low query latency while allowing the partitioned index to scale out as needed. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create a partitioned index with partition keys matching query equality predicate +==== +Lookup all airlines with non-stop flights from SFO to JFK. + +[source,sqlpp] +---- +CREATE INDEX idx_pe2 ON route +(sourceairport, destinationairport, stops, airline, id) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT airline, id +FROM route +WHERE sourceairport="SFO" AND +destinationairport="JFK" AND +stops == 0 +ORDER BY airline; +---- +==== + +The partition keys do not have to be the leading index keys in order to select qualifying partitions. +As long as the leading index keys are provided along with the partition keys in the predicate, the query engine can still select the qualifying partitions for index scan. +The following example scans a single partition with a given pair of `sourceairport` and `destinationairport`. + +.Create a partitioned index with partition keys being non-leading index keys +==== +Lookup all non-stop flights from SFO to JFK for the given airlines. + +[source,sqlpp] +---- +CREATE INDEX idx_pe3 ON route +(airline, sourceairport, destinationairport, stops, id) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT airline, id +FROM route +WHERE airline IN ["UA", "AA"] AND +sourceairport="SFO" AND +destinationairport="JFK" AND +stops == 0 +ORDER BY airline; +---- +==== + +If the partition keys are based on a {sqlpp} expression, then the query predicate should use the same expression for selecting qualifying partitions. + +.Create a partitioned index with partition keys as expressions +==== +Case-insensitive lookup for all airlines with non-stop flights from SFO to JFK. + +[source,sqlpp] +---- +CREATE INDEX idx_pe4 ON route +(LOWER(sourceairport), LOWER(destinationairport), stops, airline, id) + PARTITION BY HASH (LOWER(sourceairport), LOWER(destinationairport)) + +SELECT airline, id +FROM route +WHERE LOWER(sourceairport)="sfo" AND +LOWER(destinationairport)="jfk" AND +stops == 0 +ORDER BY airline +---- +==== + +As with equality predicate in the previous examples, the query engine can select qualifying partitions using an IN clause with matching partitioned keys. +The following example scans at most three partitions with `sourceairport "SFO"`, `"SJC"`, or `"OAK"`. + +.Create a partitioned index with partition keys matching query IN clause +==== +Lookup for all airlines with non-stop flights from SFO, SJC, or OAK to JFK. + +[source,sqlpp] +---- +CREATE INDEX idx_pe5 ON route +(sourceairport, destinationairport, stops, airline, id) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT airline, id +FROM route +WHERE sourceairport IN ["SFO", "SJC", "OAK"] AND +destinationairport="JFK" AND +stops == 0 +ORDER BY airline; +---- +==== + +As shown in the previous examples, in order to allow the query engine to select qualifying partitions, the partition keys must be present as an equality predicate in the query. +The following query only has an equality predicate on `sourceairport` and hence will not be able to select the qualifying partitions without `destinationairport`. +Consequently, this query will gather qualifying index keys from all partitions. + +.Create a partitioned index with non-matching query equality predicate +==== +Lookup all airlines with non-stop flights from SFO. + +[source,sqlpp] +---- +CREATE INDEX idx_pe6 ON route +(sourceairport, destinationairport, stops, airline, id) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT airline, id +FROM route +WHERE sourceairport="SFO" AND +stops == 0 +ORDER BY airline; +---- +==== + +Similarly, the following query gathers qualifying index keys from all partitions as `destinationairport IS NOT MISSING` is not an equality predicate. + +.Create a partitioned index with query non-equality predicate +==== +Lookup all airlines with non-stop flights from SFO. + +[source,sqlpp] +---- +CREATE INDEX idx_pe7 ON route +(sourceairport, destinationairport, stops, airline, id) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT airline, id +FROM route +WHERE sourceairport="SFO" AND +destinationairport is not missing AND +stops == 0 +ORDER BY airline; +---- +==== + +For the query engine to select qualifying partitions, the partition keys must also be a part of the index keys. +The following index always gathers keys from all partitions as `destinationairport` is not an index key. + +.Create a partitioned index with partition keys not being index keys +==== +Lookup all airlines with flights from SFO to JFK. + +[source,sqlpp] +---- +CREATE INDEX idx_pe8 ON route +(sourceairport, stops, airline, id) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT airline, id +FROM route +WHERE sourceairport="SFO" AND +destinationairport="JFK" +ORDER BY airline; +---- +==== + +When choosing partition keys other than the document key, the size of each partition can potentially be subjected to data skew of the chosen partition keys. +For example, for the index in the following example, the partitions containing the major airlines would have more entries since more index keys would end up hashing into the same partition. + +==== +[source,sqlpp] +---- +CREATE INDEX idx ON route +(airline, destinationairport, sourceairport) + PARTITION BY HASH(airline); +---- +==== + +During index rebalancing, the rebalancer takes into account the data skew among the partitions using runtime statistics. +It tries to even out resource utilization across the index service nodes by moving the partitions across the nodes when possible. + +== Choosing Partition Keys for Aggregate Query + +As with a range query, when an index is partitioned by document key, an aggregate query can gather the qualifying index keys from all the partitions before performing aggregation in the query engine. +Whenever aggregate pushdown optimization is allowed, the query engine will push down "partial aggregate" calculation to each partition. +The query engine then computes the final aggregate result from the partial aggregates across all the partitions. +For more details on aggregate query optimization, refer to {gbap}[Group By and Aggregate Performance]. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create a partitioned index with partition key being document key +==== +Find number of flights out of SFO for every destination across all airlines. + +[source,sqlpp] +---- +CREATE INDEX idx_pe9 ON route +(sourceairport, destinationairport, stops, airline, id, ARRAY_COUNT(schedule)) + PARTITION BY HASH (meta().id); + +SELECT sourceairport, destinationairport, SUM(ARRAY_COUNT(schedule)) +FROM route +WHERE sourceairport = "SFO" +GROUP BY sourceairport, destinationairport; +---- +==== + +The choice of partition keys can also improve aggregate query performance when the query engine can push down the "full aggregate" calculation to the index node. +In this case, the query engine does not have to recompute the final aggregate result from the index nodes. +In addition, certain pushdown optimizations can only be enabled when a full aggregate result is expected from the index node. +To enable a full aggregate computation, the index must be created with the following requirements: + +. The expressions in the GROUP BY clause must match the partition keys. +. The expressions in the GROUP BY clause must match the leading index keys. +. The partition keys must match the leading index keys. + +.Create a partitioned index with the partition keys for full aggregate pushdown +==== +Find number of flights out of SFO for every destination across all airlines. + +[source,sqlpp] +---- +CREATE INDEX idx_pe10 ON route +(sourceairport, destinationairport, stops, airline, id, ARRAY_COUNT(schedule)) + PARTITION BY HASH (sourceairport, destinationairport); + +SELECT sourceairport, destinationairport, SUM(ARRAY_COUNT(schedule)) +FROM route +WHERE sourceairport = "SFO" +GROUP BY sourceairport, destinationairport; +---- +==== + +== Number of Partitions + +The number of index partitions is fixed when the index is created. +By default, each index will have 8 partitions. +The Administrator can override the number of partitions at index creation time. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create a partitioned index with 16 partitions +==== +[source,sqlpp] +---- +CREATE INDEX idx_pe11 ON route +(airline, sourceairport, destinationairport) + PARTITION BY HASH(airline) WITH {"num_partition": 16}; +---- +==== + +== Partition Placement + +When a partitioned index is created, the partitions are created across available index nodes. +During placement of the new index, the index service assumes that each partition has an equal size and places the partitions according to the availability of resources on each node. +For example, if an index node has more available free memory than the other nodes, it will assign more partitions to this index node. +If the index has a replica, then the replica partition will not be placed onto the same node. + +Alternatively, you can specify the node list to restrict the set of nodes available for placement by using a command similar to the following example. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create a partitioned index on specific nodes +==== +[source,sqlpp] +---- +CREATE INDEX idx_pe12 ON route +(airline, sourceairport, destinationairport) + PARTITION BY HASH(airline) + WITH {"nodes": ["192.168.10.10:8091", "192.168.10.11:8091"]}; +---- +==== + +If you create a partitioned index on a specific set of nodes, and then decide that you want to specify a different set of nodes for partition placement, you need to remove the partitioned index and then recreate the partitioned index on a smaller or greater number of nodes. +However, refer also to the section on <> below. + +NOTE: To avoid any downtime, before removing the partitioned index, first create an equivalent index for your queries to continue using. + +[[sizing-hints]] +=== Sizing Hints + +You can optionally provide sizing hints too. +Given the sizing hints, the planner uses a formula to estimate the memory and CPU usage of the index. +Based on the estimated memory and CPU usage, the planner tries to place the partitions according to the free resources available to each index node. + +.Sizing Hints +[cols="2,5,2"] +|=== +| Optional Sizing Hint | Description | Example + +| *secKeySize* +| The average length of the combined index keys. +| `20` + +| *docKeySize* +| The average length of the document key `meta().id`. +| `20` + +| *arrSize* +| The average length of the array field. +Non-array fields will be ignored. +| `10` + +| *numDoc* +| The number of documents in the index. +| `7303` + +| *residentRatio* +| The memory usage of the index, as a percentage of its estimated data size. +| `50` +|=== + +To provide sizing estimation, you can use a command similar to the following examples. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create a partitioned index with specific key sizes +==== +[source,sqlpp] +---- +CREATE INDEX idx_pe13 ON route +(airline, sourceairport, destinationairport) + PARTITION BY HASH (airline) WITH {"secKeySize": 20, "docKeySize": 20}; +---- +==== + +.Create a partitioned index with specific key and array sizes +==== +[source,sqlpp] +---- +CREATE INDEX idx_pe14 ON route +(airline, sourceairport, schedule) + PARTITION BY HASH (airline) WITH {"secKeySize": 20, "docKeySize": 20, "arrSize": 100}; +---- +==== + +== Partition Replica + +A partitioned index can be created with multiple replicas to ensure indexes are online despite node failure. +if there are multiple server groups in a cluster, replica partitions will be spread out to each server group whenever possible. +If one of the server groups is offline, the remaining replica partitions will be available to serve all queries. +Every index replica is available to serve queries. +Therefore, index replicas can also be used to load rebalancing of query requests. + +[.server] +include::ROOT:partial$query-context.adoc[tag=section] + +.Create an index with replica +==== +[source,sqlpp] +---- +CREATE INDEX idx_pe15 ON route +(airline, sourceairport, schedule) + PARTITION BY HASH (airline) WITH {"num_replica": 2}; +---- +==== + +When an index node fails, any in-flight query requests (serviced by the failed node) will fail since the partial results are already being processed. +Any new query requests requiring the lost partition are then serviced by the partitions in the replica. + +[[rebalancing]] +== Rebalancing + +When new index nodes are added or removed from the cluster, the rebalance operation attempts to move the index partitions across available index nodes in order to balance resource consumptions. +At the time of rebalancing, the rebalance operation gathers statistics from each index. +These statistics are fed to an optimization algorithm to determine the possible placement of each partition in order to minimize the variation of resource consumption across index nodes. + +The rebalancer will only attempt to balance resource consumption on a best try basis. +There are situations where the resource consumption cannot be fully balanced. +For example: + +* The index service will not try to move the index if the cost to move an index across nodes is too high. +* A cluster has a mix of non-partitioned indexes and partitioned indexes. +* There is data skew in the partitions. + +In Couchbase Capella, the [def]_index redistribution_ setting enables you to specify how Couchbase Capella redistributes indexes on rebalance. +For further details, refer to {rebalancing-the-index-service}[Rebalancing the Index Service]. + +== Repairing Failed Partitions + +When an index node fails, the index partitions on that node will be lost. +The lost partitions can be recovered or repaired when: + +. The failed node is delta-recovered. +. The failed node is rebalanced out of the cluster. +The lost partitions on that node can be repaired/rebuilt in other index nodes whenever possible. +The lost partitions cannot be repaired when the number of remaining nodes is less than or equal to the number of index replicas. + +== Performance Considerations + +=== Max Parallelism + +Along with aggregate pushdown optimization, an application can further enhance the aggregate query performance by computing aggregation in parallel for each partition in the index service. +This can be controlled by specifying the parameter `max_parallelism` when issuing a query. +In Couchbase Capella, `max_parallelism` is set by default to match the number of partitions of the index. +Note that when `max_parallelism` is set to the default value, the index service uses more CPU and memory since the query traffic is increased. + + +=== OFFSET Pushdown + +When there are more than one qualifying partitions involved in a range query, the query engine will not push down the OFFSET clause to the index service. +Without partition elimination, a partitioned index will have higher overhead for queries with a large OFFSET value. +Alternatively, applications can use `keyset` based pagination with partitioned index to achieve good pagination query performance, detailed in this blog https://blog.couchbase.com/offset-keyset-pagination-n1ql-query-couchbase/[Database Pagination: Using OFFSET and Keyset in N1QL^]. + +For aggregate queries, the query engine will pushdown the OFFSET clause whenever full aggregate result is expected and there is only 1 qualifying partition involved in the query. + +=== LIMIT Pushdown + +When there are more than one qualifying partitions involved in a range query, the query engine will pushdown the LIMIT clause by rewriting it to be the sum of values in the LIMIT clause and OFFSET clause. + +For aggregate queries, the query engine will pushdown the LIMIT clause whenever a full aggregate result is expected. +When there are more than one qualifying partitions involved in an aggregate query, the query engine will pushdown the LIMIT clause by rewriting it to be the sum of values in the LIMIT clause and OFFSET clause. + +=== DISTINCT Aggregate Pushdown + +The query engine will not pushdown distinct aggregate calculation to the index node unless full aggregate result is expected. diff --git a/modules/n1ql/pages/n1ql-language-reference/index.adoc b/modules/n1ql/pages/n1ql-language-reference/index.adoc new file mode 100644 index 000000000..8fe18b02f --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/index.adoc @@ -0,0 +1,124 @@ += {sqlpp} for Query Reference +:description: This reference guide describes the syntax and structure of {sqlpp} for Query. +:page-topic-type: reference +:page-toclevels: 2 +:imagesdir: ../../assets/images + +:createindex: xref:n1ql-language-reference/createindex.adoc +:alterindex: xref:n1ql-language-reference/alterindex.adoc +:dropindex: xref:n1ql-language-reference/dropindex.adoc +:selectintro: xref:n1ql-language-reference/selectintro.adoc +:insert: xref:n1ql-language-reference/insert.adoc +:update: xref:n1ql-language-reference/update.adoc +:delete: xref:n1ql-language-reference/delete.adoc +:upsert: xref:n1ql-language-reference/upsert.adoc + +// TEMP +include::partial$n1ql-language-reference/column-style.adoc[] + +[abstract] +{description} +It provides information about the basic elements which can be combined to build {sqlpp} statements. +The Couchbase implementation of {sqlpp} was formerly known as https://www.couchbase.com/products/n1ql[N1QL^]. + +[[n1ql-language-structure]] +The {sqlpp} language is composed of <>, <>, and <>. + +[[statements]] +== Statements + +{sqlpp} statements are categorized into the following groups: + +* *Data Definition Language* (DDL) statements to {createindex}[create indexes], {alterindex}[modify indexes], and {dropindex}[drop indexes]. +* *Data Manipulation Language* (DML) statements to {selectintro}[select], {insert}[insert], {update}[update], {delete}[delete], and {upsert}[upsert] data into JSON documents. + +[[N1QL_Expressions]] +== Expressions + +The following are the different types of {sqlpp} expressions: + +[.two-columns] +* xref:n1ql-language-reference/literals.adoc[Literal values] +* xref:n1ql-language-reference/identifiers.adoc[Identifiers] +* xref:n1ql-language-reference/arithmetic.adoc[Arithmetic terms] +* xref:n1ql-language-reference/comparisonops.adoc[Comparison terms] +* xref:n1ql-language-reference/stringops.adoc[Concatenation terms] +* xref:n1ql-language-reference/logicalops.adoc[Logical terms] +* xref:n1ql-language-reference/conditionalops.adoc[Conditional expressions] +* xref:n1ql-language-reference/collectionops.adoc[Collection expressions] +* xref:n1ql-language-reference/constructionops.adoc[Construction expressions] +* <> +* xref:n1ql-language-reference/sequenceops.adoc[Sequence expressions] +* xref:n1ql-language-reference/functions.adoc[Function calls] +* xref:n1ql-language-reference/subqueries.adoc[Subqueries] + +[#nested-path-exp] +=== Nested Path Expressions + +In {sqlpp}, _nested paths_ indicate an expression to access nested sub-documents within a JSON document or expression. + +For example, in the document below, the latitude of an airport is stored within the `geo` sub-document, and can be addressed using the nested path `geo.lat`: + +==== +[source,json] +---- +[ + { + "airportname": "Calais Dunkerque", + "city": "Calais", + "geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + }, + "latitude": 51, + // ... + } +] +---- +==== + +You can use xref:n1ql-language-reference/nestedops.adoc[nested operators] to access sub-document fields within a document. + +[[comments]] +== Comments + +{sqlpp} supports _block comments_ and _line comments_. + +=== Block Comments + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=block-comment] +---- + +image::n1ql-language-reference/block-comment.png["Syntax diagram", align=left] + +A block comment starts with `/{asterisk}` and ends with `{asterisk}/`. +The query engine ignores the start and end markers `/{asterisk} {asterisk}/`, and any text between them. + +A block comment may start on a new line, or in the middle of a line after other {sqlpp} statements. +A block comment may contain line breaks. + +There may also be further {sqlpp} statements on the same line after the end of a block comment -- the query engine does _not_ ignore these. + +=== Line Comments + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=line-comment] +---- + +image::n1ql-language-reference/line-comment.png["Syntax diagram", align=left] + +You can use line comments in Couchbase Capella. +A line comment starts with two hyphens `--`. +The query engine ignores the two hyphens, and any text following them up to the end of the line. + +A line comment may start on a new line, or in the middle of a line after other {sqlpp} statements. +A line comment may not contain line breaks. + +=== Optimizer Hints + +In Couchbase Capella you can supply hints to the optimizer within a specially-formatted _hint comment_. +For further details, refer to xref:n1ql-language-reference/optimizer-hints.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/indexing-arrays.adoc b/modules/n1ql/pages/n1ql-language-reference/indexing-arrays.adoc new file mode 100644 index 000000000..bfdb54b49 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/indexing-arrays.adoc @@ -0,0 +1,1020 @@ += Array Indexing +:description: Array Indexing adds the capability to create global indexes on array elements and optimizes the execution of queries involving array elements. +:imagesdir: ../../assets/images +:page-topic-type: reference + +:expression: xref:n1ql-language-reference/index.adoc +:createindex: xref:n1ql-language-reference/createindex.adoc +:install-sample-buckets: xref:clusters:data-service/import-data-documents.adoc#import-sample-data +:covering-indexes: xref:indexes:covering-indexes.adoc +:use-index-clause: xref:n1ql-language-reference/hints.adoc#use-index-clause +:index-selection: xref:n1ql-language-reference/selectintro.adoc#index-selection +:flatten-keys: xref:n1ql-language-reference/metafun.adoc#flatten_keys + +{description} + +This is a huge leap from the previous versions where secondary indexes could only be created and subsequently queried on whole arrays. +You can now create an index of array elements ranging from plain scalar values to complex arrays or JSON objects nested deeper in the array. + +== Syntax + +To create an array index, the overall syntax is the same as for a global secondary index. +The distinguishing feature is the use of an array expression as an index key. + +Refer to the {createindex}[CREATE INDEX] statement for details of the syntax. + +[[index-key,index-key]] +=== Index Key + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-key] +---- + +image::n1ql-language-reference/index-key.png["Syntax diagram: refer to source code listing", align=left] + +To create an array index, one index key must be an array expression. +The index key containing the array expression is referred to as the _array index key_. +The index definition may also contain other index keys which are not array expressions. + +[[index-key-args]] +expr:: +A {sqlpp} {expression}[expression] over any fields in the document. +This cannot use constant expressions, aggregate functions, or sub-queries. + +array-expr:: +An array expression. +Refer to <> below. + +[IMPORTANT] +.Array Index Key +==== +Currently, the index definition for an array index may only contain one array index key. +However, the array index key may index more than one field or expression within the array, as described below. + +For an UNNEST scan to use an array index, the array index key containing the appropriate array expression must be the _leading key_ of the index definition. +The UNNEST scan can generate index spans on other non-leading index keys when appropriate predicates exist. + +In order for the optimizer to select the correct array index for a SELECT, UPDATE, or DELETE statement, the query predicate which appears in the WHERE clause must be constructed to match the format of the array index key. +See <> for details. +==== + +In Couchbase Capella, you can add the `INCLUDE MISSING` modifier to a leading array index key, just as you can with any other leading index key, in order to index documents in which the specified array is missing. + +[[array-expr]] +=== Array Expression + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=array-expr] +---- + +image::n1ql-language-reference/array-expr.png["Syntax diagram: refer to source code listing", align=left] + +The array expression can be either a <>, which uses the `ARRAY` operator to index specified fields and elements within the array; or a <>, which indexes all fields and elements in the array. + +[[full-array-expr,full array expression]] +==== Full Array Expression + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=full-array-expr] +---- + +image::n1ql-language-reference/full-array-expr.png["Syntax diagram: refer to source code listing", align=left] + +The `ARRAY` operator lets you map and filter the elements or attributes of a collection, object, or objects. +It evaluates to an array of the operand expression that satisfies the WHEN clause, if specified. + +[[full-array-expr-args]] +var-expr:: +A function of the `var` variable used in the FOR clause. + +var:: +Represents elements in the array specified by `expr`. + +expr:: +Evaluates to an array of objects, elements of which are represented by the `var` variable. + +cond:: +Specifies predicates to qualify the subset of documents to include in the index array. + +[NOTE] +.Variable Expression +==== +In Couchbase Capella, you can index one or more expressions _within_ the array (up to maximum of 32) by using the {flatten-keys}[FLATTEN_KEYS()] function in the `var-expr`. +This function flattens expressions within the array, as if they were separate index keys; and all subsequent index keys are accordingly moved to the right. +Queries will be {index-selection}[sargable] and will generate spans. +Refer to <> below. + +The `var-expr` itself may be a nested <>. +This enables creating array indexes on nested array fields. +Refer to <> below. + +To create an array index involving multiple array elements or multiple arrays, you may construct the `var-expr` as a compound object constituted with different elements of the same array or multiple arrays. +Refer to <> below. +==== + +In Couchbase Capella, you can add the `INCLUDE MISSING` modifier to the first argument in the {flatten-keys}[FLATTEN_KEYS()] function, in order to index array elements in which the specified field is missing. + +[[simple-array-expr,simple array expression]] +==== Simple Array Expression + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=simple-array-expr] +---- + +image::n1ql-language-reference/simple-array-expr.png["Syntax diagram: refer to source code listing", align=left] + +Couchbase Capella provides a simpler syntax for array indexing when all array elements are indexed as is, without needing to use the `ARRAY` operator in the index definition. + +[[simple-array-expr-args]] +expr:: +An array field name, or an expression that can evaluate to an array. +In this case, all fields and elements of the array are indexed. + +[#query-predicate-format] +== Format of Query Predicate + +In order for the optimizer to select the correct array index for a SELECT, UPDATE, or DELETE statement, the query predicate which appears in the WHERE clause must be constructed to match the format of the array index key. + +Consider the following expressions used in a CREATE INDEX statement: + +[cols=2*a,frame=none,grid=none] +|=== +| +.C1 +[source#c1,n1ql] +---- +DISTINCT ARRAY f(x) FOR x IN expr1 END; +---- +| +.C2 +[source#c2,n1ql] +---- +DISTINCT ARRAY f(x) FOR x WITHIN expr1 END; +---- +|=== + +And the following expressions used in the SELECT statement WHERE clause: + +[cols=2*a,frame=none,grid=none] +|=== +| +.Q1 +[source#q1,n1ql] +---- +ANY x IN expr2 SATISFIES g(x) END; +---- +| +.Q2 +[source#q2,n1ql] +---- +ANY x WITHIN expr2 SATISFIES g(x) END; +---- +|=== + +The following dependencies must be satisfied for the Query service to consider the array index: + +* The index keys used in CREATE INDEX must be used in the WHERE clause. +(The query can use different variable names from those used in the array index definition.) + +* The `expr2` in <> and <> must be equivalent to the `expr1` in <> and <>. +This is a formal notion of equivalence. +For example, they must be the same expressions, or equivalent arithmetic expressions such as `(x+y)` and `(y+x)`. + +* Usually, `g(x)` in <> and <> must be sargable for `f(x)` in <> and <>. +In other words, if there were a scalar index with key `f(x)`, then that index would be applicable to the predicate `g(x)`. +For example, the predicate `UPPER(x) LIKE "John%"` is sargable for the index key `UPPER(x)`. + +[discrete] +===== Flatten Keys + +Now consider the following variants of <> and <>, in which the index key `f(x)` uses the {flatten-keys}[FLATTEN_KEYS()] function to flatten expressions within the array: + +[cols=2*a,frame=none,grid=none] +|=== +| +.C3 +[source#c3,n1ql] +---- +DISTINCT ARRAY + FLATTEN_KEYS(f1(x) ASC, f2(x) DESC) + FOR x IN expr1 END; +---- +| +.C4 +[source#c4,n1ql] +---- +DISTINCT ARRAY + FLATTEN_KEYS(f1(x) ASC, f2(x) DESC) + FOR x WITHIN expr1 END; +---- +|=== + +* The index keys <> and <> flatten expressions within the array, as if they were separate index keys; and all subsequent index keys are accordingly moved to the right. +Queries will be sargable and will generate spans. + +* In order to select an array index defined using <> or <>, the predicate `g(x)` in <> and <> must be sargable for one of the _arguments_ of the {flatten-keys}[FLATTEN_KEYS()] function -- `f1(x)` or `f2(x)`. + +[discrete] +===== IN vs. WITHIN + +* Index key <> can be used for query predicate <>. +Index key <> can be used for both query predicates <> and <>. + +* Index key <> is strictly more expensive than index key <>, for both index maintenance and query processing. +Index key <> and query predicate <> are very powerful. +They can efficiently index and query recursive trees of arbitrary depth. + +[#examples] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[example-1]] +.Array index of distinct elements +==== +.Index: Create an index on all schedules +[[C1,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_sched +ON route +( DISTINCT ARRAY v.flight FOR v IN schedule END ); +---- + +.Query: Find the list of scheduled 'UA' flights +[[Q1,Query]] +[source,sqlpp] +---- +SELECT * FROM route +WHERE ANY v IN schedule SATISFIES v.flight LIKE 'UA%' END; +---- +==== + +[[example-2]] +.Partial array index +==== +Create a partial index (with WHERE clause) of individual attributes from selected elements (using WHEN clause) of an array. + +.Index: Create an index on flights from San Francisco scheduled in the first 4 days of the week +[[C2,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_flight_sfo +ON route +( ALL ARRAY v.flight FOR v IN schedule WHEN v.day < 4 END ) +WHERE sourceairport = "SFO"; +---- + +.Query: Find the list of scheduled 'UA' flights on day 1 +[[Q2,Query]] +[source,sqlpp] +---- +SELECT * FROM route +WHERE sourceairport = "SFO" -- <1> +AND ANY v IN schedule SATISFIES (v.flight LIKE 'UA%') -- <2> +AND (v.day=1) END; -- <3> +---- + +In this example, the <> qualifies for the <> because: + +<1> The <> predicate `sourceairport = "SFO"` matches that of the partial index WHERE clause. +<2> The ANY operator uses the index key `v.flight` on which <> is defined. +<3> The ANY-SATISFIES condition `v.day=1` in the <> is sargable to the WHEN clause condition `v.day < 4` in the index definition. +==== + +[[example-3]] +.Flattened array index +==== +.Index: Create an index on day and flight from schedule array +[[C3,Index]] +[source,sqlpp] +---- +CREATE INDEX ixf_sched + ON route + (ALL ARRAY FLATTEN_KEYS(s.day DESC, s.flight) FOR s IN schedule END, + sourceairport, destinationairport, stops); +---- + +.Query A: Find the weekday Delta flights FROM SFO to ATL +[[Q3A,Query A]] +[source,sqlpp] +---- +SELECT META(r).id + FROM route AS r + WHERE r.sourceairport = "SFO" -- <1> + AND r.destinationairport = "ATL" -- <2> + AND ANY s IN r.schedule SATISFIES s.day BETWEEN 1 AND 5 -- <3> + AND s.flight LIKE "DL%" END; -- <4> +---- + +In this example, <> is able to use the `ixf_sched` index defined by the <>, pass all the predicate information to index scan, and cover the query. + +.Partial Explain Plan +[source,JSON] +---- +"spans": [ + { + "exact": true, + "range": [ + { + "high": "5", + "inclusion": 3, + "index_key": "(`s`.`day`)", // <3> + "low": "1" + }, + { + "high": "\"DM\"", + "inclusion": 1, + "index_key": "(`s`.`flight`)", // <4> + "low": "\"DL\"" + }, + { + "high": "\"SFO\"", + "inclusion": 3, + "index_key": "`sourceairport`", // <1> + "low": "\"SFO\"" + }, + { + "high": "\"ATL\"", + "inclusion": 3, + "index_key": "`destinationairport`", // <2> + "low": "\"ATL\"" + } + + ] + } + ] +---- + +<1> `r.sourceairport = "SFO"` is able to match and pass to IndexScan. +<2> `r.destinationairport = "ATL"` is able to match and pass to IndexScan. +<3> ARRAY predicate `s.day BETWEEN 1 AND 5` is able to match and pass to IndexScan. +<4> ARRAY predicate `s.flight LIKE "DL%"` is able to match and pass to IndexScan. + +.Query B: Find the weekday Delta flights from SFO to ATL +[[Q3B,Query B]] +[source,sqlpp] +---- +SELECT s.day, s.flight,r.sourceairport, r.destinationairport, r.stops +FROM route AS r +UNNEST r.schedule AS s +WHERE r.sourceairport = "SFO" AND r.destinationairport = "ATL" + AND s.day BETWEEN 1 AND 5 AND s.flight LIKE "DL%" +ORDER BY s.day DESC +OFFSET 2 +LIMIT 3; +---- + +This query performs a covering UNNEST IndexScan, by applying all the predicates, using the `ixf_sched` index defined by the <>. +Even though the ORDER BY key uses an array index key, it can use index order, and pass LIMIT and OFFSET to the indexer. +==== + +[[example-missing]] +.Array index with missing leading key +==== + +The following statement creates an index of flight numbers from the `schedule` array for all routes. +If the schedule array is missing from any route, that route is indexed anyway. + +Compare this statement with the <> in <>. + +.Index I: Create an array index, including missing leading key +[source,sqlpp] +---- +CREATE INDEX idx_sched_missing +ON route +(DISTINCT ARRAY v.flight FOR v IN schedule END INCLUDE MISSING); +---- + +The following statement creates a flattened index on the time (`utc`) and day from the `schedule` array for all routes. +If the `utc` element is missing from any schedule, that schedule is indexed anyway. + +.Index II: Create a flattened array index, including missing leading key +[source,sqlpp] +---- +CREATE INDEX ixf_sched_missing +ON route +(DISTINCT ARRAY FLATTEN_KEYS(v.utc INCLUDE MISSING, v.day) FOR v IN schedule END); +---- +==== + +[[example-4]] +.Composite array index +==== +.Index: Create an index on individual elements of an array and other non-array fields +[[C4,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_flight_stops +ON route + ( stops, DISTINCT ARRAY v.flight FOR v IN schedule END ); +---- + +.Query: Find the list of scheduled 'FL' flights that have one or more stops +[[Q4,Query]] +[source,sqlpp] +---- +SELECT * FROM route +WHERE stops >=1 +AND ANY v IN schedule SATISFIES v.flight LIKE 'FL%' END; +---- +==== + +[[example-5]] +.Nested array index +==== +WARNING: Please note that the example below will alter the data in your sample buckets. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +.Update: Create a nested array +[source,sqlpp] +---- +UPDATE route +SET schedule[0] = {"day" : 7, "special_flights" : + [ {"flight" : "AI444", "utc" : "4:44:44"}, + {"flight" : "AI333", "utc" : "3:33:33"} + ] } +WHERE destinationairport = "CDG" AND sourceairport = "TLV"; +---- + +Use the DISTINCT ARRAY clause in a nested fashion to index specific attributes of a document when the array contains other arrays or documents that contain arrays. + +.Index I: Create a partial index on a nested array +[[C5i,Index I]] +[source,sqlpp] +---- +CREATE INDEX idx_nested ON route + (DISTINCT ARRAY + (DISTINCT ARRAY y.flight -- <1> + FOR y IN x.special_flights END) + FOR x IN schedule END); +---- + +<1> In this case, the inner ARRAY construct is used as the `var_expr` for the outer ARRAY construct in the {sqlpp} Syntax above. + +.Query A: Use nested ANY operator to use the index +[[Q5A,Query A]] +[source,sqlpp] +---- +SELECT count(*) FROM route +WHERE ANY x in schedule SATISFIES + (ANY y in x.special_flights SATISFIES y.flight IS NOT NULL END) +END; +---- + +This query uses the index `idx_nested` defined by <>. +It returns 3 results, as there are 3 routes with special flights. + +.Query B: Use UNNEST operators to use the index +[[Q5B,Query B]] +[source,sqlpp] +---- +SELECT count(*) FROM route +UNNEST schedule AS x +UNNEST x.special_flights AS y +WHERE y.flight IS NOT NULL; +---- + +This query uses the index `idx_nested` defined by <>. +It returns 6 results, as there are 3 routes with 2 special flights each. + +.Index II: Create a flattened index on a nested array +[[C5ii,Index II]] +[source,sqlpp] +---- +CREATE INDEX ixf_sched_nested ON route + (ALL ARRAY + (ALL ARRAY FLATTEN_KEYS(s.day, sf.flight) + FOR sf IN s.special_flights END) + FOR s IN schedule END); +---- + +.Query C: Use nested ANY operator to use the index +[[Q5C,Query C]] +[source,sqlpp] +---- +SELECT RAW count(1) +FROM route AS r +WHERE ANY s IN schedule + SATISFIES (ANY sf IN s.special_flights + SATISFIES sf.flight IS NOT NULL AND s.day = 7 + END) + END; +---- + +This query performs a covering UNNEST IndexScan, by applying the predicates on both levels of the ARRAY, using the index `ixf_sched_nested` defined by <>. + +.Query D: Use UNNEST operators to use the index +[[Q5D,Query D]] +[source,sqlpp] +---- +SELECT RAW count(1) +FROM route AS r +UNNEST r.schedule AS s +UNNEST s.special_flights AS sf +WHERE sf.flight IS NOT NULL AND s.day = 7; +---- + +This query performs a covering UNNEST IndexScan, by applying the predicates on both levels of the ARRAY, using the index `ixf_sched_nested` defined by <>; and uses index aggregation. +==== + +[[example-6]] +.Array index on compound object +==== +.Index: Create an index on multiple elements of an array +[[C6,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_flight_day ON route + (DISTINCT ARRAY [v.flight, v.day] FOR v IN schedule END); +---- + +.Query: Find the list of scheduled 'US681' flights on day 2 +[[Q6,Query]] +[source,sqlpp] +---- +SELECT meta().id FROM route +WHERE ANY v in schedule SATISFIES [v.flight, v.day] = ["US681", 2] END; +---- +==== + +[[example-7]] +.Simplified array index +==== +.Index: Create an index on all schedules using simplified array index syntax +[[C7,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_sched_simple +ON route (ALL schedule); +---- + +The following queries find details of all route documents matching a specific schedule. + +.Query A: Use ANY operator to use the index +[[Q7A,Query A]] +[source,sqlpp] +---- +SELECT * FROM route +WHERE ANY v IN schedule +SATISFIES v = {"day":2, "flight": "US681", "utc": "19:20:00"} END; -- <1> +---- + +<1> Elements of the schedule array are objects, and hence the right side value of the predicate condition should be a similarly structured object. + +.Query B: Use UNNEST operator to use the index +[[Q7B,Query B]] +[source,sqlpp] +---- +SELECT * FROM route t +UNNEST schedule sch +WHERE sch = {"day":2, "flight": "US681", "utc": "19:20:00"}; +---- + +This is a variant of <> using UNNEST in the SELECT statement. + +.Query C: Alternative using a flattened array index +[[Q7C,Query C]] +[source,sqlpp] +---- +SELECT META(r).id +FROM route AS r +WHERE ANY v IN r.schedule SATISFIES v.day = 2 AND v.flight = "US681" END; +---- + +For comparison, this query performs a covering index scan, by applying all the predicates, using `ixf_sched` defined by the <> in <>. +The query syntax is more intuitive than <> and <>, since the multiple fields within the array have not required complex indexing. +==== + +== Covering Array Index + +Covering indexes are an efficient method of using an Index for a particular query, whereby the index itself can completely cover the query in terms of providing all data required for the query. +Basically, it avoids the fetch phase of the query processing and related overhead in fetching the required documents from data-service nodes. +For more details, see {covering-indexes}[Covering Indexes]. + +Array indexing requires special attention to create covering array indexes. +In general, the array field itself should be included as one of the index keys in the CREATE INDEX definition. +For instance, in <>, the <> does not cover the <> because the <> projection list includes * which needs to fetch the document from the Data Service. + +include::ROOT:partial$query-context.adoc[tag=section] + +[[example-8]] +.Covering Array Index +==== +.Index I: Creating a Covering Array Index +[[C8i,Index I]] +[source,sqlpp] +---- +CREATE INDEX idx_sched_cover ON route + (DISTINCT ARRAY v.flight FOR v IN schedule END, schedule); +---- + +The index keys of an index must be used in the WHERE clause of a DML statement to use the index for that query. +In the SELECT or DML WHERE clause, Covering Array Indexes can be used by the following operators: + +* ANY: As shown in <> below. +* ANY AND EVERY: As shown in <> (a variant of <>) below. + +.Query A: Covering Array Index using the ANY clause +[[Q8A,Query A]] +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +USE INDEX (idx_sched_cover) -- <1> +WHERE ANY v IN schedule SATISFIES v.flight LIKE 'UA%' END; +---- + +<1> In this example, <> needs <> to cover it because the query predicate refers to the array `schedule` in the ANY operator. + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((distinct (array (`v`.`flight`) for `v` in (`route`.`schedule`) end)))", + "cover ((`route`.`schedule`))", + "cover ((meta(`route`).`id`))" + ], + "filter": "cover (any `v` in (`route`.`schedule`) satisfies ((`v`.`flight`) like \"UA%\") end)", + "filter_covers": { + "cover (any `v` in (`route`.`schedule`) satisfies ((\"UA\" <= (`v`.`flight`)) and ((`v`.`flight`) < \"UB\")) end)": true, + "cover (any `v` in (`route`.`schedule`) satisfies ((`v`.`flight`) like \"UA%\") end)": true + }, + "index": "idx_sched_cover", + // ... + } + } + ] + } + } +] +---- + +.Query B: Covering Array Index using the ANY AND EVERY clause +[[Q8B,Query B]] +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +USE INDEX (idx_sched_cover) +WHERE ANY AND EVERY v IN schedule SATISFIES v.flight LIKE 'UA%' END; +---- + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((distinct (array (`v`.`flight`) for `v` in (`route`.`schedule`) end)))", + "cover ((`route`.`schedule`))", + "cover ((meta(`route`).`id`))" + ], + "filter": "any and every `v` in cover ((`route`.`schedule`)) satisfies ((`v`.`flight`) like \"UA%\") end", + "index": "idx_sched_cover", + // ... + } + } + ] + } + } +] +---- + +.Query C: Covering Array Index using the UNNEST clause and aliasing +[[Q8C,Query C]] +[source,sqlpp] +---- +EXPLAIN SELECT meta(t).id FROM route t +USE INDEX (idx_sched_cover) +UNNEST schedule v +WHERE v.flight LIKE 'UA%'; +---- + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "as": "t", + "bucket": "travel-sample", + "covers": [ + "cover ((distinct (array (`v`.`flight`) for `v` in (`t`.`schedule`) end)))", + "cover ((`t`.`schedule`))", + "cover ((meta(`t`).`id`))" + ], + "filter": "is_array(cover ((`t`.`schedule`)))", + "index": "idx_sched_cover", + // ... + } + } + ] + } + } +] +---- + +[NOTE] +-- +In this example, <> has the following limitation: the collection operator EVERY cannot use array indexes or covering array indexes because the EVERY operator needs to apply the SATISFIES predicate to all elements in the array, including the case where an array has zero elements. + +As items cannot be indexed, it is not possible to index MISSING items, so the EVERY operator is evaluated in the {sqlpp} engine and cannot leverage the array index scan. + +For example, <> below uses the primary index `def_inventory_route_primary` ignoring the {use-index-clause}[USE INDEX] hint to use the array indexes. +(Note that in this example, <> defines a DISTINCT array index while <> defines an ALL array index, and both are ignored). +-- + +.Index II: Non-array index with an ALL array index +[[C8ii,Index II]] +[source,sqlpp] +---- +CREATE INDEX idx_sched_cover_all ON route + (ALL ARRAY v.flight FOR v IN schedule END, schedule); +---- + +.Query D: Non-array index with an ALL array index +[[Q8D,Query D]] +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +USE INDEX (idx_sched_cover_all, idx_sched_cover) +WHERE EVERY v IN schedule SATISFIES v.flight LIKE 'UA%' END; +---- + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + // ... + } + ] + } + } +] +---- +==== + +== Implicit Covering Array Index + +{sqlpp} supports simplified Implicit Covering Array Index syntax in certain cases where the mandatory array index-key requirement is relaxed to create a covering array-index. +This special optimization applies to those queries and DML which have WHERE clause predicates that can be exactly and completely pushed to the indexer during the array index scan. + +include::ROOT:partial$query-context.adoc[tag=section] + +[[example-9]] +.ANY operator with an =, <, >, and LIKE predicate in the SATISFIES clause +==== +Note that the GSI indexes are tree structures that support exact match and range matches. +And the ANY predicate returns `true` as long as it finds at least one matching item in the index. +Hence, an item found in the index can cover the query. +Furthermore, this is covered by both ALL and DISTINCT array indexes. + +.Index: Creating an Implicit Covering Array Index with DISTINCT +[[C9,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_sched_cover_simple ON route + (DISTINCT ARRAY v.flight FOR v IN schedule END); +---- + +.Query: Implicit Covering Array Index using the ANY clause +[[Q9,Query]] +[source,sqlpp] +---- +EXPLAIN SELECT meta().id FROM route +USE INDEX (idx_sched_cover_simple) +WHERE ANY v IN schedule SATISFIES v.flight LIKE 'UA%' END; +---- + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "bucket": "travel-sample", + "covers": [ + "cover ((distinct (array (`v`.`flight`) for `v` in (`route`.`schedule`) end)))", + "cover ((meta(`route`).`id`))" + ], + "filter": "cover (any `v` in (`route`.`schedule`) satisfies ((`v`.`flight`) like \"UA%\") end)", + "filter_covers": { + "cover (any `v` in (`route`.`schedule`) satisfies ((\"UA\" <= (`v`.`flight`)) and ((`v`.`flight`) < \"UB\")) end)": true, + "cover (any `v` in (`route`.`schedule`) satisfies ((`v`.`flight`) like \"UA%\") end)": true + }, + "index": "idx_sched_cover_simple", + // ... + } + } + ] + } + } +] +---- +==== + +[[example-10]] +.UNNEST operator with =, <, >, or LIKE predicate in the WHERE clause +==== +This applies to only ALL array indexes because, for such index, all array elements are indexed in the array index, and the UNNEST operation needs all the elements to reconstruct the array. +Note that the array cannot be reconstructed if on DISTINCT elements of the array are indexed. + +In this example, <> can be covered with the ALL index `idx_sched_cover_simple_all` defined by the <>, but <> is not covered when using the DISTINCT index `idx_sched_cover_simple` defined by the <> in <>. + +.Index: UNNEST covered with the ALL index +[[C10,Index]] +[source,sqlpp] +---- +CREATE INDEX idx_sched_cover_simple_all ON route + (ALL ARRAY v.flight FOR v IN schedule END); +---- + +.Query A: UNNEST covered with the ALL index +[[Q10A,Query A]] +[source,sqlpp] +---- +EXPLAIN SELECT meta(t).id FROM route t +USE INDEX (idx_sched_cover_simple_all) +UNNEST schedule v +WHERE v.flight LIKE 'UA%'; +---- + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", + "as": "t", + "bucket": "travel-sample", + "covers": [ + "cover ((`v`.`flight`))", + "cover ((meta(`t`).`id`))" + ], + "filter": "cover (is_array((`t`.`schedule`)))", + "filter_covers": { + "cover (((`t`.`schedule`) < {}))": true, + "cover (([] <= (`t`.`schedule`)))": true, + "cover (is_array((`t`.`schedule`)))": true + }, + "index": "idx_sched_cover_simple_all", + "index_id": "de0704c3fdb45b07", + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"UB\"", + "inclusion": 1, + "low": "\"UA\"" + } + ] + } + ], + "using": "gsi" + }, + // ... + ] + } + } +] +---- + +.Query B: UNNEST not covered when using the DISTINCT index +[[Q10B,Query B]] +[source,sqlpp] +---- +EXPLAIN SELECT meta(t).id FROM route t +USE INDEX (idx_sched_cover_simple) +UNNEST schedule v +WHERE v.flight LIKE 'UA%'; +---- + +[source,JSON] +.Result +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "DistinctScan", + "scan": { + "#operator": "IndexScan3", + "as": "t", + "bucket": "travel-sample", + "index": "idx_sched_cover_simple", + "index_id": "198a2bc8b0a3ea55", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "spans": [ + { + "exact": true, + "range": [ + { + "high": "\"UB\"", + "inclusion": 1, + "low": "\"UA\"" + } + ] + } + ], + "using": "gsi" + } + // ... + } + ] + } + } +] +---- +==== + +== Summary + +The following table summarizes {sqlpp}-supported collection operators in the DML WHERE clause for different kinds of array index features: + +.{sqlpp}-supported collection operators +[cols=4*^] +|=== +| Operator in the SELECT/DML WHERE clause | Array Index | Covering Array Index (with explicit array index-key) | Implicit Covering Array Index (without explicit array index-key) + +| *ANY* +| ✓ (both ALL & DISTINCT) +| ✓ (both ALL & DISTINCT) +| ✓ (both ALL & DISTINCT) + +| *UNNEST* +| ✓ (only ALL, with array as leading index-key) +| ✓ (only ALL, with array as leading index-key) +| ✓ (only ALL, with array as leading index-key) + +| *ANY AND EVERY* +| ✓ (both ALL & DISTINCT) +| ✓ (both ALL & DISTINCT) +| ✘ + +| *EVERY* +| ✘ +| ✘ +| ✘ +|=== + +[NOTE] +==== +In Couchbase Capella, you can use any arbitrary alias for the right side of an UNNEST -- the alias does not have to be the same as the ARRAY index variable name in order to use that index. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/indexing-meta-info.adoc b/modules/n1ql/pages/n1ql-language-reference/indexing-meta-info.adoc new file mode 100644 index 000000000..501920d06 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/indexing-meta-info.adoc @@ -0,0 +1,131 @@ += Indexing Metadata Information +:description: Couchbase Capella allows indexing on selected metadata fields, for example the expiration and CAS properties. +:page-topic-type: reference + +{description} +This improves performance of queries involving predicates on the metadata fields, such as expired documents or recently modified documents. + +== Overview + +The xref:n1ql:n1ql-language-reference/metafun.adoc#meta[META()] function enables you to return the metadata for a keyspace or document. +To index a selected metadata field, you must use a xref:n1ql-language-reference/nestedops.adoc#field-selection[nested expression] containing the `META()` function and the required property, for example `META().id`. + +The property name must be separated from the `META()` function by a dot (`.`) and only the following metadata properties can be indexed. +If you attempt to build an index on a metadata field that is not indexable, an error is returned. + +cas:: +include::./metafun.adoc[tag=metadata-cas] + +expiration:: +include::./metafun.adoc[tag=metadata-expiration] ++ +Note that this property gives correct results only when used in a xref:n1ql-language-reference/covering-indexes.adoc[Covered Index]. + +id:: +include::./metafun.adoc[tag=metadata-id] + +The `META()` function does not require a keyspace parameter when creating an index, since it implicitly uses the keyspace being indexed. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Find two documents that have no expiration date +==== +.Index +[source,sqlpp] +---- +include::example$n1ql-language-reference/meta-idx-expire.n1ql[] +---- + +.Query +[source,sqlpp] +---- +SELECT META().id, META().expiration +FROM airline +WHERE META().expiration = 0 +ORDER BY META().id +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "expiration": 0, + "id": "airline_10" + }, + { + "expiration": 0, + "id": "airline_10123" + } +] +---- +==== + +.Find all documents whose meta ID tag starts with a letter higher than "g" +==== +.Index +[source,sqlpp] +---- +include::example$n1ql-language-reference/meta-idx-id.n1ql[] +---- + +.Query +[source,sqlpp] +---- +SELECT name, META().id +FROM hotel +WHERE META().id > "g" +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "id": "hotel_10025", + "name": "Medway Youth Hostel" + }, + { + "id": "hotel_10026", + "name": "The Balmoral Guesthouse" + } +] +---- +==== + +.Find the two most recently modified hotel documents +==== +.Index +[source,sqlpp] +---- +include::example$n1ql-language-reference/meta-idx-cas.n1ql[] +---- + +.Query +[source,sqlpp] +---- +SELECT name, META().cas +FROM hotel +ORDER BY META().cas DESC +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "cas": 1612962459766947800, + "name": "The George Hotel" + }, + { + "cas": 1612962459645378600, + "name": "Texas Spring" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/infer.adoc b/modules/n1ql/pages/n1ql-language-reference/infer.adoc new file mode 100644 index 000000000..9d7e085d5 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/infer.adoc @@ -0,0 +1,468 @@ += INFER +:description: The INFER statement enables you to infer the metadata of documents in a keyspace, for example the structure of documents, data types of various attributes, sample values, and so on. +:imagesdir: ../../assets/images +:page-topic-type: reference + +:authorization-overview: xref:clusters:manage-database-users.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:keyspace-ref: xref:n1ql-language-reference/createindex.adoc#keyspace-ref +:bucket-analyzer: xref:clusters:query-service/query-workbench.adoc#bucket-analyzer + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +{description} +Since a keyspace can contain documents with varying structures, the INFER statement is statistical in nature rather than deterministic. +You can specify the sample size that must be used to analyze and identify the structure of documents in a keyspace. + +NOTE: The [.cmd]`describe` statement introduced in the Couchbase Server 4.1 release has been renamed to INFER. + +The Query tab in the Couchbase Capella UI (available under the [.ui]*Data Tools* tab) uses the INFER statement to display the structure of documents in the {bucket-analyzer}[Data Insights] area when you expand the keyspace name. + +== RBAC Privileges + +To execute the INFER statement, you must have the _Query Select_ privilege granted on the target keyspace. +For more details about user roles, see {authorization-overview}[]. + +For example, to execute <> below, you must have the _Query Select_ privilege on the `route` keyspace. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=infer] +---- + +image::n1ql-language-reference/infer.png["Syntax diagram: refer to source code listing", align=left] + +The `COLLECTION` or `KEYSPACE` keywords are optional. +These keywords are purely a visual mnemonic; +including either of them makes no difference to the operation of the INFER statement. + +// TODO: Automatic links from EBNF + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +options:: <> icon:caret-down[] + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of a keyspace. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +[[infer-parameters]] +=== Options + +An object with one or more of the following properties to guide the INFER statement. + +[.var]`sample_size`:: Specifies the number of documents to randomly sample in the keyspace when inferring the schema. +The default sample size is 1000 documents. +If a keyspace contains fewer documents than the specified [.var]`sample_size`, then all the documents in the keyspace will be used. + +[.var]`num_sample_values`:: Specifies the number of sample values for each attributes to be returned. +The sample values provide examples of the data format. +The default value is 5. + +[.var]`similarity_metric`:: The schema inferencing process groups similar schemas into document flavors. +The `similarity_metric` is the degree of similarity that two schemas must have to be considered part of the same flavor. +You can specify a real number between 0 and 1 indicating the percentage match (of attributes) required to establish similarity between two documents. +The default value is 0.6, which means two documents are considered similar if 60% of the top-level attributes are the same. + +[.var]`dictionary_threshold`:: Sometimes JSON documents follow the dictionary pattern, where a field has sub-fields that are key-value pairs, instead of general field-name and value pairs. +For example, consider a sub-document called "ratings", where the name of each rating object is a user ID: ++ +[source,json] +---- + "ratings": { + "brambliertypo75631": { + "created": 1439939260000, + "rating": 1 + }, + "croakerraisiny16166": { + "created": 1440066307000, + "rating": 3 + }, + "libidinizeddepleting17126": { + "created": 1439991036000, + "rating": 1 + }, + "lightnots66650": { + "created": 1440204913000, + "rating": 1 + }, + }, +---- ++ +While this pattern may not be ideal for a number of reasons, if your data follows this pattern it might seem that the data has a huge number of ‘fields’, since a data value is being used as a field name. +When the schema inferencing process sees more than [.var]`dictionary_threshold` fields with different names, but the same sub-document schema, it collapses them into a single schema field marked as a dictionary. + +== Schema Output + +The statement returns the output in the http://json-schema.org/documentation.html[JSON Schema draft^] format as specified by http://json-schema.org/[json-schema.org^]. +It supports the following data types: array, boolean, integer, null, number, and object. + +At the top level, the output contains an array of schemas. +Each schema recursively describes the structure of a flavor of document. +For each identified attribute, the schema may contain the following details: + +Common Details:: +[.out]`#docs`;; Specifies the number of documents in the sample that contain this attribute. +[.out]`%docs`;; Specifies the percentage of documents in the sample that contain this attribute. +[.out]`samples`;; Contains sample values for the attribute found in the sample population. +[.out]`type`;; Specifies specifying the identified data type of the attribute. + +Details for Array Data Type:: +[.out]`items`;; Contains details of the elements in the array. +[.out]`minItems`;; Specifies the minimum number of elements (array size). +[.out]`maxItems`;; Specifies the maximum number of elements (array size). + +Details for Object Data Type:: +[.out]`properties`;; Contains details of the properties of the object. ++ +Each property is described by a key-value pair, in which the key is the name of the property, and the value gives recursive details of that property. + +Details for Documents and Subdocuments:: +[.out]`$schema`;; Specifies the version of the JSON Schema standard. +[.out]`Flavor`;; Specifies the flavor of a document or sub-document. + +== Examples + +[[ex-1]] +.Infer metadata for a keyspace +==== + +include::ROOT:partial$query-context.adoc[tag=example] + +[source,sqlpp] +---- +INFER route +WITH {"sample_size": 10000, "num_sample_values": 2, "similarity_metric": 0.1}; +---- + +.Results +[source,json] +---- +[ + [ + { + "#docs": 10000, + "$schema": "http://json-schema.org/draft-06/schema", + "Flavor": "`type` = \"route\"", + "properties": { + "airline": { + "#docs": 10000, + "%docs": 100, + "samples": [ + "DL", + "WS" + ], + "type": "string" + }, + "airlineid": { + "#docs": 10000, + "%docs": 100, + "samples": [ + "airline_2009", + "airline_5416" + ], + "type": "string" + }, + "destinationairport": { + "#docs": 10000, + "%docs": 100, + "samples": [ + "DFW", + "JFK" + ], + "type": "string" + }, + "distance": { + "#docs": 10000, + "%docs": 100, + "samples": [ + 682.2052742100271, + 2819.371084516147 + ], + "type": "number" + }, + "equipment": { + "#docs": [ + 9, + 9991 + ], + "%docs": [ + 0.09, + 99.91 + ], + "samples": [ + [ + null + ], + [ + "738", + "ERJ" + ] + ], + "type": [ + "null", + "string" + ] + }, + "id": { + "#docs": 10000, + "%docs": 100, + "samples": [ + 20436, + 64755 + ], + "type": "number" + }, + "schedule": { + "#docs": 10000, + "%docs": 100, + "items": { + "#docs": 210598, + "$schema": "http://json-schema.org/draft-06/schema", + "properties": { + "day": { + "type": "number" + }, + "flight": { + "type": "string" + }, + "utc": { + "type": "string" + } + }, + "type": "object" + }, + "maxItems": 34, + "minItems": 9, + "samples": [ + [ + { + "day": 0, + "flight": "DL070", + "utc": "07:46:00" + }, + ... + ], + ... + ], + "type": "array" + }, + "sourceairport": { + "#docs": 10000, + "%docs": 100, + "samples": [ + "CLE", + "YVR" + ], + "type": "string" + }, + "stops": { + "#docs": 10000, + "%docs": 100, + "samples": [ + 0, + 1 + ], + "type": "number" + }, + "type": { + "#docs": 10000, + "%docs": 100, + "samples": [ + "route" + ], + "type": "string" + } + }, + "type": "object" + } + ] +] +---- +==== + +[[ex-2]] +.Infer metadata for a keyspace containing multiple document flavors +==== + +include::ROOT:partial$query-context.adoc[tag=unset] + +[source,sqlpp] +---- +INFER `beer-sample` +WITH {"sample_size": 10000, "num_sample_values": 5, "similarity_metric": 0.0}; +---- + +.Results +[source,json] +---- +[ + [ + { + "#docs": 823, + "$schema": "http://json-schema.org/draft-06/schema", + "Flavor": "type = \"beer\"", + "properties": { + "abv": { + "#docs": 823, + "%docs": 100, + "samples": [ + 0, + 9, + 9.5, + 8, + 7.7 + ], + "type": "number" + }, + "brewery_id": { + "#docs": 823, + "%docs": 100, + "samples": [ + "san_diego_brewing", + "drake_s_brewing", + "brouwerij_de_achelse_kluis", + "niagara_falls_brewing", + "brasserie_des_cimes" + ], + "type": "string" + }, + "category": { + "#docs": 612, + "%docs": 74.36, + "samples": [ + "North American Ale", + "British Ale", + "German Lager", + "Belgian and French Ale", + "Irish Ale" + ], + "type": "string" + }, + "description": { + "#docs": 823, + "%docs": 100, + "samples": [ + "Robust, Dark and Smooth, ho...", + "\"Pride of Milford\" is a very s...", + "Mogul is a complex blend of 5 ...", + "Just like our Porter but multi...", + "" + ], + "type": "string" + }, + "ibu": { + "#docs": 823, + "%docs": 100, + "samples": [ + 0, + 55, + 35, + 20 + ], + "type": "number" + }, + "name": { + "#docs": 823, + "%docs": 100, + "samples": [ + "Old 395 Barleywine", + "Jolly Roger", + "Trappist Extra", + "Maple Wheat", + "Yeti" + ], + "type": "string" + }, + "srm": { + "#docs": 823, + "%docs": 100, + "samples": [ + 0, + 6, + 45, + 30 + ], + "type": "number" + }, + "style": { + "#docs": 612, + "%docs": 74.36, + "samples": [ + "American-Style Pale Ale", + "Classic English-Style Pale Ale", + "American-Style India Pale Ale", + "German-Style Pilsener", + "Other Belgian-Style Ales" + ], + "type": "string" + }, + "type": { + "#docs": 823, + "%docs": 100, + "samples": [ + "beer" + ], + "type": "string" + }, + "upc": { + "#docs": 823, + "%docs": 100, + "samples": [ + 0, + 2147483647 + ], + "type": "number" + }, + "updated": { + "#docs": 823, + "%docs": 100, + "samples": [ + "2010-07-22 20:00:20", + "2010-12-13 19:33:36", + "2011-05-17 03:27:08", + "2011-04-17 12:25:31", + "2011-04-17 12:33:50" + ], + "type": "string" + } + } + }, + { + "#docs": 177, + "$schema": "http://json-schema.org/draft-06/schema", + "Flavor": "type = \"brewery\"", + "properties": { + ... + } + } + ] +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/insert.adoc b/modules/n1ql/pages/n1ql-language-reference/insert.adoc new file mode 100644 index 000000000..30ed32ac1 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/insert.adoc @@ -0,0 +1,1164 @@ += INSERT +:description: Use the INSERT statement to insert one or more new documents into an existing keyspace. +:imagesdir: ../../assets/images +:page-topic-type: reference + +:authorization-overview: xref:clusters:manage-database-users.adoc +:bucket-expiration: xref:server:learn:data/expiration.adoc +:roles: xref:organizations:organization-projects-overview.adoc +:install-sample-buckets: xref:clusters:data-service/import-data-documents.adoc#import-sample-data +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:paths: xref:n1ql-intro/queriesandresults.adoc#paths +:explain: xref:n1ql-language-reference/explain.adoc +:upsert: xref:n1ql-language-reference/upsert.adoc +:select-syntax: xref:n1ql-language-reference/select-syntax.adoc +:query-monitoring: xref:server:tools:query-monitoring.adoc +:query-preferences: xref:clusters:query-service/query-workbench.adoc#query-preferences +:document-expiration: xref:java-sdk:howtos:kv-operations.adoc#document-expiration +:datamodel: xref:java-sdk:ref:travel-app-data-model.adoc + +:metafun: xref:n1ql-language-reference/metafun.adoc +:uuid: {metafun}#uuid +:meta: {metafun}#meta + +:from: xref:n1ql-language-reference/from.adoc +:from-keyspace-ref: {from}#from-keyspace-ref +:as-clause: {from}#section_ax5_2nx_1db + +:query-settings: xref:n1ql:n1ql-manage/query-settings.adoc +:pipeline_batch_req: {query-settings}#pipeline_batch_req +:pipeline-batch-srv: {query-settings}#pipeline-batch-srv +:max_parallelism_req: {query-settings}#max_parallelism_req +:max-parallelism-srv: {query-settings}#max-parallelism-srv + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] +include::partial$n1ql-language-reference/collapsible-style.adoc[] + +[abstract] +{description} +Each INSERT statement requires a unique document key and well-formed JSON as values. +In Couchbase, documents in a single keyspace must have a unique key. + +The INSERT statement can compute and return any expression based on the actual inserted documents. + +TIP: Use the {upsert}[UPSERT] statement if you want to overwrite a document with the same key, in case it already exists. + +WARNING: Please note that the examples below will alter the data in your sample buckets. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +[#insert-prerequisites] +== Prerequisites + +The INSERT statement must include the following: + +* Name of the keyspace to insert the document. +* Unique document key. +* A well-formed JSON document specified as key-value pairs, or the projection of a SELECT statement which generates a well-formed single JSON to insert. +See and for details. +* Optionally, you can specify the values or an expression to be returned after the INSERT statement completes successfully. + +=== Security Requirements + +You should have read-write permission to the keyspace, to be able to insert documents into a keyspace. +Any user who has the keyspace credentials or any Couchbase administrator should be able to insert documents into a keyspace. +This includes the keyspace administrator for the specified keyspace, the cluster administrator, and the full administrator roles. +See {roles}[] for details about access privileges for various administrators. + +WARNING: You cannot insert documents into a SASL bucket if you have a read-only role for the SASL bucket. + +=== RBAC Privileges + +To execute the INSERT statement, you must have the _Query Insert_ privilege on the target keyspace. + +If the statement has any SELECT or RETURNING data-read clauses, then the _Query Select_ privilege is also required on the keyspaces referred in the respective clauses. +For more details about roles and privileges, see {authorization-overview}[]. + +.RBAC Examples +[%collapsible] +==== +====== +include::ROOT:partial$query-context.adoc[tag=example] + +To execute the following statement, you must have the _Query Insert_ privilege on `hotel`. + +[source,sqlpp] +---- +INSERT INTO hotel (KEY, VALUE) +VALUES ("key1", { "type" : "hotel", "name" : "new hotel" }); +---- + +To execute the following statement, you must have the _Query Insert_ and _Query Select_ privileges on `hotel`. + +[source,sqlpp] +---- +INSERT INTO hotel (KEY, VALUE) +VALUES ("key1", { "type" : "hotel", "name" : "new hotel" }) RETURNING *; +---- + +To execute the following statement, you must have the _Query Insert_ privilege on `hotel` and _Query Select_ privilege on `pass:c[`beer-sample`]`. + +[source,sqlpp] +---- +INSERT INTO landmark (KEY foo, VALUE bar) +SELECT META(doc).id AS foo, doc AS bar +FROM `beer-sample` AS doc WHERE type = "brewery"; +---- + +To execute the following statement, you must have the _Query Insert_ and _Query Select_ privileges on `hotel`. + +[source,sqlpp] +---- +INSERT INTO hotel (KEY foo, VALUE bar) +SELECT "copy_" || meta(doc).id AS foo, doc AS bar +FROM hotel AS doc; +---- +====== +==== + +[#insert-syntax] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=insert] +---- + +image::n1ql-language-reference/insert.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links from EBNF + +[horizontal.compact] +target-keyspace:: <> icon:caret-down[] +insert-values:: <> icon:caret-down[] +insert-select:: <> icon:caret-down[] +returning-clause:: <> icon:caret-down[] + +[[insert-target]] +=== Insert Target + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=target-keyspace] +---- + +image::n1ql-language-reference/target-keyspace.png["Syntax diagram: refer to source code listing", align=left] + +The insert target is the keyspace into which the documents are inserted. +Ensure that the keyspace exists before trying to insert a document. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[insert-target-ref]] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Keyspace reference for the insert target. +For more details, refer to {from-keyspace-ref}[Keyspace Reference]. + +[[insert-target-alias]] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[[insert-values]] +=== Insert Values + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=insert-values] +---- +image::n1ql-language-reference/insert-values.png["Syntax diagram: refer to source code listing", align=left] + +Specifies one or more documents to be inserted using the <>. +Each document requires a unique key and the values must be specified as well-formed JSON. + +The bracketed KEY and VALUE keywords are purely a visual mnemonic to indicate that you are setting the key and value for the inserted document. +There is no syntactic requirement to include these keywords when using the Insert Values syntax. +Also note that there is no syntactic difference between PRIMARY KEY and KEY. + +Similarly, the OPTIONS keyword is purely a visual mnemonic to indicate that you are setting metadata for the inserted document. +There is no syntactic requirement to include the OPTIONS keyword when setting metadata for the inserted document. + +[[values-clause]] +==== VALUES Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=values-clause] +---- + +image::n1ql-language-reference/values-clause.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal] +key:: +A string, or an expression resolving to a string, representing the ID of the document to be inserted. +The KEY cannot be MISSING or NULL, and must be unique within the Couchbase keyspace. +It can be a string or an expression that produces a string. + +value:: +A JSON object or value, or an expression resolving to a JSON object or value, representing the body of the document to be inserted. +(See http://json.org/example.html[^] for examples of well-formed JSON.) +You can insert NULL, empty, or MISSING values. + +options:: +[Optional] An object representing the metadata to be set for the inserted document. +Only the `expiration` attribute has any effect; any other attributes are ignored. + +expiration::: +An integer, or an expression resolving to an integer, representing the {document-expiration}[document expiration] in seconds. ++ +If the document expiration is not specified, it defaults to `0`, meaning the document expiration is the same as the {bucket-expiration}[bucket or collection expiration]. + +For examples illustrating the VALUES clause, see <>. + +[[insert-select]] +=== Insert Select + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=insert-select] +---- + +image::n1ql-language-reference/insert-select.png["Syntax diagram: refer to source code listing", align=left] + +Use the projection of a SELECT statement which generates well-formed JSON to insert. + +[horizontal] +key:: +A string, or an expression resolving to a string, representing the ID of the document to be inserted. +If the project of a SELECT statement generates multiple JSON documents, then your INSERT statement must handle the generation of unique keys for each of the documents. + +value:: +[Optional] An object, or an expression resolving to an object, representing the body of the document to be inserted. +This may be an alias assigned by the SELECT statement. +If the VALUE is omitted, the entire JSON document generated by the SELECT statement is inserted. + +options:: +[Optional] An object representing the metadata to be set for the inserted document. +Only the `expiration` attribute has any effect; any other attributes are ignored. + +expiration::: +An integer, or an expression resolving to an integer, representing the {document-expiration}[document expiration] in seconds. ++ +If the document expiration is not specified, it defaults to `0`, meaning the document expiration is the same as the {bucket-expiration}[bucket or collection expiration]. + +select:: <> icon:caret-down[] + +[[select-statement]] +==== SELECT Statement + +SELECT statements let you retrieve data from specified keyspaces. +For details, see {select-syntax}[SELECT Syntax]. + +For examples illustrating the SELECT statement, see <>. + +[[returning-clause]] +=== RETURNING Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=returning-clause] +---- + +image::n1ql-language-reference/returning-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the fields that must be returned as part of the results object. + +[horizontal.compact] +result-expr:: <> icon:caret-down[] + +[[result-expr]] +==== Result Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=result-expr] +---- + +image::n1ql-language-reference/result-expr.png["Syntax diagram: refer to source code listing", align=left] + +Specifies an expression on the inserted documents, that will be returned as output. +Use `*` to return all the fields in all the documents that were inserted. + +For examples illustrating the RETURNING clause, see <>. + +== Result + +The INSERT statement returns the requestID, the signature, results including the keyspace and JSON document inserted, status of the query, and metrics. + +* [.out]`requestID`: Request ID of the statement generated by the server. +* [.out]`signature`: Signature of the fields specified in the returning clause. +* [.out]`results`: If the query specified the returning clause, then results contains one or more fields as specified in the returning clause. +If not, returns an empty results array. +* [.out]`errors`: Returns the error codes and messages if the statement fails with errors. +Returned only when the statement fails with errors. +Errors can also include timeouts. +* [.out]`status`: Status of the statement - "[.out]``successful``" or "[.out]``errors``". +* [.out]`metrics`: Provides metrics for the statement such as [.out]`elapsedTime`, [.out]`executionTime`, [.out]`resultCount`, [.out]`resultSize`, and [.out]`mutationCount`. +For more information, see <>. + +[#insert-metrics] +=== Metrics + +The INSERT statement returns the following metrics along with the results and status: + +* [.out]`elapsedTime`: Total elapsed time for the statement. +* [.out]`executionTime`: Time taken by Couchbase Capella to execute the statement. +This value is independent of network latency, platform code execution time, and so on. +* [.out]`resultCount`: Total number of results returned by the statement. +In case of `INSERT` without a `RETURNING` clause, the value is `0`. +* [.out]`resultSize`: Total number of results that satisfy the query. +* [.out]`mutationCount`: Specifies the number of documents that were inserted by the `INSERT` statement. + +[#insert-monitoring] +=== Monitoring + +You can use the query monitoring API to gather diagnostic information. +For example, if you are performing a bulk insert using a `SELECT` statement, you can use the query monitoring API to get the number of documents being inserted. +Check [.api]`system:active_requests` catalog for more information on monitoring active queries. +For more information, see {query-monitoring}[Query Monitoring]. + +You can also take a look at the keyspace metrics from the Web Console. +To do so, go to the Data Buckets tab and click the bucket that you want to monitor. +In the General Bucket Analytics screen, scroll to the Query section to gather information such as requests/sec, selects/sec and so on. + +[#insert-restrictions] +== Restrictions + +When inserting documents into a specified keyspace, keep in mind the following restrictions which would help avoid errors during execution. + +* The keyspace must exist. +The INSERT statement returns an error if the keyspace does not exist. +* Do not insert a document with a duplicate key. +If you are inserting multiple documents, the statement aborts at the first error encountered. +* Timeouts can affect the completion of an INSERT statement, especially when performing bulk inserts. +Ensure that the timeout is set to a reasonable value that allows the bulk insert operation to complete. ++ +To set the indexer timeout, use the REST API to set the `indexer.settings.scan_timeout` property. +For example, ++ +[source,sh] +---- +curl http://localhost:9102/settings -u Administrator:password \ +-d '{"indexer.settings.scan_timeout": 1200}' +---- ++ +Use the following command to retrieve the indexer settings: ++ +[source,sh] +---- +curl -X GET http://localhost:9102/settings -u Administrator:password +---- + +* When inserting multiple documents, no cleanup or rollback is done for the already inserted documents if the INSERT operations hits an error. +This means, when you are inserting 10 documents, if the INSERT operation fails when inserting the 6th document, the operator quits and exits. +It does not rollback the first five documents that were inserted. +Nor does it ignore the failure and continue to insert the remaining documents. + +[#insert-performance] +== Performance and Best Practices + +When a single INSERT statement is executed, {sqlpp} prepares the statement, scans the values and then inserts the document. +When inserting a large number of documents, you can improve the performance of the INSERT statement by using one of the following techniques: + +* Batching the documents to perform bulk inserts, which decreases the latency and increases the throughput. +The INSERT statement sends documents to the data node in batches, with a default batch size of 16. +You can configure this value using the {pipeline_batch_req}[pipeline_batch] request-level parameter, or the {pipeline-batch-srv}[pipeline-batch] service-level setting. +Note that the maximum batch size is (2^32^ -1) and specifying a value higher than the maximum batch size may increase the memory consumption. +The following example command sets the pipeline-batch size to 32 instead of the default 16: ++ +[source,sh] +---- +curl -v -X POST http://localhost:8093/admin/settings -u Administrator:password \ +-d '{ "debug":true, "pipeline-batch": 32 }' +---- + +* Use the {max_parallelism_req}[max_parallelism] request-level parameter, or the {max-parallelism-srv}[max-parallelism] service-level setting when inserting multiple documents. +* When performing bulk inserts, use prepared statements or multiple values. +* When new documents are inserted, the indexes are updated. +When a large number of documents are inserted, this may affect the performance of the cluster. + +[#insert-examples] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[example-1]] +.Overview +==== +The following statement inserts a single JSON document into the `airline` keyspace with key "k001". +The returning clause specifies the function `META().id` to return the key of the inserted document (metadata), and the wildcard (*) to return the inserted document. + +.Query +[source,sqlpp] +---- +include::example$dml/insert-value.n1ql[] +---- + +.Results +[source,json] +---- +include::example$dml/insert-value.jsonc[] +---- +==== + +The simplest use case of an INSERT statement is to insert a single document into the keyspace. + +[[example-11]] +.Insert a single document +==== +Insert a new document with `key` "1025" into the `airline` keyspace. + +.Query +[source,sqlpp] +---- +include::example$dml/insert-doc.n1ql[] +---- + +.Results +[source,json] +---- +include::example$dml/insert-doc.jsonc[] +---- +==== + +You can batch insert multiple documents using multiple VALUES clauses. +The VALUES keyword itself is optional in the second and later iterations of the clause. + +[[example-12]] +.Perform bulk inserts +==== +Insert two documents with `key` "airline_4444" and "airline_4445" into the `airline` keyspace: + +.Query +[source,sqlpp] +---- +include::example$dml/insert-batch.n1ql[] +---- + +.Results +[source,json] +---- +include::example$dml/insert-batch.jsonc[] +---- +==== + +[[example-2]] +.Specify a key using an expression +==== +You can specify a key using an expression, as shown here. + +.Query +[source,sqlpp] +---- +INSERT INTO airline ( KEY, VALUE ) + VALUES ( "airline" || TOSTRING(1234), + { "callsign": "" } ) + RETURNING META().id; +---- +==== + +[[example-3]] +.Generate a unique key +==== +If you don't require the document key to be in a specific format, you can use the function {uuid}[UUID()] to generate a unique key, as shown here. + +.Query +[source,sqlpp] +---- +INSERT INTO airline ( KEY, VALUE ) + VALUES ( UUID(), + { "callsign": "" } ) +RETURNING META().id; +---- + +Since the document key is auto-generated, you can find the value of the key by specifying META().id in the returning clause. +==== + +[[example-4]] +.Insert an empty value +==== +.Query +[source,sqlpp] +---- +INSERT INTO airline (KEY, VALUE) + VALUES ( "airline::432", + { "callsign": "", + "country" : "USA", + "type" : "airline"} ) +RETURNING *; +---- + +.Results +[source,json] +---- +[ + { + "airline": { + "callsign": "", + "country": "USA", + "type": "airline" + } + } +] +---- +==== + +[[example-5]] +.Insert a NULL value +==== +.Query +[source,sqlpp] +---- +INSERT INTO airline (KEY, VALUE) + VALUES ( "airline::1432", + { "callsign": NULL, + "country" : "USA", + "type" : "airline"} ) +RETURNING *; +---- + +.Results +[source,json] +---- +[ + { + "airline": { + "callsign": null, + "country": "USA", + "type": "airline" + } + } +] +---- +==== + +[[example-6]] +.Insert a MISSING value +==== +.Query +[source,sqlpp] +---- +INSERT INTO airline (KEY, VALUE) + VALUES ( "airline::142", + { "callsign": MISSING, + "country" : "USA", + "type" : "airline"} ) +RETURNING *; +---- + +.Results +[source,json] +---- +[ + { + "airline": { + "country": "USA", + "type": "airline" + } + } +] +---- +==== + +[[example-7]] +.Insert a NULL JSON document +==== +.Query +[source,sqlpp] +---- +INSERT INTO hotel (KEY, VALUE) + VALUES ( "1021", + { } ) + RETURNING *; +---- +==== + +[[example-7a]] +.Insert a document with expiration +==== +Insert a document into the `airline` keyspace using an expiration of 5 days. + +.Query +[source,sqlpp] +---- +INSERT INTO airline (KEY, VALUE, OPTIONS) + VALUES ( "airline::ttl", + { "callsign": "Temporary", + "country" : "USA", + "type" : "airline" }, + { "expiration": 5*24*60*60 } ); +---- +==== + +[[example-9]] +.Return the document ID and country +==== +.Query +[source,sqlpp] +---- +INSERT INTO airline (KEY, VALUE) + VALUES ( "airline_24444", + { "callsign": "USA-AIR", + "country" : "USA", + "type" : "airline"}) +RETURNING META().id as docid, country; +---- + +.Results +[source,json] +---- +[ + { + "country": "USA", + "docid": "airline_24444" + } +] +---- +==== + +[[example-10]] +.Return the document ID and an expression +==== +Use the `UUID()` function to generate the key and show the usage of the `RETURNING` clause to retrieve the generated document key and the last element of the `callsign` array with an expression. + +.Query +[source,sqlpp] +---- +INSERT INTO airline (KEY, VALUE) + VALUES ( UUID(), + { "callsign": [ "USA-AIR", "America-AIR" ], + "country" : "USA", + "type" : "airline"} ) +RETURNING META().id as docid, callsign[ARRAY_LENGTH(callsign)-1]; +---- + +.Results +[source,json] +---- +[ + { + "$1": "America-AIR", + "docid": "6af57793-65d2-4cc3-beea-5d713c7f3c29" + } +] +---- +==== + +Instead of providing actual values, you can specify the data to be inserted using the SELECT statement which selects the data from an existing keyspace. + +[[example-13]] +.Insert values using SELECT +==== +Query the `airport` keyspace for documents with `airportname` "Heathrow", and then insert the projection (1 document) into the `airport` keyspace using a unique key generated using `UUID()`. + +.Query +[source,sqlpp] +---- +include::example$dml/insert-select.n1ql[] +---- + +.Results +[source,json] +---- +include::example$dml/insert-select.jsonc[] +---- +==== + +[[example-8a]] +.Insert with SELECT and set expiration +==== +Query the `airport` keyspace for documents with `airportname` "Heathrow", and then insert the projection into the `airport` keyspace using a unique key and an expiration of 2 hours. + +.Query +[source,sqlpp] +---- +INSERT INTO airport + (KEY UUID(), VALUE doc, OPTIONS {"expiration": 2*60*60}) + SELECT a AS doc FROM airport a + WHERE airportname = "Heathrow"; +---- +==== + +[[example-8b]] +.Insert with SELECT and preserve expiration +==== +If you want to copy the expiration of an existing document to the inserted document, you can use a {meta}[META().expiration] expression in the SELECT statement, as shown here. + +.Query +[source,sqlpp] +---- +INSERT INTO airport + (KEY UUID(), VALUE doc, OPTIONS {"expiration": ttl}) + SELECT META(a).expiration AS ttl, a AS doc FROM airport a + WHERE airportname = "Heathrow"; +---- +==== + +[[example-14]] +.Insert values with a combination key, generated using the projection and expressions +==== +Generate a document key as a combination of the projection and some function, such as `::`. +The SELECT statement retrieves the country name "k1" and concatenates it with a delimiter "::" and the system clock function using the string `concat` operator "[.code]``||``". + +.Query +[source,sqlpp] +---- +INSERT INTO airport (KEY k1||"::"||clock_str(), value t) + SELECT DISTINCT t.country AS k1,t + FROM airport t + LIMIT 5 +RETURNING META().id as docid, *; +---- + +The result shows the META().id generated as a result of this concatenation (highlighted below). + +.Results +[source,json] +---- +[ + { + "airport": { + "airportname": "Calais Dunkerque", + "city": "Calais", + "country": "France", + "faa": "CQF", + "geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + }, + "icao": "LFAC", + "id": 1254, + "type": "airport", + "tz": "Europe/Paris" + }, + "docid": "France::2021-02-09T13:53:28.445Z" + } +] +---- +==== + +[[Example_15_copy_bucket]] +.Use insert to copy keyspace data to another keyspace +==== +Use the INSERT statement to create a copy of `keyspace_1` under the new name `keyspace_2`. + +.Query +[source,sqlpp] +---- +INSERT INTO keyspace_2(key _k, value _v) + SELECT META().id _k, _v + FROM keyspace_1 _v; +---- +==== + +Sub-queries can be used with INSERT in the insert-select form of the statement. +The `SELECT` part can be any sophisticated query in itself. + +[[example-16]] +.Insert values using subqueries +==== +Insert a new `type` in documents from all hotels in the cities that have landmarks. + +.Query +[source,sqlpp] +---- +INSERT INTO hotel (KEY UUID()) -- <3> + SELECT x.name, x.city, "landmark_hotels" AS type -- <2> + FROM hotel x + WHERE x.city WITHIN + ( SELECT DISTINCT t.city -- <1> + FROM landmark t) + LIMIT 4 +RETURNING *; +---- + +<1> The inner most `SELECT` finds all cities that have landmarks. +<2> The outer `SELECT` finds the hotels that are in the cities selected by the inner query in Step 1. +It also adds a new `type` attribute with the value "landmark_hotels" to the projected result. +For brevity, we `SELECT` only 4 documents. +<3> Finally, the `INSERT` statement inserts the result of Step 2 with `UUID()` generated keys. + +.Results +[source,json] +---- +[ + { + "hotel": { + "city": "Aberdeenshire", + "name": "Castle Hotel", + "type": "landmark_hotels" + } + }, + { + "hotel": { + "city": "Aberdeenshire", + "name": "Two Bears Cottage", + "type": "landmark_hotels" + } + }, + { + "hotel": { + "city": "Agoura Hills", + "name": "Malibu Creek Campground", + "type": "landmark_hotels" + } + }, + { + "hotel": { + "city": "Altrincham", + "name": "Cresta Court Hotel", + "type": "landmark_hotels" + } + } +] +---- +==== + +[[example-17]] +.Insert values using functions +==== +Set the parameter `$faa_code` using the cbq prompt, or the {query-preferences}[Run-Time Preferences] in the Query tab. + +.Parameters +[source,sqlpp] +---- +\SET -$faa_code "blr" ; +---- + +.Query +[source,sqlpp] +---- +INSERT INTO airport (KEY, VALUE) + VALUES ("airport_" || UUID(), -- <1><2> + { "type" : "airport", + "tz" : "India Standard Time", + "country" : "India", + "faa" : UPPER($faa_code)} ) -- <3> +RETURNING *; +---- +The query uses multiple functions during the INSERT: + +<1> `UUID()` function to generate unique key for the document being inserted. +<2> The string concatenation operator `||` to join "airport_" and the `UUID`. +<3> `UPPER` string function to insert only uppercase values of the `FAA` code. + +.Results +[source,json] +---- +{ + "requestID": "4fea5296-c9f4-4fd3-be78-95e5a04531eb", + "signature": { + "*": "*" + }, + "results": [ + { + "airport": { + "country": "India", + "faa": "BLR", + "type": "airport", + "tz": "India Standard Time" + } + } + ], + "status": "success", + "metrics": { + "elapsedTime": "7.7853ms", + "executionTime": "7.6472ms", + "resultCount": 1, + "resultSize": 167, + "serviceLoad": 4, + "mutationCount": 1 + } +} +---- +==== + +[[example-18]] +.Insert values using prepared statements +==== +Prepare an `INSERT` statement and execute it by passing parameters. +The `INSERT` statement has some of the attribute values preset while it takes the document `key` and airport `faa_code` as parameters. + +First, prepare the `INSERT` statement. + +.Query +[source,sqlpp] +---- +PREPARE ins_india FROM + INSERT INTO airport (KEY, VALUE) + VALUES ( $key, + { "type" : "airport", + "tz" : "India Standard Time", + "country" : "India", + "faa" : $faa_code} ) +RETURNING *; +---- + +Now execute the prepared statement using the cbq shell or the Query tab, passing the parameters `key` and `faa_code`. + +.Query +[source,sqlpp] +---- +EXECUTE ins_india +USING {"key": "airport_10001", "faa_code": "DEL"}; +---- + +.Results +[source,json] +---- +[ + { + "airport": { + "country": "India", + "faa": "DEL", + "type": "airport", + "tz": "India Standard Time" + } + } +] +---- + +Alternatively, execute the prepared statement using the REST API, passing `$key` and `$faa_code` as REST parameters. + +.Request +[source,sh] +---- +curl -v http://localhost:8093/query/service -u Administrator:password \ +-d 'prepared="ins_india"&$key="airport_10002"&$faa_code="BLR"' +---- + +.Results +[source,json] +---- +{ + "requestID":"55ff7e8a-7410-470f-ab83-c464f9d0092d", + "signature":{ + "*":"*" + }, + "results":[ + { + "airport":{ + "country":"India", + "faa":"BLR", + "type":"airport", + "tz":"India Standard Time" + } + } + ], + "status":"success", + "metrics":{ + "elapsedTime":"22.6797ms", + "executionTime":"17.0216ms", + "resultCount":1, + "resultSize":87, + "serviceLoad":4, + "mutationCount":1 + } +} +---- +==== + +[#insert-explain-plan] +== Explain Plan + +To understand how the INSERT statement is executed by {sqlpp}, let us take a look at two examples. +For detailed explanation about the EXPLAIN plan, see the {explain}[EXPLAIN] statement. + +include::ROOT:partial$query-context.adoc[tag=section] + +[[example-19]] +.Simple INSERT statement using KEY VALUE pairs to insert two documents +==== +.Query +[source,sqlpp] +---- +EXPLAIN INSERT INTO airline (KEY,VALUE) +VALUES ( "1025", + { "callsign": "SKY-AIR", + "country": "United States", + "id": "1025", + "type": "airline" + } ), +VALUES ( "1026", + { "callsign": "F1-AIR", + "country": "United States", + "id": "1014" + } ) +RETURNING *; +---- + +.Results +[source,json] +---- +{ + "requestID": "5d1797cb-a7df-409d-b924-130ba0cc597a", + "signature": "json", + "results": [ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "ValueScan", + "cardinality": 2, + "cost": 0.032, + "values": "[[\"1025\", {\"callsign\": \"SKY-AIR\", \"country\": \"United States\", \"id\": \"1025\", \"type\": \"airline\"}], [\"1026\", {\"callsign\": \"F1-AIR\", \"country\": \"United States\", \"id\": \"1014\"}]]" + }, + { + "#operator": "Parallel", + "maxParallelism": 1, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "SendInsert", + "alias": "airline", + "bucket": "travel-sample", + "keyspace": "airline", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + "text": "INSERT INTO airline (KEY,VALUE) VALUES ( \"1025\", { \"callsign\": \"SKY-AIR\", \"country\": \"United States\", \"id\": \"1025\", \"type\": \"airline\" } ), VALUES ( \"1026\", { \"callsign\": \"F1-AIR\", \"country\": \"United States\", \"id\": \"1014\" } ) RETURNING *;" + } + ], + "status": "success", + "metrics": { + "elapsedTime": "6.5577ms", + "executionTime": "6.2773ms", + "resultCount": 1, + "resultSize": 1898, + "serviceLoad": 4 + } +} +---- +The query engine first scans the input values shown by the operator `ValueScan` to obtain the input values, and then it inserts the documents into the specified keyspace (shown by the operator `SendInsert`). +==== + +[[example-20]] +.INSERT statement using the projection of a select statement to generate values +==== +.Query +[source,sqlpp] +---- +EXPLAIN INSERT INTO airport (key UUID(), value airport) + SELECT airport FROM airport + WHERE airportname = "Heathrow"; +---- + +.Results +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "IndexScan3", // <1> + "bucket": "travel-sample", + "index": "def_inventory_airport_airportname", + "index_id": "14b05d2b21bd6eee", +// ... + }, + { + "#operator": "Fetch", // <2> + "bucket": "travel-sample", + "keyspace": "airport", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", // <3> + "condition": "((`airport`.`airportname`) = \"Heathrow\")" + }, +// ... + ] + } + } + ] + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "SendInsert", // <4> + "alias": "airport", + "bucket": "travel-sample", + "key": "uuid()", + "keyspace": "airport", + "namespace": "default", + "scope": "inventory", + "value": "`airport`" + }, +// ... + ] + } + } + ] + }, + "text": "INSERT INTO airport (key UUID(), value airport)\n SELECT airport FROM airport\n WHERE airportname = \"Heathrow\";" + } +] +---- + +The Query Engine first executes the `SELECT` statement and then uses the projection to insert into the `airport` keyspace, performing the operations in the order listed: + +<1> An `IndexScan` to search for documents using the `def_inventory_airport_airportname` index. +<2> A `Fetch` for the document in the `airport` keyspace. +<3> A `Filter` for documents with `airportname="Heathrow"`. +<4> An `Insert` of the value along with the auto-generated key into the `airport` keyspace. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/join.adoc b/modules/n1ql/pages/n1ql-language-reference/join.adoc new file mode 100644 index 000000000..c4863e423 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/join.adoc @@ -0,0 +1,1373 @@ += JOIN Clause +:description: The JOIN clause enables you to create new input objects by combining two or more source objects. +:imagesdir: ../../assets/images +:from-term: pass:q[`JOIN` clause] +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `JOIN` clause enables you to create new input objects by combining two or more source objects. + +== Purpose + +The `JOIN` clause is used within the xref:n1ql-language-reference/from.adoc[FROM] clause. +It creates an input object by combining two or more source objects. +Couchbase Capella supports three types of `JOIN` clause, which are described in the sections below: <>, <>, and <>. + +In Couchbase Capella, you may also use comma-separated joins. +For further details, refer to xref:n1ql-language-reference/comma.adoc[]. + +== Prerequisites + +For you to select data from keyspace or expression, you must have the [.param]`query_select` privilege on that keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=join-clause] +---- + +image::n1ql-language-reference/join-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +ansi-join-clause:: <> icon:caret-down[] +lookup-join-clause:: <> icon:caret-down[] +index-join-clause:: <> icon:caret-down[] + +[#section_nkd_3nx_1db] +include::partial$n1ql-language-reference/from-term.adoc[] + +[#section_ek1_jnx_1db] +== ANSI JOIN Clause + +=== Purpose + +To be closer to standard SQL syntax, ANSI JOIN can join arbitrary fields of the documents and can be chained together. + +include::partial$n1ql-language-reference/ansi-join-nest.adoc[] + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-join-clause] +---- + +image::n1ql-language-reference/ansi-join-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +ansi-join-type:: <> icon:caret-down[] +ansi-join-rhs:: <> icon:caret-down[] +ansi-join-predicate:: <> icon:caret-down[] + +[#ansi-join-type] +==== Join Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-join-type] +---- + +image::n1ql-language-reference/ansi-join-type.png["Syntax diagram", align=left] + +This clause represents the type of ANSI join. + +`INNER`:: +For each joined object produced, both the left-hand side and right-hand side source objects of the `ON` clause must be non-MISSING and non-NULL. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +For each joined object produced, only the left-hand source objects of the `ON` clause must be non-MISSING and non-NULL. + +`RIGHT [OUTER]`:: +{startsb}Query Service interprets `RIGHT` as `RIGHT OUTER`{endsb} ++ +For each joined object produced, only the right-hand source objects of the `ON` clause must be non-MISSING and non-NULL. + +This clause is optional. +If omitted, the default is `INNER`. + +The following table summarizes the ANSI join types currently supported, and describes how you may chain them together. + +include::ROOT:partial$query-context.adoc[tag=section] + +[cols="2,1,3"] +|=== +| Join Type | Remarks | Example + +| *[INNER] JOIN \... ON* +.2+.^| INNER JOIN and LEFT OUTER JOIN can be mixed in any number and/or order. +a| +[source,sqlpp] +---- +SELECT * +FROM route +JOIN airline +ON route.airlineid = META(airline).id +WHERE airline.country = "France"; +---- +| *LEFT [OUTER] JOIN \... ON* +a| +[source,sqlpp] +---- +SELECT * +FROM route +LEFT JOIN airline +ON route.airlineid = META(airline).id +WHERE route.sourceairport = "SFO"; +---- +| *RIGHT [OUTER] JOIN \... ON* +| RIGHT OUTER JOIN can only be the first join specified in a FROM clause. +a| +[source,sqlpp] +---- +SELECT * +FROM route +RIGHT JOIN airline +ON route.airlineid = META(airline).id +WHERE route.sourceairport = "SFO"; +---- +|=== + +[NOTE] +-- +In Couchbase Capella, if you create either of the following: + +* A LEFT OUTER JOIN where all the NULL or MISSING results on the right-hand side are filtered out by the xref:n1ql-language-reference/where.adoc[WHERE clause] or by the ON clause of a subsequent INNER JOIN, or +* A RIGHT OUTER JOIN where all the NULL or MISSING results on the left-hand side are filtered out by the xref:n1ql-language-reference/where.adoc[WHERE clause] or by the ON clause of a subsequent INNER JOIN, + +Then the query is transformed internally into an INNER JOIN for greater efficiency. +-- + +[#ansi-join-lateral] +==== LATERAL Join + +When an expression on the right-hand side of an ANSI join references a keyspace that is already specified in the same FROM clause, the expression is said to be correlated. +In relational databases, a join which contains correlated expressions is referred to as a lateral join. +In {sqlpp}, lateral correlations are detected automatically, and there is no need to specify that a join is lateral. + +In clusters using Couchbase Server 7.6 and later, you can use the LATERAL keyword as a visual reminder that a join contains correlated expressions. +The LATERAL keyword is not required -- the keyword is included solely for compatibility with queries from relational databases. + +If you use the LATERAL keyword in a join that has no lateral correlation, the keyword is ignored. + +INNER JOINS and LEFT OUTER JOINS support the optional LATERAL keyword in front of the right-hand side keyspace. + +RIGHT OUTER JOINS do not support the optional LATERAL keyword. + +NOTE: Using the LATERAL keyword in an ANSI join implies that the right-hand side of the join must appear after the left-hand side of the join. This may prevent the cost-based optimizer from reordering joins in the query to give the optimal join order. For details, see xref:n1ql:n1ql-language-reference/cost-based-optimizer.adoc#join-enumeration[Join Enumeration]. + +[#ansi-join-predicate] +==== Join Predicate + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-join-predicate] +---- + +image::n1ql-language-reference/ansi-join-predicate.png["Syntax diagram", align=left] + +`expr`:: Boolean expression representing the join condition between the left-hand side <> and the <>. +This expression may contain fields, constant expressions, or any complex {sqlpp} expression. + +=== Limitations + +* A RIGHT OUTER join is only supported when it’s the only join in the query; or when it's the first join in a chain of joins. + +* No mixing of ANSI join syntax with lookup or index join syntax in the same FROM clause. + +* If the right-hand side of an ANSI join is a keyspace reference, then for the nested-loop join method an appropriate secondary index must exist on the right-hand side keyspace; for the hash join method, a primary index can be used. + +* Adaptive indexes are not considered when selecting indexes on inner side of the join. + +* You may chain ANSI joins with comma-separated joins; however, the comma-separated joins must come after any JOIN, NEST, or UNNEST clauses. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ANSI-Join-Example-1] +.Inner Join +==== +List the source airports and airlines that fly into SFO, where only the non-null `route` documents join with matching `airline` documents. + +[source,sqlpp] +---- +include::example$select/ansi-join-inner.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-join-inner.jsonc[tags=extract;ellipsis] +---- + +The INNER JOIN only returns results where a left-side document matches a right-side document. +==== + +[#ANSI-Join-Example-1A] +.Inner LATERAL Join +==== +This example is the same as <>, but it includes the optional LATERAL keyword. + +[source,sqlpp] +---- +include::example$select/ansi-join-lateral.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-join-lateral.jsonc[tags=extract;ellipsis] +---- + +The INNER LATERAL JOIN returns the same results as <>. +==== + +[#ANSI-Join-Example-2] +.Left Outer Join of U.S. airports in the same city as a landmark +==== +List the airports and landmarks in the same city, ordered by the airports. + +[source,sqlpp] +---- +include::example$select/ansi-join-left.n1ql[] +---- + +<.> The `airport` keyspace is on the left-hand side of the join. +<.> The `landmark` keyspace is on the right-hand side of the join. + +.Results +[source,JSON] +---- +include::example$select/ansi-join-left.jsonc[] +---- + +<.> The LEFT OUTER JOIN lists all the left-side results, even if there are no matching right-side documents, as indicated by the results in which the fields from the `landmark` keyspace are null or missing. +==== + +[#ANSI-Join-Example-3] +.RIGHT OUTER JOIN of <> +==== +List the airports and landmarks in the same city, ordered by the landmarks. + +[source,sqlpp] +---- +include::example$select/ansi-join-right.n1ql[] +---- + +<.> The `airport` keyspace is on the left-hand side of the join. +<.> The `landmark` keyspace is on the right-hand side of the join. + +.Results +[source,JSON] +---- +include::example$select/ansi-join-right.jsonc[] +---- + +<.> The RIGHT OUTER JOIN lists all the right-side results, even if there are no matching left-side documents, as indicated by the results in which the fields from the `airport` keyspace are null or missing. +==== + +[#ANSI-Join-Example-4] +.Inner Join with Covering Index +==== +Use an ANSI JOIN to list the routes and destination airports that are available from London Heathrow (ICAO code `EGLL`). + +By default, the ANSI JOIN uses the `def_inventory_route_sourceairport` index, which is installed with the `travel-sample` bucket. +This index has `sourceairport` as its leading key. + +.Index +[source,sqlpp] +---- +include::example$select/ansi-join-cover.n1ql[tag=default] +---- + +.Query +[source,sqlpp] +---- +include::example$select/ansi-join-cover.n1ql[tag=query] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-join-cover.jsonc[tags=extract;ellipsis] +---- + +If no covering index is available, the Query Service has to fetch each matching record from the `route` keyspace to get the airline and destination airport information, as shown in the query plan: + +image::FROM_AnsiJoin-Ex4-BeerVisual1.png["Query plan with Fetch 'route' step before Nested Loop Join"] + +If you create a covering index, with `sourceairport` as the leading key, and `airline` and `destinationairport` as additional index keys: + +.Covering Index +[source,sqlpp] +---- +include::example$select/ansi-join-cover.n1ql[tag=cover] +---- + +\... then the Query Service does not need to fetch any records from the `route` keyspace, as shown in the query plan: + +image::FROM_AnsiJoin-Ex4-BeerVisual2.png["Query plan with no Fetch 'route' step before Nested Loop Join"] +==== + +[#ansi-join-rhs] +== ANSI JOIN Right-Hand Side + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-join-rhs] +---- + +image::n1ql-language-reference/ansi-join-rhs.png["Syntax diagram", align=left] + +In Couchbase Capella, the right-hand side of an ANSI join may be a keyspace reference, a subquery, or a generic expression term. + +[horizontal.compact] +rhs-keyspace:: <> icon:caret-down[] +rhs-subquery:: <> icon:caret-down[] +rhs-generic:: <> icon:caret-down[] + +[#ansi-rhs-keyspace] +=== Right-Hand Side Keyspace + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=rhs-keyspace] +---- + +image::n1ql-language-reference/rhs-keyspace.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] +ansi-join-hints:: <> icon:caret-down[] + +[#ansi-keyspace-ref] +==== Keyspace Reference + +Keyspace reference for the right-hand side of the ANSI join. +For details, see xref:n1ql-language-reference/from.adoc#from-keyspace-ref[Keyspace Reference]. + +[#ansi-keyspace-alias] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#ansi-rhs-subquery] +=== Right-Hand Side Subquery + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=rhs-subquery] +---- + +image::n1ql-language-reference/rhs-subquery.png["Syntax diagram", align=left] + +[horizontal.compact] +subquery-expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#ansi-subquery-expr] +==== Subquery Expression + +Use parentheses to specify a subquery for the right-hand side of the ANSI join. +For details, see xref:n1ql-language-reference/from.adoc#select-expr-clause[Subquery Expression]. + +NOTE: A subquery on the right-hand side of the ANSI join cannot be *correlated*, i.e. it cannot refer to a keyspace in the outer query block. +This will lead to an error. + +[#ansi-subquery-alias] +==== AS Alias + +Assigns another name to the subquery. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +You must assign an alias to a subquery on the right-hand side of the join. +However, when you assign an alias to the subquery, the `AS` keyword may be omitted. + +[#ansi-rhs-generic] +=== Right-Hand Side Generic Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=rhs-generic] +---- + +image::n1ql-language-reference/rhs-generic.png["Syntax diagram", align=left] + +[horizontal.compact] +expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#ansi-generic-expr] +==== Expression Term + +A {sqlpp} xref:n1ql-language-reference/index.adoc[expression] generating JSON documents or objects for the right-hand side of the ANSI join. + +NOTE: An expression on the right-hand side of the ANSI join may be *correlated*, i.e. it may refer to a keyspace on the left-hand side of the join. +In this case, only a <> may be used. + +[#ansi-generic-alias] +==== AS Alias + +Assigns another name to the generic expression. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +You must assign an alias to the generic expression if it is not an identifier; otherwise, assigning an alias is optional. +However, when you assign an alias to the generic expression, the `AS` keyword may be omitted. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ANSI-Join-Example-sub] +.Inner Join with Subquery on Right-Hand Side +==== +Find the destination airport of all routes whose source airport is in San Francisco. + +[source,sqlpp] +---- +include::example$select/ansi-join-sub.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-join-sub.jsonc[tags=extract;ellipsis] +---- +==== + +[#ANSI-Join-Example-expr] +.Inner Join with Generic Expression on Right-Hand Side +==== +Find the destination airport of all routes in the given array whose source airport is in San Francisco. + +[source,sqlpp] +---- +include::example$select/ansi-join-expr.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-join-expr.jsonc[] +---- +==== + +[#ansi-join-hints] +== ANSI JOIN Hints + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-join-hints] +---- + +image::n1ql-language-reference/ansi-join-hints.png["Syntax diagram", align=left] + +[horizontal.compact] +use-hash-hint:: <> icon:caret-down[] +use-nl-hint:: <> icon:caret-down[] +multiple-hints:: <> icon:caret-down[] + +There are two join methods for performing ANSI join: nested-loop join and hash join. +Two corresponding join hints are introduced: `USE HASH` and `USE NL`. + +The ANSI join hints are similar to the xref:n1ql-language-reference/hints.adoc#use-index-clause[USE INDEX] or xref:n1ql-language-reference/hints.adoc#use-keys-clause[USE KEYS] hints. +The ANSI join hints can be specified after the right-hand side of an ANSI join specification. + +NOTE: The join hint for the first join should be specified on the first join's right-hand side, and the join hint for the second join should be specified on the second join's right-hand side, etc. +If a join hint is specified on the first FROM term, i.e. the first join's left-hand side, an error is returned. + +TIP: In Couchbase Capella, you can also supply a join hint within a specially-formatted xref:n1ql-language-reference/optimizer-hints.adoc[hint comment]. +Note that you cannot specify a join hint for the same keyspace using both the `USE` clause and a hint comment. +If you do this, the `USE` clause and the hint comment are both marked as erroneous and ignored by the optimizer. + +[#default-join-method] +.Default Join Method + +For an ANSI join with a subquery or a generic expression as the right-hand side, the default method is hash. +In this case: + +* The subquery or expression on the right-hand side of the join is used as the <> of the hash join. +If `USE HASH(PROBE)` is specified, then the expression or subquery will be used as the <> of the hash join. + +* If an expression on the right-hand side is <>, a nested-loop join is used. +(If a subquery on the right-hand side is <>, the query returns an error.) + +* If a hash join is not feasible or not supported, or if the `USE NL` hint is specified, a nested-loop join is used. + +For other types of join, the default method is nested-loop. +In this case: + +* Hash join is only considered when the `USE HASH` hint is specified, and it requires at least one equality predicate between the left-hand side and right-hand side. + +* If the join meets these conditions, hash join is used. +If the hash join cannot be generated, then the planner will further consider nested-loop join, and will either generate a nested-loop join or return an error for the join. + +* If no join hint is specified, or the `USE NL` hint is specified, then nested-loop join is considered. + +''' + +[#use-hash-hint] +=== USE HASH Hint + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-hash-hint] +---- + +// <> +image::n1ql-language-reference/use-hash-hint.png["Syntax diagram", align=left] + +[source#use-hash-term,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-hash-term] +---- + +image::n1ql-language-reference/use-hash-term.png["Syntax diagram", align=left] + +There are two versions of the `USE HASH` hint: + +* `USE HASH(BUILD)` -- The right-hand side of the join is to be used as the build side. +* `USE HASH(PROBE)` -- The right-hand side of the join is to be used as the probe side. + +A hash join has two sides: a *build* side and a *probe* side. +The build side of the join will be used to create an in-memory hash table. +The probe side will use that table to find matches and perform the join. +Typically, this means you want the build side to be used on the smaller of the two sets. +However, you can only supply one hash hint, and only to the right side of the join. +So if you specify `BUILD` on the right side, then you are implicitly using `PROBE` on the left side (and vice versa). + +In Couchbase Capella, this clause is equivalent to the `USE_HASH` optimizer hint. +For more details, refer to xref:n1ql-language-reference/keyspace-hints.adoc#use-hash[Keyspace Hints]. + +[#use-nl-hint] +=== USE NL Hint + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-nl-hint] +---- + +// <> +image::n1ql-language-reference/use-nl-hint.png["Syntax diagram", align=left] + +[source#use-nl-term,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=use-nl-term] +---- + +image::n1ql-language-reference/use-nl-term.png["Syntax diagram", align=left] + +This join hint instructs the planner to use nested-loop join (NL join) for the join being considered. + +In Couchbase Capella, this clause is equivalent to the `USE_NL` optimizer hint. +For more details, refer to xref:n1ql-language-reference/keyspace-hints.adoc#use-hash[Keyspace Hints]. + +[#multiple-hints] +=== Multiple Hints + +// <> <> + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=multiple-hints] +---- + +image::n1ql-language-reference/multiple-hints.png["Syntax diagram", align=left] + +[source#ansi-hint-terms,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-hint-terms] +---- + +image::n1ql-language-reference/ansi-hint-terms.png["Syntax diagram", align=left] + +[source#other-hint-terms,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=other-hint-terms] +---- + +image::n1ql-language-reference/other-hint-terms.png["Syntax diagram", align=left] + +You can use only one join hint (<> or <>) together with only one other hint (xref:n1ql-language-reference/hints.adoc#use-index-term[USE INDEX] or xref:n1ql-language-reference/hints.adoc#use-keys-term[USE KEYS]) for a total of two hints. +The order of the two hints doesn't matter. + +When multiple hints are being specified, use only one `USE` keyword with one following the other, as shown in <> and <>. + +When chosen, the hash join will always work; the restrictions are on any USE KEYS hint clause: + +* Must not depend on any previous keyspaces. +* The expression must be constants, host variables, etc. +* Must not contain any subqueries. + +NOTE: If the USE KEYS hint contains references to other keyspaces or subqueries, then the USE HASH hint will be ignored and nested-loop join will be used instead. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#USE-HASH-Example-1] +.USE HASH with PROBE +==== +The keyspace `aline` is to be joined (with `rte`) using hash join, and `aline` is used as the probe side of the hash join. + +[source,sqlpp] +---- +include::example$select/use-hash-probe-legacy.n1ql[tag=query] +---- + +.Results +[source,JSON] +---- +[ + { + "Total_Count": 17629 + } +] +---- +==== + +[#USE-HASH-Example-2] +.USE HASH with BUILD +==== +This is effectively the same query as the previous example, except the two keyspaces are switched, and here the `USE HASH(BUILD)` hint is used, indicating the hash join should use `rte` as the build side. + +[source,sqlpp] +---- +include::example$select/use-hash-build-legacy.n1ql[tag=query] +---- + +.Results +[source,JSON] +---- +[ + { + "Total_Count": 17629 + } +] +---- +==== + +.USE NL +==== +[source,sqlpp] +---- +include::example$select/use-nl-legacy.n1ql[tag=query] +---- +==== + + +[#Multiple-hint-Example-1] +.USE INDEX with USE HASH +==== +[source,sqlpp] +---- +SELECT COUNT(1) AS Total_Count +FROM route rte +INNER JOIN airline aline +USE INDEX (idx_destinations) HASH (PROBE) +ON (rte.airlineid = META(aline).id); +---- +==== + +[#Multiple-hint-Example-2] +.USE HASH with USE KEYS +==== +[source,sqlpp] +---- +SELECT COUNT(1) AS Total_Count +FROM route rte +INNER JOIN airline aline +USE HASH (PROBE) KEYS ["airline_10", "airline_21", "airline_22"] +ON (rte.airlineid = META(aline).id); +---- +==== + +== ANSI JOIN and Arrays + +ANSI JOIN provides great flexibility since the `ON` clause of an ANSI JOIN can be any expression as long as it evaluates to TRUE or FALSE. +Below are different join scenarios involving arrays and ways to handle each scenario. + +[NOTE] +==== +These keyspaces and indexes will be used throughout this section's array scenarios. +As a convention, when a field name starts with `a` it is an array, so each keyspace has two array fields and two regular fields. + +[plantuml,ansi-join-example,svg] +.... +@startuml +object "Keyspace b1" as b1 { +a11 +a12 +c11 +c12 +} + +object "Keyspace b2" as b2 { +a21 +a22 +c21 +c22 +} +@enduml +.... + +Within each keyspace, both `_idx1` indexes index each element of its array, while both `_idx2` indexes use its entire array as the index key. + +[source,sqlpp] +---- +CREATE INDEX b1_idx1 ON b1 (c11, c12, DISTINCT a11); +CREATE INDEX b1_idx2 ON b1 (a12); +CREATE INDEX b2_idx1 ON b2 (c21, c22, DISTINCT a21); +CREATE INDEX b2_idx2 ON b2 (a22); +---- +==== + +=== ANSI JOIN with No Arrays + +In this scenario, there is no involvement of arrays in the join. +These are just straight-forward joins: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b1.c11 = b2.c21 + AND b2.c22 = 100 +WHERE b1.c12 = 10; +---- + +Here the joins are using non-array fields of each keyspace. + +The following case also falls in this scenario: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b1.c11 = b2.c21 + AND b2.c22 = 100 + AND ANY v IN b2.a21 SATISFIES v = 10 END +WHERE b1.c12 = 10; +---- + +In this example, although there is an ANY predicate on the right-hand side array `b2.a21`, the ANY predicate does not involve any joins, and thus, as far as the join is concerned, it is still a 1-to-1 join. +Similarly: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b1.c11 = b2.c21 +WHERE b1.c11 = 10 + AND b1.c12 = 100 + AND ANY v IN b1.a11 SATISFIES v = 20 END; +---- + +In this case the ANY predicate is on the left-hand side array `b1.a11`; however, similar to above, the ANY predicate does not involve any joins, and thus the join is still 1-to-1. +We can even have ANY predicates on both sides: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b1.c11 = b2.c21 + AND b2.c22 = 100 + AND ANY v IN b2.a21 SATISFIES v = 10 END +WHERE b1.c11 = 10 + AND b1.c12 = 100 + AND ANY v IN b1.a11 SATISFIES v = 10 END; +---- + +Again, the ANY predicates do not involve any join, and the join is still 1-to-1. + +=== ANSI JOIN with Entire Array as Index Key + +As a special case, it is possible to perform ANSI JOIN on an entire array as a join key: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b1.a21 = b2.a22 +WHERE b1.c11 = 10 + AND b1.c12 = 100; +---- + +In this case, the entire array must match each other for the join to work. +For all practical purposes, the array here is treated as a scalar since there is no logic to iterate through elements of an array here. +The entire array is used as an index key (`b2_idx2`) and as such, an entire array is used as an index span to probe the index. +The join here can also be considered as 1-to-1. + +=== ANSI JOIN Involving Right-Hand Side Arrays + +In this scenario, the join involves an array on the right-hand side keyspace: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b2.c21 = 10 + AND b2.c22 = 100 + AND ANY v IN b2.a21 SATISFIES v = b1.c12 END +WHERE b1.c11 = 10; +---- + +In this case, the ANY predicate involves a join, and thus, effectively we are joining `b1` with elements of the `b2.a21` array. +This now becomes a 1-to-many join. +Note that we use an ANY clause for this scenario since it’s a natural extension of the existing support for array indexes; the only difference is for index span generation, we now can have a potential join expression. +Array indexes can be used for join in this scenario. + +=== ANSI JOIN Involving Left-Hand Side Arrays + +This is a slightly more complex scenario, where the array reference is on the left-hand side of the join, and it’s a many-to-1 join. +There are two alternative ways to handle the scenario where the array appears on the left-hand side of the join. + +==== Use UNNEST + +This alternative will flatten the left-hand side array first, before performing the join: + +[source,sqlpp] +---- +SELECT * +FROM b1 UNNEST b1.a12 AS ba1 +JOIN b2 + ON ba1 = b2.c22 + AND b2.c21 = 10 +WHERE b1.c11 = 10 + AND b1.c12 = 100; +---- + +The <> operation is used to flatten the array, turning one left-hand side document into multiple documents; and then for each one of them, join with the right-hand side. +This way, by the time join is being performed, it is a regular join, since the array is already flattened in the UNNEST step. + +==== Use IN clause + +This alternative uses the IN clause to handle the array: + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON b2.c22 IN b1.a12 AND b2.c21 = 10 +WHERE b1.c11 = 10 AND b1.c12 = 100; +---- + +By using the xref:n1ql-language-reference/indexing-arrays.adoc[IN] clause, the right-hand side field value can match any of the elements of the left-hand side array. +Conceptually, we are using each element of the left-hand side array to probe the right-hand side index. + +==== Differences Between the Two Alternatives + +There is a semantical difference between the two alternatives. +With UNNEST, we are first turning one left-hand side document into multiple documents and then performing the join. +With IN-clause, there is still only one left-hand side document, which can then join with one or more right-hand side documents. +Thus: + +* If the array contains duplicate values, + ** the UNNEST method treats each duplicate as an individual value and thus duplicated results will be returned; + ** the IN clause method will not duplicate the result. + +* If no duplicate values exists and we are performing inner join, + ** then the two alternatives will likely give the same result. + +* If outer join is performed, assuming there are N elements in the left-hand side array, and assuming there is at most one matching document from the right-hand side for each element of the array, + ** the UNNEST method will produce N result documents; + ** the IN clause method may produce < N result documents if some of the array elements do not have matching right-hand side documents. + +=== ANSI JOIN with Arrays on Both Sides + +If the join involves arrays on both sides, then we can combine the approaches above, i.e., using ANY clause to handle the right-hand side array and either UNNEST or IN clause to handle the left-hand side array. +For example: + +[source,sqlpp] +---- +SELECT * +FROM b1 +UNNEST b1.a12 AS ba1 + JOIN b2 + ON ANY v IN b2.a21 SATISFIES v = ba1 END + AND b2.c21 = 10 + AND b2.c22 = 100 +WHERE b1.c11 = 10 + AND b1.c12 = 100; +---- + +or + +[source,sqlpp] +---- +SELECT * +FROM b1 +JOIN b2 + ON ANY v IN b2.a21 SATISFIES v IN b1.a12 END + AND b2.c21 = 10 + AND b2.c22 = 100 +WHERE b1.c11 = 10 + AND b1.c12 = 100; +---- + +[#lookup-join-clause] +== Lookup JOIN Clause + +=== Purpose + +A _lookup join_ is a legacy syntax for joins. +It enables you to join a foreign key field on the left-hand side of the join with the primary xref:server:learn:data/data.adoc#keys[document key] on the right-hand side of the join. + +In the join predicate for a lookup join, the `ON KEYS` expression must refer to the foreign key in the left-hand side keyspace. +This is then used to retrieve documents from the right-hand side keyspace. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-join-clause] +---- + +image::n1ql-language-reference/lookup-join-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +lookup-join-type:: <> icon:caret-down[] +lookup-join-rhs:: <> icon:caret-down[] +lookup-join-predicate:: <> icon:caret-down[] + +[#lookup-join-type] +==== Join Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-join-type] +---- + +image::n1ql-language-reference/lookup-join-type.png["Syntax diagram", align=left] + +This clause represents the type of join. + +`INNER`:: +For each joined object produced, both the left-hand and right-hand source objects must be non-`MISSING` and non-`NULL`. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +For each joined object produced, only the left-hand source objects must be non-`MISSING` and non-`NULL`. + +This clause is optional. +If omitted, the default is `INNER`. + +[#lookup-join-rhs] +==== Join Right-Hand Side + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-join-rhs] +---- + +image::n1ql-language-reference/lookup-join-rhs.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#lookup-keyspace-ref] +===== Keyspace Reference + +Keyspace reference for the right-hand side of the lookup join. +For details, see xref:n1ql-language-reference/from.adoc#from-keyspace-ref[Keyspace Reference]. + +NOTE: The right-hand side of a lookup join must be a keyspace. +Expressions, subqueries, or other join combinations cannot be on the right-hand side of a lookup join. + +[#lookup-as-alias] +===== AS Alias + +Assigns another name to the right-hand side of the lookup join. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#lookup-join-predicate] +==== Join Predicate + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-join-predicate] +---- + +image::n1ql-language-reference/lookup-join-predicate.png["Syntax diagram", align=left] + +The `ON KEYS` expression produces a document key or array of document keys, which is used to retrieve documents from the right-hand side keyspace. + +expr:: +[Required] String or expression representing the foreign key in the left-hand side keyspace. + +=== Return Values + +If `LEFT` or `LEFT OUTER` is specified, then a left outer join is performed. + +At least one joined object is produced for each left-hand source object. + +If the right-hand source object is `NULL` or `MISSING`, then the joined object's right-hand side value is also `NULL` or `MISSING` (omitted), respectively. + +=== Limitations + +Lookup joins can be chained with other lookup joins or nests and index joins or nests, but they cannot be mixed with ANSI joins, ANSI nests, or comma-separated joins. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#Lookup-JOIN-Example-1] +.Inner Lookup Join +==== +List all airlines and non-stop routes from SFO in the `route` keyspace. + +[source,sqlpp] +---- +include::example$select/lookup-join-inner.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/lookup-join-inner.jsonc[] +---- +==== + +[#Lookup-JOIN-Example-2] +.Left Outer Lookup Join +==== +List routes from Atlanta to Seattle, including those for which there is no airline in the `airline` keyspace. + +[source,sqlpp] +---- +include::example$select/lookup-join-left.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/lookup-join-left.jsonc[] +---- +==== + +[#index-join-clause] +== Index JOIN Clause + +=== Purpose + +An _index join_ is another legacy syntax for joins which reverses the direction of a lookup join. +It enables you to join the primary xref:server:learn:data/data.adoc#keys[document key] on the left-hand side of the join with a foreign key field on the right-hand side of the join. + +You can use an index join when a lookup join would be inefficient, and you need to flip the relationship so the join predicate is on the right-hand side of the join. + +For index joins, the syntax uses `ON KEY ... FOR` (singular) instead of `ON KEYS` (plural). +This is because an index join's `ON KEY ... FOR` expression produces a single scalar value; whereas a lookup join's `ON KEYS` expression can produce either a single scalar or an array of scalar values. + +NOTE: An index join requires an inverse index on the foreign key in the keyspace on the right-hand side of the join. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-join-clause] +---- + +image::n1ql-language-reference/index-join-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +index-join-type:: <> icon:caret-down[] +index-join-rhs:: <> icon:caret-down[] +index-join-predicate:: <> icon:caret-down[] + +[#index-join-type] +==== Join Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-join-type] +---- + +image::n1ql-language-reference/index-join-type.png["Syntax diagram", align=left] + +This clause represents the type of join. + +`INNER`:: For each joined object produced, both the left-hand and right-hand source objects must be non-`MISSING` and non-`NULL`. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +For each joined object produced, only the left-hand source objects must be non-`MISSING` and non-`NULL`. + +This clause is optional. +If omitted, the default is `INNER`. + +[#index-join-rhs] +==== Join Right-Hand Side + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-join-rhs] +---- + +image::n1ql-language-reference/index-join-rhs.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#index-keyspace-ref] +===== Keyspace Reference + +Keyspace reference for right-hand side of an index join. +For details, see xref:n1ql-language-reference/from.adoc#from-keyspace-ref[Keyspace Reference]. + +NOTE: The right-hand side of an index join must be a keyspace. +Expressions, subqueries, or other join combinations cannot be on the right-hand side of an index join. + +[#index-as-alias] +===== AS Alias + +Assigns another name to the right-hand side of the index join. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#index-join-predicate] +==== Join Predicate + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-join-predicate] +---- + +image::n1ql-language-reference/index-join-predicate.png["Syntax diagram", align=left] + +`expr`:: Expression in the form `__rhs-expression__.__lhs-expression-key__`: + +`__rhs-expression__`;; Keyspace reference for the right-hand side of the index join. + +`__lhs-expression-key__`;; String or expression representing the attribute in `__rhs-expression__` and referencing the document key for `alias`. + +`alias`:: Keyspace reference for the left-hand side of the index join. + +=== Limitations + +Index joins can be chained with other index joins or nests and lookup joins or nests, but they cannot be mixed with ANSI joins, ANSI nests, or comma-separated joins. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#Index-JOIN-Example-0] +.Use INDEX join to flip the direction of <> above +==== +Consider the query below, similar to <> above with route and airline documents, where `route.airlineid` is the document key of route documents and airline documents have no reference to route documents: + +[source,sqlpp] +---- +include::example$select/index-join.n1ql[tag=lookup] +---- + +This query gets a list of Southwest Airlines (`SWA`) flights, but getting `SWA` flights cannot be efficiently executed without making a Cartesian product of all route documents (left-hand side) with all airline documents (right-hand side). + +This query cannot use any index on airline to directly access SWA flights because airline is on the right-hand side. + +Also, you cannot rewrite the query to put the airline document on the left-hand side (to use any index) and the route document on the right-hand side because the airline documents (on the left-hand side) have no primary keys to access the route documents (on the right-hand side). + +Using index joins, the same query can be written as: + +.Required Index +[source,sqlpp] +---- +include::example$select/index-join.n1ql[tag=index-req] +---- + +.Optional Index +[source,sqlpp] +---- +include::example$select/index-join.n1ql[tag=index-opt] +---- + +.Query +[source,sqlpp] +---- +include::example$select/index-join.n1ql[tag=query] +---- + +.Results +[source,JSON] +---- +include::example$select/index-join.jsonc[tags=extract;ellipsis] +---- + +If you generalize the same query, it looks like the following: + +[subs="normal"] +---- +CREATE INDEX _on-key-for-index-name_ _rhs-expression_ (__lhs-expression-key__); +---- + +[subs="normal"] +---- +SELECT _projection-list_ +FROM _lhs-expression_ +JOIN _rhs-expression_ + ON KEY __rhs-expression__.__lhs-expression-key__ FOR _lhs-expression_ +[ WHERE _predicates_ ] ; +---- +==== + +There are three important changes in the index scan syntax example above: + +* `CREATE INDEX` on the `ON KEY` expression `route.airlineid` to access `route` documents using `airlineid`, which are produced on the left-hand side. +* The `ON KEY route.airlineid FOR airline` enables {sqlpp} to use the index `route.airlineid`. +* Create any optional index such as `route.airline` that can be used on airline (left-hand side). + +[#Index-JOIN-Example-1] +.`+ON KEY ... FOR+` +==== +The following example counts the number of distinct "AA" airline routes for each airport after creating the following index, if not already created. + +[source,sqlpp] +---- +CREATE INDEX route_airlineid ON route(airlineid); +---- + +[source,sqlpp] +---- +SELECT COUNT(DISTINCT route.sourceairport) AS DistinctAirports +FROM airline + JOIN route + ON KEY route.airlineid FOR airline +WHERE airline.iata = "AA"; +---- + +.Results +[source,JSON] +---- +[ + { + "DistinctAirports": 429 + } +] +---- +==== + +== Appendix: Summary of JOIN Types + +include::ROOT:partial$query-context.adoc[tag=section] + +=== ANSI + +[cols=".^1s,3"] +|=== +| Left-Hand Side (lhs) +| Any field or expression that produces a value that will be matched on the right-hand side. + +| Right-Hand Side (rhs) +| Anything that can have a proper index on the join expression. + +| Syntax +a| +[subs="normal"] +---- +_lhs-expr_ +JOIN _rhs-keyspace_ +ON _any join condition_ +---- + +| Example +a| +[source,sqlpp] +---- +SELECT * +FROM route r +JOIN airline a +ON r.airlineid = META(a).id +---- +|=== + +Refer also to xref:n1ql-language-reference/comma.adoc[]. + +=== Lookup + +[cols=".^1s,3"] +|=== +| Left-Hand Side (lhs) +| Must produce a Document Key for the right-hand side. + +| Right-Hand Side (rhs) +| Must have a Document Key. + +| Syntax +a| +[subs="normal"] +---- +_lhs-expr_ +JOIN _rhs-keyspace_ +ON KEYS _lhs-expr.foreign-key_ +---- + +| Example +a| +[source,sqlpp] +---- +SELECT * +FROM route r +JOIN airline +ON KEYS r.airlineid +---- +|=== + +=== Index + +[cols=".^1s,3"] +|=== +| Left-Hand Side (lhs) +| Must produce a key for the right-hand side index. + +| Right-Hand Side (rhs) +| Must have a proper index on the field or expression that maps to the Document Key of the left-hand side. + +| Syntax +a| +[subs="normal"] +---- +_lhs-keyspace_ +JOIN _rhs-keyspace_ +ON KEY _rhs-kspace.idx_key_ +FOR _lhs-keyspace_ +---- + +| Example +a| +[source,sqlpp] +---- +SELECT * +FROM airline a +JOIN route r +ON KEY r.airlineid +FOR a +---- +|=== diff --git a/modules/n1ql/pages/n1ql-language-reference/jsonfun.adoc b/modules/n1ql/pages/n1ql-language-reference/jsonfun.adoc new file mode 100644 index 000000000..001e6f855 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/jsonfun.adoc @@ -0,0 +1,32 @@ += JSON Functions +:description: DECODE_JSON(expression) +:page-topic-type: reference + +{description} + +Unmarshals the JSON-encoded string into a {sqlpp} value. +The empty string is MISSING. + +ENCODE_JSON(expression) + +Marshals the {sqlpp} value into a JSON-encoded string. +MISSING becomes the empty string. + +ENCODED_SIZE(expression) + +Number of bytes in an uncompressed JSON encoding of the value. +The exact size is implementation-dependent. +Always returns an integer, and never MISSING or NULL. +Returns 0 for MISSING. + +POLY_LENGTH(expression) + +Returns length of the value after evaluating the expression. +The exact meaning of length depends on the type of the value: + +* MISSING: MISSING +* NULL: NULL +* String: The length of the string. +* Array: The number of elements in the array. +* Object: The number of name/value pairs in the object +* Any other value: NULL diff --git a/modules/n1ql/pages/n1ql-language-reference/keyspace-hints.adoc b/modules/n1ql/pages/n1ql-language-reference/keyspace-hints.adoc new file mode 100644 index 000000000..2762af7da --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/keyspace-hints.adoc @@ -0,0 +1,684 @@ += Keyspace Hints +:page-topic-type: reference +:imagesdir: ../../assets/images +:description: Keyspace hints apply to a specific keyspace. +:cbo-preamble: For the examples in this section, it is assumed that the cost-based optimizer is active, and all optimizer statistics are up-to-date. +:page-partial: +:!example-caption: + +[abstract] +{description} + +A keyspace hint is a type of xref:n1ql-language-reference/optimizer-hints.adoc[optimizer hint]. +Keyspace hints include _index_ hints, which enable you to specify indexes, and _join_ hints, which enable you to specify join methods. + +For each keyspace hint, you must specify the keyspace or keyspaces that the hint applies to. +If a keyspace is given an explicit alias in the query, then the hint must refer to the explicit alias, not the keyspace name. This is to avoid confusion in situations where the same keyspace can be used multiple times (with different aliases) in the same query. + +If the keyspace is _not_ given an explicit alias in the query, the hint must refer to the keyspace using the keyspace name. +(If the keyspace name is a dotted path, the hint must refer to the keyspace using its implicit alias, which is the last component in the keyspace path.) + +There are two possible formats for each optimizer hint: simple syntax and JSON syntax. +Note that you cannot mix simple syntax and JSON syntax in the same hint comment. + +== INDEX + +This hint directs the optimizer to consider one or more specified secondary indexes. +If not specified, the optimizer selects the optimal available index. + +=== Simple Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=gsi-hint-simple] +---- + +image::n1ql-language-reference/gsi-hint-simple.png["Syntax diagram: refer to source code listing", align=left] + +With the simple syntax, this hint specifies a single keyspace expression, and zero, one, or more indexes. +You can use this hint multiple times within the hint comment to specify hints for more than one keyspace. + +==== Arguments + +keyspace:: +// tag::keyspace[] +The keyspace or alias to which this hint applies. +// end::keyspace[] + +index:: +A secondary index that the optimizer should consider for the given keyspace. +This argument is optional; if omitted, the optimizer considers _all_ secondary indexes available in the given keyspace. + +=== JSON Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=gsi-hint-json] +---- + +image::n1ql-language-reference/gsi-hint-json.png["Syntax diagram: refer to source code listing", align=left] + +With the JSON syntax, this hint takes the form of an `index` property. +You may only use this property once within the hint comment. +The value of this property may be an <> or an <>. + +[#index-array] +==== Index Array + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=index-array] +---- + +image::n1ql-language-reference/index-array.png["Syntax diagram: refer to source code listing", align=left] + +Use this array to specify indexes for multiple keyspaces. +Each element must be an <>. + +[#index-object] +==== Index Object + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=index-object] +---- + +image::n1ql-language-reference/index-object.png["Syntax diagram: refer to source code listing", align=left] + +Use this object to specify indexes for a single keyspace. +It must contain a <> and an <>. +The order of the properties within the object is not significant. + +[#keyspace-property] +==== Keyspace Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=keyspace-property] +---- + +image::n1ql-language-reference/keyspace-property.png["Syntax diagram: refer to source code listing", align=left] + +Synonym for `"keyspace"`: `"alias"` + +// tag::keyspace-property[] +The value of this property is the keyspace or alias to which this hint applies. +// end::keyspace-property[] + +[#indexes-property] +==== Indexes Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=indexes-property] +---- + +image::n1ql-language-reference/indexes-property.png["Syntax diagram: refer to source code listing", align=left] + +The value of this property may be: + +[horizontal] +`null`:: +The optimizer considers all secondary indexes available in the given keyspace. + +An _index_ string:: +A secondary index that the optimizer should consider for the given keyspace. + +An array of _index_ strings:: +An array of secondary indexes that the optimizer should consider for the given keyspace. + +[#index-examples,reftext="INDEX Examples"] +=== Examples + +{cbo-preamble} + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ex-index-opt] +.Optimized index selection +==== +The following query does not include an index hint. + +.Query +[source,sqlpp] +---- +include::example$select/index-opt.n1ql[tag=query] +---- + +If you examine the plan for this query, you can see that the optimizer has selected the index `def_inventory_route_sourceairport`, which is installed with the travel sample dataset. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/index-opt.jsonc[tag=index] +---- +==== + +[#ex-index-hint] +.INDEX hint +==== +The following query hints that the optimizer should select the index `def_inventory_route_route_src_dst_day` for the keyspace `route`. + +.Query +[source,sqlpp] +---- +include::example$select/index-hint.n1ql[tag=query] +---- + +<.> The keyspace is not given an explicit alias in the query. +You must therefore refer to the keyspace using the keyspace name or implicit alias -- in this case, `route`. +<.> The implicit alias is the last element in the keyspace path. + +If you examine the plan for this query, you can see that the query uses the suggested index. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/index-hint.jsonc[tag=index] +---- +==== + +=== Legacy Equivalent + +This hint is equivalent to the legacy `USE INDEX (USING GSI)` clause. +For more details, refer to xref:n1ql-language-reference/hints.adoc#use-index-clause[USE INDEX Clause]. + +Note that you cannot use a hint comment and the `USE` clause to specify optimizer hints on the same keyspace. +If you do this, the hint comment and the `USE` clause are marked as erroneous and ignored by the optimizer. + +== INDEX_FTS + +This hint directs the optimizer to consider one or more specified full-text indexes. +If not specified, the optimizer selects the optimal available index. + +=== Simple Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=fts-hint-simple] +---- + +image::n1ql-language-reference/fts-hint-simple.png["Syntax diagram: refer to source code listing", align=left] + +With the simple syntax, this hint specifies a single keyspace expression; and zero, one, or more indexes. +You can use this hint multiple times within the hint comment to specify hints for more than one keyspace. + +==== Arguments + +keyspace:: +include::keyspace-hints.adoc[tag=keyspace] + +index:: +A full-text index that the optimizer should consider for the given keyspace. +This argument is optional; if omitted, the optimizer considers _all_ full-text indexes available in the given keyspace. + +=== JSON Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=fts-hint-json] +---- + +image::n1ql-language-reference/fts-hint-json.png["Syntax diagram: refer to source code listing", align=left] + +With the JSON syntax, this hint takes the form of an `index_fts` property. +You may only use this property once within the hint comment. +The value of this property may be an <> or an <>. + +[#index-array-fts] +==== Index Array + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=index-array] +---- + +image::n1ql-language-reference/index-array.png["Syntax diagram: refer to source code listing", align=left] + +Use this array to specify indexes for multiple keyspaces. +Each element must be an <>. + +[#index-object-fts] +==== Index Object + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=index-object] +---- + +image::n1ql-language-reference/index-object.png["Syntax diagram: refer to source code listing", align=left] + +Use this object to specify indexes for a single keyspace. +It must contain a <> and an <>. +The order of the properties within the object is not significant. + +[#keyspace-property-fts] +==== Keyspace Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=keyspace-property] +---- + +image::n1ql-language-reference/keyspace-property.png["Syntax diagram: refer to source code listing", align=left] + +Synonym for `"keyspace"`: `"alias"` + +include::keyspace-hints.adoc[tag=keyspace-property] + +[#indexes-property-fts] +==== Indexes Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=indexes-property] +---- + +image::n1ql-language-reference/indexes-property.png["Syntax diagram: refer to source code listing", align=left] + +The value of this property may be: + +[horizontal] +`null`:: +The optimizer considers all full-text indexes available in the given keyspace. + +_index_ string:: +A full-text index that the optimizer should consider for the given keyspace. + +_index_ array:: +An array of full-text indexes that the optimizer should consider for the given keyspace. + +[#index-fts-examples,reftext="INDEX_FTS Examples"] +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ex-index-fts-hint] +.INDEX_FTS hint +==== +This example specifies that the optimizer should prefer any suitable FTS index, without specifying an index by name. +To qualify for this query, there must be an FTS index on `state` and `type`, using the keyword analyzer. +(Or alternatively, an FTS index on `state`, with a custom type mapping on "hotel".) + +.Query +[source,sqlpp] +---- +SELECT /*+ INDEX_FTS (hotel) */ + META().id +FROM hotel +WHERE state = "Corse" OR state = "California"; +---- + +All FTS indexes are considered. +If a qualified FTS index is available, it is selected for the query. +If none of the available FTS indexes are qualified, the available GSI indexes are considered instead. +==== + +=== Legacy Equivalent + +This hint is equivalent to the legacy `USE INDEX (USING FTS)` clause. +For more details, refer to xref:n1ql-language-reference/hints.adoc#use-index-clause[USE INDEX Clause]. + +Note that you cannot use a hint comment and the `USE` clause to specify optimizer hints on the same keyspace. +If you do this, the hint comment and the `USE` clause are marked as erroneous and ignored by the optimizer. + +== USE_NL + +This hint directs the optimizer to consider a nested-loop join for the specified keyspace. +This hint must be specified on the keyspace on the right-hand side of the join. +If not specified, the optimizer selects the optimal join method. + +=== Simple Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=nl-hint-simple] +---- + +image::n1ql-language-reference/nl-hint-simple.png["Syntax diagram: refer to source code listing", align=left] + +With the simple syntax, this hint specifies one or more keyspaces. +You may also use this hint multiple times within the hint comment. + +==== Arguments + +keyspace:: +include::keyspace-hints.adoc[tag=keyspace] + +=== JSON Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=nl-hint-json] +---- + +image::n1ql-language-reference/nl-hint-json.png["Syntax diagram: refer to source code listing", align=left] + +With the JSON syntax, this hint takes the form of a `use_nl` property. +You may only use this property once within the hint comment. +The value of this property may be a <> or a <>. + +[#keyspace-array] +==== Keyspace Array + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=keyspace-array] +---- + +image::n1ql-language-reference/keyspace-array.png["Syntax diagram: refer to source code listing", align=left] + +Use this array to apply the hint to multiple keyspaces. +Each element must be a <>. + +[#keyspace-object] +==== Keyspace Object + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=keyspace-object] +---- + +image::n1ql-language-reference/keyspace-object.png["Syntax diagram: refer to source code listing", align=left] + +Use this object to apply the hint to a single keyspace. +It must contain a <>. + +[#keyspace-property-nl] +==== Keyspace Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=keyspace-property] +---- + +image::n1ql-language-reference/keyspace-property.png["Syntax diagram: refer to source code listing", align=left] + +Synonym for `"keyspace"`: `"alias"` + +include::keyspace-hints.adoc[tag=keyspace-property] + +[#use-nl-examples,reftext="USE_NL Examples"] +=== Examples + +{cbo-preamble} + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ex-use-nl-opt] +.Optimized join method selection +==== +The following query does not include a join hint. + +.Query +[source,sqlpp] +---- +include::example$select/use-nl-opt.n1ql[tag=query] +---- + +If you examine the plan for this query, you can see that the optimizer has selected the hash join method. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/use-nl-opt.jsonc[tag=method] +---- +==== + +[#ex-use-nl-hint] +.USE_NL hint +==== +The following query is equivalent to the one in the <> example, but includes a nested-loop join hint. + +.Query +[source,sqlpp] +---- +include::example$select/use-nl-hint.n1ql[tag=query] +---- + +<.> The keyspace is given an explicit alias in the query. +You must therefore refer to the keyspace using the explicit alias. +<.> In this case, the explicit alias is `a`. + +If you examine the plan text for this query, you can see that the query uses the suggested join method. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/use-nl-hint.jsonc[tag=method] +---- +==== + +=== Legacy Equivalent + +This hint is equivalent to the legacy `USE NL` clause. +For more details, refer to xref:n1ql-language-reference/join.adoc#use-nl-hint[USE NL Clause]. + +Note that you cannot specify optimizer hints and the `USE` clause on the same keyspace in the same query. +If you do this, the optimizer hints and `USE` clause are both marked as erroneous and ignored by the optimizer. + +== USE_HASH + +This hint directs the optimizer to consider a hash join for the specified keyspace. +This hint must be specified on the keyspace on the right-hand side of the join. +If not specified, the optimizer selects the optimal join method. + +A hash join has two sides: a *build* side and a *probe* side. +The build side of the join is used to create an in-memory hash table. +The probe side uses that table to find matches and perform the join. +Typically, this means you want the build side to be used on the smaller of the two sets. + +This hint enables you specify whether the right side of the join should be the build side or the probe side. +If you specify that the right side of the join is the build side, then the left side will be the probe side, and vice versa. + + +=== Simple Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=hash-hint-simple] +---- + +image::n1ql-language-reference/hash-hint-simple.png["Syntax diagram: refer to source code listing", align=left] + +With the simple syntax, this hint specifies one or more keyspaces. +For each keyspace, you may also add a slash, followed by an option. +You may also use this hint multiple times within the hint comment. + +==== Arguments + +keyspace:: +include::keyspace-hints.adoc[tag=keyspace] + +==== Options + +/BUILD:: +// tag::build[] +The specified keyspace is to be used as the build side of the join. +// end::build[] + +/PROBE:: +// tag::probe[] +The specified keyspace is to be used as the probe side of the join. +// end::probe[] + +If you omit the option (including the slash), the optimizer determines whether the specified keyspace is to be used as the build side or the probe side of the join, based on the estimated cardinality of both sides. + +=== JSON Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=hash-hint-json] +---- + +image::n1ql-language-reference/hash-hint-json.png["Syntax diagram: refer to source code listing", align=left] + +With the JSON syntax, this hint takes the form of a `use_hash` property. +You may only use this property once within the hint comment. +The value of this property may be a <> or a <>. + +[#hash-array] +==== Hash Array + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=hash-array] +---- + +image::n1ql-language-reference/hash-array.png["Syntax diagram: refer to source code listing", align=left] + +Use this array to apply the hint to multiple keyspaces. +Each element must be a <>. + +[#hash-object] +==== Hash Object + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=hash-object] +---- + +image::n1ql-language-reference/hash-object.png["Syntax diagram: refer to source code listing", align=left] + +Use this object to apply the hint to a single keyspace. +It must contain a <> and an optional <>. +The order of the properties within the object is not significant. + +[#keyspace-property-hash] +==== Keyspace Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=keyspace-property] +---- + +image::n1ql-language-reference/keyspace-property.png["Syntax diagram: refer to source code listing", align=left] + +Synonym for `"keyspace"`: `"alias"` + +include::keyspace-hints.adoc[tag=keyspace-property] + +[#option-property] +==== Option Property + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=option-property] +---- + +image::n1ql-language-reference/option-property.png["Syntax diagram: refer to source code listing", align=left] + +The value of this property may be: + +[horizontal] +`"build"`:: +include::keyspace-hints.adoc[tag=build] + +`"probe"`:: +include::keyspace-hints.adoc[tag=probe] + +`null`:: +The optimizer determines whether the specified keyspace is to be used as the build side or the probe side of the join, based on the estimated cardinality of both sides. + +Similarly, if you omit this property entirely, the optimizer determines whether the specified keyspace is to be used as the build side or the probe side of the join. + +[#use-hash-examples,reftext="USE_HASH Examples"] +=== Examples + +{cbo-preamble} + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ex-use-hash-opt] +.Optimized join method selection +==== +The following query does not include a join hint. + +.Query +[source,sqlpp] +---- +include::example$select/use-hash-opt.n1ql[tag=query] +---- + +If you examine the plan for this query, you can see that the optimizer has selected to use the hash join method, and to put the `aline` keyspace on the build side of the join. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/use-hash-opt.jsonc[tags=method;ellipsis] +---- +==== + +[#ex-use-hash-probe-hint] +.USE_HASH with PROBE +==== +The following query is equivalent to the one in the <> example, but specifies that the keyspace `aline` is to be joined (with `rte`) using a hash join, and `aline` is used as the probe side of the hash join. + +.Query -- simple syntax +[source,sqlpp] +---- +include::example$select/use-hash-probe-hint.n1ql[tag=query] +---- + +If you examine the explain plan for this query, you can see that the query uses the hash join method as suggested, with the `aline` keyspace on the probe side of the join. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/use-hash-probe-hint.jsonc[tags=method;ellipsis] +---- +==== + +[#ex-use-hash-build-hint] +.USE_HASH with BUILD +==== +This is effectively the same query as the <> example, except the two keyspaces are switched, and here the `BUILD` option is used, indicating the hash join should use `rte` as the build side. + +.Query +[source,sqlpp] +---- +include::example$select/use-hash-build-hint.n1ql[tag=query] +---- + +If you examine the explain plan for this query, you can see that the query uses the hash join method as suggested, with the `rte` keyspace on the build side. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/use-hash-probe-hint.jsonc[tags=method;ellipsis] +---- +==== + +[#ex-use-hash-null-hint] +.USE_HASH with optimizer +==== +This is the same query as the <> example, but the hint does not specify whether the `aline` keyspace should be on the probe side or the build side of the join. + +.Query -- JSON syntax +[source,sqlpp] +---- +include::example$select/use-hash-null-hint.n1ql[tag=query] +---- + +If you examine the explain plan for this query, you can see that the query uses the hash join method as suggested, but the optimizer has selected to put the `aline` keyspace on the build side of the join. + +.Explain plan +[source,json,indent=0] +---- +include::example$select/use-hash-null-hint.jsonc[tags=method;ellipsis] +---- +==== + +=== Legacy Equivalent + +This hint is equivalent to the legacy `USE HASH` clause. +For more details, refer to xref:n1ql-language-reference/join.adoc#use-hash-hint[USE HASH Clause]. + +Note that you cannot specify both optimizer hints and the `USE` clause on the same keyspace. +If you do this, the optimizer hints and the `USE` clause are both marked as erroneous and ignored by the optimizer. + +== Related Links + +* xref:n1ql-language-reference/cost-based-optimizer.adoc[] +* xref:n1ql-language-reference/optimizer-hints.adoc[] +* xref:n1ql-language-reference/query-hints.adoc[] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/let.adoc b/modules/n1ql/pages/n1ql-language-reference/let.adoc new file mode 100644 index 000000000..4c58e357c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/let.adoc @@ -0,0 +1,168 @@ += LET clause +:description: Use LET to create variables for later use within a query. +:imagesdir: ../../assets/images +:page-topic-type: reference + +[abstract] +Use `LET` to create variables for later use within a query. + +== Purpose + +In a query expression, it is sometimes useful to store the result of a sub-expression in order to use it in subsequent clauses. +You can do this with the `LET` keyword, which creates a new variable and initializes it with the result of the expression you supply. +You can use the `LET` clause within an array, in a for-loop, or independently. + +Without the `LET` clause, your complex queries would need to be divided into two separate queries: + +* One query to get a particular value (or set of values), and +* One query to use the value (or values) from the first query. + +If the `LET` variable is referenced in the `WHERE` clause, then it is evaluated before the `WHERE` clause; otherwise, it is evaluated after the `WHERE` clause. + +Couchbase Capella supports chained `LET` clauses. +A variable that you create in one `LET` clause may be referenced in a later `LET` clause, as detailed in <>. + +Each `LET` alias needs to be unique within its scope. + +== Prerequisites + +The `LET` clause can only be used in a `SELECT` statement, and in order for you to select data from a document or keyspace, you must have the [.param]`query_select` privilege on the document or keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=let-clause] +---- + +image::n1ql-language-reference/let-clause.png["Syntax diagram", align=left] + +[#arguments] +== Arguments + +alias:: [Required] xref:n1ql-language-reference/identifiers.adoc[Identifier] that represents the name of the variable. + +expr:: [Required] xref:n1ql-language-reference/index.adoc#N1QL_Expressions[Expression] that represents the value assigned to its `alias`. + +[#examples_section] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ex1] +.Use LET to set variables to a number, an operation on a field, and a subquery +==== +Find all airports and cities between certain latitudes in a country with a landmark. + +[source,sqlpp] +---- +SELECT t1.airportname, t1.geo.lat, t1.geo.lon, t1.city, t1.type +FROM airport t1 +LET min_lat = 71, max_lat = ABS(t1.geo.lon)*4+1, + place = (SELECT RAW t2.country + FROM landmark t2) +WHERE t1.geo.lat > min_lat +AND t1.geo.lat < max_lat +AND t1.country IN place; +---- + +.Results +[source,JSON] +---- +[ + { + "airportname": "Wiley Post Will Rogers Mem", + "city": "Barrow", + "lat": 71.285446, + "lon": -156.766003, + "type": "airport" + }, + { + "airportname": "Dillant Hopkins Airport", + "city": "Keene", + "lat": 72.270833, + "lon": 42.898333, + "type": "airport" + } +] +---- +==== + +[#ex2] +.Use LET to set a variable in an array +==== +Find all Sunday flights (`day = 0`) to the Charles De Gaulle airport (`CDG`) on Air India (`AI`) airlines. + +[source,sqlpp] +---- +SELECT t1.airline, t1.destinationairport, sch AS schedule +FROM route AS t1 +LET sch = ARRAY v FOR v IN t1.schedule WHEN v.day = 0 END -- <1> +WHERE t1.destinationairport = "CDG" +AND t1.airline = "AI"; +---- + +<1> In this example, the variable `sch` is not used in the `WHERE` clause, but used only in the projection. +Therefore, the Query Planner defers the evaluation to post-predicate evaluation, so there is no overhead for documents that are not qualified by the predicates. + +.Results +[source,JSON] +---- +[ + { + "airline": "AI", + "destinationairport": "CDG", + "schedule": [ + { + "day": 0, + "flight": "AI988", + "utc": "00:24:00" + }, + { + "day": 0, + "flight": "AI972", + "utc": "17:32:00" + } + ] + } +] +---- +==== + +[#ex3] +.Use chained LET +==== +Variant of <>. + +[source,sqlpp] +---- +SELECT t1.airportname, t1.geo.lat, t1.geo.lon, t1.city, t1.type +FROM airport t1 +LET max_lat = ABS(t1.geo.lon)*4+1, -- <1> + min_lat = max_lat - 90, -- <2> + place = (SELECT RAW t2.country + FROM landmark t2) +WHERE t1.geo.lat > min_lat +AND t1.geo.lat < max_lat +AND t1.country IN place; +---- + +<1> The variable `max_lat` is defined in the first clause of the `LET` statement. +<2> The variable `max_lat` is referenced by the `min_lat` variable in the second clause of the `LET` statement. + +.Results +[source,JSON] +---- +[ + { + "airportname": "Wideawake Field", + "city": "Georgetown Acension Island Santa Helena", + "lat": -7.969597, + "lon": -14.393664, + "type": "airport" + } +] +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/limit.adoc b/modules/n1ql/pages/n1ql-language-reference/limit.adoc new file mode 100644 index 000000000..81fad95a3 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/limit.adoc @@ -0,0 +1,72 @@ += LIMIT clause +:description: The LIMIT clause specifies the maximum number of documents to be returned in a resultset by a SELECT statement. +:imagesdir: ../../assets/images +:keywords: paginate, pagination +:page-topic-type: reference + +[abstract] +{description} + +== Purpose + +When you don't need the entire resultset, use the `LIMIT` clause to specify the maximum number of documents to be returned in a resultset by a `SELECT` query. + +The `LIMIT` and `OFFSET` clauses are evaluated after the `ORDER BY` clause. + +(((pagination))) +You can use the `OFFSET` and `LIMIT` clauses together to [def]_paginate_ the results -- that is, to split the resultset into pages, each containing a specified number of documents, for display purposes. + +NOTE: Starting from version 4.5, the LIMIT clause in INSERT, UPDATE, and DELETE statements is no longer a hint. +It indicates that the actual number of mutations will be less than or equal to the specified LIMIT. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=limit-clause] +---- + +image::n1ql-language-reference/limit-clause.png["Syntax diagram", align=left] + +== Arguments + +expr:: Integer or an expression that evaluates to an integer representing the number of resulting documents. +A negative value is the same as `LIMIT 0`. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex1]] +.Get only 2 documents of hotels with an empty room +==== +[source,sqlpp] +---- +include::example$select/limit-number.n1ql[] +---- + +.Result +[source,json] +---- +include::example$select/limit-result.jsonc[] +---- +==== + +[[ex2]] +.Paginate the results using OFFSET and LIMIT +==== +The following query uses named parameters and expressions to display the specified page of results, assuming that page numbering starts at zero. + +[source,sqlpp] +---- +include::example$select/limit-expr.n1ql[tags=query] +---- + +Setting the page number to zero, with two results per page, the results are the same as <>. + +.Result +[source,json] +---- +include::example$select/limit-result.jsonc[] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/literals.adoc b/modules/n1ql/pages/n1ql-language-reference/literals.adoc new file mode 100644 index 000000000..ed14f646e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/literals.adoc @@ -0,0 +1,113 @@ += Literals +:description: Literal values include strings, numbers, TRUE, FALSE, NULL, and MISSING. +:page-topic-type: reference +:imagesdir: ../../assets/images + +[abstract] +{description} + +{sqlpp} supports the same literals as JSON, as defined by http://json.org/[json.org^], with these exceptions: + +* In {sqlpp}, "true", "false," and "null" are case-insensitive to be consistent with other {sqlpp} keywords. +In standard JSON, "true", "false," and "null" are case-sensitive. +* "missing" is added as a literal expression, although it is not returned in final results. +Missing is omitted from objects, and is converted to null in result arrays. +* In {sqlpp} single and double quotation marks can be used for strings. +JSON supports only double quotation marks. + +Wherever a value is expected, either of two special values may appear: NULL (denoting an out-of-band value that is not comparable to any other value), and MISSING (denoting the absence of a value). +Every value also has a "truth" value; these truth value conversions are explained in xref:n1ql-language-reference/booleanlogic.adoc[Boolean Logic]. + +== Booleans + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=boolean] +---- + +image::n1ql-language-reference/boolean.png["Syntax diagram", align=left] + +Boolean propositions evaluate to TRUE and FALSE. +These values are case-insensitive. + +== Numbers + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=number] +---- + +image::n1ql-language-reference/number.png["Syntax diagram", align=left] + +[source#int,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=integer] +---- + +image::n1ql-language-reference/integer.png["Syntax diagram", align=left] + +[source#frac,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=fraction] +---- + +image::n1ql-language-reference/fraction.png["Syntax diagram", align=left] + +[source#exp,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=exponent] +---- + +image::n1ql-language-reference/exponent.png["Syntax diagram", align=left] + +Numbers can be either signed or unsigned integers with an optional fractional component and an optional exponent. +If the integer component has more than one digit, the number should not start with a leading zero. + +== Strings + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=string] +---- + +image::n1ql-language-reference/string.png["Syntax diagram", align=left] + +[source#char,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=char] +---- + +image::n1ql-language-reference/char.png["Syntax diagram", align=left] + +[source#hex,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=hex] +---- + +image::n1ql-language-reference/hex.png["Syntax diagram", align=left] + +Strings can be either Unicode characters or escaped characters. + +== NULL + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=null] +---- + +image::n1ql-language-reference/null.png["Syntax diagram", align=left] + +The literal NULL represents an empty value. +This value is case-insensitive. + +== MISSING + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=missing] +---- + +image::n1ql-language-reference/missing.png["Syntax diagram", align=left] + +The MISSING literal is specific to {sqlpp} and represents a missing name-value pair in a document. +This value is case-insensitive. diff --git a/modules/n1ql/pages/n1ql-language-reference/logicalops.adoc b/modules/n1ql/pages/n1ql-language-reference/logicalops.adoc new file mode 100644 index 000000000..64716a4f7 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/logicalops.adoc @@ -0,0 +1,133 @@ += Logical Operators +:description: Logical terms let you combine other expressions using Boolean logic. +:page-topic-type: reference +:imagesdir: ../../assets/images + +Logical terms let you combine other expressions using xref:n1ql-language-reference/booleanlogic.adoc[Boolean logic]. +{sqlpp} provides the following logical operators: + +* AND +* OR +* NOT + +In {sqlpp}, logical operators have their usual meaning; however, Boolean propositions can evaluate to NULL or MISSING as well as to TRUE and FALSE. +The truth tables for these operators therefore use four-valued logic. + +[#logical-op-and] +== AND + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=and] +---- + +image::n1ql-language-reference/and.png["Syntax diagram", align=left] + +AND evaluates to TRUE only if both conditions are TRUE. + +.AND Truth Table +[cols="s,d,d,d,d"] +|=== +| | TRUE | FALSE | NULL | MISSING + +| TRUE +| TRUE +| FALSE +| NULL +| MISSING + +| FALSE +| FALSE +| FALSE +| FALSE +| FALSE + +| NULL +| NULL +| FALSE +| NULL +| MISSING + +| MISSING +| MISSING +| FALSE +| MISSING +| MISSING +|=== + +[#or-operator] +== OR + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=or] +---- + +image::n1ql-language-reference/or.png["Syntax diagram", align=left] + +OR evaluates to TRUE if one of the conditions is TRUE. + +.OR Truth Table +[cols="s,d,d,d,d"] +|=== +| | TRUE | FALSE | NULL | MISSING + +| TRUE +| TRUE +| TRUE +| TRUE +| TRUE + +| FALSE +| TRUE +| FALSE +| NULL +| MISSING + +| NULL +| TRUE +| NULL +| NULL +| NULL + +| MISSING +| TRUE +| MISSING +| NULL +| MISSING +|=== + +[#logical-op-not] +== NOT + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=not] +---- + +image::n1ql-language-reference/not.png["Syntax diagram", align=left] + +NOT evaluates to TRUE if the condition is FALSE, and vice versa. + +.NOT Truth Table + +[cols="s,d"] +|=== +| | NOT + +| TRUE +| FALSE + +| FALSE +| TRUE + +| NULL +| NULL + +| MISSING +| MISSING +|=== + +== Related Links + +For further details, refer to xref:n1ql-language-reference/booleanlogic.adoc[Boolean Logic]. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/merge.adoc b/modules/n1ql/pages/n1ql-language-reference/merge.adoc new file mode 100644 index 000000000..0176afdb2 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/merge.adoc @@ -0,0 +1,781 @@ += MERGE +:description: A MERGE statement provides the ability to update, insert into, or delete from a keyspace based on the results of a join with another keyspace or subquery. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:bucket-expiration: xref:server:learn:data/expiration.adoc +:preserve_expiry: xref:n1ql:n1ql-manage/query-settings.adoc#preserve_expiry +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:selectclause: xref:n1ql-language-reference/selectclause.adoc +:subqueries: xref:n1ql-language-reference/subqueries.adoc +:expression: xref:n1ql-language-reference/index.adoc +:uuid: xref:n1ql-language-reference/metafun.adoc#uuid +:document-expiration: xref:java-sdk:howtos:kv-operations.adoc#document-expiration + +:from: xref:n1ql-language-reference/from.adoc +:from-keyspace-ref: {from}#from-keyspace-ref +:as-clause: {from}#section_ax5_2nx_1db + +:hints: xref:n1ql-language-reference/hints.adoc +:use-index-clause: {hints}#use-index-clause + +:join: xref:n1ql-language-reference/join.adoc +:ansi-join-hints: {join}#ansi-join-hints +:multiple-hints: {join}#multiple-hints + +:update: xref:n1ql-language-reference/update.adoc +:set-clause: {update}#set-clause +:unset-clause: {update}#unset-clause +:update-for: {update}#update-for +:where-clause: {update}#where-clause + +:insert: xref:n1ql-language-reference/insert.adoc +:limit-clause: {insert}#limit-clause +:returning-clause: {insert}#returning-clause + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} +It is possible to specify actions (insert, update, delete) on the keyspace based on a match or no match in the join. +Multiple actions can be specified in the same query. + +Couchbase Capella supports two types of merge clause, which are described in the sections below: <> and <>. + +NOTE: The ANSI merge clause has much more flexible functionality than its earlier legacy equivalent. +Since it is standard compliant and more flexible, we recommend you to use ANSI merge exclusively, where possible. + +== Privileges + +User executing the MERGE statement must have the following privileges: + +* _Query Select_ privileges on the source keyspace +* _Query Insert_, _Query Update_, or _Query Delete_ privileges on the target keyspace as per the MERGE actions +* _Query Select_ privileges on the keyspaces referred in the RETURNING clause + +For more details about user roles, refer to +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +[NOTE] +A user with the _Data Writer_ privilege may set documents to expire. +When the document expires, the data service deletes the document, even though the user may not have the _Query Delete_ privilege. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=merge] +---- + +image::n1ql-language-reference/merge.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links from EBNF + +[horizontal.compact] +ansi-merge:: <> icon:caret-down[] +lookup-merge:: <> icon:caret-down[] +limit-clause:: <> icon:caret-down[] +returning-clause:: <> icon:caret-down[] + +[[ansi-merge]] +== ANSI Merge + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=ansi-merge] +---- + +image::n1ql-language-reference/ansi-merge.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal.compact] +target-keyspace:: <> icon:caret-down[] +use-index-clause:: <> icon:caret-down[] +ansi-merge-source:: <> icon:caret-down[] +ansi-merge-predicate:: <> icon:caret-down[] +ansi-merge-actions:: <> icon:caret-down[] + +[[ansi-merge-target]] +=== ANSI Merge Target + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=target-keyspace] +---- + +image::n1ql-language-reference/target-keyspace.png["Syntax diagram: refer to source code listing", align=left] + +The merge target is the keyspace which you want to update, insert into, or delete from. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[ansi-target-ref]] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Keyspace reference for the merge target. +For more details, refer to {from-keyspace-ref}[Keyspace Reference]. + +[[ansi-target-alias]] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[[target-hint]] +=== ANSI Merge Target Hint + +You can use a `USE INDEX` hint on the merge target to specify that the merge should use a particular index. +For details, refer to {use-index-clause}[USE INDEX Clause]. + +NOTE: The `USE INDEX` hint is the only hint allowed on the target. +You cannot specify a `USE KEYS` hint or a join hint (`USE NL` or `USE HASH`) on the target of a merge statement. + +[[ansi-merge-source]] +=== ANSI Merge Source + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=ansi-merge-source] +---- + +image::n1ql-language-reference/ansi-merge-source.png["Syntax diagram: refer to source code listing", align=left] + +The merge source is the recordset that you want to merge with the merge target. +It can be a keyspace reference, a subquery, or a generic expression. + +[horizontal.compact] +merge-source-keyspace:: <> icon:caret-down[] +merge-source-subquery:: <> icon:caret-down[] +merge-source-expr:: <> icon:caret-down[] +ansi-join-hints:: <> icon:caret-down[] + +[[ansi-merge-source-keyspace]] +==== ANSI Merge Keyspace + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=merge-source-keyspace] +---- + +image::n1ql-language-reference/merge-source-keyspace.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[ansi-keyspace-ref]] +===== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#source-keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#source-keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Keyspace reference for the merge source. +For details, refer to {from-keyspace-ref}[Keyspace Reference]. + +[[ansi-keyspace-alias]] +===== AS Alias + +Assigns another name to the keyspace reference. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[[ansi-merge-source-subquery]] +==== ANSI Merge Subquery + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=merge-source-subquery] +---- + +image::n1ql-language-reference/merge-source-subquery.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal.compact] +subquery-expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[ansi-subquery-expr]] +===== Subquery Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=subquery-expr] +---- + +image::n1ql-language-reference/subquery-expr.png["Syntax diagram: refer to source code listing", align=left] + +// {selectclause}[select] + +Use parentheses to specify a subquery for the merge source. +For details, refer to {subqueries}[Subqueries]. + +[[ansi-subquery-alias]] +===== AS Alias + +Assigns another name to the subquery. +For details, refer to {as-clause}[AS Clause]. + +You must assign an alias to a subquery on the merge source. +However, when you assign an alias to the subquery, the `AS` keyword may be omitted. + +[[ansi-merge-source-expr]] +==== ANSI Merge Expression + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=merge-source-expr] +---- + +image::n1ql-language-reference/merge-source-expr.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal.compact] +expr:: A {sqlpp} {expression}[expression] generating JSON documents or objects for the merge source. +alias:: <> icon:caret-down[] + +[[ansi-generic-alias]] +===== AS Alias + +Assigns another name to the generic expression. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the generic expression is optional. +If you assign an alias to the generic expression, the `AS` keyword may be omitted. + +[[ansi-merge-source-hints]] +==== ANSI Merge Source Hints + +You can specify ANSI join hints (`USE HASH` or `USE NL`) on the source of an ANSI merge. +For details, refer to {ansi-join-hints}[ANSI JOIN Hints]. + +[NOTE] +-- +If the merge source is a keyspace, you can also specify a `USE KEYS` or `USE INDEX` hint on the merge source. For details, refer to {multiple-hints}[Multiple Hints]. + +If the merge action is <> or <>, you can specify any of the join methods: `USE HASH(BUILD)`, `USE HASH(PROBE)`, or `USE NL`. + +If the merge action is <>, the only join methods you can specify are `USE HASH(PROBE)` or `USE NL`. +In this case, if you specify `USE HASH(BUILD)`, the join method will default to `USE NL`. + +The ANSI join hint is optional. +If omitted, the default hint is `USE NL`. + +If you are using a nested-loop join, i.e. `USE NL` is specified or no join hint is specified, the target keyspace reference must have an appropriate secondary index defined for the join to work. +If such an index cannot be found an error will be returned. +-- + +[[ansi-merge-predicate]] +=== ANSI Merge Predicate + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=ansi-merge-predicate] +---- + +image::n1ql-language-reference/ansi-merge-predicate.png["Syntax diagram: refer to source code listing", align=left] + +The merge predicate enables you to specify an ANSI join between the <> and the <>. + +[horizontal.compact] +expr:: Boolean expression representing the join condition. +This expression may contain fields, constant expressions, or any complex {sqlpp} expression. + +[[ansi-merge-actions]] +=== ANSI Merge Actions + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=ansi-merge-actions] +---- + +image::n1ql-language-reference/ansi-merge-actions.png["Syntax diagram: refer to source code listing", align=left] + +The merge actions enable you to specify insert, update, and delete actions on the target keyspace, based on a match or no match in the join. + +[horizontal.compact] +merge-update:: <> icon:caret-down[] +merge-delete:: <> icon:caret-down[] +ansi-merge-insert:: <> icon:caret-down[] + +[[ansi-merge-update]] +==== ANSI Merge Update + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=merge-update] +---- + +image::n1ql-language-reference/merge-update.png["Syntax diagram: refer to source code listing", align=left] + +Updates a document that already exists with updated values. + +[horizontal.compact] +set-clause:: <> icon:caret-down[] +unset-clause:: <> icon:caret-down[] +where-clause:: <> icon:caret-down[] + +[[ansi-set-clause]] +===== SET Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=set-clause] +---- + +image::n1ql-language-reference/set-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the value for an attribute to be changed. +Also enables you to set the expiration of the document. +For more details, refer to {set-clause}[SET Clause]. + +[horizontal.compact] +update-for:: <> icon:caret-down[] + +[[ansi-unset-clause]] +===== UNSET Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=unset-clause] +---- + +image::n1ql-language-reference/unset-clause.png["Syntax diagram: refer to source code listing", align=left] + +Removes a specified attribute from the document. +For more details, refer to {unset-clause}[UNSET Clause]. + +[horizontal.compact] +update-for:: <> icon:caret-down[] + +[[ansi-update-for]] +===== FOR Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=update-for] +---- + +image::n1ql-language-reference/update-for.png["Syntax diagram: refer to source code listing", align=left] + +[source#ansi-path,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=path] +---- + +image::n1ql-language-reference/path.png["Syntax diagram: refer to source code listing", align=left] + +Iterates over a nested array to SET or UNSET the given attribute for every matching element in the array. +For more details, refer to {update-for}[FOR Clause]. + +[[ansi-update-where]] +===== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +Optionally specifies a condition that must be met for data to be updated. +For more details, refer to {where-clause}[WHERE Clause]. + +[[ansi-merge-delete]] +==== ANSI Merge Delete + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=merge-delete] +---- + +image::n1ql-language-reference/merge-delete.png["Syntax diagram: refer to source code listing", align=left] + +Removes the specified document from the keyspace. + +[horizontal.compact] +where-clause:: <> icon:caret-down[] + +[[ansi-delete-where]] +===== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +Optionally specifies a condition that must be met for data to be deleted. +For more details, refer to {where-clause}[WHERE Clause]. + +[[ansi-merge-insert]] +==== ANSI Merge Insert + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=ansi-merge-insert] +---- + +image::n1ql-language-reference/ansi-merge-insert.png["Syntax diagram: refer to source code listing", align=left] + +Inserts a new document into the keyspace. +Use parentheses to specify the key and value for the inserted document, separated by a comma. + +TIP: Use the {uuid}[UUID()] function to generate a random, unique document key. + +[horizontal] +key:: +An expression specifying the key for the inserted document. ++ +The `KEY` keyword may be omitted. +If it is omitted, the `VALUE` keyword must be omitted also. + +value:: +[Optional] An expression specifying the value for the inserted document. +If the value is omitted, an empty document is inserted. ++ +The `VALUE` keyword may be omitted. +If it is omitted, the `KEY` keyword must be omitted also. + +options:: +[Optional] An object representing the metadata to be set for the inserted document. +Only the `expiration` attribute has any effect; any other attributes are ignored. + +expiration::: +An integer, or an expression resolving to an integer, representing the {document-expiration}[document expiration] in seconds. ++ +If the document expiration is not specified, it defaults to `0`, meaning the document expiration is the same as the {bucket-expiration}[bucket or collection expiration]. + ++ +The `OPTIONS` keyword may be omitted. +If it is omitted, the `KEY` and `VALUE` keywords must be omitted also. + +where-clause:: <> icon:caret-down[] + +[[ansi-insert-where]] +===== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +Optionally specifies a condition that must be met for data to be inserted. +For more details, refer to {where-clause}[WHERE clause]. + +[[lookup-merge]] +== Lookup Merge + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=lookup-merge] +---- + +image::n1ql-language-reference/lookup-merge.png["Syntax diagram: refer to source code listing", align=left] + +[horizontal.compact] +target-keyspace:: <> icon:caret-down[] +lookup-merge-source:: <> icon:caret-down[] +lookup-merge-predicate:: <> icon:caret-down[] +lookup-merge-actions:: <> icon:caret-down[] + +[[lookup-merge-target]] +=== Lookup Merge Target + +Keyspace reference for the merge target. +The syntax is the same as for an ANSI merge. +Refer to <>. + +[[lookup-merge-source]] +=== Lookup Merge Source + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=lookup-merge-source] +---- + +image::n1ql-language-reference/lookup-merge-source.png["Syntax diagram: refer to source code listing", align=left] + +The merge source is the recordset that you want to merge with the merge target. +It can be a keyspace reference, a subquery, or a generic expression. + +[horizontal.compact] +merge-source-keyspace:: <> icon:caret-down[] +use-clause:: <> icon:caret-down[] +merge-source-subquery:: <> icon:caret-down[] +merge-source-expression:: <> icon:caret-down[] + +[[lookup-merge-source-keyspace]] +==== Lookup Merge Keyspace + +Keyspace reference for the merge source. +The syntax is the same as for an ANSI merge. +Refer to <>. + +[[lookup-merge-source-hints]] +==== Lookup Merge Source Hint + +If the merge source is a keyspace, you can specify a USE KEYS or USE INDEX hint on the merge source. +For details, refer to xref:n1ql-language-reference/hints.adoc[USE clause]. + +[[lookup-merge-source-subquery]] +==== Lookup Merge Subquery + +Specifies a subquery for the merge source. +The syntax is the same as for an ANSI merge. +Refer to <>. + +[[lookup-merge-source-expr]] +==== Lookup Merge Expression + +Specifies a generic expression for the merge source. +The syntax is the same as for an ANSI merge. +Refer to <>. + +[[lookup-merge-predicate]] +=== Lookup Merge Predicate + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=lookup-merge-predicate] +---- + +image::n1ql-language-reference/lookup-merge-predicate.png["Syntax diagram: refer to source code listing", align=left] + +The merge predicate produces a document key for the target of the lookup merge. + +[horizontal.compact] +expr:: [Required] String or expression representing the primary key of the documents for the target keyspace. + +[[lookup-merge-actions]] +=== Lookup Merge Actions + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=lookup-merge-actions] +---- + +image::n1ql-language-reference/lookup-merge-actions.png["Syntax diagram: refer to source code listing", align=left] + +The merge actions enable you to specify insert, update, and delete actions on the target keyspace, based on a match or no match in the join. + +[horizontal.compact] +merge-update:: <> icon:caret-down[] +merge-delete:: <> icon:caret-down[] +lookup-merge-insert:: <> icon:caret-down[] + +[[lookup-merge-update]] +==== Lookup Merge Update + +Updates a document that already exists with updated values. +The syntax is the same as for an ANSI merge. +Refer to <>. + +[[lookup-merge-delete]] +==== Lookup Merge Delete + +Removes the specified document from the keyspace. +The syntax is the same as for an ANSI merge. +Refer to <> for details. + +[[lookup-merge-insert]] +==== Lookup Merge Insert + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=lookup-merge-insert] +---- + +image::n1ql-language-reference/lookup-merge-insert.png["Syntax diagram: refer to source code listing", align=left] + +Inserts a new document into the keyspace. +The key specified in the <> is used as the key for the newly inserted document. + +[horizontal.compact] +expr:: An expression specifying the value for the inserted document. +where-clause:: <> icon:caret-down[] + +[NOTE] +The Lookup Merge Insert syntax does not enable you to specify the document expiration. +If you need to specify the document expiration, rewrite the query using the ANSI Merge Insert syntax. + +[[lookup-merge-insert-where]] +===== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +Optionally specifies a condition that must be met for data to be inserted. +For more details, refer to {where-clause}[WHERE clause]. + +== Common Clauses + +The following clauses are common to both ANSI Merge and Lookup Merge. + +[[limit-clause]] +=== LIMIT Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=limit-clause] +---- + +image::n1ql-language-reference/limit-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the _minimum_ number of records to be processed. +For more details, refer to {limit-clause}[LIMIT Clause]. + +[[returning-clause]] +=== RETURNING Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=returning-clause] +---- + +image::n1ql-language-reference/returning-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the information to be returned by the operation as a query result. +For more details, refer to {returning-clause}[RETURNING Clause]. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +WARNING: Please note that the examples below will alter the data in your sample buckets. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +[[example-1]] +.ANSI merge with expression source +==== +This example updates the vacancy field based on the source expression. + +[source,sqlpp] +---- +include::example$dml/ansi-merge-expr.n1ql[] +---- +==== + +[[example-2]] +.ANSI merge with keyspace source +==== +This example finds all BA routes whose source airport is in France. +If any flights are using equipment 319, they are updated to use 797. +If any flights are using equipment 757, they are deleted. + +[source,sqlpp] +---- +include::example$dml/ansi-merge-keyspace.n1ql[] +---- +==== + +[[example-3]] +.ANSI merge with updates and inserts +==== +This example compares a source set of airport data with the `airport` keyspace data. +If the airport already exists in the `airport` keyspace, the record is updated. +If the airport does not exist in the `airport` keyspace, a new record is created. + +[source,sqlpp] +---- +include::example$dml/ansi-merge-else.n1ql[] +---- +==== + +[[example-4]] +.ANSI merge with expiration +==== +This example compares a source set of airport data with the `airport` keyspace data. +If the airport already exists in the `airport` keyspace, the record is updated, and the existing document expiration is preserved. +If the airport does not exist in the `airport` keyspace, a new record is created with an expiration of one week. + +[source,sqlpp] +---- +include::example$dml/ansi-merge-expire.n1ql[] +---- + +Note that it is possible to preserve the document expiration using the request-level {preserve_expiry}[preserve_expiry] parameter. +==== + +.Lookup merge with expression source +==== +Lookup merge version of <>. + +[source,sqlpp] +---- +include::example$dml/lookup-merge-expr.n1ql[] +---- +==== + +.Lookup merge with keyspace source +==== +The following statement updates product based on orders. + +[source,sqlpp] +---- +include::example$dml/lookup-merge-keyspace.n1ql[] +---- +==== + +.Lookup merge with updates and inserts +==== +The following statement merges two datasets containing employee information. +It then updates `all_empts` on match with `emps_deptb` and inserts when there is no match. + +[source,sqlpp] +---- +include::example$dml/lookup-merge-else.n1ql[] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/metafun.adoc b/modules/n1ql/pages/n1ql-language-reference/metafun.adoc new file mode 100644 index 000000000..9cb171b05 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/metafun.adoc @@ -0,0 +1,1601 @@ += Miscellaneous Utility Functions +:page-topic-type: reference +:page-partial: +:example-caption!: +:description: Miscellaneous utility functions enable you to perform tasks beyond the usual evaluation and transformation of data. + +{description} +For example, there are functions to retrieve information about a document or item, perform base64 encoding and decoding, generate UUIDs, and control the flow of a query. + +[[abort,ABORT()]] +== ABORT(`expression`) + +=== Description + +Generates an error. +The error message contains the text specified by the given [.var]`expression`. + +This function is useful for flow control when xref:n1ql:n1ql-language-reference/createfunction.adoc[creating inline user-defined functions]. +You can use xref:n1ql:n1ql-language-reference/conditionalops.adoc[conditional operators] to check the parameters, and use this function to generate an error if something is wrong. + +=== Arguments + +expression:: An expression resolving to a string. + +=== Return Value + +The function does not return a return value. + +If this function is executed in a query, it causes the query to halt with an error code 5011. +The error message contains the text specified by the given [.var]`expression`. + +When this function is executed by a user-defined function, it causes the query to halt with an error code 10109. +The error message shows the name of the user-defined function and contains the text specified by the given [.var]`expression`. + +=== Examples + +[[abort-ex1,ABORT() Example 1]] +.Abort a query +==== + +.Query +[source,sqlpp] +---- +SELECT ABORT("Something went wrong"); +---- + +.Result +[source,json] +---- +[ + { + "code": 5011, + "msg": "Abort: \"Something went wrong\". - cause: \"Something went wrong\"" + } +] +---- +==== + +[[abort-ex2,ABORT() Example 2]] +.User-defined function with error checking +==== + +.Function +[source,sqlpp] +---- +CREATE OR REPLACE FUNCTION rstr(vString, vLen) LANGUAGE INLINE AS +CASE + WHEN NOT IS_STRING(vString) + THEN ABORT("Search string is not a string") + WHEN NOT IS_NUMBER(vLen) + THEN ABORT("Substring length is not a number") + WHEN vLen > LENGTH(vString) + THEN ABORT("Substring longer than search string") + ELSE SUBSTR(vString, LENGTH(vString) - vLen, vLen) +END; +---- + +.Test invalid string argument +[source,sqlpp] +---- +EXECUTE FUNCTION rstr(100, 4); +---- + +.Result +[source,json] +---- +[ + { + "code": 10109, + "msg": "Error executing function rstr : \"Search string is not a string\" - cause: \"Search string is not a string\"" + } +] +---- + +.Test invalid number argument +[source,sqlpp] +---- +EXECUTE FUNCTION rstr("Couchbase", "foo"); +---- + +.Result +[source,json] +---- +[ + { + "code": 10109, + "msg": "Error executing function rstr : \"Substring length is not a number\" - cause: \"Substring length is not a number\"" + } +] +---- + +.Test out-of-range value +[source,sqlpp] +---- +EXECUTE FUNCTION rstr("Couchbase", 10); +---- + +.Result +[source,json] +---- +[ + { + "code": 10109, + "msg": "Error executing function rstr : \"Substring longer than search string\" - cause: \"Substring longer than search string\"" + } +] +---- + +.Test with valid arguments +[source,sqlpp] +---- +EXECUTE FUNCTION rstr("Couchbase", 4); +---- + +.Result +[source,json] +---- +[ + "base" +] +---- +==== + +[[base64,BASE64()]] +== BASE64(`expression`) + +_Alias_: <> + +=== Description + +Returns the https://en.wikipedia.org/wiki/Base64[base64^] encoding of the given [.var]`expression`. + +=== Arguments + +expression:: An expression representing any supported {sqlpp} datatype. + +=== Return Value + +A string representing the base64 encoding of the input expression. +If the input expression is `missing`, the return value is also `missing`. + +=== Example + +[[base64-ex,BASE64() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT BASE64([1, 2, 3, 4]) AS `array`, + BASE64(false) AS `boolean`, + BASE64(missing) AS `missing`, + BASE64(null) AS `null`, + BASE64(1234) AS `number`, + BASE64( {"a": 1, "b": 2, "c": [1, 2, 3]} ) AS `object`, + BASE64("Couchbase") AS `string`; +---- + +.Result +[source,json] +---- +[ + { + "array": "WzEsMiwzLDRd", + "boolean": "ZmFsc2U=", + "null": "bnVsbA==", + "number": "MTIzNA==", + "object": "eyJhIjoxLCJiIjoyLCJjIjpbMSwyLDNdfQ==", + "string": "IkNvdWNoYmFzZSI=" + } +] +---- +==== + +[[base64-encode,BASE64_ENCODE()]] +== BASE64_ENCODE(`expression`) + +Alias of <>. + +[[base64-decode,BASE64_DECODE()]] +== BASE64_DECODE(`expression`) + +=== Description + +Reverses the encoding done by the <> or <> functions. + +=== Arguments + +expression:: An expression representing a valid base64-encoded string. + +=== Return Value + +The decoded value of the input expression. +If the input expression is `missing`, the return value is also `missing`. + +=== Example + +[[base64-decode-ex,BASE64_DECODE() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT BASE64_DECODE("WzEsMiwzLDRd") AS `array`, + BASE64_DECODE("ZmFsc2U=") AS `boolean`, + BASE64_DECODE(missing) AS `missing`, + BASE64_DECODE("bnVsbA==") AS `null`, + BASE64_DECODE("MTIzNA==") AS `number`, + BASE64_DECODE("eyJhIjoxLCJiIjoyLCJjIjpbMSwyLDNdfQ==") AS `object`, + BASE64_DECODE("IkNvdWNoYmFzZSI=") AS `string`; +---- + +.Result +[source,json] +---- +[ + { + "array": [ + 1, + 2, + 3, + 4 + ], + "boolean": false, + "null": null, + "number": 1234, + "object": { + "a": 1, + "b": 2, + "c": [ + 1, + 2, + 3 + ] + }, + "string": "Couchbase" + } +] +---- +==== + +[[current-users]] +== CURRENT_USERS() + +=== Description + +Returns the authenticated users for the current statement. + +=== Arguments + +None. + +=== Return Value + +An array of strings, each representing a user name. + +=== Example + +[[current-users-ex,CURRENT_USERS() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT CURRENT_USERS() as current_users; +---- + +.Results +[source,json] +---- +[ + { + "current_users": [ + "local:" + ] + } +] +---- +==== + +[[ds-version]] +== DS_VERSION() + +=== Description + +Returns the Couchbase Server version. + +=== Arguments + +None. + +=== Return Value + +Returns string containing the Couchbase Server version. + +=== Example + +[[ds-version-ex,DS_VERSION() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT DS_VERSION() as server_version; +---- + +.Results +[source,json] +---- +[ + { + "server_version": "7.6.0-1886-enterprise" + } +] +---- +==== + +[[finderr,FINDERR()]] +== FINDERR(`expression`) + +[.status]#Couchbase Server 7.6.5# + +=== Description + +Returns the full details of any Query service or cbq shell error. + +=== Arguments + +expression:: One of the following: ++ +-- +* A number representing an error code. +In this case, the function returns the full details of the error matching the error code. + +* A string. +In this case, the function searches for the target string in all of the error message fields except for `user_error`, and returns the full details of any errors that match the string. + +* A regular expression. +In this case, the function searches for the regular expression in all of the error message fields except for `user_error`, and returns the full details of any errors that match the pattern. +-- + +=== Return Value + +The return value is an array of one or more objects, each of which contains the details of an error that matches the find expression. + +For each error, the function returns the following fields. + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**applies_to** + +__required__ +|One of the following: + +* `cbq-shell`: The error applies to the cbq shell. +* `Server`: The error applies to the server. +|enum (cbq-shell, Server) + +|**code** + +__required__ +|A number representing the error. +|Integer + +|**description** + +__required__ +|Message describing why the error occurred. +|String + +|**reason** + +__optional__ +|List of possible causes of the error. +|String array + +|**user_action** + +__optional__ +|List of possible steps a user can take to mitigate the error. +|String array + +|**user_error** + +__optional__ +|One of the following: + +* `Yes`: The error was caused by the user. +* `No`: The error was caused by other services, or was internal to the server. +* `Maybe`: A combination of both. +|enum (Yes, No, Maybe) +|=== + +NOTE: The error details also include a `symbol` field, which contains a representation string for the error. +This field is for internal use only, and is not shown in the results. +However, the FINDERR function does search this field when the find expression is a string or a regular expression. + +=== Examples + +[[finderr-ex1,FINDERR() Example 1]] +.Find error details by code number +==== +.Query +[source,sqlpp] +---- +SELECT FINDERR(5011); +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + { + "applies_to": "Server", + "code": 5011, + "description": "Abort: «reason»", + "reason": [ + [ + "The SQL++ abort() function was called in the statement.", + "e.g. SELECT abort('An example cause')" + ] + ], + "user_error": "Yes" + } + ] + } +] +---- +==== + +[[finderr-ex2,FINDERR() Example 2]] +.Find error details by matching a string +==== +.Query +[source,sqlpp] +---- +SELECT FINDERR("A semantic error is present in the statement."); +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + { + "applies_to": "Server", + "code": 3100, + "description": "A semantic error is present in the statement.", + "reason": [ + "The statement includes portions that violate semantic constraints." + ], + "user_action": [ + "The cause will contain more detail on the violation; revise the statement and re-submit." + ], + "user_error": "Yes" + } + ] + } +] +---- +==== + +[[finderr-ex3,FINDERR() Example 3]] +.Find multiple error details by matching a string +==== +.Query +[source,sqlpp] +---- +SELECT FINDERR("semantic"); +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + { + "applies_to": "Server", + "code": 3100, + "description": "A semantic error is present in the statement.", + "reason": [ + "The statement includes portions that violate semantic constraints." + ], + "user_action": [ + "The cause will contain more detail on the violation; revise the statement and re-submit." + ], + "user_error": "Yes" + }, + { + "applies_to": "Server", + "code": 3220, + "description": "«name» window function «clause» «reason»", + "reason": [ + "A violation of the window function semantic restrictions was present in the statement." + ], + "user_action": [ + "Revise the statement to remove the violation." + ], + "user_error": "Yes" + }, + { + "applies_to": "Server", + "code": 3300, + "description": "recursive_with semantics: «cause»", + "reason": [ + "The statement specifies restricted syntax in a recursive common table expression definition." + ], + "user_action": [ + "Revise the statement removing the restricted syntax." + ], + "user_error": "Yes" + } + ] + } +] +---- +==== + +[[finderr-ex4,FINDERR() Example 4]] +.Find multiple error details by matching a regular expression +==== +.Query +[source,sqlpp] +---- +SELECT FINDERR("[IU][NP]SERT"); +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + { + "applies_to": "Server", + "code": 3150, + "description": "MERGE with ON KEY clause cannot have document key specification in INSERT action.", + "reason": [ + [ + "A lookup merge statement specified a document key.", + "e.g. MERGE INTO default USING [{},{}] AS source ON KEY 'aaa' WHEN NOT MATCHED THEN INSERT ('key',{})" + ] + ], + "user_action": [ + "Refer to the documentation for lookup merge statements." + ], + "user_error": "Yes" + }, +// ... + { + "applies_to": "Server", + "code": 5072, + "description": "No UPSERT key for «value»", + "user_action": [ + "Contact support." + ] + }, +// ... + { + "applies_to": "Server", + "code": 15005, + "description": "No keys to insert «details»" + } + ] + } +] +---- +==== + +=== See Also + +* xref:n1ql:n1ql-language-reference/n1ql-error-codes.adoc[] + +[[flatten_keys,FLATTEN_KEYS()]] +== FLATTEN_KEYS(`expr1` [ `modifiers` ], `expr2` [ `modifiers` ], ...) + +=== Description + +This function can only be used when defining an index key for an xref:n1ql:n1ql-language-reference/indexing-arrays.adoc[array index]. + +If you need to index multiple fields within an array, this function enables you to _flatten_ the specified expressions, and index them as if they were separate index keys. +All subsequent index keys are accordingly moved to the right. +Queries will be xref:n1ql-language-reference/selectintro.adoc#index-selection[sargable] and will generate spans. + +=== Arguments + +expr1, expr2, ...:: [At least 1 and at most 32 argument-values are required] +Each argument is an expression over a field within an array, which constitutes an array index key. + +modifiers:: [Optional] +Arguments can be modified with `ASC` or `DESC` to specify the xref:n1ql:n1ql-language-reference/createindex.adoc#index-order[sort order] of the index key. +If this modifier is omitted, the default sort order is `ASC`. ++ +The first argument may be also modified with `IGNORE MISSING`. +This modifier may only be used when the function is being used in the definition of the leading index key. +If this modifier is present, documents which do not contain the specified field are indexed anyway. +If this modifier is omitted, documents which do not contain the specified field are not indexed. ++ +When the `IGNORE MISSING` modifier and the `ASC` or `DESC` modifier are used together, the order of the modifiers does not matter. + +Note that `FLATTEN_KEYS()` cannot be used recursively. + +=== Return Value + +The return value is a flattened list of array elements for use in an array index key. + +=== Examples + +For examples, refer to xref:n1ql:n1ql-language-reference/indexing-arrays.adoc#examples[Array Indexing Examples]. + +[[formalize,FORMALIZE()]] +== FORMALIZE(`statement` [ `,query_context` ]) + +=== Description + +Fully expands all references within a query, using the specified query context. + +This function has a synonym FORMALISE(). + +=== Arguments + +statement:: A string containing the statement to formalize. + +query_context:: [ Optional ] +A string query context value for the function to use when formalizing. + +=== Return Value + +Returns a query with all references fully specified. + +=== Examples + +[[formalize-ex1,FORMALIZE() Example 1]] +.Formalize a query +==== +.Query +[source,sqlpp] +---- +SELECT formalize("SELECT * FROM landmark WHERE country = 'United Kingdom'","default:`travel-sample`.inventory") +---- +.Results +[source,json] +---- +[ + { + "$1": "select self.* from `default`:`travel-sample`.`inventory`.`landmark` where ((`landmark`.`country`) = \"United Kingdom\")" + } +] +---- +==== + +[[formalize-ex2,FORMALIZE() Example 2]] +.Formalize recently completed requests +==== +.Query +[source,sqlpp] +---- +SELECT statement, + NVL(queryContext,"") AS queryContext, + formalize(statement, queryContext) AS formalized +FROM system:completed_requests; + +---- +.Results +[source,json] +---- +[ + { + "statement": "select * from `travel-sample`.inventory.landmark where country = 'United Kingdom' limit 1;", + "queryContext": "", + "formalized": "select self.* from `default`:`travel-sample`.`inventory`.`landmark` where ((`landmark`.`country`) = \"United Kingdom\") limit 1" + }, + { + "statement": "select * from landmark where country = 'United Kingdom' limit 1;", + "queryContext": "`travel-sample`.inventory", + "formalized": "select self.* from `default`:`travel-sample`.`inventory`.`landmark` where ((`landmark`.`country`) = \"United Kingdom\") limit 1" + }, + // ... +] +---- +==== + +[[len,LEN()]] +== LEN(`expression`) + +=== Description + +A general function to return the length of an item. + +=== Arguments + +expression:: An expression representing any supported {sqlpp} datatype. + +=== Return Value + +The return value is usually a number, depending on the datatype of the input expression. + +[cols="1,3"] +|=== +| Input Expression | Return Value + +| String +| The number of code points in the string -- equivalent to xref:n1ql-language-reference/stringfun.adoc#fn-str-length[LENGTH()]. + +| Object +| The field count -- equivalent to xref:n1ql-language-reference/objectfun.adoc#fn-obj-length[OBJECT_LENGTH()]. + +| Array +| The number of elements -- equivalent to xref:n1ql-language-reference/arrayfun.adoc#fn-array-length[ARRAY_LENGTH()]. + +| Binary +| The size of the binary object. + +| Boolean +| `1` + +| Number +| The number of characters in the number's text representation. + +| MISSING +| `missing` + +| NULL +| `null` +|=== + +For any item not listed above, the return value is `null`. + +=== Example + +[[len-ex,LEN() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT LEN([1, 2, 3, 4]) AS `array`, + LEN(false) AS `boolean`, + LEN(missing) AS `missing`, + LEN(null) AS `null`, + LEN(1234) AS `number`, + LEN( {"a": 1, "b": 2, "c": [1, 2, 3]} ) AS `object`, + LEN("Couchbase") AS `string`; +---- + +.Result +[source,json] +---- +[ + { + "array": 4, + "boolean": 1, + "null": null, + "number": 4, + "object": 3, + "string": 9 + } +] +---- +==== + +[[meta,META()]] +== META( {startsb} `keyspace_expr` {endsb} ) {startsb} .`property` {endsb} + +=== Description + +This function returns the xref:server:learn:data/data.adoc#metadata[metadata] for the document or keyspace specified by [.var]`keyspace_expr`. +The metadata is returned as a JSON object. + +To return a single property from the metadata, you must use a xref:n1ql-language-reference/nestedops.adoc#field-selection[nested expression] containing the `META()` function and the required property, for example `META().id`. +The supported metadata properties are described below. + +You can use the `META()` function with a property to xref:n1ql-language-reference/indexing-meta-info.adoc[index metadata information]. +Only certain metadata properties are indexable; these are indicated in the description below. + +You can also use the `META()` function with a property in the predicate of an xref:n1ql:n1ql-language-reference/join.adoc#section_ek1_jnx_1db[ANSI JOIN Clause]. + +If your cluster is running Couchbase Server version 7.6.2 and later, use the `META()` function with the xref:searchfun.adoc[SEARCH() function] when you want to return XATTRs data through the Search Service and do not have a suitable Search index for your query. + +=== Arguments + +keyspace_expr:: +[Optional. +Default is current keyspace.] ++ +String or an expression that results in a keyspace or a document. +This argument is not required when creating an index, since the `META()` function implicitly uses the keyspace being indexed. + +property:: +[Optional] The name of a single metadata property. +The property name must be separated from the `META()` function by a dot (`.`) and may be one of the following: + +cas::: +// tag::metadata-cas[] +Value representing the current state of an item which changes every time the item is modified. +For details, refer to xref:java-sdk:howtos:concurrent-document-mutations.adoc[Concurrent Document Mutations]. +// end::metadata-cas[] ++ +This property is indexable. + +expiration::: +// tag::metadata-expiration[] +Value representing a document's expiration date. +A value of 0 (zero) means no expiration date. +For details, refer to xref:java-sdk:howtos:kv-operations.adoc#document-expiration[KV Operations]. +// end::metadata-expiration[] ++ +This property is indexable. + +flags::: +Value set by the SDKs for non-JSON documents. +For details, refer to xref:java-sdk:howtos:transcoders-nonjson.adoc[Non-JSON Documents]. ++ +This property is not indexable. +If you attempt to build an index on this property, an error is returned. + +id::: +// tag::metadata-id[] +Value representing a document's unique ID number. +// end::metadata-id[] ++ +This property is indexable. + +type::: Value for the type of document; currently only `json` is supported. ++ +This property is not indexable. +If you attempt to build an index on this property, an error is returned. + +=== Return Value + +The bare function returns a JSON object containing the specified document's metadata. +When the function is used with a property as part of a nested expression, the expression returns the JSON value of the property. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[meta-ex1,META() Example 1]] +.Return all metadata +==== +.Query +[source,sqlpp] +---- +SELECT META() AS metadata +FROM airline +LIMIT 3; +---- + +.Results +[source,json] +---- +[ + { + "metadata": { + "cas": 1583859008179798016, + "expiration": 0, + "flags": 33554432, + "id": "airline_10", + "type": "json" + } + }, + { + "metadata": { + "cas": 1583859008180846592, + "expiration": 0, + "flags": 33554432, + "id": "airline_10123", + "type": "json" + } + }, + { + "metadata": { + "cas": 1583859008181895168, + "expiration": 0, + "flags": 33554432, + "id": "airline_10226", + "type": "json" + } + } +] +---- +==== + +[[meta-ex2,META() Example 2]] +.Return a single metadata property +==== +.Query +[source,sqlpp] +---- +SELECT META().id AS id +FROM airline +LIMIT 3; +---- + +.Results +[source,json] +---- +[ + { + "id": "airline_10" + }, + { + "id": "airline_10123" + }, + { + "id": "airline_10226" + } +] +---- +==== + +[[meta-ex3,META() Example 3]] +.Return a single metadata property for a specified keyspace +==== +.Query +[source,sqlpp] +---- +SELECT META(route).id AS id -- <1> +FROM route +JOIN airport +ON route.sourceairport = airport.faa +WHERE airport.city = "Paris" +LIMIT 3; +---- + +<1> You must specify a keyspace for the `META()` function because there is more than one FROM term. + +.Results +[source,json] +---- +[ + { + "id": "route_10136" + }, + { + "id": "route_10137" + }, + { + "id": "route_10138" + } +] +---- +==== + +For examples showing how to index metadata information, refer to xref:n1ql-language-reference/indexing-meta-info.adoc[Indexing Meta Info]. + +For examples showing how to use metadata information in the predicate of an ANSI JOIN clause, refer to xref:n1ql:n1ql-language-reference/join.adoc[JOIN Clause]. + +[[node-name]] +== NODE_NAME() + +=== Description + +Returns the name of the node on which the query is running. + +=== Arguments + +None. + +=== Return Value + +A string representing a node name. + +=== Example + +[[node-name-ex,NODE_NAME() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT NODE_NAME() AS node_name; +---- + +.Results +[source,json] +---- +[ + { + "node_name": "-node-001.:8091" + } +] +---- +==== + +[[node-uuid,NODE_UUID()]] +== NODE_UUID(`expression`) + +=== Description + +Returns the UUID of a node. + +=== Arguments + +expression:: +A string, or an expression resolving to a string, representing a node name. +To get the UUID of the node on which the query is running, use the empty string `""`. + +=== Return Value + +A string representing the node UUID. + +If the input expression is not a string, the return value is `null`. + +If the input expression is `missing`, the return value is also `missing`. + +=== Example + +[[node-uuid-ex,NODE_UUID() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT NODE_UUID("") AS from_empty_string, + NODE_UUID("-node-001.:8091") AS from_node_name, + NODE_UUID(NODE_NAME()) AS from_node_name_function; +---- + +.Result +[source,json] +---- +[ + { + "from_empty_string": "", + "from_node_name": "", + "from_node_name_function": "" + } +] +---- +==== + +[[pairs,PAIRS()]] +== PAIRS(`obj`) + +=== Description + +This function generates an array of arrays of {startsb}[.var]``field_name``, ``value``{endsb} pairs of all possible fields in the given JSON object [.var]`obj`. + +NOTE: Nested sub-object fields are explored recursively. + +=== Arguments + +obj:: An expression resolving to an object. + +=== Return Value + +Array of {startsb}[.var]``field_name``, ``value``{endsb} arrays for each field in the input object [.var]`obj`. + +* If [.var]`obj` has nested objects, then fields of such nested sub-objects are also explored and corresponding inner-array elements are produced. +* If [.var]`obj` is an array, then each element of the array is explored and corresponding inner-array elements are produced. +* If [.var]`obj` is a primitive data type of integer or string, then it returns NULL, as they don't have a name. +* If [.var]`obj` is an array of primitive data types, then it returns an empty array `[]`. +* If [.var]`obj` is an array of objects, then it returns an array of objects. + +[TIP] +==== +If you wrap an array of primitive data types in an xref:n1ql-language-reference/constructionops.adoc#object-construction[object constructor], it's treated as an object and returns an array; without the object constructor, it's treated as an array of primitive data types and returns `[]`. +For example, in <>: + +* `PAIRS(public_likes)` returns `[]` +* `+PAIRS({public_likes})+` returns an array +==== + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[pairs-example1,PAIRS() Example 1]] +.Input value of a nested object +==== +.Query +[source,sqlpp] +---- +SELECT t AS orig_t, + PAIRS(t) AS pairs_t +FROM airport t +LIMIT 1; +---- + +.Result +[source,json] +---- +[ + { + "orig_t": { + "airportname": "Calais Dunkerque", + "city": "Calais", + "country": "France", + "faa": "CQF", + "geo": { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + }, + "icao": "LFAC", + "id": 1254, + "type": "airport", + "tz": "Europe/Paris" + }, + "pairs_t": [ + [ + "id", + 1254 + ], + [ + "city", + "Calais" + ], + [ + "faa", + "CQF" + ], + [ + "geo", + { + "alt": 12, + "lat": 50.962097, + "lon": 1.954764 + } + ], + [ + "lon", + 1.954764 + ], + [ + "alt", + 12 + ], + [ + "lat", + 50.962097 + ], + [ + "type", + "airport" + ], + [ + "tz", + "Europe/Paris" + ], + [ + "airportname", + "Calais Dunkerque" + ], + [ + "country", + "France" + ], + [ + "icao", + "LFAC" + ] + ] + } +] +---- +==== + +[[pairs-example2,PAIRS() Example 2]] +.Input value of an array +==== +.Query +[source,sqlpp] +---- +SELECT public_likes AS orig_t, + PAIRS(public_likes) AS pairs_array_t, + PAIRS({public_likes}) AS pairs_obj_t +FROM hotel +LIMIT 1; +---- + +.Result +[source,json] +---- +[ + { + "orig_t": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ], + "pairs_array_t": [], + "pairs_obj_t": [ + [ + "public_likes", + [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ] + ], + [ + "public_likes", + "Julius Tromp I" + ], + [ + "public_likes", + "Corrine Hilll" + ], + [ + "public_likes", + "Jaeden McKenzie" + ], + [ + "public_likes", + "Vallie Ryan" + ], + [ + "public_likes", + "Brian Kilback" + ], + [ + "public_likes", + "Lilian McLaughlin" + ], + [ + "public_likes", + "Ms. Moses Feeney" + ], + [ + "public_likes", + "Elnora Trantow" + ] + ] + } +] +---- +==== + +[[pairs-example3a,PAIRS() Example 3a]] +.Input value of a primitive (field document string) data type +==== +.Query +[source,sqlpp] +---- +SELECT country AS orig_t, + PAIRS(country) AS pairs_t +FROM airport +LIMIT 1; +---- + +.Result +[source,json] +---- +[ + { + "orig_t": "France", + "pairs_t": null + } +] +---- +==== + +[[pairs-example3b,PAIRS() Example 3b]] +.Input value of a primitive (constant) data type +==== +.Query +[source,sqlpp] +---- +SELECT PAIRS("N1QL") AS constant_string, + PAIRS(4) AS constant_int, + PAIRS([1,2,3]) AS constant_int_array, + PAIRS({"name" : 3}) AS object_constant_int, + PAIRS({"name" : [1,2,3]}) AS object_constant_int_array; +---- + +.Result +[source,json] +---- +[ + { + "constant_int": null, + "constant_int_array": [], + "constant_string": null, + "object_constant_int": [ + [ + "name", + 3 + ] + ], + "object_constant_int_array": [ + [ + "name", + [ + 1, + 2, + 3 + ] + ], + [ + "name", + 1 + ], + [ + "name", + 2 + ], + [ + "name", + 3 + ] + ] + } +] +---- +==== + +[[pairs-example4,PAIRS() Example 4]] +.Input value of an array of objects +==== +.Query +[source,sqlpp] +---- +SELECT reviews[*].ratings, + PAIRS({reviews[*].ratings}) AS pairs_t +FROM hotel +LIMIT 1; +---- + +.Result +[source,json] +---- +[ + { + "pairs_t": [ + [ + "ratings", + [ + { + "Cleanliness": 5, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 5, + "Value": 4 + }, + { + "Business service (e.g., internet access)": 4, + "Check in / front desk": 4, + "Cleanliness": 4, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 3, + "Value": 5 + } + ] + ], + [ + "ratings", + { + "Cleanliness": 5, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 5, + "Value": 4 + } + ], + [ + "ratings", + { + "Business service (e.g., internet access)": 4, + "Check in / front desk": 4, + "Cleanliness": 4, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 3, + "Value": 5 + } + ], + [ + "Cleanliness", + 5 + ], + [ + "Location", + 4 + ], + [ + "Overall", + 4 + ], + [ + "Rooms", + 3 + ], + [ + "Service", + 5 + ], + [ + "Value", + 4 + ], + [ + "Cleanliness", + 4 + ], + [ + "Location", + 4 + ], + [ + "Rooms", + 3 + ], + [ + "Value", + 5 + ], + [ + "Business service (e.g., internet access)", + 4 + ], + [ + "Check in / front desk", + 4 + ], + [ + "Overall", + 4 + ], + [ + "Service", + 3 + ] + ], + "ratings": [ + { + "Cleanliness": 5, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 5, + "Value": 4 + }, + { + "Business service (e.g., internet access)": 4, + "Check in / front desk": 4, + "Cleanliness": 4, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 3, + "Value": 5 + } + ] + } +] +---- +==== + +[[unnest-pos,UNNEST_POS()]] +== UNNEST_POS(`expr`) + +You can use the `UNNEST_POS()` function with the xref:n1ql-language-reference/unnest.adoc[UNNEST Clause] to return the position of each element in an unnested array. + +This function has a synonym <>. + +=== Description + +The `UNNEST_POS` function takes an unnested array and returns the position value of each element in the array. + +=== Arguments + +expr:: [Required] The alias of the unnested array from an xref:n1ql-language-reference/unnest.adoc[UNNEST Clause]. + +=== Return Values + +The `UNNEST_POS` function returns the position of each element in the unnested array, `expr`, as an integer. It returns each position value as a separate row in JSON format. The first element in the array is at position `0`. + +In all other cases, the `UNNEST_POS` function returns `NULL` or `MISSING`. + +=== Example + +==== +In the following example, the `UNNEST_POS` function takes the result of an `UNNEST` Clause on a given array, `a1`. The `UNNEST` function returns the position of each element in the unnested `a1` array , `u`, as the `upos` value. + +[source,N1QL] +---- +include::example$functions/unnest-pos.n1ql[] +---- + +.Results +[source,json] +---- +include::example$functions/unnest-pos.jsonc[] +---- +==== + +=== Related Clauses + +- xref:n1ql-language-reference/unnest.adoc[UNNEST Clause] +- xref:n1ql-language-reference/from.adoc[FROM Clause] + +[[unnest-position,UNNEST_POSITION()]] +== UNNEST_POSITION(`expr`) + +Synonym of <>. + +[[uuid]] +== UUID() + +=== Description + +Generates a universally unique identifier (UUID) according to https://www.ietf.org/rfc/rfc4122.txt[RFC 4122^]. + +=== Arguments + +None. + +=== Return Value + +A string representing a version 4 UUID. + +=== Example + +[[uuid-ex,UUID() Example]] +==== +This query will return a different UUID each time you run it. + +.Query +[source,sqlpp] +---- +SELECT UUID() AS uuid; +---- + +.Results +[source,json] +---- +[ + { + "uuid": "2ca78bd8-0a28-4d68-995f-0da5e20e0964" + } +] +---- +==== + +For further examples using `UUID()`, refer to the xref:n1ql-language-reference/insert.adoc[INSERT] and xref:n1ql-language-reference/merge.adoc[MERGE] statements. + +[[version]] +== VERSION() + +=== Description + +Returns {sqlpp} version. + +=== Arguments + +None. + +=== Return Value + +Returns string containing the {sqlpp} version. + +=== Example + +[[version-ex,VERSION() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT VERSION() as language_version; +---- + +.Results +[source,json] +---- +[ + { + "language_version": "7.6.0-N1QL" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/n1ql-auditing.adoc b/modules/n1ql/pages/n1ql-language-reference/n1ql-auditing.adoc new file mode 100644 index 000000000..626c28707 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/n1ql-auditing.adoc @@ -0,0 +1,492 @@ += {sqlpp} Auditing +:description: {sqlpp}-related activities can be audited, by Couchbase Capella. +:page-topic-type: reference + +// Pass through HTML table styles for this page + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +== Understanding {sqlpp} Auditing + +This section provides specific information on Couchbase Capella auditing as it relates to {sqlpp}. +For a general description of auditing with Couchbase Capella, see xref:security:auditing.adoc[]. + +Couchbase Capella provides auditing for {sqlpp}-related activities such as the following: + +* Authenticating +* Starting and stopping the Query Service +* Editing Query Service settings +* Executing {sqlpp} statements +ifdef::flag-devex-rest-api[] +* Non-query API requests +endif::flag-devex-rest-api[] + +{sqlpp}-related activities are logged whether they are executed by a person or by an application running on behalf of a person. +Auditing occurs at the level of _requests_, rather than of _operations_. +Thus, when a request arrives with a SELECT query, only the SELECT query itself is logged: the associated subsidiary operations performed by the Data and Index Services are _not_ logged. + +Auditing causes a reduction in {sqlpp} query-performance. +This is in the range of 9% to 17% of queries performed per second: the exact reduction depends on query-size, and on the amount of auditing that has been enabled. +Large queries and minimal auditing cause less performance-reduction. + +You can configure auditing by means of the Management REST API: see xref:security:audit-management.adoc[]. +You can audit Query and Index service events that are issued through the Query tab, the cbq shell, and the SDK. + +== Audit Log Format + +The audit records are written in JSON format to match the format used for Admin Auditing to allow easy integration with downstream auditing tools for audit log analysis. +The syslog format will allow for integration with third party SIEM tools, such as QRadar. + +.Required auditing fields for executed statements +[cols="1,4a,4a"] +|=== +| Field | Description | Example + +| `timestamp` +| Exact date and time of the access event in UTC format. +| `2018-02-09T14:52:35.163-08:00` + +| `real_userid` +| Source/User from basic authentication fields of request. +| `"source":"local",` + +`"user":"Administrator"` + +| `requestId` +| UUID of request, generated by the {sqlpp} server. +| `aee53bf0-d009-4015-8a1d-efec74f2cd74` + +| `statement` +| The actual {sqlpp} query that was executed. +| `pass:c[SELECT * FROM `travel-sample`]` + +| `isAdHoc` +| `TRUE` for statements made directly. + +`FALSE` for prepared statements. +| `TRUE` + +| `userAgent` +| To identify the type of user by a combination of the User-Agent and CB-User-Agent headers in one of the following formats: + +. Query tab + +ifdef::flag-devex-rest-api[] +. CURL request +endif::flag-devex-rest-api[] + +. cbq shell + +. SDK +| . `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 (Couchbase Query Workbench (5.1.0-1434-enterprise))` + +ifdef::flag-devex-rest-api[] +. `curl/7.43.0` +endif::flag-devex-rest-api[] + +. `Go-http-client/1.1 (CBQ/2.0)` + +. `+couchbase-java-client/2.5.2 (git: 2.5.2, core: 1.5.2) (Mac OS X/10.11.6 x86_64; Java HotSpot(TM) 64-Bit Server VM 1.8.0_101-b13)+` + +| `node` +| Assigned name (IP address) of the server where the request ran. +| + +| `status` +| Status of the request, as `success` or `failed` or `stopped`. +| `success` + +| `metrics` +| The elapsed time (ms), execution time (ms), result count, and result size (MB). +| `"elapsedTime":"7.599684ms",` + +`"executionTime":"7.507755ms",` + +`"resultCount":0,` + +`"resultSize":0` + +| `id` +| Number for the <>. +| `28672` + +| `name` +| The {sqlpp} command or REST API request type. +| `SELECT` + +| `description` +| Description of the event type. +| `A {sqlpp} SELECT statement was executed` +|=== + +.Optional auditing fields for statements +[cols="2,5,5"] +|=== +| Field | Description | Example + +| `namedArgs` +| Names and values of name arguments. +| `$val` and `$user` + +| `positionalArgs` +| Array of values of positional arguments. +| `$1` and `?` + +| `clientContextId` +a| +Captured from the `client_context_id` parameter of the {sqlpp} query. + +May be used to distinguish between user-generated queries and UI-generated queries from the Query tab. + +UI-generated queries have the prefix `INTERNAL-` in this field. +| +|=== + +NOTE: The client context ID has no security guarantees. +The parameter can be set by any user in any request and is not verified in the server, so it should not be relied upon for security purposes. + +ifdef::flag-devex-rest-api[] +.Required auditing fields for API requests +[cols="2,5,5"] +|=== +| Field | Description | Example + +| `timestamp` +| Exact date and time of the access event in UTC format. +| `2018-02-09T14:52:35.163-08:00` + +| `real_userid` +| Source/User from basic authentication fields of request. +| `"source":"local","user":"Administrator"` + +| `httpMethod` +| The API method call, either `GET, PUT, DELETE, POST` +| `GET` + +| `httpResultCode` +| The number representing the API result. +| `200` + +| `errorMessage` +| If an error occurred, this will contain information on the error. +| `User does not have credentials to run queries accessing the system tables.` + +| `id` +| Number for the <>. +| `28689` + +| `name` +| The API request location. +| `/admin/ping` + +| `description` +| Description of the event type. +| `An HTTP request was made to the API at /admin/ping.` +|=== +endif::flag-devex-rest-api[] + +== Examples + +To reduce disk usage and improve performance, the log files are as compact as possible. + +To make the log entry easier-to-read, use a formatting utility such as https://stedolan.github.io/jq/[jq^]. + +.{blank} +==== +Execute `SELECT * FROM orders`. + +[source,json] +---- +{ + "timestamp": "2018-02-09T14:52:35.163-08:00", + "real_userid": { + "source": "local", + "user": "Administrator" + }, + "requestId": "aee53bf0-d009-4015-8a1d-efec74f2cd74", + "statement": "SELECT * FROM orders", + "isAdHoc": true, + "userAgent": "curl/7.43.0", + "node": "local_node", + "status": "success", + "metrics": { + "elapsedTime": "7.599684ms", + "executionTime": "7.507755ms", + "resultCount": 0, + "resultSize": 0 + }, + "id": 28672, + "name": "SELECT statement", + "description": "A N1QL SELECT statement was executed" +} +---- +==== + +.{blank} +==== +Execute `DELETE FROM orders WHERE priority = 6`. + +[source,json] +---- +{ + "timestamp": "2018-02-09T14:52:55.786-08:00", + "real_userid": { + "source": "local", + "user": "Administrator" + }, + "requestId": "ded68ae3-d964-4d87-b1c2-70cf72041c6b", + "statement": "DELETE FROM orders WHERE priority = 6", + "isAdHoc": true, + "userAgent": "curl/7.43.0", + "node": "local_node", + "status": "success", + "metrics": { + "elapsedTime": "8.884558ms", + "executionTime": "8.853976ms", + "resultCount": 0, + "resultSize": 0 + }, + "id": 28678, + "name": "DELETE statement", + "description": "A N1QL DELETE statement was executed" +} +---- +==== + +ifdef::flag-devex-rest-api[] +.{blank} +==== +Make an HTTP `GET` method from an `/admin/ping` API request. + +[source,json] +---- +{ + "timestamp": "2018-02-09T14:53:10.856-08:00", + "real_userid": { + "source": "internal", + "user": "unknown" + }, + "httpMethod": "GET", + "httpResultCode": 200, + "errorMessage": "", + "id": 28697, + "name": "/admin/ping API request", + "description": "An HTTP request was made to the API at /admin/ping." +} +---- +==== +endif::flag-devex-rest-api[] + +== Audit Rotation + +The auditing Rotation parameters can be only one of the following: + +[cols="1,3"] +|=== +| Audit Log Rotation Type | Examples + +| Time-based (days) +| 7 (for weekly); 30 (for monthly). + +| Size-based (MB) +| 10 (for 10 MB); 10000 (for 10 GB). +|=== + +== Audit Failure Semantics + +When the audit target fails, the auditing system can be set to one of the following: + +[cols="1,3"] +|=== +| Failure Response Type | Description + +| Ignore +| Continue the action without firing an audit record. + +| Block +| Cancel the operation. + +| Log Reuse +a| +This option is for out-of-space failures: + +* *Time-Based*: Limit audit logs to the specified number of recent days. +* *Size-Based*: Limit audit log size to the specified number of megabytes. +|=== + +If an audit record attempt fails in the query engine, an error message will be printed to the `query.log` file. + +== Audit Trail Protection + +To prevent unauthorized modification of the audit service configuration, the auditing system restricts access to configuring only to Full and Local User Security Administrators. + +Audit records are immutable since the auditing system prevents changes of audit event records once written. + +Once archived, audit data is deleted from Capella, and the file space is recovered. + +ifdef::flag-devex-command-line[] +The xref:server:cli:cbcollect-info-tool.adoc[cbcollect_info] utility does not collect audit logs. +endif::flag-devex-command-line[] + +[#section_nyb_jsh_wcb] +== Audit Event Types + +Below is the list of all events that are captured in the audit logs. + +. System clock modifications, as captured in the operating system audit log +. Disabling auditing +. Enabling auditing, with audit settings written +. Login, both success and failure +. Logout, both success and failure +. Data access operations -- see xref:server:audit-event-reference:audit-event-reference.adoc#query-service-event-list-table[Query and Index Service Events] in the Server documentation +. Audit archive +. System backup +. Data service: + .. Read + .. Write + .. DCP-Read + .. DCP-Write +. Search service: + .. FTS-Read +. Analytics audit events + +ifdef::flag-devex-rest-api[] +Items that will not be captured in the audit logs: + + ** API calls that are not statements + ** API requests sent to URLs the query engine does not service + ** API requests which are handled by the autonomic functionality of the HTTP server +endif::flag-devex-rest-api[] + +ifdef::flag-devex-rest-api[] +[#section_cmd_lyh_wcb] +== API Auditing Codes + +Audit records will be issued by the query engine for requests to its secondary APIs. +This does not include the main URL used for queries (/query/service) but does include all other URLs the query engine listens to. + +There will be a separate audit record code for each registered URL. +The mapping from URLs to audit record codes is given below. +Some URLs require extra fields, as noted. + +[cols="^1,4,5"] +|=== +| Audit Code | API | Remarks + +| 28689 +| `/admin/stats` + +`+/admin/stats/{stat}+` +| Field "stat": optional, string, for input parameter \{stat} if present. + +| 28690 +| `/admin/vitals` +| + +| 28691 +| `/admin/prepareds` + +`+/admin/prepareds/{name}+` +| Field "name": optional, string, for input parameter \{name} if present. + +Do not audit POST requests. + +| 28692 +| `/admin/active_requests` + +`+/admin/active_requests/{request}+` +| Field "request": optional, string, for input parameter \{request} if present. + +Do not audit POST requests. + +| 28693 +| `/admin/indexes/prepareds` +| + +| 28694 +| `/admin/indexes/active_requests` +| + +| 28695 +| `/admin/indexes/completed_requests` +| + +| 28696 +| `/debug/vars` +| + +| 28697 +| `/admin/ping` +| + +| 28698 +| `/admin/config` +| + +| 28699 +| `/admin/ssl_cert` +| + +| 28700 +| `/admin/settings` +| + +| 28701 +| `/admin/clusters` + +`+/admin/clusters/{cluster}+` + +`+/admin/clusters/{cluster}/nodes+` + +`+/admin/clusters/{cluster}/nodes/{node}+` +| Field "cluster": optional, string, for input parameter \{cluster} if present. + +Field "node": optional, string, for input parameter \{node} if present. + +Field "body": PUT/POST only, JSON representation of cluster or node from request body. + +| 28702 +| `/admin/completed_requests` + +`+/admin/completed_requests/{request}+` +| Field "request": optional, string, for input parameter \{request} if present. + +Do not audit POST requests. +|=== +endif::flag-devex-rest-api[] diff --git a/modules/n1ql/pages/n1ql-language-reference/n1ql-error-codes.adoc b/modules/n1ql/pages/n1ql-language-reference/n1ql-error-codes.adoc new file mode 100644 index 000000000..bd4b999cd --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/n1ql-error-codes.adoc @@ -0,0 +1,976 @@ += {sqlpp} Error Codes +:description: The following table lists all of the {sqlpp} error codes, their error message, and some tips to resolve them. +:page-topic-type: reference + +[abstract] +{description} + +== 1xx Codes (shell) + +These errors are related to the shell. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| *10x* +| +| *Connection Errors* + +| `100` +| `CONNECTION_REFUSED [string]` +| Connection refused. + +| `101` +| `UNSUPPORTED_PROTOCOL [string]` +| Unsupported protocol scheme. + +| `102` +| `NO_SUCH_HOST [string]` +| No such host. + +| `103` +| `NO_HOST_IN_URL [string]` +| No host in request URL. + +| `104` +| `UNKNOWN_PORT_TCP [string]` +| Unknown port. + +| `105` +| `NO_ROUTE_TO_HOST [string]` +| No route to host. + +| `106` +| `UNREACHABLE_NETWORK [string]` +| Network is unreachable. + +| `107` +| `NO_CONNECTION [string]` +| Not connected to any cluster. + +Use `\\CONNECT` command. + +| `108` +| `DRIVER_OPEN [string]` +| Driver open. + +| `109` +| `INVALID_URL [string]` +| Invalid input URL. + +| *11x* +| +| *Read/Write/Update file errors* + +| `116` +| `READ_FILE [string]` +| Error during file read. + +| `117` +| `WRITE_FILE [string]` +| Error during file write. + +| `118` +| `FILE_OPEN [string]` +| Unable to open file. + +| `119` +| `FILE_CLOSE [string]` +| Unable to close file. + +| *12x* +| +| *Authentication Errors* + +| `121` +| `INVALID_PASSWORD [string]` +| Invalid password. + +| `122` +| `INVALID_USERNAME [string]` +| Invalid username. + +| `123` +| `MISSING_CREDENTIAL [string]` +| Username missing in -credentials/-c option. + +| `124` +| `INVALID_CREDENTIAL [string]` +| Invalid format for credentials. + +Separate username and password by a `:.` + +| *13x* +| +| *Command Errors* + +| `136` +| `NO_SUCH_COMMAND [string]` +| Command does not exist. + +| `137` +| `NO_SUCH_PARAM [string]` +| Parameter does not exist. + +| `138` +| `TOO_MANY_ARGS [string]` +| Too many input arguments to command. + +| `139` +| `TOO_FEW_ARGS [string]` +| Too few input arguments to command. + +| `140` +| `STACK_EMPTY [string]` +| Stack empty. + +| `141` +| `NO_SUCH_ALIAS [string]` +| Alias does not exist. + +| `142` +| `BATCH_MODE [string]` +| Error when running in batch mode. +Incorrect input value + +| `143` +| `STRING_WRITE [string]` +| Cannot write to string buffer. + +| *17x* +| +| *Generic Errors* + +| `170` +| `OPERATION_TIMEOUT [string]` +| Operation timed out. + +Check query service URL. + +| `171` +| `ROWS_SCAN [string]` +| Error in scanning a row. + +| `172` +| `JSON_MARSHAL [string]` +| Error in marshalling the JSON data. + +| `173` +| `JSON_UNMARSHAL [string]` +| Error in unmarshalling the JSON data. + +| `174` +| `DRIVER_QUERY [string]` +| Error in the query driver. + +| `175` +| `WRITER_OUTPUT [string]` +| Error with I/O Writer. + +| `176` +| `UNBALANCED_PAREN [string]` +| Unbalanced parenthesis in the input. + +| `177` +| `ROWS_CLOSE [string]` +| Error in closing the row. + +| `178` +| `CMD_LINE_ARG [string]` +| Place input argument URL at the end, after input flags. + +| `179` +| `INVALID_INPUT_ARGUMENTS [string]` +| Input Argument format is invalid. + +| *19x* +| +| *Untracked Errors* + +| `199` +| `UNKNOWN_ERROR [string]` +| Unknown error. +|=== + +== 1xxx Codes (service) + +These errors are related to the service. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `1000` +| `service.io.readonly [message]` +| Service I/O is readonly. + +| `1010` +| `Unsupported http method: [method]` +| Unsupported HTTP method. + +| `1020` +| `[value] [feature] not yet implemented` +| That value or feature is not yet implemented. + +| `1030` +| `Unknown [feature] value: [value]` +| Unknown feature value. + +| `1040` +| `Error processing [feature]` +| Error processing that feature. + +For example, the Query Service REST API returns this error if you specify request parameters as form data and include an unescaped semicolon (;) in a statement. + +| `1050` +| `No [feature] value` +| Missing value for that feature. + +| `1060` +| `Multiple values for [feature]` +| Multiple values for that feature. + +| `1065` +| `Unrecognized parameter in request: [parameter]` +| Unrecognized parameter in that request. + +| `1070` +| `[feature] has to be of type [expected]` +| Type mismatch. + +Another type was expected. + +| `1080` +| `Timeout [setting] exceeded` +| Timeout was exceeded. + +| `1100` +| `Invalid JSON in results` +| Invalid JSON in results. + +| `1110` +| `forbidden character (\\ or \") in client_context_id` +| Forbidden character (\ or ") in `client_context_id`. + +Remove the \ or " in `client_context_id`. + +| `1120` +| `Unsupported media type: [type]` +| Unsupported media type. + +| `1130` +| `Request [id] is not a http request` +| Request is not an HTTP request. + +| `1140` +| `Array [vec] should be of length 2` +| Array should be of length 2. + +| `1150` +| `Bad sequence number [seq]. +Expected an unsigned 64-bit integer.` +| Bad sequence number. + +Use an unsigned 64-bit integer. + +| `1150` +| `Bad UUID [uuid]. +Expected a string.` +| Bad UUID. + +Use a string value. + +| `1160` +| `Failed to decode nil value.` +| Failed to decode nil value. + +| `1170` +| `Unsupported method [method]` +| Unsupported HTTP method. +|=== + +== 2xxx Codes (admin) + +These codes are related to the admin. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `2130` +| `[Internal Caller message]` +| Admin endpoint error. + +| `2140` +| `server is not ssl enabled` +| Server is not SSL enabled. + +| `2150` +| `Not a proper creds JSON array of user/pass structures:` +| Invalid username or password. + +| `2160` +| `Completed requests qualifier already set: [InternalCaller]` +| Completed requests qualifier is already set. + +| `2170` +| `Completed requests qualifier can only be deployed once: [InternalCaller]` +| Completed requests qualifier can only be deployed once. + +| `2180` +| `Completed requests qualifier unknown: [CondString]` +| Completed requests has an invalid argument. + +| `2190` +| `Completed requests qualifier can only be deployed once: [InternalCaller]` +| Completed requests qualifier can only be deployed once. + +| `2200` +| `Completed requests qualifier unknown: [CondString]` +| Completed requests has an invalid argument. + +| `2210` +| _[port string]_ +| Bad service port. +|=== + +== 3xxx Codes (parse) + +These codes are related to parsing. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `3000` +| `parse.syntax_error` +| Parse syntax error. +|=== + +== 4xxx Codes (plan) + +These error are related to the query plan. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `4000` +| `plan_error` +| Plan error. + +| `4010` +| `[alias] term must have a name or alias` +| Term must have a name or alias. + +| `4020` +| `Duplicate [termType] alias [alias]` +| Duplicate alias. + +| `4025` +| `Unknown [termType] for alias [keyFor]` +| Unknown for alias. + +| `4030` +| `FROM in correlated subquery must have USE KEYS clause: FROM [keyspace]` +| FROM in correlated subquery must have USE KEYS clause. + +| `4040` +| `No such prepared statement: [name]` +| No such prepared statement. + +| `4050` +| `Unrecognizable prepared statement` +| Unrecognizable prepared statement. + +| `4060` +| `Unable to add name: [msg]` +| Unable to add prepared name. + +| `4070` +| `Unable to decode prepared statement` +| Unable to decode prepared statement. + +| `4080` +| `Encoded plan parameter does not match encoded plan of [name]` +| Encoded plan parameter does not match this encoded plan. + +| `4090` +| `Prepared name in encoded plan parameter is not [name]` +| Prepared name in encoded plan parameter is mismatched. + +| *41xx* +| +| + +| `4100` +| `No index available for join term [alias]` +| No index available for this JOIN term. + +| `4110` +| `[alias] term should not have USE KEYS` +| This should not have USE KEYS. + +| *42xx* +| +| + +| `4210` +| `Expression must be a group key or aggregate: [expr]` +| This expression must be a group key or aggregate. + +| *43xx* +| +| + +| `4300` +| `The index [idx] already exists.` +| The index already exists. + +| `4310` +| `META() in query with multiple FROM terms requires an argument.` +| META() in query with multiple FROM terms requires an argument. + +| `4320` +| `DESC option in the index keys is not supported by indexer.` +| DESC option in the index keys is not supported by indexer. + +| `4321` +| `Plan error: [msg]` +| Plan internal error. +|=== + +== 5000 & 9999 Codes (errors) + +These are general errors. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `5000` +| `Internal Error` +| Internal error. + +| `9999` +| `not_implemented` +| The feature is not implemented in this edition. + +|=== + +== 5xxx Codes (exec) + +These codes are related to the execution. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `5001` +| `execution.panic` +| Execution panic. + +| `5002` +| `execution.internal_error` +| Internal error during execution. + +| `5003` +| `Execution parameter error` +| Cannot have both USING clause and request parameters. + +| `5010` +| `execution.evaluation_error` +| Evaluation error. + +| `5015` +| `execution.explain_error` +| Explain error. + +| `5020` +| `execution.group_update_error` +| Group update error. + +| `5030` +| `execution.invalid_value_error` +| Invalid value. + +| `5035` +| `Out of range evaluating [termType]` +| Out of range. + +| `5040` +| `execution.duplicate_final_group` +| Duplicate final group. + +| `5050` +| `No INSERT key for [value]` +| No INSERT key. + +| `5060` +| `No INSERT value for [value]` +| No INSERT value. + +| `5070` +| `Cannot INSERT non-string key [key] of type [type]` +| Cannot INSERT non-string key of the type used. + +| `5072` +| `No UPSERT key for [value]` +| No UPSERT key for value used. + +| `5075` +| `No UPSERT value for [value]` +| No UPSERT value. + +| `5078` +| `Cannot UPSERT non-string key [value] of type [type]` +| Cannot UPSERT non-string key of the type used. + +| `5080` +| `DELETE alias [alias] not found in item.` +| DELETE alias not found in item. + +| `5090` +| `DELETE alias [alias] has no metadata in item.` +| DELETE alias has no metadata in item. + +| *51xx* +| +| + +| `5100` +| `UPDATE alias [alias] not found in item.` +| UPDATE alias not found in item. + +| `5110` +| `UPDATE alias [alias] has no metadata in item.` +| UPDATE alias has no metadata in item. + +| `5120` +| `Missing UPDATE clone.` +| Missing UPDATE clone. + +| `5180` +| `Invalid UNNEST position of type [type]` +| Invalid UNNEST position. + +| `5190` +| `execution.scan_vector_too_many_scanned_vectors` +| Too many scanned vectors. + +The `scan_vector` parameter should not be used for queries accessing more than one keyspace. +Use `scan_vectors` instead. + +| *52xx* +| +| + +| `5200` +| `Unable to find a value for key [key]` +| Unable to find a value for the given key. + +| `5210` +| `Unable to find user [user]` +| User not found. + +| `5220` +| `Role [role] requires a keyspace.` +| Role requires a keyspace. + +| `5230` +| `Role [role] does not take a keyspace.` +| Role does not take a keyspace. + +| `5240` +| `Keyspace [keyspace] is not valid.` +| Keyspace is not valid. + +| `5250` +| `Role [role] is not valid.` +| Role is not valid. + +| `5260` +| `User [user] already has role [role]` +| User already has this role. + +| `5270` +| `User [user] did not have role [role]` +| User did not have this role. + +| `5280` +| `User [user] has no roles. +Connecting with this user may not be possible.` +| User has no roles and may not be possible to connect with. + +| *55xx* +| +| + +| `5500` +| `Request has exceeded memory quota` +a| The query request exceeded the set Query Memory Quota. + +ifdef::flag-devex-rest-api[] +You can set a memory quota with the Couchbase Capella UI, the REST API, or the CLI. +For more information, see xref:n1ql:n1ql-manage/query-settings.adoc[]. + +* To set a memory quota with the UI, see xref:server:manage:manage-settings/general-settings.adoc#query-settings[Query Settings] in the General settings for Couchbase Capella. +* To set a memory quota with the REST API, see the cluster-level xref:n1ql:n1ql-manage/query-settings.adoc#queryMemoryQuota[queryMemoryQuota] setting. +* To set a memory quota with the CLI, see xref:server:cli:cbcli/couchbase-cli-setting-query.adoc[setting-query] in the CLI Reference. +endif::flag-devex-rest-api[] + +|=== + +== 10xxx Codes (ds_auth) + +These errors are related to the Datastore authentication. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `10000` +| `Unable to authorize user.` +| Unable to authorize user. +|=== + +== 11xxx Codes (ds_sys) + +These errors are related to the Datastore system. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `11000` +| `datastore.system.generic_error` +| System Datastore error. + +| `11001` +| `Datastore : namespace not found [msg]` +| System Datastore: Namespace not found. + +| `11002` +| `Keyspace not found [msg]` +| System Datastore: Keyspace not found. + +| `11003` +| `System datastore : Not implemented [msg]` +| System Datastore: Not implemented. + +| `11004` +| `System datastore : Not supported [msg]` +| System Datastore: Not supported. + +| `11005` +| `System datastore : Index not found [msg]` +| System Datastore: Index not found. + +| `11006` +| `System datastore : This index cannot be dropped [msg]` +| System Datastore: This index cannot be dropped. + +| `11007` +| `System datastore : Statement not found [msg]` +| System Datastore: Statement not found. + +| `11008` +| `System datastore : [op] on [keyspace] failed` +| System Datastore: Remote warning. + +| `11009` +| `System datastore : unable to retrieve user roles from server` +| System Datastore: Unable to retrieve user roles from server. + +| `11010` +| `System datastore : unable to update user information in server` +| System Datastore: Unable to update user information in server. + +| `11011` +| `One or more documents were excluded from the [keyspace] bucket because of insufficient user permissions.` +| One or more documents were excluded from the bucket because of insufficient user permissions. + +| `11012` +| `System datastore : key [key] is not of the correct format for keyspace [keyspace]` +| System datastore: A key is not of the correct format for the keyspace. +|=== + +== 12xxx Codes (ds_cb) + +These errors are related to the Couchbase Datastore. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `12000` +| `Cannot connect [msg]` +| Cannot connect. + +| `12001` +| `Cannot parse url [msg]` +| Cannot parse URL. + +| `12002` +| `Namespace not found [msg]` +| Namespace not found. + +| `12003` +| `Keyspace not found [msg]` +| Keyspace not found. + +| `12004` +| `Primary Index not found [msg]` +| Primary index not found. + +| `12005` +| `Indexer not implemented [msg]` +| Indexer not implemented + +| `12006` +| `Failed to get keyspace count [msg]` +| Failed to get Keyspace count. + +| `12007` +| `No keys to fetch [msg]` +| No keys to fetch. + +| `12008` +| `Error performing bulk get operation [msg]` +| Error performing bulk GET operation. + +| `12009` +| `DML Error, possible causes include CAS mismatch or concurrent modification [msg]` +| DML error. + +CAS mismatch or concurrent modification. + +| `12010` +| `No keys to insert [msg]` +| No keys to insert. + +| `12011` +| `datastore.couchbase.delete_failed` +| Couchbase Datastore delete failed. + +| `12012` +| `Failed to load indexes [msg]` +| Failed to load indexes. + +| `12013` +| `This bucket type is not supported [msg]` +| This keyspace type is not supported. + +| `12014` +| `datastore.couchbase.index_state_error` +| Invalid datastore index state. + +| `12015` +| `datastore.couchbase.index_scan_timeout` +| Index scan timed out. + +| `12016` +| `Index Not Found` +| Index not found. + +| `12017` +| `Error getting random entry from keyspace [msg]` +| Error getting random entry from Keyspace. + +| `12018` +| `Unable to initialize authorization system as required` +| Unable to initialize authorization system as required. +|=== + +== 13xxx Codes (ds_view) + +These errors are related to the Datastore view. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `13000` +| `Failed to create view [msg]` +| Failed to create view. + +| `13001` +| `View Index not found [msg]` +| View Index not found. + +| `13002` +| +| _[not used]_ + +| `13003` +| `View index exists [msg]` +| View index already exists. + +| `13004` +| `Views not allowed for WITH keyword [msg]` +| Views not allowed with keyword WITH. + +| `13005` +| `View indexes not supported [msg]` +| View indexes not supported. + +| `13006` +| `Failed to drop index [msg]` +| Failed to drop index. + +| `13007` +| `Failed to access view [msg]` +| Failed to access view. + +| `13008` +| `Failed to load indexes for keyspace [msg]` +| Failed to load indexes for keyspace. + +| `13009` +| `Unable to store the view definition.` +| Unable to store the view definition. + +Not all index target expressions are supported. +Check whether the JavaScript of the view definition is valid. +The map function has been output to `query_log`. + +| `13010` +| `No user supplied for query.` +| No user supplied for the query. + +| `13011` +| `Invalid username/password.` +| Invalid username or password. + +| `13012` +| `Error retrieving cluster [msg]` +| Error retrieving cluster. + +| `13013` +| `Unable to retrieve roles from server.` +| Unable to retrieve roles from server. + +| `13014` +| `datastore.couchbase.insufficient_credentials` +| Datastore: Insufficient credentials +|=== + +== 14xxx Codes (ds_gsi) + +These errors are related to the Datastore Global Secondary Index. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `14000` +| `Unacceptable size for index scan: [size]` +| Unacceptable size for index scan. +|=== + +== 15xxx Codes (ds_file) + +These errors are related to the Datastore files. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `15000` +| `Error in file datastore [msg]` +| Error in file datastore. + +| `15001` +| `Namespace not found [msg]` +| Namespace not found. + +| `15002` +| `Keyspace not found [msg]` +| Keyspace not found. + +| `15003` +| `Duplicate Namespace [msg]` +| Duplicate Namespace. + +Rename one of the Namespaces. + +| `15004` +| `Duplicate Keyspace [msg]` +| Duplicate Keyspace. + +Rename one of the Keyspaces. + +| `15005` +| `No keys to insert [msg]` +| No keys to insert. + +| `15006` +| `Key Exists [msg]` +| Key exists. + +| `15007` +| `DML Error [msg]` +| DML error. + +| `15008` +| `Keyspace path must be a directory [msg]` +| Keyspace path must be a directory. + +| `15009` +| `Index not found [msg]` +| Index not found. + +| `15010` +| `Operation not supported [msg]` +| Operation not supported. + +| `15011` +| `Primary Index cannot be dropped [msg]` +| Primary index cannot be dropped. +|=== + +== 16xxx Codes (ds_other) + +These error are related to other Datastore aspects. + +[cols="1,4,4"] +|=== +| ICode | Error Message | Description + +| `16000` +| `datastore.other.datastore_generic_error` +| Error in Datastore. + +| `16001` +| `datastore.other.namespace_not_found` +| Datastore Namespace not found. + +| `16002` +| `datastore.other.keyspace_not_found` +| Datastore Keyspace not found. + +| `16003` +| `datastore.other.not_implemented` +| Not implemented. + +| `16004` +| `datastore.other.idx_not_found` +| Datastore Index not found. + +| `16005` +| `Index Cannot be dropped [msg]` +| Index cannot be dropped. + +| `16006` +| `Not supported for this datastore [msg]` +| Not supported for this Datastore. + +| `16007` +| `Key not found [msg]` +| Key not found. + +| `16020` +| `Inferencer not found [msg]` +| Inferencer not found. +|=== diff --git a/modules/n1ql/pages/n1ql-language-reference/nest.adoc b/modules/n1ql/pages/n1ql-language-reference/nest.adoc new file mode 100644 index 000000000..b76cd2cb0 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/nest.adoc @@ -0,0 +1,609 @@ += NEST Clause +:description: The NEST clause creates an input object by producing a single result of nesting keyspaces. +:imagesdir: ../../assets/images +:from-term: pass:q[`NEST` clause] +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `NEST` clause creates an input object by producing a single result of nesting keyspaces. + +== Purpose + +The `NEST` clause is used within the xref:n1ql-language-reference/from.adoc[FROM] clause. +It enables you to create an input object by producing a single result of nesting keyspaces via <>, <>, or <>. + +== Prerequisites + +For you to select data from keyspace or expression, you must have the [.param]`query_select` privilege on that keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=nest-clause] +---- + +image::n1ql-language-reference/nest-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +ansi-nest-clause:: <> icon:caret-down[] +lookup-nest-clause:: <> icon:caret-down[] +index-nest-clause:: <> icon:caret-down[] + +[#from-term] +include::partial$n1ql-language-reference/from-term.adoc[] + +[#section_tc1_nnx_1db] +== ANSI NEST Clause + +include::partial$n1ql-language-reference/ansi-join-nest.adoc[] + +ANSI NEST supports more nest types than Lookup NEST or Index NEXT. +ANSI NEST can nest arbitrary fields of the documents, and can be chained together. + +The key difference between ANSI NEST and other supported NEST types is the replacement of the `ON KEYS` or `ON KEY … FOR` clauses with a simple `ON` clause. +The `ON KEYS` or `ON KEY … FOR` clauses dictate that those nests can only be done on a document key (primary key for a document). +The `ON` clause can contain any expression, and thus it opens up many more nest possibilities. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-nest-clause] +---- + +image::n1ql-language-reference/ansi-nest-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +ansi-nest-type:: <> icon:caret-down[] +ansi-nest-lateral:: <> icon:caret-down[] +ansi-nest-rhs:: <> icon:caret-down[] +ansi-nest-predicate:: <> icon:caret-down[] + +[#ansi-nest-type] +==== Nest Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-nest-type] +---- + +image::n1ql-language-reference/ansi-nest-type.png["Syntax diagram", align=left] + +This clause represents the type of ANSI nest. + +`INNER`:: +For each nested object produced, both the left-hand and right-hand source objects must be non-MISSING and non-NULL. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +For each nested object produced, only the left-hand source objects must be non-MISSING and non-NULL. + +This clause is optional. +If omitted, the default is `INNER`. + +[#ansi-nest-lateral] +==== LATERAL Nest + +When an expression on the right-hand side of an ANSI nest references a keyspace that is already specified in the same FROM clause, the expression is said to be correlated. +In relational databases, a join which contains correlated expressions is referred to as a lateral join. +In {sqlpp}, lateral correlations are detected automatically, and there is no need to specify that a nest or join is lateral. + +In clusters using Couchbase Server 7.6 and later, you can use the LATERAL keyword as a visual reminder that a nest contains correlated expressions. +The LATERAL keyword is not required -- the keyword is included solely for compatibility with queries from relational databases. + +If you use the LATERAL keyword in a nest that has no lateral correlation, the keyword is ignored. + +INNER NEST and LEFT OUTER NEST support the optional LATERAL keyword in front of the right-hand side keyspace. + +[#ansi-nest-rhs] +==== Nest Right-Hand Side + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-nest-rhs] +---- + +image::n1ql-language-reference/ansi-nest-rhs.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#ansi-keyspace-ref] +===== Keyspace Reference + +Keyspace reference or expression representing the right-hand side of the NEST clause. +For details, see xref:n1ql-language-reference/from.adoc#from-keyspace-ref[Keyspace Reference]. + +[#ansi-as-alias] +===== AS Alias + +Assigns another name to the right-hand side of the NEST clause. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#ansi-nest-predicate] +==== Nest Predicate + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ansi-nest-predicate] +---- + +image::n1ql-language-reference/ansi-nest-predicate.png["Syntax diagram", align=left] + +`expr`:: Boolean expression representing the nest condition between the left-hand side <> and the right-hand side <>. +This expression may contain fields, constant expressions, or any complex {sqlpp} expression. + +=== Limitations + +* Full OUTER nest and cross nest types are currently not supported. + +* No mixing of ANSI nest syntax with lookup or index nest syntax in the same FROM clause. + +* The right-hand-side of any nest must be a keyspace. +Expressions, subqueries, or other join combinations cannot be on the right-hand-side of a nest. + +* A nest can only be executed when appropriate index exists on the inner side of the ANSI nest. + +* Adaptive indexes are not considered when selecting indexes on inner side of the nest. + +* You may chain ANSI nests with comma-separated joins; however, the comma-separated joins must come after any JOIN, NEST, or UNNEST clauses. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ANSI-NEST-Example-1] +.Inner ANSI NEST +==== +List only airports in Toulouse which have routes starting from them, and nest details of the routes. + +.Query +[source,sqlpp] +---- +include::example$select/ansi-nest-inner.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-nest-inner.jsonc[tags=extract;ellipsis] +---- +==== + +[#ANSI-NEST-Example-1A] +.Inner LATERAL NEST +==== +This example is the same as <>, but it includes the optional LATERAL keyword. + +.Query +[source,sqlpp] +---- +include::example$select/ansi-nest-lateral.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-nest-lateral.jsonc[tags=extract;ellipsis] +---- +==== + +[#ANSI-NEST-Example-2] +.Left Outer ANSI NEST +==== +List all airports in Toulouse, and nest details of any routes that start from each airport. + +.Query +[source,sqlpp] +---- +include::example$select/ansi-nest-left.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/ansi-nest-left.jsonc[tags=extract;ellipsis] +---- + +<.> The LEFT OUTER NEST lists all the left-side results, even if there are no matching right-side documents, as indicated by the results in which the fields from the `route` keyspace are null or missing. +==== + +[#nest] +== Lookup NEST Clause + +Nesting is conceptually the inverse of unnesting. +Nesting performs a join across two keyspaces. +But instead of producing a cross-product of the left and right inputs, a single result is produced for each left input, while the corresponding right inputs are collected into an array and nested as a single array-valued field in the result object. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-nest-clause] +---- + +image::n1ql-language-reference/lookup-nest-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +lookup-nest-type:: <> icon:caret-down[] +lookup-nest-rhs:: <> icon:caret-down[] +lookup-nest-predicate:: <> icon:caret-down[] + +[#lookup-nest-type] +==== Nest Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-nest-type] +---- + +image::n1ql-language-reference/lookup-nest-type.png["Syntax diagram", align=left] + +This clause represents the type of lookup nest. + +`INNER`:: +For each result object produced, both the left-hand and right-hand source objects must be non-`MISSING` and non-`NULL`. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +A left-outer unnest is performed, and at least one result object is produced for each left source object. ++ +For each joined object produced, only the left-hand source objects must be non-`MISSING` and non-`NULL`. + +This clause is optional. +If omitted, the default is `INNER`. + +[#lookup-nest-rhs] +==== Nest Right-Hand Side + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-nest-rhs] +---- + +image::n1ql-language-reference/lookup-nest-rhs.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#lookup-keyspace-ref] +===== Keyspace Reference + +Keyspace reference for the right-hand side of the lookup nest. +For details, see xref:n1ql-language-reference/from.adoc#from-keyspace-ref[Keyspace Reference]. + +[#lookup-as-alias] +===== AS Alias + +Assigns another name to the right-hand side of the lookup nest. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#lookup-nest-predicate] +==== Nest Predicate + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=lookup-nest-predicate] +---- + +image::n1ql-language-reference/lookup-nest-predicate.png["Syntax diagram", align=left] + +The `ON KEYS` expression produces a document key or array of document keys for the right-hand side of the lookup nest. + +expr:: +[Required] String or expression representing the primary keys of the documents for the right-hand side keyspace. + +=== Return Values + +If the right-hand source object is NULL, MISSING, empty, or a non-array value, then the result object's right-side value is MISSING (omitted). + +Nests can be chained with other NEST, JOIN, and UNNEST clauses. +By default, an INNER NEST is performed. +This means that for each result object produced, both the left and right source objects must be non-missing and non-null. +The right-hand side result of NEST is always an array or MISSING. +If there is no matching right source object, then the right source object is as follows: + +|=== +| If the `ON KEYS` expression evaluates to | Then the right-side value is + +| `MISSING` +| `MISSING` + +| `NULL` +| `MISSING` + +| an array +| an empty array + +| a non-array value +| an empty array +|=== + +=== Limitations + +Lookup nests can be chained with other lookup joins or nests and index joins or nests, but they cannot be mixed with ANSI joins, ANSI nests, or comma-separated joins. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#Lookup-NEST-Example-1] +.Join two keyspaces producing an output for each left input +==== +Show one set of routes for one airline in the `airline` keyspace. + +.Query +[source,sqlpp] +---- +include::example$select/lookup-nest.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/lookup-nest.jsonc[tags=extract;ellipsis] +---- +==== + +[#section_rgr_rnx_1db] +== Index NEST Clause + +Index NESTs allow you to flip the direction of a Lookup NEST clause. +Index NESTs can be used efficiently when Lookup NESTs cannot efficiently nest left-hand side documents with right-to-left nests, and your situation cannot be flipped because your predicate needs to be on the left-hand side, such as <> above where airline documents have no reference to route documents. + +NOTE: For index nests, the syntax uses `ON KEY` (singular) instead of `ON KEYS` (plural). +This is because an Index NEST's `ON KEY` expression must produce a scalar value; whereas a Lookup NEST's `ON KEYS` expression can produce either a scalar or an array value. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-nest-clause] +---- + +image::n1ql-language-reference/index-nest-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +index-nest-type:: <> icon:caret-down[] +index-nest-rhs:: <> icon:caret-down[] +index-nest-predicate:: <> icon:caret-down[] + +[#index-nest-type] +==== Nest Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-nest-type] +---- + +image::n1ql-language-reference/index-nest-type.png["Syntax diagram", align=left] + +This clause represents the type of index nest. + +`INNER`:: +For each nested object produced, both the left-hand and right-hand source objects must be non-MISSING and non-NULL. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +For each nested object produced, only the left-hand source objects must be non-MISSING and non-NULL. + +This clause is optional. +If omitted, the default is `INNER`. + +[#index-nest-rhs] +==== Nest Right-Hand Side + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-nest-rhs] +---- + +image::n1ql-language-reference/index-nest-rhs.png["Syntax diagram", align=left] + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#index-keyspace-ref] +===== Keyspace Reference + +Keyspace reference or expression representing the right-hand side of the NEST clause. +For details, see xref:n1ql-language-reference/from.adoc#from-keyspace-ref[Keyspace Reference]. + +[#index-as-alias] +===== AS Alias + +Assigns another name to the right-hand side of the NEST clause. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[#index-nest-predicate] +==== Nest Predicate + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=index-nest-predicate] +---- + +image::n1ql-language-reference/index-nest-predicate.png["Syntax diagram", align=left] + +`expr`:: Expression in the form `__rhs-expression__.__lhs-expression-key__`: + +`__rhs-expression__`;; Keyspace reference for the right-hand side of the index nest. + +`__lhs-expression-key__`;; String or expression representing the attribute in `__rhs-expression__` and referencing the document key for `alias`. + +`alias`:: Keyspace reference for the left-hand side of the index nest. + +=== Limitations + +Index nests can be chained with other index joins or nests and lookup joins or nests, but they cannot be mixed with ANSI joins, ANSI nests, or comma-separated joins. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#Index-NEST-Example-1] +.Use INDEX nest to flip the direction of <> above +==== +This example nests the airline routes for each airline after creating the following index. +(Note that the index will not match if it contains a WHERE clause.) + +.Index +[source,sqlpp] +---- +include::example$select/index-nest.n1ql[tag=index] +---- + +.Query +[source,sqlpp] +---- +include::example$select/index-nest.n1ql[tag=query] +---- + +.Results +[source,JSON] +---- +include::example$select/index-nest.jsonc[tags=extract;ellipsis] +---- + +If you generalize the same query, it looks like the following: + +[subs="normal"] +---- +CREATE INDEX _on-key-for-index-name_ _rhs-expression_ (__lhs-expression-key__); +---- + +[subs="normal"] +---- +SELECT _projection-list_ +FROM _lhs-expression_ + NEST _rhs-expression_ + ON KEY __rhs-expression__.__lhs-expression-key__ FOR _lhs-expression_ +[ WHERE _predicates_ ] ; +---- +==== + +There are three important changes in the index scan syntax example above: + +* `CREATE INDEX` on the `ON KEY` expression `rte.airlineid` to access `route` documents using `airlineid` (which are produced on the left-hand side). +* The `ON KEY rte.airlineid FOR aline` enables {sqlpp} to use the index `route_airlineid`. +* Create any optional index, such as `route_airline`, that can be used on `airline` (left-hand side). + +[#as] +== Appendix: Summary of NEST Types + +include::ROOT:partial$query-context.adoc[tag=section] + +=== ANSI + +[cols="1s,3"] +|=== +| Left-Hand Side (lhs) +| Any field or expression that produces a value that will be matched on the right-hand side. + +| Right-Hand Side (rhs) +| Anything that can have a proper index on the join expression. + +| Syntax +a| +[subs="normal"] +---- +_lhs-expr_ +NEST _rhs-keyspace_ +ON _any nest condition_ +---- + +| Example +a| +[source,sqlpp] +---- +SELECT * +FROM route r +NEST airline a +ON r.airlineid = META(a).id +LIMIT 4; +---- +|=== + +=== Lookup + +[cols=".^1s,3"] +|=== +| Left-Hand Side (lhs) +| Must produce a Document Key for the right-hand side. + +| Right-Hand Side (rhs) +| Must have a Document Key. + +| Syntax +a| +[subs="normal"] +---- +_lhs-expr_ +NEST _rhs-keyspace_ +ON KEYS _lhs-expr.foreign_key_ +---- + +| Example +a| +[source,sqlpp] +---- +SELECT * +FROM route r +NEST airline a +ON KEYS r.airlineid +LIMIT 4; +---- +|=== + +=== Index + +[cols=".^1s,3"] +|=== +| Left-Hand Side (lhs) +| Must produce a key for the right-hand side index. + +| Right-Hand Side (rhs) +| Must have a proper index on the field or expression that maps to the Document Key of the left-hand side. + +| Syntax +a| +[subs="normal"] +---- +_lhs-keyspace_ +NEST _rhs-keyspace_ +ON KEY _rhs-kspace.idx_key_ +FOR _lhs-keyspace_ +---- + +| Example +a| +[source,sqlpp] +---- +SELECT * +FROM airline a +NEST route r +ON KEY r.airlineid FOR a +LIMIT 4; +---- +|=== diff --git a/modules/n1ql/pages/n1ql-language-reference/nestedops.adoc b/modules/n1ql/pages/n1ql-language-reference/nestedops.adoc new file mode 100644 index 000000000..d9540795f --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/nestedops.adoc @@ -0,0 +1,167 @@ += Nested Operators and Expressions +:description: In {sqlpp}, nested operators and paths indicate expressions to access nested sub-documents within a JSON document or expression. +:page-topic-type: reference +:imagesdir: ../../assets/images + +{description} + +A nested expression may contain field selection operators, element selection operators, and array slicing operators. + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=nested-expr] +---- + +image::n1ql-language-reference/nested-expr.png["Syntax diagram", align=left] + +These special operators are needed to access the data because Couchbase documents can have nested objects and embedded arrays. +A field selection operator is used to refer to a field in an object, and an element selection operator is used to refer to an element in an array. +You can use a combination of these operators to access nested data at any depth in a document. + +== Field Selection + +Field selection operators use the dot notation `.` to refer to a child field, that is, a field one level down in a nested object. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=field-expr] +---- + +image::n1ql-language-reference/field-expr.png["Syntax diagram", align=left] + +=== Arguments + +expr:: +An expression resolving to an object. + +identifier:: +escaped-identifier:: An identifier which specifies the name of a field in the object. + +name-expr:: An expression resolving to a string which specifies the name of a field in the object. + +By default, field names are case sensitive. +To access a field case-insensitively, include the trailing `i`. + +=== Return Value + +The value of the specified field. + +=== Example + +==== +Given the following data: + +[source,json] +---- +{ + "address": { + "city": "Mountain View" + }, + "revisions": [2013, 2012, 2011, 2010] +} +---- + +The following expressions all evaluate to `"Mountain View"`. + +`address.city`, `pass:c[address.`CITY`i]`, `address.["city"]`, and `address.["CITY"]i` +==== + +== Element Selection + +Element selection operators use the bracket notation `[ ]` to access an element inside a nested array. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=element-expr] +---- + +image::n1ql-language-reference/element-expr.png["Syntax diagram", align=left] + +=== Arguments + +expr:: +An expression resolving to an array. + +position:: +A numeric expression specifying the position of an element in the array, counting from 0. +Negative positions are counted backwards from the end of the array. + +=== Return Value + +The value of the specified element. + +=== Example + +==== +Given the following data: + +[source,json] +---- +{ + "address": { + "city": "Mountain View" + }, + "revisions": [2013, 2012, 2011, 2010] +} +---- + +The expression `revisions[0]` evaluates to `2013`. +The expression `revision[-1]` evaluates to `2010`. +==== + +== Array Slicing + +The array slicing operator enables you to get subsets or segments of an array. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=slice-expr] +---- + +image::n1ql-language-reference/slice-expr.png["Syntax diagram", align=left] + +=== Arguments + +expr:: +An expression resolving to an array. + +start-expr:: +A numeric expression specifying a start position in the array, counting from 0. +Negative positions are counted backwards from the end of the array. + +end-expr:: +[Optional] A numeric expression specifying an end position in the array, counting from 0. +Negative positions are counted backwards from the end of the array. + +=== Return Value + +A new subset of the source array, containing the elements from the start position to the end position minus 1. +The element at the start position is included, while the element at the end position is not. + +If the end position is omitted, all elements from the start position to the end of the source array are included. + +=== Example + +==== +Given the following data: + +[source,json] +---- +{ + "address": { + "city": "Mountain View" + }, + "revisions": [2013, 2012, 2011, 2010] +} +---- + +The expression `revisions[1:3]` evaluates to the array value `[2012, 2011]`. + +The expression `revisions[1:]` evaluates to the array value `[2012, 2011, 2010]`. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/numericfun.adoc b/modules/n1ql/pages/n1ql-language-reference/numericfun.adoc new file mode 100644 index 000000000..0a803d5ea --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/numericfun.adoc @@ -0,0 +1,124 @@ += Number Functions +:description: Number functions are functions that are performed on a numeric field. +:page-topic-type: reference + +{description} + +ABS(expression) + +Returns absolute value of the number. + +ACOS(expression) + +Returns arccosine in radians. + +ASIN(expression) + +Returns arcsine in radians. + +ATAN(expression) + +Returns arctangent in radians. + +ATAN2(expression1, expression2) + +Returns arctangent of expression2/expression1. + +CEIL(expression) + +Returns smallest integer not less than the number. + +COS(expression) + +Returns cosine. + +DEGREES(expression) + +Returns radians to degrees. + +E() + +Base of natural logarithms. + +EXP(expression) + +Returns e^expression^. + +LN(expression) + +Returns log base e. + +LOG(expression) + +Returns log base 10. + +FLOOR(expression) + +Largest integer not greater than the number. + +PI() + +Returns PI. + +POWER(expression1, expression2): + +Returns expression1^expression2^. + +RADIANS(expression) + +Returns degrees to radians. + +RANDOM([ expression ]) + +Returns pseudo-random number with optional seed. + +ROUND(expression [, digits ]) + +Rounds the value to the given number of integer digits to the right of the decimal point (left if digits is negative). +Digits is 0 if not given. + +SIGN(expression) + +Valid values: -1, 0, or 1 for negative, zero, or positive numbers respectively. + +SIN(expression) + +Returns sine. + +SQRT(expression) + +Returns square root. + +TAN(expression) + +Returns tangent. + +TRUNC(expression [, digits ]) + +Truncates the number to the given number of integer digits to the right of the decimal point (left if digits is negative). +Digits is 0 if not given. + +Example + +---- +SELECT + AVG(reviews.rating) / 5 AS normalizedRating, + ROUND((avg(reviews.rating) / 5), 2) AS roundedRating, + TRUNC((avg(reviews.rating) / 5), 3) AS truncRating + FROM reviews AS reviews + WHERE reviews.customerId = "customer62" +---- + +Returns + +---- +{ + "results": [ + { + "normalizedRating": 0.42000000000000004, + "roundedRating": 0.42, + "truncRating": 0.42 + } + ] + } +---- diff --git a/modules/n1ql/pages/n1ql-language-reference/objectfun.adoc b/modules/n1ql/pages/n1ql-language-reference/objectfun.adoc new file mode 100644 index 000000000..a4e426916 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/objectfun.adoc @@ -0,0 +1,1497 @@ += Object Functions +:description: You can use object functions to evaluate objects, perform computations on attributes in an object, and to return a new object based on a transformation. +:page-topic-type: reference +:example-caption!: + +{description} + +[[fn-obj-add,OBJECT_ADD()]] +== OBJECT_ADD(`object`, `new_attr_key`, `new_attr_value`) + +=== Description + +This function adds new attributes and values to a given object. + +=== Arguments + +object:: An expression representing the object that you want to add to. +new_attr_key:: The name of the attribute to add. +new_attr_value:: The value of the attribute to add. + +=== Return Value + +The updated object. + +* This function does not perform key substitution. +* If you add a duplicate attribute (that is, if the key is found), it returns an error or NULL object. +* If [.var]`new_attr_key` or [.var]`new_attr_value` is MISSING, or if [.var]`new_attr_key` is NULL, it returns the [.var]`object` unmodified. +* If [.var]`object` is not an object or NULL, it returns a NULL value object. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[obj-add-ex,OBJECT_ADD() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT schedule[0] AS original, + OBJECT_ADD(schedule[0], "day_new", 1) AS output +FROM route +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "original": { + "day": 0, + "flight": "AF198", + "utc": "10:13:00" + }, + "output": { + "day": 0, + "day_new": 1, + "flight": "AF198", + "utc": "10:13:00" + } + } +] +---- +==== + +[[fn-obj-concat,OBJECT_CONCAT()]] +== OBJECT_CONCAT(`expr`, `expr` ...) + +=== Description + +This function concatenates the input objects and returns a new object. +It requires a minimum of two input objects. + +=== Arguments + +expr:: An expression representing an object. + +=== Return Value + +An object constructed by concatenating all the input objects. +If any of the input objects contain the same attribute name, the attribute from the last relevant object in the input list is copied to the output; similarly-named attributes from earlier objects in the input list are ignored. + +=== Examples + +[[obj-concat-ex,OBJECT_CONCAT() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_CONCAT({"abc": 1}, {"def": 2}, {"ghi": 3}, {"ghi": 4}, {"ghi": [5, 6, 7]}); +---- + +.Results +[source,json] +---- +[ + { + "$1": { + "abc": 1, + "def": 2, + "ghi": [ + 5, + 6, + 7 + ] + } + } +] +---- +==== + +[[fn-obj-field,OBJECT_FIELD()]] +== OBJECT_FIELD(`object`, `field`) + + +=== Description + +This function returns the value of the specified field within the given object. +A field in this context may be any attribute or element, nested at any level within the object. + +=== Arguments + +expr:: An expression representing an object. + +field:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the path to a field within the object. ++ +You can use xref:n1ql-language-reference/nestedops.adoc[nested operators] to specify the path to a nested attribute or element. +If any attribute names within the field path contain special characters, they must be escaped using backticks (`{backtick}{backtick}`). + +=== Return Value + +The value of the specified field. +If the object does not exist, or the field cannot be found within the object at the specified location, the function returns NULL. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[obj-field-ex1,OBJECT_FIELD() Example 1]] +.Top-Level Fields +==== +This example returns the complete values of the specified attributes at the top level of the object. + +.Query +[source,sqlpp] +---- +SELECT OBJECT_FIELD(hotel, "public_likes") AS `array`, + OBJECT_FIELD(hotel, "vacancy") AS `boolean`, + OBJECT_FIELD(hotel, "id") AS `number`, + OBJECT_FIELD(hotel, "geo") AS `object`, + OBJECT_FIELD(hotel, "name") AS `string` +FROM hotel +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "array": [ + "Julius Tromp I", + "Corrine Hilll", + "Jaeden McKenzie", + "Vallie Ryan", + "Brian Kilback", + "Lilian McLaughlin", + "Ms. Moses Feeney", + "Elnora Trantow" + ], + "boolean": true, + "number": 10025, + "object": { + "accuracy": "RANGE_INTERPOLATED", + "lat": 51.35785, + "lon": 0.55818 + }, + "string": "Medway Youth Hostel" + } +] +---- +==== + +[[obj-field-ex2,OBJECT_FIELD() Example 2]] +.Nested Fields +==== +This example specifies a nested array element and a nested object attribute at different depths in the hierarchy. +In the path to the nested object attribute, the final attribute name is escaped, as it contains special characters. + +.Query +[source,sqlpp] +---- +SELECT + OBJECT_FIELD(hotel, "reviews[1]") + AS array_element, + OBJECT_FIELD(hotel, "reviews[1].ratings.`Business service (e.g., internet access)`") + AS object_attribute +FROM hotel +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "array_element": { + "author": "Barton Marks", + "content": "We found the hotel de la Monnaie through Interval ...", + "date": "2015-03-02 19:56:13 +0300", + "ratings": { + "Business service (e.g., internet access)": 4, + "Check in / front desk": 4, + "Cleanliness": 4, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 3, + "Value": 5 + } + }, + "object_attribute": 4 + } +] +---- +==== + +[[fn-obj-inner-pairs,OBJECT_INNER_PAIRS()]] +== OBJECT_INNER_PAIRS(`expression`) + +=== Description + +This function returns an array of objects, containing the names and values of each attribute in the input object. +It is particularly useful when iterating over multiple objects in an array, as it collates the values from similarly-named attributes into a single nested array. + +In this case, the function does not return a value from any object which does not contain the shared attribute name, rather like an INNER JOIN. +For an illustration, refer to the examples below. + +=== Arguments + +expression:: An expression representing an object. + +=== Return Value + +An array of objects, each containing two attributes: + +name:: The name of an attribute in the source object. + +val:: The value of an attribute in the source object; or an array, containing the collated values of similarly-named attributes in the source objects. + +The objects in the array are sorted by attribute name, in {sqlpp} collation order. + +=== Examples + +[[obj-inner-pairs-ex1,OBJECT_INNER_PAIRS() Example 1]] +.Single object +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_INNER_PAIRS({"flight": "AI444", "utc": "4:44:44", "codename": "green"}) + AS inner_pairs; +---- + +.Results +[source,json] +---- +[ + { + "inner_pairs": [ + { + "name": "codename", + "val": "green" + }, + { + "name": "flight", + "val": "AI444" + }, + { + "name": "utc", + "val": "4:44:44" + } + ] + } +] +---- +==== + +[[obj-inner-pairs-ex2,OBJECT_INNER_PAIRS() Example 2]] +.Iterating over objects in an array +==== +In this example, notice that where the source objects have similarly-named attributes, the values from each of those attributes are collated into a single array in the output. + +.Query +[source,sqlpp] +---- +WITH special_flights AS ([{"flight": "AI444", "utc": "4:44:44", "codename": "green"}, + {"flight": "AI333", "utc": "3:33:33", "alert": "red"}, + {"flight": "AI222", "utc": "2:22:22", "codename": "yellow"}]) +SELECT OBJECT_INNER_PAIRS(special_flights[*]) AS inner_pairs; +---- + +.Results +[source,json] +---- +[ + { + "inner_pairs": [ + { + "name": "alert", + "val": "red" + }, + { + "name": "codename", + "val": [ + "green", + "yellow" + ] + }, + { + "name": "flight", + "val": [ + "AI444", + "AI333", + "AI222" + ] + }, + { + "name": "utc", + "val": [ + "4:44:44", + "3:33:33", + "2:22:22" + ] + } + ] + } +] +---- +==== + +[[fn-obj-inner-values,OBJECT_INNER_VALUES()]] +== OBJECT_INNER_VALUES(`expression`) + +=== Description + +This function returns an array, containing the values of each attribute in the input object. +It is particularly useful when iterating over multiple objects in an array, as it collates the values from similarly-named attributes into a single nested array. + +In this case, the function does not return a value from any object which does not contain the shared attribute name, rather like an INNER JOIN. +For an illustration, refer to the examples below. + +=== Arguments + +expression:: An expression representing an object. + +=== Return Value + +An array of the values contained within the source object. +The values in the array are sorted by the corresponding attribute names in the source object, in {sqlpp} collation order. + +=== Examples + +[[obj-inner-values-ex1,OBJECT_INNER_VALUES() Example 1]] +.Single object +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_INNER_VALUES({"flight": "AI444", "utc": "4:44:44", "codename": "green"}) + AS inner_values; +---- + +.Results +[source,json] +---- +[ + { + "inner_values": [ + "green", + "AI444", + "4:44:44" + ] + } +] +---- +==== + +[[obj-inner-values-ex2,OBJECT_INNER_VALUES() Example 2]] +.Iterating over objects in an array +==== +In this example, notice that where the source objects have similarly-named attributes, the values from each of those attributes are collated into a single array in the output. + +.Query +[source,sqlpp] +---- +WITH special_flights AS ([{"flight": "AI444", "utc": "4:44:44", "codename": "green"}, + {"flight": "AI333", "utc": "3:33:33", "alert": "red"}, + {"flight": "AI222", "utc": "2:22:22", "codename": "yellow"}]) +SELECT OBJECT_INNER_VALUES(special_flights[*]) AS inner_values; +---- + +.Results +[source,json] +---- +[ + { + "inner_values": [ + "red", + [ + "green", + "yellow" + ], + [ + "AI444", + "AI333", + "AI222" + ], + [ + "4:44:44", + "3:33:33", + "2:22:22" + ] + ] + } +] +---- +==== + +[[fn-obj-length,OBJECT_LENGTH()]] +== OBJECT_LENGTH(`expression`) + +_Equivalent_: xref:n1ql-language-reference/metafun.adoc#len[LEN()] + +=== Description + +This function returns the number of name-value pairs in the object. +It only counts the top-level attributes and does not recurse into nested objects. + +=== Arguments + +expression:: An object or an expression that evaluates to an object. + +=== Return Value + +An integer. + +If the input expression is not an object, the function returns `null`; if the input expression is `missing`, the function returns `missing`. + +=== Examples + +[[obj-length-ex,OBJECT_LENGTH() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_LENGTH({"abc": 1, "def": 2, "ghi": {"uvw": 3, "xyz": 4}}); +---- + +.Results +[source,json] +---- +[ + { + "$1": 3 + } +] +---- +==== + +[[fn-obj-names,OBJECT_NAMES()]] +== OBJECT_NAMES(`expression`) + +=== Description + +This function returns an array, containing the names of each attribute in the input object. +It is particularly useful when iterating over multiple objects in an array, as it collates similar attribute names. + +=== Arguments + +expression:: An expression representing an object. + +=== Return Value + +An array of the attribute names contained within the source object. +The attribute names are sorted in {sqlpp} collation order. + +=== Examples + +[[obj-names-ex1,OBJECT_NAMES() Example 1]] +.Single object +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_NAMES({"flight": "AI444", "utc": "4:44:44", "codename": "green"}) + AS names; +---- + +.Results +[source,json] +---- +[ + { + "names": [ + "codename", + "flight", + "utc" + ] + } +] +---- +==== + +[[obj-names-ex2,OBJECT_NAMES() Example 2]] +.Iterating over objects in an array +==== +.Query +[source,sqlpp] +---- +WITH special_flights AS ([{"flight": "AI444", "utc": "4:44:44", "codename": "green"}, + {"flight": "AI333", "utc": "3:33:33", "alert": "red"}, + {"flight": "AI222", "utc": "2:22:22", "codename": "yellow"}]) +SELECT OBJECT_NAMES(special_flights[*]) AS names; +---- + +.Results +[source,json] +---- +[ + { + "names": [ + "alert", + "codename", + "flight", + "utc" + ] + } +] +---- +==== + +[[fn-obj-pairs,OBJECT_PAIRS()]] +== OBJECT_PAIRS(`expression`) + +_Alias_: *OBJECT_OUTER_PAIRS(`expression`)* + +=== Description + +This function returns an array of objects, containing the names and values of each attribute in the input object. +It is particularly useful when iterating over multiple objects in an array, as it collates the values from similarly-named attributes into a single nested array. + +In this case, the function returns a null entry from any object which does not contain the shared attribute name, rather like an OUTER JOIN. +For an illustration, refer to the examples below. + +=== Arguments + +expression:: An expression representing an object. + +=== Return Value + +An array of objects, each containing two attributes: + +name:: The name of an attribute in the source object. + +val:: The value of an attribute in the source object; or an array, containing the collated values of similarly-named attributes in the source objects. + +The objects in the array are sorted by attribute name, in {sqlpp} collation order. + +=== Examples + +[[obj-pairs-ex1,OBJECT_PAIRS() Example 1]] +.Single object +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_PAIRS({"flight": "AI444", "utc": "4:44:44", "codename": "green"}) + AS outer_pairs; +---- + +.Results +[source,json] +---- +[ + { + "outer_pairs": [ + { + "name": "codename", + "val": "green" + }, + { + "name": "flight", + "val": "AI444" + }, + { + "name": "utc", + "val": "4:44:44" + } + ] + } +] +---- +==== + +[[obj-pairs-ex2,OBJECT_PAIRS() Example 2]] +.Iterating over objects in an array +==== +In this example, notice that where the source objects have similarly-named attributes, the values from each of those attributes are collated into a single array in the output. + +.Query +[source,sqlpp] +---- +WITH special_flights AS ([{"flight": "AI444", "utc": "4:44:44", "codename": "green"}, + {"flight": "AI333", "utc": "3:33:33", "alert": "red"}, + {"flight": "AI222", "utc": "2:22:22", "codename": "yellow"}]) +SELECT OBJECT_PAIRS(special_flights[*]) AS outer_pairs; +---- + +.Results +[source,json] +---- +[ + { + "outer_pairs": [ + { + "name": "alert", + "val": [ + null, + "red", + null + ] + }, + { + "name": "codename", + "val": [ + "green", + null, + "yellow" + ] + }, + { + "name": "flight", + "val": [ + "AI444", + "AI333", + "AI222" + ] + }, + { + "name": "utc", + "val": [ + "4:44:44", + "3:33:33", + "2:22:22" + ] + } + ] + } +] +---- +==== + +[[fn-obj-pairs-nested,OBJECT_PAIRS_NESTED()]] +== OBJECT_PAIRS_NESTED(`object` [, `options`]) + + +=== Description + +Similar to <>, this function returns an array of objects, containing the names and values of each field in the input object. +A field in this context may be any attribute or element, nested at any level within the object. + +This function may be useful when iterating over multiple objects in an array, as it collates and unnests the values from similarly-named fields across all objects in the input array. +In this case, the function returns a null entry from any object which does not contain the shared field name, rather like an OUTER JOIN. +For an illustration, refer to the examples below. + +=== Arguments + +object:: An expression representing an object. + +options:: [Optional] An object containing the following possible parameters: + +composites;; A boolean. +If `true`, every level of every nested field is displayed; if `false`, only the deepest possible nested fields are returned. +Default `false`. + +pattern;; A regular expression used to filter the returned paths. +The pattern is matched against the composite path names, not the individual field names. + +=== Return Value + +An array of objects, each containing two attributes: + +name:: The full path to every possible field within the source object, subject to the specified options. ++ +The result uses xref:n1ql-language-reference/nestedops.adoc[nested operators] to specify the path to all nested attributes or elements. +If any attribute names within a field path contain special characters, they are escaped using backticks (`{backtick}{backtick}`). + +val:: The value of an attribute in the source object; or an array, containing the collated values of similarly-named attributes in the source objects. + +The objects in the array are sorted by attribute name, in {sqlpp} collation order. + +=== Examples + +[[obj-pairs-nested-ex1,OBJECT_PAIRS_NESTED() Example 1]] +.Single object +==== +.Query +[source,sqlpp] +---- +WITH input AS ({ + "attribute": {"first-part": 1, "second-part": 2} +}) +SELECT OBJECT_PAIRS_NESTED(input) AS nested_pairs, + OBJECT_PAIRS_NESTED(input, {"composites": true}) AS nested_pairs_comp, + OBJECT_PAIRS_NESTED(input, {"pattern": "first"}) AS nested_pairs_pattern; +---- + +.Results +[source,json] +---- +[ + { + "nested_pairs": [ + { + "name": "attribute.first-part", + "val": 1 + }, + { + "name": "attribute.second-part", + "val": 2 + } + ], + "nested_pairs_comp": [ + { + "name": "attribute", + "val": { + "first-part": 1, + "second-part": 2 + } + }, + { + "name": "attribute.first-part", + "val": 1 + }, + { + "name": "attribute.second-part", + "val": 2 + } + ], + "nested_pairs_pattern": [ + { + "name": "attribute.first-part", + "val": 1 + } + ] + } +] +---- +==== + +[[obj-pairs-nested-ex2,OBJECT_PAIRS_NESTED() Example 2]] +.Iterating over objects in an array +==== +In this example, notice that where the source objects have similarly-named attributes, the values from each of those attributes are collated into a single array in the output. +Each collated array is then unnested to show the name and value of its elements. + +.Query +[source,sqlpp] +---- +WITH special_flights AS ([{"flight": "AI444", "utc": "4:44:44", "codename": "green"}, + {"flight": "AI333", "utc": "3:33:33", "alert": "red"}, + {"flight": "AI222", "utc": "2:22:22", "codename": "yellow"}]) +SELECT OBJECT_PAIRS_NESTED(special_flights[*], {"composites": true}) AS nested_pairs; +---- + +.Results +[source,json] +---- +[ + { + "nested_pairs": [ + { + "name": "alert", + "val": [ + null, + "red", + null + ] + }, + { + "name": "alert[0]", + "val": null + }, + { + "name": "alert[1]", + "val": "red" + }, + { + "name": "alert[2]", + "val": null + }, + { + "name": "codename", + "val": [ + "green", + null, + "yellow" + ] + }, + { + "name": "codename[0]", + "val": "green" + }, + { + "name": "codename[1]", + "val": null + }, + { + "name": "codename[2]", + "val": "yellow" + }, + { + "name": "flight", + "val": [ + "AI444", + "AI333", + "AI222" + ] + }, + { + "name": "flight[0]", + "val": "AI444" + }, + { + "name": "flight[1]", + "val": "AI333" + }, + { + "name": "flight[2]", + "val": "AI222" + }, + { + "name": "utc", + "val": [ + "4:44:44", + "3:33:33", + "2:22:22" + ] + }, + { + "name": "utc[0]", + "val": "4:44:44" + }, + { + "name": "utc[1]", + "val": "3:33:33" + }, + { + "name": "utc[2]", + "val": "2:22:22" + } + ] + } +] +---- + +Compare this example with <>. +==== + +[[fn-obj-paths,OBJECT_PATHS()]] +== OBJECT_PATHS(`object` [, `options`] ) + +=== Description + +This function returns the paths to all the fields within an object. +A field in this context may be any attribute or element, nested at any level within the object. + +=== Arguments + +object:: An expression representing an object. + +options:: [Optional] An object containing the following possible parameters: + +composites;; A boolean. +If `true`, every level of every nested field is displayed; if `false`, only the deepest possible nested fields are returned. +Default `true`. + +arraysubscript;; A boolean. +If `true`, array subscripts are returned; if `false`, array subscripts are replaced by `*`. +Default `true`. + +unique;; A boolean. +If `true`, duplicate field names are collapsed to single unique field name; if `false`, all duplicate field names are returned. +Typically used when arrays are expanded and array subscripts are not returned. +Default `true`. + +pattern;; A regular expression used to filter the returned paths. +Used in conjunction with the following setting. + +patternspace;; A string literal with two possible values. +Default `"path"`. ++ +[horizontal] +`"field"`::: The pattern is matched against individual field names. + +`"path"`::: The pattern is matched against composite path names. + +=== Return Value + +An array containing the full path to every possible field within the source object, subject to the specified options. + +The result uses xref:n1ql-language-reference/nestedops.adoc[nested operators] to specify the path to all nested attributes or elements. +If any attribute names within a field path contain special characters, they are escaped using backticks (`{backtick}{backtick}`). + +* If `object` is MISSING, the function returns a MISSING value. +* If `object` is not an object, the function returns a NULL value. +* If `options` is not an object, the function returns a NULL value. + +=== Examples + +[[obj-paths-ex1,OBJECT_PATHS() Example 1]] +.Composite paths +==== +.Query +[source,sqlpp] +---- +WITH input AS ({ + "attribute": {"first-part": 1, "second-part": 2} +}) +SELECT OBJECT_PATHS(input, {"composites": true}) AS composite, + OBJECT_PATHS(input, {"composites": false}) AS non_composite; +---- + +.Results +[source,json] +---- +[ + { + "composite": [ + "attribute", + "attribute.first-part", + "attribute.second-part" + ], + "non_composite": [ + "attribute.first-part", + "attribute.second-part" + ] + } +] +---- +==== + +[[obj-paths-ex2,OBJECT_PATHS() Example 2]] +.Array subscripts and unique field names +==== +.Query +[source,sqlpp] +---- +WITH input AS ({ + "attribute": [ { "name": "elem1"}, {"name": "elem2"}] +}) +SELECT + OBJECT_PATHS(input, {"arraysubscript": true}) + AS subscripts, + OBJECT_PATHS(input, {"arraysubscript": false, "unique": false}) + AS no_subscripts_not_unique, + OBJECT_PATHS(input, {"arraysubscript": false, "unique": true}) + AS no_subscripts_unique; +---- + +.Results +[source,json] +---- +[ + { + "no_subscripts_not_unique": [ + "attribute", + "attribute[*].name", + "attribute[*].name" + ], + "no_subscripts_unique": [ + "attribute", + "attribute[*].name" + ], + "subscripts": [ + "attribute", + "attribute[0].name", + "attribute[1].name" + ] + } +] +---- +==== + +[[obj-paths-ex3,OBJECT_PATHS() Example 3]] +.Pattern matching and pattern space +==== +This example searches for strings beginning with "n" in the given object paths. + +.Query +[source,sqlpp] +---- +WITH input AS ({ + "attribute": {"name": "elem1"} +}) +SELECT + OBJECT_PATHS(input) + AS all_paths, + OBJECT_PATHS(input, {"pattern": "^n", "patternspace": "field"}) + AS field_starts_with_n, + OBJECT_PATHS(input, {"pattern": "^n", "patternspace": "path"}) + AS path_starts_with_n; +---- + +.Results +[source,json] +---- +[ + { + "all_paths": [ + "attribute", + "attribute.name" + ], + "field_starts_with_n": [ + "attribute.name" + ], + "path_starts_with_n": [] + } +] +---- +==== + +[[obj-paths-ex4,OBJECT_PATHS() Example 4]] +.Complex example +==== +include::ROOT:partial$query-context.adoc[tag=example] + +.Query +[source,sqlpp] +---- +SELECT OBJECT_PATHS(hotel, {"composites": false, "arraysubscript": false}) AS paths +FROM hotel +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "paths": [ + "address", + "alias", + "checkin", + "checkout", + "city", + "country", + "description", + "directions", + "email", + "fax", + "free_breakfast", + "free_internet", + "free_parking", + "geo.accuracy", + "geo.lat", + "geo.lon", + "id", + "name", + "pets_ok", + "phone", + "price", + "public_likes", + "reviews[*].author", + "reviews[*].content", + "reviews[*].date", + "reviews[*].ratings[*].Cleanliness", + "reviews[*].ratings[*].Location", + "reviews[*].ratings[*].Overall", + "reviews[*].ratings[*].Rooms", + "reviews[*].ratings[*].Service", + "reviews[*].ratings[*].Value", + "reviews[*].ratings[*].`Business service (e.g., internet access)`", + "reviews[*].ratings[*].`Check in / front desk`", + "state", + "title", + "tollfree", + "type", + "url", + "vacancy" + ] + } +] +---- +==== + +[[fn-obj-put,OBJECT_PUT()]] +== OBJECT_PUT(`object`, `attr_key`, `attr_value`) + +=== Description + +This function adds new or updates existing attributes and values to a given object. + +=== Arguments + +object:: An expression representing an object. + +attr_key:: The name of the attribute to insert or update. + +attr_value:: The value of the attribute. + +=== Return Value + +The updated object. + +* If [.var]`attr_key` is found in the object, it replaces the corresponding attribute value by [.var]`attr_value`. +* If [.var]`attr_value` is MISSING, it deletes the corresponding existing key (if any), like <>. +* If [.var]`attr_key` is MISSING, it returns a MISSING value. +* If [.var]`attr_key` is not an object, it returns a NULL value. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[obj-put-ex,OBJECT_PUT() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT schedule[0] AS original, + OBJECT_PUT(schedule[0], "day", 1) AS output +FROM route +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "original": { + "day": 0, + "flight": "AF198", + "utc": "10:13:00" + }, + "output": { + "day": 1, + "flight": "AF198", + "utc": "10:13:00" + } + } +] +---- +==== + +[[fn-obj-rename,OBJECT_RENAME()]] +== OBJECT_RENAME(`input_obj`, `old_field`, `new_field`) + +=== Description + +Renames the attribute `old_field` to `new_field` in the JSON input object `input_obj`. + +=== Arguments + +input_obj:: Any JSON object, or {sqlpp} expression that can evaluate to a JSON object, representing the search object. + +old_field:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the old (original) attribute name inside the JSON object `input_obj`. + +new_field:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the new attribute name to replace `old_field` inside the JSON object `input_obj`. + +=== Return Value + +The input object with the new attribute name. +Note that if the new attribute name already exists in the input object, the original attribute with that name is replaced. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[obj-rename-ex,OBJECT_RENAME() Example]] +.Changing a field name +==== +.Query +[source,sqlpp] +---- +SELECT t AS original, + OBJECT_RENAME(t, "name", "new_name") AS output +FROM airline AS t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "original": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + }, + "output": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "new_name": "40-Mile Air", + "type": "airline" + } + } +] +---- +==== + +[[fn-obj-remove,OBJECT_REMOVE()]] +== OBJECT_REMOVE(`object`, `attr_key`) + +=== Description + +This function removes the specified attribute and corresponding values from the given object. + +=== Attributes + +object:: An expression representing an object. + +attr_key:: The name of the attribute to remove. + +=== Return Value + +The input object without the removed attribute. + +* If the [.var]`attr_key` is MISSING, it returns a MISSING value. +* If the [.var]`attr_key` is not an object, it returns a NULL value. + +=== Examples + +[[obj-remove-ex1,OBJECT_REMOVE() Example 1]] +==== +include::ROOT:partial$query-context.adoc[tag=example] + +.Query +[source,sqlpp] +---- +SELECT schedule[0] AS original, + OBJECT_REMOVE(schedule[0], "day") AS output +FROM route +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "original": { + "day": 0, + "flight": "AF198", + "utc": "10:13:00" + }, + "output": { + "flight": "AF198", + "utc": "10:13:00" + } + } +] +---- +==== + +[[obj-remove-ex2,OBJECT_REMOVE() Example 2]] +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_REMOVE({"abc": 1, "def": 2, "ghi": 3}, "def"); +---- + +.Results +[source,json] +---- +[ + { + "$1": { + "abc": 1, + "ghi": 3 + } + } +] +---- +==== + +[[fn-obj-replace,OBJECT_REPLACE()]] +== OBJECT_REPLACE(`input_obj`, `old_value`, `new_value`) + +=== Description + +Replaces all occurrences of the value `value_old` to `value_new` in the JSON input object `input_obj`. + +=== Arguments + +input_obj:: Any JSON object, or {sqlpp} expression that can evaluate to a JSON object, representing the search object. + +old_value:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the old (original) value name inside the JSON object `input_obj`. + +new_value:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, representing the new value name to replace `old_value` inside the JSON object `input_obj`. + +=== Return Value + +The JSON object `input_obj` with replaced values. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[obj-replace-ex,OBJECT_REPLACE() Example]] +.Replace any occurrences of "airline" with "airplane" +==== +.Query +[source,sqlpp] +---- +SELECT t AS original, + OBJECT_REPLACE(t, "airline", "airplane") AS output +FROM airline AS t +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "original": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + }, + "output": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airplane" + } + } +] +---- +==== + +[[fn-obj-unwrap,OBJECT_UNWRAP()]] +== OBJECT_UNWRAP(`expression`) + +=== Description + +This function enables you to unwrap an object without knowing the name of the attribute. + +=== Arguments + +expression:: An expression representing an object. + +=== Return Value + +If the argument is an object with exactly one attribute, this function returns the value in the attribute. +If the argument is MISSING, it returns MISSING. +For all other cases, it returns NULL. + +=== Examples + +[[obj-unwrap-ex,OBJECT_UNWRAP() Example]] +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_UNWRAP({"name": "value"}) AS single, + OBJECT_UNWRAP({"name": MISSING}) AS `missing`, + OBJECT_UNWRAP({"name": "value", "name2": "value2"}) AS multiple, + OBJECT_UNWRAP("some-string") AS `string`; +---- + +.Results +[source,json] +---- +[ + { + "missing": null, + "multiple": null, + "single": "value", + "string": null + } +] +---- +==== + +[[fn-obj-values,OBJECT_VALUES()]] +== OBJECT_VALUES(`expression`) + +_Alias_: *OBJECT_OUTER_VALUES(`expression`)* + +=== Description + +This function returns an array, containing the values of each attribute in the input object. +It is particularly useful when iterating over multiple objects in an array, as it collates the values from similarly-named attributes into a single nested array. + +In this case, the function returns a null entry from any object which does not contain the shared attribute name, rather like an OUTER JOIN. +For an illustration, refer to the examples below. + +=== Arguments + +expression:: An expression representing an object. + +=== Return Value + +An array of the values contained within the source object. +The values in the array are sorted by the corresponding attribute names in the source object, in {sqlpp} collation order. + +=== Examples + +[[obj-values-ex1,OBJECT_VALUES() Example 1]] +.Single object +==== +.Query +[source,sqlpp] +---- +SELECT OBJECT_VALUES({"flight": "AI444", "utc": "4:44:44", "codename": "green"}) + AS outer_values; +---- + +.Results +[source,json] +---- +[ + { + "outer_values": [ + "green", + "AI444", + "4:44:44" + ] + } +] +---- +==== + +[[obj-values-ex2,OBJECT_VALUES() Example 2]] +.Iterating over objects in an array +==== +In this example, notice that where the source objects have similarly-named attributes, the values from each of those attributes are collated into a single array in the output. + +.Query +[source,sqlpp] +---- +WITH special_flights AS ([{"flight": "AI444", "utc": "4:44:44", "codename": "green"}, + {"flight": "AI333", "utc": "3:33:33", "alert": "red"}, + {"flight": "AI222", "utc": "2:22:22", "codename": "yellow"}]) +SELECT OBJECT_VALUES(special_flights[*]) AS outer_values; +---- + +.Results +[source,json] +---- +[ + { + "outer_values": [ + [ + null, + "red", + null + ], + [ + "green", + null, + "yellow" + ], + [ + "AI444", + "AI333", + "AI222" + ], + [ + "4:44:44", + "3:33:33", + "2:22:22" + ] + ] + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/offset.adoc b/modules/n1ql/pages/n1ql-language-reference/offset.adoc new file mode 100644 index 000000000..a6d0f280e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/offset.adoc @@ -0,0 +1,85 @@ += OFFSET clause +:description: The OFFSET clause specifies the number of resultset objects to skip in a SELECT query. +:imagesdir: ../../assets/images +:keywords: paginate, pagination +:page-topic-type: reference + +[abstract] +{description} + +== Purpose + +When you want the resultset to skip over the first few resulting objects, use the `OFFSET` clause to specify that number of objects to ignore. + +The `LIMIT` and `OFFSET` clauses are evaluated after the `ORDER BY` clause. + +If a `LIMIT` clause is also present, the `OFFSET` is applied prior to the `LIMIT`; that is, the specified number of objects is omitted from the result set before enforcing a specified `LIMIT`. + +(((pagination))) +You can use the `OFFSET` and `LIMIT` clauses together to [def]_paginate_ the results -- that is, to split the resultset into pages, each containing a specified number of documents, for display purposes. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=offset-clause] +---- + +image::n1ql-language-reference/offset-clause.png["Syntax diagram", align=left] + +== Arguments + +expr:: Integer or an expression that evaluates to an integer which is non-negative. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.List 4 airport cities after skipping the first 200 +==== +[source,sqlpp] +---- +SELECT DISTINCT city +FROM airport +ORDER BY city +LIMIT 4 +OFFSET 200; +---- + +.Results +[source,json] +---- +[ + { + "city": "Brownsville" + }, + { + "city": "Brownwood" + }, + { + "city": "Brunswick" + }, + { + "city": "Bryan" + } +] +---- +==== + +.Paginate the results using OFFSET and LIMIT +==== +The following query uses named parameters and expressions to display the specified page of results, assuming that page numbering starts at zero. + +[source,sqlpp] +---- +include::example$select/limit-expr.n1ql[tags=query] +---- + +Setting the page number to zero, with two results per page, the results are as follows. + +.Result +[source,json] +---- +include::example$select/limit-result.jsonc[] +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/operators.adoc b/modules/n1ql/pages/n1ql-language-reference/operators.adoc new file mode 100644 index 000000000..5c90b0f5f --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/operators.adoc @@ -0,0 +1,77 @@ += Operators Overview +:description: Operators perform a specific operation on the input values or expressions. +:page-topic-type: reference + +[abstract] +{description} + +{sqlpp} provides a full set of operators that you can use within its statements. +Here are the categories of {sqlpp} operators: + +* xref:n1ql-language-reference/arithmetic.adoc[Arithmetic Operators] to perform basic mathematical operations (such as addition, subtraction, multiplication, and divisions) on numbers. +* xref:n1ql-language-reference/collectionops.adoc[Collection Operators] to evaluate expressions on collections or objects. +* xref:n1ql-language-reference/comparisonops.adoc[Comparison Operators] to compare two expressions. +* xref:n1ql-language-reference/conditionalops.adoc[Conditional Operators] to evaluate conditional logic in an expression. +* xref:n1ql-language-reference/constructionops.adoc[Construction Operators] to construct arrays and objects. +* xref:n1ql-language-reference/logicalops.adoc[Logical Operators] to combine operators using Boolean logic. +* xref:n1ql-language-reference/nestedops.adoc[Nested Operators and Expressions] to access nested elements and embedded arrays. +* xref:n1ql-language-reference/sequenceops.adoc[Sequence Operators] to access values in a sequence. +* xref:n1ql-language-reference/stringops.adoc[String Operators] to concatenate two expressions. + +== Operator Precedence + +{sqlpp} supports the use of parentheses to group operators and expressions. +Expressions enclosed in parentheses are evaluated first. + +The following table shows operator precedence level. +An operator at a higher level is evaluated before an operator at a lower level. + +[cols="1,3"] +|=== +| Evaluation Order | Operator + +| 1 +| `CASE` + +| 2 +| `.` (period) + +| 3 +| `[ ]` (left and right bracket) + +| 4 +| `-` (unary) + +| 5 +| `*` (multiply), `/` (divide), `%` (modulo) + +| 6 +| `+`, `-` (binary) + +| 7 +| `IS` + +| 8 +| `IN` + +| 9 +| `BETWEEN` + +| 10 +| `LIKE` + +| 11 +| `<` (less than, `\<=` (less than or equal to, `>` (greater than), and `\=>` (equal to or greater than) + +| 12 +| `=` (equal to) , `==` (equal to), `<>` (less than or greater than), `!=` (not equal to) + +| 13 +| `NOT` + +| 15 +| `AND` + +| 16 +| `OR` +|=== diff --git a/modules/n1ql/pages/n1ql-language-reference/optimizer-hints.adoc b/modules/n1ql/pages/n1ql-language-reference/optimizer-hints.adoc new file mode 100644 index 000000000..a43b4f6a4 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/optimizer-hints.adoc @@ -0,0 +1,429 @@ += Optimizer Hints +:page-topic-type: reference +:imagesdir: ../../assets/images +:description: Optimizer hints enable you to supply directives to the optimizer. +:page-partial: + +[abstract] +{description} + +You can use optimizer hints to request that the xref:n1ql-language-reference/cost-based-optimizer.adoc[optimizer] should consider specific indexes, join methods, join ordering, and so on, when creating the plan for a query. +This may be useful in situations where the optimizer is not able to come up with the preferred plan, due to lack of optimizer statistics, high level of skew in data, data correlations, and so on. + +Generally speaking, you should rely on the optimizer to generate the query plan. + +.Examples on this Page +**** +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=hint-comment] +---- + +image::n1ql-language-reference/hint-comment.png["Syntax diagram: refer to source code listing", align=left] + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=block-hint-comment] +---- + +image::n1ql-language-reference/block-hint-comment.png["Syntax diagram: refer to source code listing", align=left] + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=line-hint-comment] +---- + +image::n1ql-language-reference/line-hint-comment.png["Syntax diagram: refer to source code listing", align=left] + +You can supply hints to the operator within a specially-formatted _hint comment_. +The hint comment may be a block comment or a line comment. +There must be a plus sign `+` immediately after the start of the comment; this is the distinguishing delimiter of the hint comment. + +Note that a line comment includes all text up to the end of the line. +Therefore, if the hint comment is a line comment, the next part of the query must start on the following line. + +[#ex-block-hint] +.Block hint comment +==== +.Query +[source,sqlpp] +---- +SELECT /*+ INDEX(airport def_inventory_airport_city) */ airportname +FROM airport +WHERE city = "San Francisco"; +---- +==== + +[#ex-line-hint] +.Line hint comment +==== +.Equivalent to <> +[source,sqlpp] +---- +SELECT --+ INDEX(airport def_inventory_airport_city) + airportname +FROM airport +WHERE city = "San Francisco"; +---- +==== + +== Placement + +Currently, a hint comment is only supported in the `SELECT` statement. +The hint comment must be located immediately after the `SELECT` keyword. +For details, refer to xref:n1ql-language-reference/selectclause.adoc[SELECT Clause]. + +There can only be one hint comment in a query block. +If there is more than one hint comment, a syntax error is generated. +However, the hint comment may contain one or more hints. + +[#ex-multi-hints] +.Multiple hint comments +==== +.Incorrect query +[source,sqlpp] +---- +SELECT /*+ USE_HASH(r) */ + /*+ INDEX(a def_inventory_airport_city) */ + a.airportname, r.airline +FROM airport a +JOIN route r +ON a.faa = r.sourceairport +WHERE a.city = "San Francisco"; +---- + +This query generates a syntax error, as it contains multiple hint comments. +==== + +== Format + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=hints] +---- + +image::n1ql-language-reference/hints.png["Syntax diagram: refer to source code listing", align=left] + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=simple-hint-sequence] +---- + +image::n1ql-language-reference/simple-hint-sequence.png["Syntax diagram: refer to source code listing", align=left] + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=json-hint-object] +---- + +image::n1ql-language-reference/json-hint-object.png["Syntax diagram: refer to source code listing", align=left] + +Internally, the hint comment may take one of two equivalent formats: + +* The _simple_ syntax is a plain text format, similar to the type of hint comment found in many relational databases. + +* Alternatively, you may supply optimizer hints using _JSON_ syntax. +In this case, the hint comment contains a single top-level hint object. + +You cannot mix the simple syntax and the JSON syntax within the same hint comment; each hint comment must use one syntax or the other exclusively. + +To use multiple hints with the simple syntax, simply specify the hints one after another within the hint comment. +To use multiple hints with the JSON syntax, specify each hint as a property within the top-level hint object. + +[#ex-simple-hint] +.Simple hint +==== +.Query +[source,sqlpp] +---- +SELECT /*+ INDEX(airport def_inventory_airport_city) */ + airportname, faa +FROM airport +WHERE city = "San Francisco"; +---- +==== + +[#ex-json-hint] +.JSON hint +==== +.Equivalent to <> +[source,sqlpp] +---- +SELECT /*+ {"index": {"keyspace": "airport", + "indexes": "def_inventory_airport_city"}} */ + airportname, faa +FROM airport +WHERE city = "San Francisco"; +---- +==== + +[#ex-multi-simple] +.Multiple simple hints +==== +.Query +[source,sqlpp] +---- +SELECT /*+ INDEX(a def_inventory_airport_city) USE_HASH(r) */ + a.airportname, r.airline +FROM airport a +JOIN route r +ON a.faa = r.sourceairport +WHERE a.city = "San Francisco"; +---- +==== + +[#ex-multi-json] +.Multiple JSON hints +==== +.Equivalent to <> +[source,sqlpp] +---- +SELECT /*+ {"index": {"keyspace": "a", + "indexes": "def_inventory_airport_city"}, + "use_hash": {"keyspace": "r"}} */ + a.airportname, r.airline +FROM airport a +JOIN route r +ON a.faa = r.sourceairport +WHERE a.city = "San Francisco"; +---- +==== + +== Legacy Equivalents + +Many optimizer hints have an equivalent legacy syntax using the `USE` clause. +Details of these are given on the pages for individual optimizer hints, and in the pages describing the `USE` clause. +For details, refer to xref:n1ql-language-reference/hints.adoc#use-index-clause[USE INDEX Clause] +and xref:n1ql-language-reference/join.adoc#ansi-join-hints[ANSI JOIN Hints]. + +Note that you cannot use a hint comment and the `USE` clause to specify optimizer hints on the same keyspace. +If you do this, the hint comment and the `USE` clause are marked as erroneous and ignored by the optimizer. + +[#ex-legacy-hint] +.Legacy hint +==== +.Legacy equivalent to <> +[source,sqlpp] +---- +SELECT airportname, faa +FROM airport +USE INDEX (def_inventory_airport_city) +WHERE city = "San Francisco"; +---- +==== + +== Explain Plans + +When optimizer hints are specified for a query, the explain plan reports the status of each hint: that is, whether the hint was followed or not followed by the optimizer in choosing the query plan. +Invalid hints are also reported. +Specific error messages are given for any hint that is not followed, or invalid. + +[#ex-simple-hint-explain] +.Simple hint explain plan +==== +When the optimizer follows a simple hint, the hint is shown in the explain plan. + +.Explain plan for <> +[source,sqlpp] +---- +EXPLAIN SELECT /*+ INDEX(airport def_inventory_airport_city) */ + airportname, faa +FROM airport +WHERE city = "San Francisco"; +---- + +.Result +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "INDEX(airport def_inventory_airport_city)" + ] + }, +// ... + } +] +---- +==== + +[#ex-json-hint-explain] +.JSON hint explain plan +==== +When the optimizer follows a JSON hint, the hint is shown in the explain plan in JSON format. + +.Explain plan for <> +[source,sqlpp] +---- +EXPLAIN SELECT /*+ {"index": {"keyspace": "airport", + "indexes": "def_inventory_airport_city"}} */ + airportname, faa +FROM airport +WHERE city = "San Francisco"; +---- + +.Result +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "hint": "{\"index\":{\"indexes\":[\"def_inventory_airport_city\"],\"keyspace\":\"airport\"}}" + ] + }, +// ... + } +] +---- +==== + +[#ex-multi-simple-explain] +.Multiple hint explain plan +==== +When the optimizer follows multiple hints, all the followed hints are shown in the explain plan. + +.Explain plan for <> +[source,sqlpp] +---- +EXPLAIN SELECT /*+ USE_HASH(r) INDEX(a def_inventory_airport_city) */ + a.airportname, r.airline +FROM airport a +JOIN route r +ON a.faa = r.sourceairport +WHERE a.city = "San Francisco"; +---- + +.Result +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "USE_HASH(r)", + "INDEX(a def_inventory_airport_city)" + ] + }, +// ... + } +] +---- +==== + +[#ex-legacy-hint-explain] +.Legacy hint explain plan +==== +When the optimizer follows a hint specified using the legacy `USE` clause, the hint is likewise shown in the explain plan. + +.Explain plan for <> +[source,sqlpp] +---- +EXPLAIN SELECT airportname, faa +FROM airport +USE INDEX (def_inventory_airport_city) +WHERE city = "San Francisco"; +---- + +.Result +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "INDEX(airport def_inventory_airport_city)" + ] + }, +// ... + } +] +---- +==== + +[#ex-unused-hint-explain] +.Unused hint explain plan +==== +When the optimizer cannot follow a hint, any hints that cannot be followed are shown in the explain plan. + +.Explain plan +[source,sqlpp] +---- +EXPLAIN SELECT /*+ USE_HASH(r) INDEX(a def_inventory_airport_city) */ + a.airportname, r.airline +FROM airport a +JOIN route r +ON a.faa = r.sourceairport +WHERE a.city IS MISSING; +---- + +.Result +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "USE_HASH(r)" + ], + "hints_not_followed": [ + "INDEX(a def_inventory_airport_city): INDEX hint cannot be followed" + ] + }, +// ... + } +] +---- +==== + +[#ex-invalid-hint-explain] +.Invalid hint explain plan +==== +When you specify an invalid hint, any invalid hints are shown in the explain plan. + +.Explain plan +[source,sqlpp] +---- +EXPLAIN SELECT /*+ USE_HASH(r) INDEX_SS(a def_inventory_airport_city) */ + a.airportname, r.airline +FROM airport a +JOIN route r +ON a.faa = r.sourceairport +WHERE a.city = "San Francisco"; +---- + +.Result +[source,json] +---- +[ + { + "optimizer_hints": { + "hints_followed": [ + "USE_HASH(r)" + ], + "invalid_hints": [ + "INDEX_SS(a def_inventory_airport_city): Invalid hint name" + ] + }, +// ... + } +] +---- +==== + +== Further Details + +Refer to the following pages for details of individual optimizer hints: + +* xref:n1ql-language-reference/query-hints.adoc[] apply to an entire query block. +* xref:n1ql-language-reference/keyspace-hints.adoc[] apply to a specific keyspace. + +== Related Links + +* xref:n1ql-language-reference/cost-based-optimizer.adoc[Cost-Based Optimizer] diff --git a/modules/n1ql/pages/n1ql-language-reference/orderby.adoc b/modules/n1ql/pages/n1ql-language-reference/orderby.adoc new file mode 100644 index 000000000..d686849d2 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/orderby.adoc @@ -0,0 +1,141 @@ += ORDER BY clause +:description: The ORDER BY clause sorts the result-set by one or more columns, in ascending or descending order. +:imagesdir: ../../assets/images +:page-topic-type: reference + +[abstract] +{description} + +[#section_Purpose] +== Purpose + +In a SELECT statement, the ORDER BY clause sorts the result-set in ascending or descending order, based on one or more fields or expressions of those fields in the projection. + +[#section_Prerequisites] +== Prerequisites + +For you to select data from a document or keyspace, you must have the [.param]`query_select` privilege on the document or keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +[#section_Syntax] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=order-by-clause] +---- + +image::n1ql-language-reference/order-by-clause.png["Syntax diagram", align=left] + +[[ordering-term,ordering-term]] +=== Ordering Term + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ordering-term] +---- + +image::n1ql-language-reference/ordering-term.png["Syntax diagram", align=left] + +[[collation]] +=== Collation +The collation clause determines the order of the search. + +`ASC`:: The results are ordered in ascending order. + +`DESC`:: The results are ordered in descending order. + +If the collation clause is missing, the default is `ASC`. + +[[nulls-ordering]] +=== Nulls Ordering + +The nulls ordering clause determines how NULL or MISSING values are treated when ordering the results: + +`NULLS FIRST`:: If any results evaluate to NULL or MISSING, those results ordered first. + +`NULLS LAST`:: If any results evaluate to NULL or MISSING, those results are ordered last. + +If the nulls ordering clause is omitted, the default is `NULLS FIRST` for an ascending search with `ASC`, or `NULLS LAST` for a descending search with `DESC`. + +[[arguments]] +== Arguments + +expr:: [Required] The identifier or expression by which to order the query results. +This may be a document field, a new expression, or an alias in the SELECT clause. + +== Return Values + +If no ORDER BY clause is specified, the order in which the result objects are returned is undefined. + +Objects are sorted first by the left-most expression in the list of expressions. +Any items with the same sort value will be sorted with the next expression in the list. +This process repeats until all items are sorted and all expressions in the list are evaluated. + +When a field has a mix of data types, the different JSON types are sorted in the following order, from first to last: + +|=== +| ASC NULLS FIRST | ASC NULLS LAST | DESC NULLS FIRST | DESC NULLS LAST + +| MISSING | FALSE | NULL | BINARY +| NULL | TRUE | MISSING | OBJECT +| FALSE | NUMBER | BINARY | ARRAY +| TRUE | STRING | OBJECT | STRING +| NUMBER | ARRAY | ARRAY | NUMBER +| STRING | OBJECT | STRING | TRUE +| ARRAY | BINARY | NUMBER | FALSE +| OBJECT | MISSING | TRUE | NULL +| BINARY | NULL | FALSE | MISSING +|=== + +[NOTE] +==== +* NULL values include JSON NULL. +* String comparison is done using a raw byte collation of UTF8 encoded strings. +The ascending order is lowercase, then uppercase, then accented letters. +* Arrays are sorted in order of the first element in each array, then the second element in each array, and so on. +In an ascending sort, longer arrays are sorted after shorter arrays, where all the elements are equal as far as the end of the shorter array. +* Objects are first sorted in order of size. +In an ascending sort, larger objects are sorted after shorter objects. +Where objects are the same size, objects are sorted in order of the first key in each object, then the first value in each object, then the second key in each object, then the second value in each object, and so on. +* {sqlpp} always sorts the key-value pairs _within each object_ by key in ascending string order before comparison or ordering. +==== + +== Examples + +. <> +. <> + +[[Ex1]] +.List cities in descending order and then landmarks in ascending order +==== +[source,sqlpp] +---- +include::example$select/order-by.n1ql[] +---- + +.Results: +[source,json] +---- +include::example$select/order-by.jsonc[] +---- +==== + +[[Ex2]] +.List the names of hotels and landmarks resulting from a UNION query +==== +[source,sqlpp] +---- +include::example$select/order-by-union.n1ql[] +---- + +.Results: +[source,json] +---- +include::example$select/order-by-union.jsonc[] +---- +==== + +Note that the `name` field in the first SELECT statement and the `name` field in the second SELECT statement give two different result expressions, so you cannot use the `name` field to order all the results of the UNION query together. +To do this, you must give the `name` fields in the two SELECT statements an identical alias, and order the results by that alias. diff --git a/modules/n1ql/pages/n1ql-language-reference/patternmatchingfun.adoc b/modules/n1ql/pages/n1ql-language-reference/patternmatchingfun.adoc new file mode 100644 index 000000000..015b0f29c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/patternmatchingfun.adoc @@ -0,0 +1,401 @@ += Pattern-Matching Functions +:description: Pattern-matching functions allow you to find regular expression patterns in strings or attributes. +:page-topic-type: reference +:example-caption!: + +{description} +Regular expressions can formally represent various string search patterns using different special characters to indicate wildcards, positional characters, repetition, optional or mandatory sequences of letters, etc. +{sqlpp} functions are available to find matching patterns, find position of matching pattern, or replace a pattern with a new string. + +For more information on all supported REGEX patterns, see https://golang.org/pkg/regexp/syntax[^]. + +NOTE: {sqlpp} supports regular expressions supported by The Go Programming Language version 1.8. + +[[section_regex_contains,REGEXP_CONTAINS()]] +== REGEXP_CONTAINS(`expression`, `pattern`) + +This function has an alias <>. + +=== Arguments + +expression:: String, or any {sqlpp} expression that evaluates to a string. + +pattern:: String representing a supported regular expression. + +=== Return Value + +Returns TRUE if the string value contains any sequence that matches the regular expression pattern. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +.Query +[source,sqlpp] +---- +SELECT name +FROM landmark +WHERE REGEXP_CONTAINS(name, "In+.*") +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "name": "Beijing Inn" + }, + { + "name": "Sportsman Inn" + }, + { + "name": "In-N-Out Burger" + }, + { + "name": "Mel's Drive-In" + }, + { + "name": "Inverness Castle" + } +] +---- +==== + +[[section_regex_like,REGEXP_LIKE()]] +== REGEXP_LIKE(`expression`, `pattern`) + +This function has an alias <>. + +=== Arguments + +expression:: String, or any {sqlpp} expression that evaluates to a string. + +pattern:: String representing a supported regular expression. + +=== Return Value + +Returns TRUE if the string value exactly matches the regular expression pattern. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +.Query +[source,sqlpp] +---- +SELECT name +FROM landmark +WHERE REGEXP_LIKE(name, "In+.*") +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "name": "In-N-Out Burger" + }, + { + "name": "Inverness Castle" + }, + { + "name": "Inverness Museum & Art Gallery" + }, + { + "name": "Inverness Botanic Gardens" + }, + { + "name": "International Petroleum Exchange" + } +] +---- +==== + +[[section_regex_matches,REGEXP_MATCHES()]] +== REGEXP_MATCHES(`expression`, `pattern`) + +// This function has no alias + +=== Arguments + +expression:: String, or any {sqlpp} expression that evaluates to a string. + +pattern:: String representing a supported regular expression. + +=== Return Value + +Returns an array of all substrings matching the expression _pattern_ within the input string _expression_. +Returns an empty array if no match is found. + +=== Examples + +.REGEXP_MATCHES() Example 1 +==== +The following query finds all words beginning with upper or lower case B. + +.Query +[source,sqlpp] +---- +SELECT REGEXP_MATCHES("So, 'twas better Betty Botter bought a bit of better butter", + "\\b[Bb]\\w+"); -- <1> +---- + +<1> The backslash that introduces an escape sequence in the regular expression must itself be escaped by another backslash in the {sqlpp} query. +So `\b` (word boundary) must be entered as `\\b` and `\w` (word character) must be entered as `\\w`. + +.Results +[source,json] +---- +[ + { + "$1": [ + "better", + "Betty", + "Botter", + "bought", + "bit", + "better", + "butter" + ] + } +] +---- +==== + +.REGEXP_MATCHES() Example 2 +==== +The following query finds sequences of two words beginning with upper or lower case B. + +.Query +[source,sqlpp] +---- +SELECT REGEXP_MATCHES("So, 'twas better Betty Botter bought a bit of better butter", + "\\b[Bb]\\w+ \\b[Bb]\\w+"); +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + "better Betty", + "Botter bought", // <1> + "better butter" + ] + } +] +---- + +<1> Note that `Betty Botter` is not found in this example, because `Betty` has already been found by the first match. +==== + +[[section_regex_position,REGEXP_POSITION()]] +== REGEXP_POSITION(`expression`, `pattern`) + +This function has an alias <>. + +=== Arguments + +expression:: String, or any {sqlpp} expression that evaluates to a string. + +pattern:: String representing a supported regular expression. + +=== Return Value + +Returns first position of the occurrence of the regular expression _pattern_ within the input string _expression_. +Returns -1 if no match is found. +Position counting starts from zero. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +The following query finds positions of first occurrence of vowels in each word of the _name_ attribute. + +.Query +[source,sqlpp] +---- +SELECT name, ARRAY REGEXP_POSITION(x, "[aeiou]") FOR x IN TOKENS(name) END +FROM hotel +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + 1, + 1, + 1 + ], + "name": "Medway Youth Hostel" + }, + { + "$1": [ + 2, + 1, + 1 + ], + "name": "The Balmoral Guesthouse" + } +] +---- + +Note that the order of tokens in the second result may be different. +==== + +[[section_regex_replace,REGEXP_REPLACE()]] +== REGEXP_REPLACE(`expression`, `pattern`, `repl` [, `n`]) + +This function has an alias <>. + +=== Arguments + +expression:: String, or any {sqlpp} expression that evaluates to a string. + +pattern:: String representing a supported regular expression. + +repl:: String, or any {sqlpp} expression that evaluates to a string. + +n:: [Optional] The maximum number of times to find and replace the matching pattern. + +=== Return Value + +Returns new string with occurrences of pattern replaced with _repl_. +If _n_ is given, at the most _n_ replacements are performed. +If _n_ is not provided, all matching occurrences are replaced. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.REGEXP_REPLACE() Example 1 +==== +.Query +[source,sqlpp] +---- +SELECT REGEXP_REPLACE("Sql++ is sql for NoSql", "[sS][qQ][lL]", "SQL"), + REGEXP_REPLACE("Winning innings Inn", "[Ii]n+", "Hotel", 6), + REGEXP_REPLACE("Winning innings Inn", "[IiNn]+g", upper("inning"), 2); +---- + +.Results +[source,json] +---- +[ + { + "$1": "SQL++ is SQL for NoSQL", + "$2": "WHotelHotelg HotelHotelgs Hotel", + "$3": "WINNING INNINGs Inn" + } +] +---- +==== + +.REGEXP_REPLACE() Example 2 +==== +In this example, the query retrieves first 4 documents and replaces the pattern of repeating n with emphasized NNNN. + +.Query +[source,sqlpp] +---- +SELECT name, REGEXP_REPLACE(name, "n+", "NNNN") as new_name +FROM airline +LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "name": "40-Mile Air", + "new_name": "40-Mile Air" + }, + { + "name": "Texas Wings", + "new_name": "Texas WiNNNNgs" + }, + { + "name": "Atifly", + "new_name": "Atifly" + }, + { + "name": "Jc royal.britannica", + "new_name": "Jc royal.britaNNNNica" + } +] +---- +==== + +[[section_regex_split,REGEXP_SPLIT()]] +== REGEXP_SPLIT(`expression`, `pattern`) + +// This function has no alias + +=== Arguments + +expression:: String, or any {sqlpp} expression that evaluates to a string. + +pattern:: String representing a supported regular expression. + +=== Return Value + +Returns an array of all the substrings created by splitting the input string _expression_ at each occurrence of the expression _pattern_. +Returns an empty array if no match is found. + +=== Example + +==== +.Query +[source,sqlpp] +---- +SELECT REGEXP_SPLIT("C:\\Program Files\\couchbase\\server\\bin", "[\\\\]") AS Windows, -- <1> +REGEXP_SPLIT("/opt/couchbase/bin", "/") AS Unix; +---- + +<1> The regular expression `[\\\\]` matches the escaped backslash `\\`. + +.Results +[source,json] +---- +[ + { + "Unix": [ + "", // <1> + "opt", + "couchbase", + "bin" + ], + "Windows": [ + "C:", + "Program Files", + "couchbase", + "server", + "bin" + ] + } +] +---- + +<1> The `REGEXP_SPLIT` function returns any zero-length matches that occur at the start of the _expression_ string, except when the split pattern is zero-length. +Otherwise, it returns any zero-length matches immediately after a previous match. +==== + +[[aliases]] +== Aliases + +Some pattern-matching functions have an alias whose name begins with `REGEX_`. + +* `REGEX_CONTAINS()` is an alias for <>. +* `REGEX_LIKE()` is an alias for <>. +* `REGEX_POSITION()` is an alias for <>. +* `REGEX_REPLACE()` is an alias for <>. diff --git a/modules/n1ql/pages/n1ql-language-reference/prepare.adoc b/modules/n1ql/pages/n1ql-language-reference/prepare.adoc new file mode 100644 index 000000000..28b48ee00 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/prepare.adoc @@ -0,0 +1,368 @@ += PREPARE +:description: The PREPARE statement prepares a query for repeated execution. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// TEMP +include::partial$n1ql-language-reference/collapsible-style.adoc[] + +[abstract] +{description} + +[[purpose]] +== Purpose + +Building plans for {sqlpp} requests may be expensive, in particular where a cluster has many indexes. +Sometimes planning may take more time than actually executing a request. + +If you know that a statement text will be executed repeatedly, you can request the {sqlpp} service to prepare the execution plan beforehand, and then request to execute the prepared plan as many times as needed, thereby avoiding the cost of repeated planning. + +== Prerequisites + +[[authorization]] +=== RBAC Privileges + +The user executing the PREPARE statement must have the RBAC privileges of the statement being prepared. +For more details about user roles, refer to xref:server:learn:security/authorization-overview.adoc[Authorization]. + +.RBAC Examples +[%collapsible] +==== +====== +include::ROOT:partial$query-context.adoc[tag=example] + +To execute the following statement, user must have the _Query Select_ privilege on both keyspaces `pass:c[airport]` and `pass:c[landmark]`. + +[source,sqlpp] +---- +PREPARE SELECT * FROM airport +WHERE city = (SELECT RAW city FROM landmark) +---- + +To execute the following statement, user must have the _Query Update_ and _Query Select_ privileges on `pass:c[hotel]`. + +[source,sqlpp] +---- +PREPARE UPDATE hotel +SET city = "San Francisco" WHERE lower(city) = "sanfrancisco" +RETURNING * +---- +====== +==== + +[[query-context]] +=== Query Context + +A prepared statement is created and stored relative to the current _query context_. +You can create multiple prepared statements with the same name, each stored relative to a different query context. +This enables you to run multiple instances of the same application against different datasets. + +To execute a prepared statement, the query context must be the same as it was when the prepared statement was created; otherwise the prepared statement will not be found. + +You must therefore set the required query context, or unset the query context if necessary, before creating the prepared statement. +If you do not set the query context, it defaults to the empty string. + +For further information, refer to xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +[[syntax]] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=prepare] +---- + +image::n1ql-language-reference/prepare.png["Syntax diagram: refer to source code listing", align=left] + +statement:: +The full text of the {sqlpp} statement to prepare. +The {sqlpp} statement may contain parameters. +For more details, refer to <> below. + +=== FORCE + +[Optional] The FORCE keyword forces the query engine to create the prepared statement again, even if a matching prepared statement already exists in the cache. +For more details, refer to <> below. + +The FORCE keyword does _not_ enable you to assign a new prepared statement to an existing name. + +=== FROM / AS Clause + +[Optional] The FROM or AS clause enables you to specify a name for the prepared statement. + +name:: +A local name for the prepared statement. +If you do not specify a local name for the prepared statement, the query engine generates a UUID from the statement text. +For more details, refer to <> below. + + +[[parameters]] +== Parameters + +A prepared statement may contain parameters. +These are replaced by a supplied value when the statement is executed. +Parameters may be _named parameters_ or _positional parameters_. + +Named parameters are specified by name when the prepared statement is executed. +To refer to a named parameter in a statement, use `$` followed by the name of the parameter, e.g. `$city`. +See <>. + +Positional parameters are specified by the position of each supplied parameter when the statement is executed. +To refer to a positional parameter in a statement, use `$` followed by the position of the supplied parameter. +So `$1` refers to the first supplied parameter, `$2` refers to the second supplied parameter, etc. +See <>. + +You may also use `?` to refer to a positional parameter in a statement. +In this case, the order of parameters in the statement must exactly match the order of parameters when the statement is executed. +So the first `?` refers to the first supplied parameter, the second `?` refers to the second supplied parameter, etc. +See <>. + +[[result]] +== Result + +A JSON object is returned that contains the following properties: + +name:: The full name of the prepared statement. +This has the format `[host:port]local-name-or-UUID`, and consists of: ++ +* The host and port of the node where the prepared statement was created, in square brackets, followed by +* The local name that you specified for the prepared statement, or a UUID that was generated from the statement text. + ++ +The host and port can be used when executing to retrieve the prepared statement from the node where it was created. + +operator:: The execution plan of the statement being prepared. + +signature:: The signature of the statement being prepared. + +text:: The full PREPARE statement text. + +encoded_plan:: The full prepared statement in encoded format. +This is included for backward compatibility. + +[[cache]] +== Statement Cache + +Prepared statements are stored in the prepared statement cache until you restart the Couchbase Server. + +In Couchbase Capella, the query engine uses the prepared statement cache to speed up the creation of prepared statements. + +When you create a prepared statement with a local name: + +* The query engine checks whether a prepared statement with that name already exists. + +** If it does not, the prepared statement is created. + +** If it does, the query engine checks whether the text of your {sqlpp} statement matches the {sqlpp} statement associated with the existing prepared statement. + +*** If it does not match, a duplicate name error is generated. + +*** If it matches, the existing prepared statement is returned. +However, if the FORCE keyword is present, the prepared statement is created again. + +When you create an anonymous prepared statement, i.e. a prepared statement without a local name: + +* The query engine generates a UUID from the statement text. + +* The query engine then searches the prepared cache to see if the UUID is already listed. + +** If not found, the statement is created and added to the prepared cache. + +** If found, the existing prepared statement is returned. +However, if the FORCE keyword is present, the prepared statement is created again. + +[NOTE] +When you create an anonymous prepared statement, if there is a named prepared statement in the cache with identical statement text, the named prepared statement is not returned. +The anonymous prepared statement is added to the cache in addition to the named prepared statement. + +[[auto-prepare]] +== Auto-Prepare + +When the _auto-prepare_ feature is active, a prepared statement is created every time you submit a {sqlpp} request, whether you use the PREPARE statement or not. + +The process is similar to creating a prepared statement without a local name: + +* The query engine generates a UUID from the statement text. + +* The query engine then searches the prepared cache to see if the UUID is already listed. + +** If found, the existing prepared statement is returned. + +** If not found, the statement is created and added to the prepared cache. + +The auto-prepare feature is inactive by default. +You can turn the auto-prepare feature on or off using the `auto-prepare` service-level query setting. +For more details, refer to xref:n1ql:n1ql-manage/query-settings.adoc#auto-prepare[]. + +Auto-prepare is disabled for {sqlpp} requests which contain parameters, if they do not use the PREPARE statement. + +[[auto-execute]] +== Auto-Execute + +When the _auto-execute_ feature is active, a prepared statement is executed automatically as soon as it is created. +This saves you from having to make two separate {sqlpp} requests in cases where you want to prepare a statement and execute it immediately. + +When this feature is active, a {sqlpp} request to prepare a statement returns the xref:n1ql:n1ql-intro/queriesandresults.adoc#results[result of the execution step]. +It does not return the full <>, such as the execution plan. +However, the output of the {sqlpp} request does include a `prepared` field, which contains the full name of the prepared statement. +You can use this when you need to execute the prepared statement again. + +The auto-execute feature is inactive by default. +You can turn the auto-execute feature on or off using the `auto_execute` request-level query setting. +For more details, refer to xref:n1ql:n1ql-manage/query-settings.adoc#auto_execute[]. + +The auto-execute feature only works for {sqlpp} requests which actually contain the PREPARE statement. +Prepared statements created by the <> feature are not executed by the auto-execute feature. + +[[propagation]] +== Statement Propagation + +When prepared, new statements are distributed to all query nodes. + +In Couchbase Capella, when a query node is started or restarted, the prepared statement cache is primed from another node. + +If it is not possible to prime the statement cache from another node, you must prepare the statements again before you can execute them. + +[[example]] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-prepare]] +.Prepared statement +==== +.Query +[source,sqlpp] +---- +PREPARE SELECT * FROM route +WHERE airline = "FL"; +---- + +.Result +[source,JSON] +---- +[ + { + "encoded_plan": "H4sIAAAAAAAA/wEAAP//AAAAAAAAAAA=", + "featureControls": 12, + "indexApiVersion": 4, + "indexScanKeyspaces": { + "default:travel-sample.inventory.route": false + }, + "name": "[127.0.0.1:8091]26898aa0-04b2-518c-aa11-2fd13cd377b1", + "namespace": "default", + "operator": { + "#operator": "Authorize", + "privileges": { + "List": [ + { + "Priv": 7, + "Props": 0, + "Target": "default:travel-sample.inventory.route" + } + ] + }, + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "Filter", + "condition": "((`route`.`airline`) = \"FL\")" + }, + { + "#operator": "InitialProject", + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + } + ] + } + } + ] + }, + { + "#operator": "Stream" + } + ] + } + }, + "queryContext": "", + "signature": { + "*": "*" + }, + "text": "PREPARE SELECT * FROM route\nWHERE airline = \"FL\";", + "useCBO": true + } +] +---- +==== + +[[ex-prepare-names]] +.Prepared statement with named parameters +==== +[source,sqlpp] +---- +include::example$utility/prepare-names.n1ql[] +---- +==== + +[[ex-prepare-numbers]] +.Prepared statement with numbered parameters +==== +[source,sqlpp] +---- +include::example$utility/prepare-numbers.n1ql[] +---- +==== + +[[ex-prepare-positions]] +.Prepared statement with positional parameters +==== +[source,sqlpp] +---- +include::example$utility/prepare-positions.n1ql[] +---- +==== + +[[related]] +== Related + +* For information on executing the prepared statement, refer to xref:n1ql-language-reference/execute.adoc[EXECUTE]. + +* For information on using prepared statements with the `cbq` command line shell, refer to xref:n1ql:n1ql-intro/cbq.adoc[]. + +ifdef::flag-devex-rest-api[] +* For information on using prepared statements with the Query REST API (`/query/service` endpoint), refer to xref:n1ql-rest-query:index.adoc[]. +endif::flag-devex-rest-api[] + +* For information on using prepared statements with an SDK, refer to xref:java-sdk:concept-docs:n1ql-query.adoc#prepared-statements-for-query-optimization[Prepared Statements for Query Optimization] and xref:java-sdk:howtos:n1ql-queries-with-sdk.adoc#parameterized-queries[Parameterized Queries]. diff --git a/modules/n1ql/pages/n1ql-language-reference/query-hints.adoc b/modules/n1ql/pages/n1ql-language-reference/query-hints.adoc new file mode 100644 index 000000000..80bff1fb4 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/query-hints.adoc @@ -0,0 +1,125 @@ += Query Block Hints +:page-topic-type: reference +:imagesdir: ../../assets/images +:description: Query block hints are hints that apply to an entire query block. +:cbo-preamble: For the examples in this section, it is assumed that the cost-based optimizer is active, and all optimizer statistics are up-to-date. +:!example-caption: + +[abstract] +{description} + +A query hint is a type of xref:n1ql-language-reference/optimizer-hints.adoc[optimizer hint]. +Currently {sqlpp} supports only one query block hint: ORDERED. + +There are two possible formats for each optimizer hint: simple syntax and JSON syntax. +Note that you cannot mix simple syntax and JSON syntax in the same hint comment. + +== ORDERED + +If present, this hint directs the optimizer to order any joins just as they are ordered in the query. +If not specified, the optimizer determines the optimal join order. + +=== Simple Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=ordered-hint-simple] +---- + +image::n1ql-language-reference/ordered-hint-simple.png["Syntax diagram: refer to source code listing", align=left] + +With the simple syntax, this hint takes no arguments. +You may only use this hint once within the hint comment. + +=== JSON Syntax + +[source,ebnf] +---- +include::partial$grammar/hints.ebnf[tag=ordered-hint-json] +---- + +image::n1ql-language-reference/ordered-hint-json.png["Syntax diagram: refer to source code listing", align=left] + +With the JSON syntax, this hint takes the form of an `ordered` property. +You may only use this property once within the hint comment. +The value of this property must be set to `true`. + +[#ordered-examples,reftext="ORDERED Examples"] +=== Examples + +{cbo-preamble} + +include::ROOT:partial$query-context.adoc[tag=section] + +[#ex-ordered-opt] +.Optimized join ordering +==== +Consider the following query, which does not contain an ordering hint. + +.Query +[source,sqlpp] +---- +include::example$select/ordered-hint.n1ql[tag=none] +---- + +<1> Join the `airport` keyspace to the `route` keyspace. +<2> Join the resulting dataset to the `airline` keyspace. + +If you examine the plan for this query, you can see that with no hint specified, the optimizer has re-ordered the joins. + +image::join-order-optimize.png["Query plan with optimized join order"] + +[discrete] +<1> Join the `airline` keyspace to the `route` keyspace. +<2> Join the resulting dataset to the `airport` keyspace. +==== + +[#ex-ordered-simple] +.ORDERED hint -- simple syntax +==== +This example is equivalent to the one in the <> example, but includes an ordering hint using simple syntax. + +.Query +[source,sqlpp] +---- +include::example$select/ordered-hint.n1ql[tag=simple] +---- + +<1> Join the `airport` keyspace to the `route` keyspace. +<2> Join the resulting dataset to the `airline` keyspace. + +If you examine the plan for this query, you can see that the joins are ordered just as they were written. + +image::join-order-hint.png["Query plan with ORDERED hint"] + +[discrete] +<1> Join the `airport` keyspace to the `route` keyspace. +<2> Join the resulting dataset to the `airline` keyspace. +==== + +[#ex-ordered-json] +.ORDERED hint -- JSON syntax +==== +This example is equivalent to the one in the <> example, but includes an ordering hint using JSON syntax. + +.Query +[source,sqlpp] +---- +include::example$select/ordered-hint.n1ql[tag=json] +---- + +<1> Join the `airport` keyspace to the `route` keyspace. +<2> Join the resulting dataset to the `airline` keyspace. + +If you examine the plan for this query, you can see that the joins are ordered just as they were written, just like the query in the previous example. +==== + +=== Legacy Equivalent + +There is no legacy clause equivalent to this hint. + +== Related Links + +* xref:n1ql-language-reference/cost-based-optimizer.adoc[] +* xref:n1ql-language-reference/optimizer-hints.adoc[] +* xref:n1ql-language-reference/keyspace-hints.adoc[] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/reservedwords.adoc b/modules/n1ql/pages/n1ql-language-reference/reservedwords.adoc new file mode 100644 index 000000000..531547c32 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/reservedwords.adoc @@ -0,0 +1,303 @@ += Reserved Words +:description: {sqlpp} defines an extensive list of keywords that are reserved words. \ +You cannot use these keywords as identifiers unless you escape them. +:page-topic-type: reference + +[abstract] +{description} +All of the {sqlpp} keywords are case insensitive. + +Some of the keywords are not currently implemented but are reserved for future use. + +== Using Reserved Words as Identifiers + +{sqlpp} allows escaped identifiers to overlap with keywords. +To use a reserved word as an identifier, you must escape it by enclosing the reserved word inside backticks ({backtick}{backtick}). +For example, if your JSON document contains a field named `index`, you can use it in your queries by escaping it like this: + +[source,json] +---- +{ + "age": "42", + "index": 27, + "name": "Elvis" +} +---- + +[source,sqlpp] +---- +CREATE INDEX myindex ON default(`index`) USING GSI; +---- + +== {sqlpp} Reserved Words + +The following keywords are reserved and cannot be used as unescaped identifiers: + +[cols=6*] +|=== +| _INDEX_CONDITION +| _INDEX_KEY +| xref:n1ql-language-reference/advise.adoc[ADVISE] +| xref:n1ql-language-reference/selectclause.adoc#all[ALL] +| ALTER +| ANALYZE + +| xref:n1ql-language-reference/logicalops.adoc#logical-op-and[AND] +| xref:n1ql-language-reference/collectionops.adoc#collection-op-any[ANY] +| xref:n1ql-language-reference/collectionops.adoc#array[ARRAY] +| xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS] +| ASC +| AT + +| BEGIN +| BETWEEN +| xref:n1ql-language-reference/datatypes.adoc#datatype-binary[BINARY] +| xref:n1ql-language-reference/datatypes.adoc#datatype-boolean[BOOLEAN] +| BREAK +| BUCKET + +| BUILD +| BY +| CACHE +| CALL +| CASE +| CAST + +| CLUSTER +| COLLATE +| COLLECTION +| COMMIT +| xref:n1ql:n1ql-language-reference/set-transaction.adoc[COMMITTED] +| CONNECT + +| CONTINUE +| CORRELATED +| COVER +| xref:n1ql-language-reference/createindex.adoc[CREATE] +| xref:n1ql-language-reference/window.adoc#window-frame-extent[CURRENT] +| CYCLE + +| DATABASE +| DATASET +| DATASTORE +| DECLARE +| DECREMENT +| DEFAULT + +| xref:n1ql-language-reference/delete.adoc[DELETE] +| DERIVED +| DESC +| DESCRIBE +| xref:n1ql-language-reference/selectclause.adoc#distinct[DISTINCT] +| DO + +| xref:n1ql-language-reference/dropindex.adoc[DROP] +| EACH +| ELEMENT +| ELSE +| END +| ESCAPE + +| xref:n1ql-language-reference/collectionops.adoc#collection-op-every[EVERY] +| xref:n1ql-language-reference/union.adoc[EXCEPT] +| EXCLUDE +| EXECUTE +| xref:n1ql-language-reference/collectionops.adoc#exists[EXISTS] +| xref:n1ql-language-reference/explain.adoc[EXPLAIN] + +| FALSE +| FETCH +| FILTER +| FIRST +| FLATTEN +| FLATTEN_KEYS + +| FLUSH +| xref:n1ql-language-reference/window.adoc#window-frame-extent[FOLLOWING] +| FOR +| FORCE +| xref:n1ql-language-reference/from.adoc[FROM] +| xref:n1ql-language-reference/hints.adoc#index-type[FTS] + +| xref:n1ql-language-reference/createfunction.adoc[FUNCTION] +| GOLANG +| GRANT +| xref:n1ql-language-reference/groupby.adoc[GROUP] +| xref:n1ql-language-reference/window.adoc#window-frame-clause[GROUPS] +| xref:n1ql-language-reference/hints.adoc#index-type[GSI] + +| xref:n1ql-language-reference/join.adoc#use-hash-hint[HASH] +| HAVING +| IF +| IGNORE +| ILIKE +| xref:n1ql-language-reference/collectionops.adoc#collection-op-in[IN] + +| INCLUDE +| INCREMENT +| INDEX +| INFER +| INLINE +| INNER + +| xref:n1ql-language-reference/insert.adoc[INSERT] +| xref:n1ql-language-reference/union.adoc[INTERSECT] +| INTO +| IS +| xref:n1ql:n1ql-language-reference/set-transaction.adoc[ISOLATION] +| xref:n1ql-language-reference/createfunction.adoc[JAVASCRIPT] + +| xref:n1ql-language-reference/join.adoc[JOIN] +| KEY +| KEYS +| KEYSPACE +| KNOWN +| xref:n1ql-language-reference/createfunction.adoc[LANGUAGE] + +| LAST +| LATERAL +| LEFT +| xref:n1ql-language-reference/let.adoc[LET] +| LETTING +| xref:n1ql:n1ql-language-reference/set-transaction.adoc[LEVEL] + +| LIKE +| xref:n1ql-language-reference/limit.adoc[LIMIT] +| LSM +| MAP +| MAPPING +| MATCHED + +| MATERIALIZED +| MAXVALUE +| xref:n1ql-language-reference/merge.adoc[MERGE] +| MINVALUE +| xref:n1ql-language-reference/comparisonops.adoc#null-and-missing[MISSING] +| NAMESPACE + +| xref:n1ql-language-reference/nest.adoc[NEST] +| NEXT +| NEXTVAL +| xref:n1ql-language-reference/join.adoc#use-nl-hint[NL] +| xref:n1ql-language-reference/window.adoc#window-frame-exclusion[NO] +| xref:n1ql-language-reference/logicalops.adoc#logical-op-not[NOT] + +| xref:n1ql-language-reference/windowfun.adoc#fn-window-nth-value[NTH_VALUE] +| xref:n1ql-language-reference/comparisonops.adoc#null-and-missing[NULL] +| xref:n1ql-language-reference/window.adoc#nulls-treatment[NULLS] +| NUMBER +| OBJECT +| xref:n1ql-language-reference/offset.adoc[OFFSET] + +| ON +| OPTION +| xref:n1ql-language-reference/insert.adoc#insert-values[OPTIONS] +| xref:n1ql-language-reference/logicalops.adoc#or-operator[OR] +| xref:n1ql-language-reference/orderby.adoc[ORDER] +| xref:n1ql-language-reference/window.adoc#window-frame-exclusion[OTHERS] + +| OUTER +| xref:n1ql-language-reference/window.adoc[OVER] +| PARSE +| PARTITION +| PASSWORD +| PATH + +| POOL +| xref:n1ql-language-reference/window.adoc#window-frame-extent[PRECEDING] +| PREPARE +| PREV +| PREVIOUS +| PREVVAL + +| PRIMARY +| PRIVATE +| PRIVILEGE +| xref:n1ql-language-reference/join.adoc#use-hash-hint[PROBE] +| PROCEDURE +| PUBLIC + +| xref:n1ql-language-reference/window.adoc#window-frame-clause[RANGE] +| RAW +| READ +| REALM +| RECURSIVE +| REDUCE + +| RENAME +| REPLACE +| xref:n1ql-language-reference/window.adoc#nulls-treatment[RESPECT] +| RESTART +| RESTRICT +| RETURN + +| RETURNING +| REVOKE +| RIGHT +| ROLE +| xref:n1ql:n1ql-language-reference/rollback-transaction.adoc[ROLLBACK] +| xref:n1ql-language-reference/window.adoc#window-frame-extent[ROW] + +| xref:n1ql-language-reference/window.adoc#window-frame-clause[ROWS] +| SATISFIES +| xref:n1ql:n1ql-language-reference/savepoint.adoc[SAVEPOINT] +| SCHEMA +| SCOPE +| xref:n1ql-language-reference/selectclause.adoc[SELECT] + +| SELF +| SEQUENCE +| SET +| SHOW +| SOME +| START + +| STATISTICS +| STRING +| SYSTEM +| THEN +| xref:n1ql-language-reference/window.adoc#window-frame-exclusion[TIES] +| TO + +| xref:n1ql:n1ql-language-reference/begin-transaction.adoc[TRAN] +| xref:n1ql:n1ql-language-reference/begin-transaction.adoc[TRANSACTION] +| TRIGGER +| TRUE +| TRUNCATE +| xref:n1ql-language-reference/window.adoc#window-frame-extent[UNBOUNDED] + +| UNDER +| xref:n1ql-language-reference/union.adoc[UNION] +| UNIQUE +| UNKNOWN +| xref:n1ql-language-reference/unnest.adoc[UNNEST] +| UNSET + +| xref:n1ql-language-reference/update.adoc[UPDATE] +| xref:n1ql-language-reference/upsert.adoc[UPSERT] +| xref:n1ql-language-reference/hints.adoc[USE] +| USER +| USERS +| USING + +| VALIDATE +| VALUE +| VALUED +| VALUES +| VECTOR +| VIA + +| VIEW +| WHEN +| xref:n1ql-language-reference/where.adoc[WHERE] +| WHILE +| WINDOW +| WITH + +| xref:n1ql-language-reference/collectionops.adoc#collection-op-within[WITHIN] +| xref:n1ql:n1ql-language-reference/begin-transaction.adoc[WORK] +| XOR +| +| +| +|=== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/revoke.adoc b/modules/n1ql/pages/n1ql-language-reference/revoke.adoc new file mode 100644 index 000000000..a9f1e978b --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/revoke.adoc @@ -0,0 +1,97 @@ += REVOKE +:description: The REVOKE statement allows revoking of any RBAC roles from specific users. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:clusters:manage-database-users.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:keyspace-ref: xref:n1ql-language-reference/createindex.adoc#keyspace-ref + +[abstract] +{description} + +Roles can be of the following two types: + +simple:: +Roles which apply generically to all keyspaces/resources in the cluster. ++ +For example: `ClusterAdmin` or `BucketAdmin` + +parameterized by a keyspace:: +Roles which are defined for the scope of the specified keyspace only. +The keyspace name is specified after ON. ++ +For example: `pass:c[DataReader ON `travel-sample`]` + +or `pass:c[Query_Select ON `travel-sample`]` + +NOTE: Only Full Administrators can run the REVOKE statement. +For more details about user roles, see {authorization-overview}[]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dcl.ebnf[tag=revoke] +---- + +image::n1ql-language-reference/revoke.png["Syntax diagram: refer to source code listing", align=left] + +role:: +One of the {authorization-overview}[RBAC role names predefined] by Couchbase Capella. ++ +The following roles have short forms that can be used as well: + +* `query_select` → `select` +* `query_insert` → `insert` +* `query_update` → `update` +* `query_delete` → `delete` + +user:: +A user name created by the Couchbase Capella RBAC system. + +[[keyspace-ref,keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of a keyspace. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +== Examples + +.Revoke the role of ClusterAdmin from three people +==== +[source,sqlpp] +---- +REVOKE ClusterAdmin FROM david, michael, robin +---- +==== + +.Revoke the roles of ClusterAdmin and QueryUpdate in the travel-sample keyspace from debby +==== +[source,sqlpp] +---- +REVOKE ClusterAdmin, QueryUpdate + ON `travel-sample` + FROM debby +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/rollback-transaction.adoc b/modules/n1ql/pages/n1ql-language-reference/rollback-transaction.adoc new file mode 100644 index 000000000..2db05ec9c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/rollback-transaction.adoc @@ -0,0 +1,298 @@ += ROLLBACK TRANSACTION +:description: The ROLLBACK TRANSACTION statement enables you to rollback a transaction. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:transactions: xref:n1ql:n1ql-language-reference/transactions.adoc +:preparation: xref:n1ql:n1ql-language-reference/transactions.adoc#preparation + +// Related links +:overview: xref:server:learn:data/transactions.adoc +:begin-transaction: xref:n1ql-language-reference/begin-transaction.adoc +:set-transaction: xref:n1ql-language-reference/set-transaction.adoc +:savepoint: xref:n1ql-language-reference/savepoint.adoc +:commit-transaction: xref:n1ql-language-reference/commit-transaction.adoc +:rollback-transaction: xref:n1ql-language-reference/rollback-transaction.adoc + +[abstract] +{description} + +== Purpose + +The `ROLLBACK TRANSACTION` statement enables you to rollback an ACID transaction. +You can rollback the entire transaction, or rollback to a previous savepoint. +Refer to {transactions}[] for further information. + +This statement may only be used within a transaction. + +ifdef::flag-devex-rest-api[] +include::partial$n1ql-language-reference/transaction-id.adoc[] +endif::flag-devex-rest-api[] + +When you rollback the entire transaction, this statement removes all savepoints within the transaction. + +NOTE: If you are using the cbq shell, and a transaction fails for any reason, you must use the `ROLLBACK TRANSACTION` statement to remove the transaction context and reset the transaction ID. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/tcl.ebnf[tag=rollback-transaction] +---- + +image::n1ql-language-reference/rollback-transaction.png["Syntax diagram: refer to source code listing", align=left] + +The `WORK`, `TRAN`, and `TRANSACTION` keywords are synonyms. +These keywords are optional; you may include one of these keywords, or omit them entirely. + +=== Rollback to a Savepoint + +The `TO SAVEPOINT` clause enables you to rollback to a specified savepoint. +This clause is optional. +If omitted, the entire transaction is rolled back. + +savepointname:: +An identifier specifying a name for the savepoint. + +== Examples + +If you want to try these examples, first refer to {preparation}[Preparation] to set up your environment. + +[[ex-1]] +.Rollback a transaction +==== +// Line highlighting doesn't work with highlight.js. +// Markup for future use [source,n1ql,highlight=47..48;57..58] + +.Transaction +[source,sqlpp,subs=macros] +---- +-- Start the transaction +BEGIN WORK; + +-- Specify transaction settings +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; + +-- Create a booking document +UPSERT INTO `travel-sample`.tenant_agent_00.bookings +VALUES("42641d7a-cde3-4a4d-bfd5-fec321510f70", { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "price": 964.13, + "route": "63986" +}); + +-- Set a savepoint +SAVEPOINT s1; + +-- Update the booking document to include a user +UPDATE `travel-sample`.tenant_agent_00.bookings AS b +SET b.`user` = "0" +WHERE META(b).id = "42641d7a-cde3-4a4d-bfd5-fec321510f70"; + +-- Check the content of the booking and user +SELECT b.*, u.name +FROM `travel-sample`.tenant_agent_00.bookings b +JOIN `travel-sample`.tenant_agent_00.users u +ON b.`user` = META(u).id +WHERE META(b).id = "42641d7a-cde3-4a4d-bfd5-fec321510f70"; + +-- Set a second savepoint +SAVEPOINT s2; + +-- Update the booking documents to change the user +UPDATE `travel-sample`.tenant_agent_00.bookings AS b +SET b.`user` = "1" +WHERE META(b).id = "42641d7a-cde3-4a4d-bfd5-fec321510f70"; + +-- Check the content of the booking and user +SELECT b.*, u.name +FROM `travel-sample`.tenant_agent_00.bookings b +JOIN `travel-sample`.tenant_agent_00.users u +ON b.`user` = META(u).id +WHERE META(b).id = "42641d7a-cde3-4a4d-bfd5-fec321510f70"; + +-- pass:[Roll back the transaction to the second savepoint] +ROLLBACK TRAN TO SAVEPOINT s2; + +-- Check the content of the booking and user again +SELECT b.*, u.name +FROM `travel-sample`.tenant_agent_00.bookings b +JOIN `travel-sample`.tenant_agent_00.users u +ON b.`user` = META(u).id +WHERE META(b).id = "42641d7a-cde3-4a4d-bfd5-fec321510f70"; + +-- pass:[Roll back the entire transaction] +ROLLBACK WORK; +---- + +.Results +[source,json] +---- +[ + { + "_sequence_num": 1, + "_sequence_query": "-- Start the transaction\nBEGIN WORK;", + "_sequence_query_status": "success", + "_sequence_result": [ + { + "txid": "d81d9b4a-b758-4f98-b007-87ba262d3a51" + } + ] + }, + { + "_sequence_num": 2, + "_sequence_query": "\n\n-- Specify transaction settings\nSET TRANSACTION ISOLATION LEVEL READ COMMITTED;", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 3, + "_sequence_query": "\n\n-- Create a booking document\nUPSERT INTO `travel-sample`.tenant_agent_00.bookings\nVALUES(\"42641d7a-cde3-4a4d-bfd5-fec321510f70\", {\n \"date\": \"07/24/2021\",\n \"flight\": \"WN533\",\n \"flighttime\": 7713,\n \"price\": 964.13,\n \"route\": \"63986\"\n});", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 4, + "_sequence_query": "\n\n-- Set a savepoint\nSAVEPOINT s1;", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 5, + "_sequence_query": "\n\n-- Update the booking document to include a user\nUPDATE `travel-sample`.tenant_agent_00.bookings AS b\nSET b.`user` = \"0\"\nWHERE META(b).id = \"42641d7a-cde3-4a4d-bfd5-fec321510f70\";", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 6, + "_sequence_query": "\n\n-- Check the content of the booking and user\nSELECT b.*, u.name\nFROM `travel-sample`.tenant_agent_00.bookings b\nJOIN `travel-sample`.tenant_agent_00.users u\nON b.`user` = META(u).id\nWHERE META(b).id = \"42641d7a-cde3-4a4d-bfd5-fec321510f70\";", + "_sequence_query_status": "success", + "_sequence_result": [ + { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "name": "Keon Hoppe", + "price": 964.13, + "route": "63986", + "user": "0" // <.> + } + ] + }, + { + "_sequence_num": 7, + "_sequence_query": "\n\n-- Set a second savepoint\nSAVEPOINT s2;", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 8, + "_sequence_query": "\n\n-- Update the booking documents to change the user\nUPDATE `travel-sample`.tenant_agent_00.bookings AS b\nSET b.`user` = \"1\"\nWHERE META(b).id = \"42641d7a-cde3-4a4d-bfd5-fec321510f70\";", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 9, + "_sequence_query": "\n\n-- Check the content of the booking and user\nSELECT b.*, u.name\nFROM `travel-sample`.tenant_agent_00.bookings b\nJOIN `travel-sample`.tenant_agent_00.users u\nON b.`user` = META(u).id\nWHERE META(b).id = \"42641d7a-cde3-4a4d-bfd5-fec321510f70\";", + "_sequence_query_status": "success", + "_sequence_result": [ + { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "name": "Rigoberto Bernier", + "price": 964.13, + "route": "63986", + "user": "1" // <.> + } + ] + }, + { + "_sequence_num": 10, + "_sequence_query": "\n\n-- Roll back the transaction to the second savepoint\nROLLBACK TRAN TO SAVEPOINT s2;", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + }, + { + "_sequence_num": 11, + "_sequence_query": "\n\n-- Check the content of the booking and user again\nSELECT b.*, u.name\nFROM `travel-sample`.tenant_agent_00.bookings b\nJOIN `travel-sample`.tenant_agent_00.users u\nON b.`user` = META(u).id\nWHERE META(b).id = \"42641d7a-cde3-4a4d-bfd5-fec321510f70\";", + "_sequence_query_status": "success", + "_sequence_result": [ + { + "date": "07/24/2021", + "flight": "WN533", + "flighttime": 7713, + "name": "Keon Hoppe", + "price": 964.13, + "route": "63986", + "user": "0" // <.> + } + ] + }, + { + "_sequence_num": 12, + "_sequence_query": "\n\n-- Roll back the entire transaction\nROLLBACK WORK;", + "_sequence_query_status": "success", + "_sequence_result": { + "results": [] + } + } +] +---- + +<.> Before setting the second savepoint, the booking document has user `"0"`, name `"Keon Hoppe"`. +<.> After setting the second savepoint and performing an update, the booking document has user `"1"`, name `"Rigoberto Bernier"`. +<.> After rolling back to the second savepoint, the booking document again has user `"0"`, name `"Keon Hoppe"`. +==== + +[[ex-2]] +.Check the result of <> +==== +Check the result of rolling back the transaction. + +.Query +[source,sqlpp] +---- +SELECT b.*, u.name +FROM `travel-sample`.tenant_agent_00.bookings b +JOIN `travel-sample`.tenant_agent_00.users u +ON b.`user` = META(u).id +WHERE META(b).id = "42641d7a-cde3-4a4d-bfd5-fec321510f70"; +---- + +.Results +[source,json] +---- +{ + "results": [] +} +---- + +Notice the booking document no longer exists. +==== + +== Related Links + +* For an overview of Couchbase transactions, refer to {overview}[]. +* To begin a transaction, refer to {begin-transaction}[]. +* To specify transaction settings, refer to {set-transaction}[]. +* To set a savepoint, refer to {savepoint}[]. +* To commit a transaction, refer to {commit-transaction}[]. +* Blog post: https://blog.couchbase.com/transactions-n1ql-couchbase-distributed-nosql/[Couchbase Transactions: Elastic, Scalable, and Distributed^]. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/savepoint.adoc b/modules/n1ql/pages/n1ql-language-reference/savepoint.adoc new file mode 100644 index 000000000..9128bb5bf --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/savepoint.adoc @@ -0,0 +1,80 @@ += SAVEPOINT +:description: The SAVEPOINT statement enables you to set a savepoint within a transaction. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:overview: xref:server:learn:data/transactions.adoc +:transactions: xref:n1ql:n1ql-language-reference/transactions.adoc +:preparation: xref:n1ql:n1ql-language-reference/transactions.adoc#preparation + +// Related links +:begin-transaction: xref:n1ql-language-reference/begin-transaction.adoc +:set-transaction: xref:n1ql-language-reference/set-transaction.adoc +:savepoint: xref:n1ql-language-reference/savepoint.adoc +:commit-transaction: xref:n1ql-language-reference/commit-transaction.adoc +:rollback-transaction: xref:n1ql-language-reference/rollback-transaction.adoc + +[abstract] +{description} + +== Purpose + +The `SAVEPOINT` statement enables you to set a savepoint within an ACID transaction. +Refer to {transactions}[] for further information. + +This statement may only be used within a transaction. + +ifdef::flag-devex-rest-api[] +include::partial$n1ql-language-reference/transaction-id.adoc[] +endif::flag-devex-rest-api[] + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/tcl.ebnf[tag=savepoint] +---- + +image::n1ql-language-reference/savepoint.png["Syntax diagram: refer to source code listing", align=left] + +savepointname:: +An identifier specifying a name for the savepoint. + +If a savepoint with the same name already exists, the existing savepoint is replaced. + +== Example + +If you want to try this example, first refer to {preparation}[Preparation] to set up your environment. + +.Set savepoints +==== +// Line highlighting doesn't work with highlight.js. +// Markup for future use [source,n1ql,highlight=34..36;55..57] + +.Transaction +[source,sqlpp,subs=macros] +---- +include::example$transactions/multiple.n1ql[tags=transaction;savepoint-mark;!begin-mark;!set-mark;!savepoint-plain;!rollback-mark;!commit-mark] +---- + +.Results +[source,json] +---- +include::example$transactions/results.jsonc[tags=!ellipsis] +---- + +<.> Beginning a transaction returns a transaction ID. +<.> Before setting the second savepoint, the booking document has user `"0"`, name `"Keon Hoppe"`. +<.> After setting the second savepoint and performing an update, the booking document has user `"1"`, name `"Rigoberto Bernier"`. +<.> After rolling back to the second savepoint, the booking document again has user `"0"`, name `"Keon Hoppe"`. +==== + +== Related Links + +* For an overview of Couchbase transactions, refer to {overview}[]. +* To begin a transaction, refer to {begin-transaction}[]. +* To specify transaction settings, refer to {set-transaction}[]. +* To rollback a transaction, refer to {rollback-transaction}[]. +* To commit a transaction, refer to {commit-transaction}[]. +* Blog post: https://blog.couchbase.com/transactions-n1ql-couchbase-distributed-nosql/[Couchbase Transactions: Elastic, Scalable, and Distributed^]. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/searchfun.adoc b/modules/n1ql/pages/n1ql-language-reference/searchfun.adoc new file mode 100644 index 000000000..8707b2b6a --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/searchfun.adoc @@ -0,0 +1,691 @@ += Search Functions +:description: Search functions enable you to use Full Text Search (FTS) queries directly within a {sqlpp} query. +:page-topic-type: reference +:example-caption!: +:imagesdir: ../../assets/images +:underscore: _ + +Search functions enable you to use xref:search:search.adoc[Full Text Search (FTS)] queries directly within a {sqlpp} query. + +[float] +=== Prerequisites + +To use any of the search functions, the Search Service must be available on the cluster. +It's recommended that you create a suitable Search index for the searches that you want to run. +For more information, refer to xref:search:create-search-indexes.adoc[]. + +[NOTE] +-- +The examples in this page all assume that demonstration Search indexes have been created, as described in xref:server:fts:fts-demonstration-indexes.adoc[Demonstration Indexes]. +-- + +[float] +=== Authorization + +You do not need credentials for the Search Service to be able to use the search functions in a query. +The role *Data Admin* must be assigned to those who intend to create indexes; and the role *Data Reader* to those who intend to perform searches. +For information on creating users and roles in Capella, see xref:organizations:organization-projects-overview.adoc[]. + +[float] +=== When to Use Search Functions + +The search functions are useful when you need to combine a Full Text Search with the power of a {sqlpp} query; for example, combining joins and natural-language search in the same query. +If your cluster is running Couchbase Server version 7.6.2 and later, you can also use the search functions to use document metadata stored in Extended Attributes (XATTRs) inside a {sqlpp} query. + +If you only need to use the capabilities of a Full Text Search without any {sqlpp} features, consider making use of the Search Service directly, through the user interface, the REST API, or an SDK. + +[[search,SEARCH()]] +== SEARCH(`identifier`, `query`[, `options`]) + +=== Description + +This function enables you to use a Full Text Search to filter a result set, or as a join predicate. +It is only allowed in the xref:n1ql-language-reference/where.adoc[WHERE] clause or the xref:n1ql-language-reference/join.adoc[ON] clause. + +If a query contains a SEARCH function, the Query engine analyzes the entire query, including the search specification, to select the best index to use with this search, taking any index hints into account. +The Query engine then passes the search specification over to the Search engine to perform the search. + +[TIP] +-- +If no suitable Search index can be selected, or no Search index exists, the Query engine falls back on a Primary index or qualified GSI index to produce document keys, and then fetches the documents. +The Search Service then creates a temporary index in memory to perform the search. +This process may be slower than using a suitable Search index. +-- + +If your cluster is running Couchbase Server version 7.6.2 and there is no suitable Search index, but you want to return XATTRs data from your documents in another part of your {sqlpp} query, you must use the xref:metafun.adoc#meta[META function] to select the XATTRs field you want to return. +{sqlpp} cannot return XATTRs data without a specific field name. + +If you do have a Search index available for your query that includes XATTRs data, and you still want to use that data outside of the SEARCH function, you must use the <> to select the XATTRs field. +You must also include the xref:search:search-request-params.adoc#fields[fields property] with the name of the XATTRs field in your Search request. + +NOTE: From Couchbase Server 7.6 and later, when you use the SEARCH function, you do not need to use the xref:search:default-analyzers-reference.adoc#keyword[keyword analyzer] in your Search index to run a non-analytic query. +You also do not need to match the analyzer in a query to the analyzer in the Search index for an analytic query. +For more information about how to set the analyzer for a Search index, see xref:search:create-search-index-ui.adoc#default-analyzer[Configure Global Search Index Settings] or the xref:search:search-index-params.adoc#mapping[Mapping Object]. + +=== Arguments + +identifier:: +[Required] An expression in the form `__keyspaceAlias__[.__path__]`, consisting of the keyspace or keyspace alias in which to search, followed by the path to a field in which to search, using dot notation. ++ +[NOTE] +-- +* The identifier must contain the keyspace or keyspace alias if there is more than one input source in the FROM clause. +If there is only one input source in the FROM clause, and the identifier contains a path, the keyspace or keyspace alias may be omitted. +However, if the path is omitted, the keyspace or keyspace alias is mandatory. + +* When the identifier contains a path, it is used as the default field in the _query_ argument, as long as the _query_ argument is a query string. +If the path is omitted, the default field is set to `{underscore}all`. +If the _query_ argument is a query string which specifies a field, this field takes priority, and the path in the identifier is ignored. +Similarly, if the _query_ argument is a query object, the path is ignored. + +* The path must use Search syntax rather than {sqlpp} syntax; in other words, you cannot specify array locations such as `[*]` or `[3]` in the path. + +* If the keyspace, keyspace alias, or path contains any characters such as `-`, you must surround that part of the identifier with backticks `{backtick}{backtick}`. +-- ++ +The _identifier_ argument cannot be replaced by a {sqlpp} query parameter. + +query:: +[Required] The Full Text Search query. +This may be one of the following: ++ +[cols="1a,4a", options="header"] +|=== +| Type +| Description + +| string +| A query string. +For more information about how to format a query string, refer to xref:search:search-request-params.adoc#query-string-query-syntax[Query String Query]. + +| object +| The `query` object within a Full Text Search request. +For more information about how to format the `query` object, see xref:search:search-request-params.adoc#query-object[Query object]. + +| object +| A complete Full Text Search request, including sort and pagination options, and so on. +For more information about how to format a full search request object, refer to xref:search:search-request-params.adoc[]. + +[NOTE] +==== +When specifying a complete Full Text Search request with the {sqlpp} SEARCH() function, if the value of the `size` parameter is greater than the xref:server:fts:fts-response-object-schema.adoc#request[maximum number of Full Text Search results], the query ignores the `size` parameter and returns all matching results. + +This is different to the behavior of a complete Full Text Search request in the Search Service, where the query returns an error if the value of the `size` parameter is greater than the maximum number of Full Text Search results. +==== +|=== ++ +The _query_ argument may be replaced by a {sqlpp} query parameter, as long as the query parameter resolves to a string or an object. + +options:: +[Optional] A JSON object containing options for the search. +The object may contain the following fields: ++ +[cols="1a,1a,3a", options="header"] +|=== +| Name +| Type +| Description + +| `index` +[Optional] +| string, object +| The `index` field can be a string, containing the name of a Search index in the keyspace. +(This might be a Search index alias, but only if the Search index is in the same keyspace.) +This provides an index hint to the Query engine. +If the Search index does not exist, an error occurs. + +[TIP] +-- +You can also provide an index hint to the Query engine with the xref:n1ql-language-reference/hints.adoc#use-index-clause[USE INDEX clause]. +This takes precedence over a hint provided by the `index` field. +-- + +''' + +The `index` field may also be an object, containing an example of a Search index mapping. +This is treated as an input to the index mapping. +It overrides the default mapping and is used during index selection and filtering. + +The object must either have a default mapping with no type mapping, or a single type mapping with the default mapping disabled. +For more information, refer to xref:search:customize-index.adoc[]. + +| `indexUUID` +[Optional] +| string +| A string, containing the xref:search:search-index-params.adoc#uuid[UUID] of a Search index in the keyspace. +This provides an index hint to the Query engine. +If the Search index cannot be identified, an error occurs. + +You can use the `indexUUID` field alongside the `index` field to help identify a Search index. +The `indexUUID` field and the `index` field must both identify the same Search index. +If they identify different Search indexes, or if either of them does not identify a Search index, an error occurs. + +You can find the UUID of a Search index by viewing the index definition. +Click a Search index name in the Capella UI to open the editor. +Click btn:[Index Definition] to view the index definition. + +| `out` +[Optional] +| string +| A name given to this Full Text Search operation in this keyspace. +You can use this name to refer to this operation using the <> and <> functions. +If this field is omitted, the name of this Full Text Search operation defaults to `"out"`. + +| (other) +[Optional] +| (any) +| Other fields are ignored by the Query engine and are passed on to the Search engine as options. +The values of these options may be replaced with {sqlpp} query parameters, such as `"analyzer": $analyzer`. +|=== + ++ +The _options_ argument cannot be replaced by a {sqlpp} query parameter, but it may contain {sqlpp} query parameters. + +=== Return Value + +A boolean, representing whether the search query is found within the input path. + +This returns `true` if the search query is found within the input path, or `false` otherwise. + +=== Limitations + +The Query service can select a Search index for efficient search in the following cases: + +* If the SEARCH() function is used in a WHERE clause or in an ANSI JOIN. +The SEARCH() function must be on the leftmost (first) JOIN. +It may be on the outer side of a nested-loop JOIN, or either side of a hash JOIN. +RIGHT OUTER JOINs are rewritten as LEFT OUTER JOINs. + +* If the SEARCH() function is evaluated on the `true` condition in positive cases: for example, `SEARCH(_field_, _query_, _options_)`, `SEARCH(_field_, _query_, _options_) = true`, `SEARCH(_field_, _query_, _options_) IN [true, true, true]`, or a condition including one of these with `AND` or `OR`. + +The Query service cannot select a Search index for efficient search in the following cases: + +* If a USE KEYS hint is present; or if the SEARCH() function is used on the inner side of a nested-loop JOIN, a lookup JOIN or lookup NEST, an index JOIN or index NEST, an UNNEST clause, a subquery expression, a subquery result, or a correlated query. + +* If the SEARCH() function is evaluated on the `false` condition, or in negative cases: for example, `NOT SEARCH(_field_, _query_, _options_)`, `SEARCH(_field_, _query_, _options_) = false`, `SEARCH(_field_, _query_, _options_) != false`, `SEARCH(_field_, _query_, _options_) IN [false, true, 1, "a"]`, or in a condition using the relation operators `<`, `{lt}=`, `>`, `>=`, `BETWEEN`, `NOT`, `LIKE`, or `NOT LIKE`. + +In these cases, the Query service must fetch the documents, and the Search service creates a temporary index in memory to perform the search. +This may affect performance. + +If the SEARCH() function is present for a keyspace, no GSI covering scan is possible on that keyspace. +If more than one FTS or GSI index are used in the plan, IntersectScan or Ordered IntersectScan is performed. +To avoid this, use a USE INDEX hint. + +Order pushdown is possible only if query ORDER BY has only <> on the leftmost keyspace. +Offset and Limit pushdown is possible if the query only has a SEARCH() predicate, using a single search index -- no IntersectScan or OrderIntersectScan. +Group aggregates and projection are not pushed. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Search using a query string +==== +The following queries are equivalent: + +.Query +[source,sqlpp] +---- +SELECT META(t1).id +FROM airline AS t1 +WHERE SEARCH(t1.country, "+United +States"); +---- + +.Query +[source,sqlpp] +---- +SELECT META(t1).id +FROM airline AS t1 +WHERE SEARCH(t1, "country:\"United States\""); +---- + +.Results +[source,json] +---- +[ + + { + "id": "airline_10" + }, + { + "id": "airline_10123" + }, + { + "id": "airline_10226" + }, + { + "id": "airline_10748" + }, + // ... +] +---- + +The results are unordered, so they may be returned in a different order each time. +==== + +.Search using a query object +==== +.Query +[source,sqlpp] +---- +SELECT t1.name +FROM hotel AS t1 +WHERE SEARCH(t1, { + "match": "bathrobes", + "field": "reviews.content", + "analyzer": "standard" +}); +---- + +.Results +[source,json] +---- +[ + { + "name": "Typoeth Cottage" + }, + { + "name": "Great Orme Lighthouse" + }, + { + "name": "New Road Guest House (B&B)" + }, + // ... +] +---- + +The results are unordered, so they may be returned in a different order each time. +==== + +.Search using a complete Full Text Search request +==== +.Query +[source,sqlpp] +---- +SELECT t1.name +FROM hotel AS t1 +WHERE SEARCH(t1, { + "explain": false, + "fields": [ + "*" + ], + "highlight": {}, + "query": { + "match": "bathrobes", + "field": "reviews.content", + "analyzer": "standard" + }, + "size" : 5, + "sort": [ + { + "by" : "field", + "field" : "reviews.ratings.Overall", + "mode" : "max", + "missing" : "last" + } + ] +}); +---- + +.Results +[source,json] +---- +[ + { + "name": "Waunifor" + }, + { + "name": "Bistro Prego With Rooms" + }, + { + "name": "Thornehill Broome Beach Campground" + }, + // ... +] +---- + +This query returns 5 results, and the results are ordered, as specified by the search options. +As an alternative, you could limit the number of results and order them using the {sqlpp} xref:n1ql-language-reference/limit.adoc[LIMIT] and xref:n1ql-language-reference/orderby.adoc[ORDER BY] clauses. +==== + +.Search against a Full Text Search index that carries a custom type mapping +==== +.Query +[source,sqlpp] +---- +SELECT META(t1).id +FROM hotel AS t1 +WHERE t1.type = "hotel" AND SEARCH(t1.description, "amazing"); +---- + +.Results +[source,json] +---- +[ + { + "id": "hotel_20422" + }, + { + "id": "hotel_22096" + }, + { + "id": "hotel_25243" + }, + { + "id": "hotel_27741" + } +] +---- + +If the Full Text Search index being queried has its default mapping disabled and has a custom type mapping defined, the query needs to specify the type explicitly. +The above query uses the demonstration index xref:server:fts:fts-demonstration-indexes.adoc#travel-sample-index-hotel-description[travel-sample-index-hotel-description], which has the custom type mapping "hotel". + +For more information about defining custom type mappings within a Search index, refer to xref:search:create-type-mapping.adoc[Create a Type Mapping]. +Note that for {sqlpp} queries, only Search indexes with one type mapping are searchable. +Also the supported type identifiers at the moment are "type_field" and "docid_prefix"; "docid_regexp" isn't supported yet for SEARCH queries via {sqlpp}. +==== + +.Search against a Vector Search index for the closest 2 vectors +==== +NOTE: This example does not use the travel sample data or query context mentioned before, as it requires documents that contain vector data. + +.Query +[source,sqlpp] +---- +SELECT t1.color +FROM rgb AS t1 +WHERE SEARCH(t1, + { + "fields": ["*"], + "knn": [ + { + "k": 2, + "field": "colorvect_dot", + "vector": [ 0.707106781186548, 0, 0.707106781186548 ] + } + ] + } +) +---- + +.Results +---- +[ + { + "color": "magenta / fuchsia" + }, + { + "color": "dark lavender" + } +] +---- +Using a Search index that contains vectors that describe colors, the query returns the color names of the closest `k` vectors to the vector in the `knn` object. + +For more information about Vector Search and the Search Services, see xref:vector-search:vector-search.adoc[]. +==== + +.(Version 7.6.2) Search with XATTRs data and no suitable Search index +==== + +If there is no suitable Search index, but you want to return XATTRs data from your documents in another part of your {sqlpp} query, you must use the xref:metafun.adoc#meta[META function] to select the XATTRs field you want to return. +{sqlpp} cannot return XATTRs data without a specific field name in your `SEARCH` function. + +Add `_$xattrs` with a period (.) to the start of the field name you want to return in the `SEARCH` function. + +NOTE: Documents in the `travel-sample` do not include any XATTRs data. +You can add XATTRs to the `travel-sample` documents yourself to use with these queries. + +.Query +[source,sqlpp] +---- +SELECT META().xattrs.field +FROM `travel-sample` T +WHERE SEARCH(T, "_$xattrs.field:*"); +---- + +.Results +---- +[ + { + "field": "field data" + } +] +---- +==== + +.(Version 7.6.2) Search with XATTRs data and a specific Search index +==== + +If you have a Search index available for your query that includes XATTRs data, and you still want to use that data outside of the SEARCH function, you must use the <> to select the XATTRs field. +You must also include the xref:search:search-request-params.adoc#fields[fields property] with the name of the XATTRs field in your Search request. + +Add `_$xattrs` with a period (.) to the start of the field name you want to return in the `SEARCH_META` and `SEARCH` functions. + +NOTE: Documents in the `travel-sample` do not include any XATTRs data. +You can add XATTRs to the `travel-sample` documents yourself to use with these queries. + +.Query +[source,sqlpp] +---- +SELECT SMETA().fields.`_$xattrs.field` +FROM `travel-sample` T +LET SMETA = SEARCH_META() +WHERE SEARCH(T, + { "query": {"query": "_$xattrs.field:*"}, "fields": ["_$xattrs.field"]}, + {"index": "travel-sample._default.xattrsTest"}); +---- + +.Results +---- +[ + { + "_$xattrs.field": "field data" + } +] +---- +==== + +[[search_meta,SEARCH_META()]] +== SEARCH_META([`identifier`]) + +=== Description + +This function is intended to be used in a query which contains a <> function. +It returns the metadata given by the Search engine for each document found by the <> function. +If there is no <> function in the query, or if a Search index was not used to evaluate the search, the function returns MISSING. + +If your cluster is running Couchbase Server version 7.6.2 or later and you want to return XATTRs data from a Search index in a <> function, you must use the `SEARCH_META()` function to select the XATTRs field you want. + +=== Arguments + +identifier:: +[Optional] An expression in the form `{startsb}__keyspaceAlias__.{endsb}__outname__`, consisting of the keyspace or keyspace alias in which the Full Text Search operation was performed, followed by the outname of the Full Text Search operation, using dot notation. + +[NOTE] +-- +* The identifier must contain the keyspace or keyspace alias if there is more than one input source in the FROM clause. +If there is only one input source in the FROM clause, the keyspace or keyspace alias may be omitted. + +* The identifier must contain the outname if there is more than one <> function in the query. +If there is only one <> function in the query, the identifier may be omitted altogether. + +* The outname is specified by the `out` field within the <> function's _options_ argument. +If an outname was not specified by the <> function, the outname defaults to `"out"`. + +* If the keyspace or keyspace alias contains any characters such as `-`, you must surround that part of the identifier with backticks `{backtick}{backtick}`. +-- + +=== Return Value + +A JSON object containing the metadata returned by the Search engine. +By default, the metadata includes the score and ID of the search result. +It may also include other metadata requested by advanced search options, such as the location of the search terms or an explanation of the search results. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Select search metadata +==== +.Query +[source,sqlpp] +---- +SELECT SEARCH_META() AS meta -- <1> +FROM hotel AS t1 +WHERE SEARCH(t1, { + "query": { + "match": "bathrobes", + "field": "reviews.content", + "analyzer": "standard" + }, + "includeLocations": true +}) -- <2> +LIMIT 3; +---- + +<1> There is only one <> function in this query, so the SEARCH_META() function does not need to specify the outname. +<2> The Full Text Search specifies that locations should be included in the search result metadata. + +.Result +[source,json] +---- +[ + { + "meta": { + "id": "hotel_12068", // <.> + "locations": { // <.> + "reviews.content": { + "bathrobes": [ + { + "array_positions": [ + 8 + ], + "end": 664, + "pos": 122, + "start": 655 + } + ] + } + }, + "score": 0.3471730605306995 // <.> + } + }, + // ... +] +---- + +<.> The id is included in the search result metadata by default. +<.> The location of the search term is included in the search result metadata as requested. +<.> The score is included in the search result metadata by default. +==== + +.Select the search metadata by outname +==== +.Query +[source,sqlpp] +---- +SELECT t1.name, SEARCH_META(s1) AS meta -- <1> +FROM hotel AS t1 +WHERE SEARCH(t1.description, "mountain", {"out": "s1"}) -- <2> +AND SEARCH(t1, { + "query": { + "match": "bathrobes", + "field": "reviews.content", + "analyzer": "standard" + } +}); +---- + +<1> This query contains two <> functions. +The outname indicates which metadata we want. +<2> The outname is set by the _options_ argument in this <> function. +This query only uses one data source, so there is no need to specify the keyspace. + +.Results +[source,json] +---- +[ + { + "name": "Marina del Rey Marriott" + } +] +---- +==== + +[[search_score,SEARCH_SCORE()]] +== SEARCH_SCORE([`identifier`]) + +=== Description + +This function is intended to be used in a query which contains a <> function. +It returns the score given by the Search engine for each document found by the <> function. +If there is no <> function in the query, or if a Search index was not used to evaluate the search, the function returns MISSING. + +This function is the same as <>. + +=== Arguments + +identifier:: +[Optional] An expression in the form `{startsb}__keyspaceAlias__.{endsb}__outname__`, consisting of the keyspace or keyspace alias in which the Full Text Search operation was performed, followed by the outname of the Full Text Search operation, using dot notation. + +[NOTE] +-- +* The identifier must contain the keyspace or keyspace alias if there is more than one input source in the FROM clause. +If there is only one input source in the FROM clause, the keyspace or keyspace alias may be omitted. + +* The identifier must contain the outname if there is more than one <> function in the query. +If there is only one <> function in the query, the identifier may be omitted altogether. + +* The outname is specified by the `out` field within the <> function's _options_ argument. +If an outname was not specified by the <> function, the outname defaults to `"out"`. + +* If the keyspace or keyspace alias contains any characters such as `-`, you must surround that part of the identifier with backticks `{backtick}{backtick}`. +-- + +=== Return Value +A number reflecting the score of the result. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Select the search score +==== +.Query + +[source,sqlpp] +---- +SELECT name, description, SEARCH_SCORE() AS score -- <1> +FROM hotel AS t1 +WHERE SEARCH(t1.description, "mountain") +ORDER BY score DESC +LIMIT 3; +---- + +<1> There is only one <> function in this query, so the SEARCH_SCORE() function does not need to specify the outname. + +.Results +[source,json] +---- +[ + { + "description": "3 Star Hotel next to the Mountain Railway terminus and set in 30 acres of grounds which include Dolbadarn Castle", + "name": "The Royal Victoria Hotel" + }, + { + "description": "370 guest rooms offering both water and mountain view.", + "name": "Marina del Rey Marriott" + }, + { + "description": "This small family run hotel captures the spirit of Mull and is a perfect rural holiday retreat. The mountain and sea blend together to give fantastic, panoramic views from the hotel which is in an elevated position on the shoreline. Panoramic views are also available from the bar and restaurant which serves local produce 7 days a week.", + "name": "The Glenforsa Hotel" + } +] +---- +==== + +== Related Links + +* xref:search:search.adoc[] +* xref:vector-search:vector-search.adoc[] + diff --git a/modules/n1ql/pages/n1ql-language-reference/select-syntax.adoc b/modules/n1ql/pages/n1ql-language-reference/select-syntax.adoc new file mode 100644 index 000000000..d4e426eec --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/select-syntax.adoc @@ -0,0 +1,744 @@ += SELECT Syntax +:description: This page enables you to drill down through the syntax of a SELECT query. +:idprefix: _ +:imagesdir: ../../assets/images +:page-topic-type: reference + +:expression: xref:n1ql-language-reference/index.adoc#N1QL_Expressions +:hints: xref:n1ql-language-reference/optimizer-hints.adoc +:conventions: xref:n1ql-language-reference/conventions.adoc +:number: xref:n1ql-language-reference/literals.adoc#numbers +:identifier: xref:n1ql-language-reference/identifiers.adoc +:alias: {identifier}#identifier-alias + +[abstract] +{description} + +[#select,reftext="select",subs="normal"] +---- +select ::= <> ( <> <> )* <>? <>? <>? +---- + +image::n1ql-language-reference/select.png["Syntax diagram", align=left] + +[#select-term,reftext="select-term",subs="normal"] +---- +select-term ::= <> | '(' <> | {expression}[expression] ) ')' + ( ',' {alias}[alias] 'AS' '(' ( <> ')' +---- + +image::n1ql-language-reference/subquery-expr.png["Syntax diagram", align=left] + +[#from-generic,reftext="from-generic",subs="normal"] +---- +from-generic ::= {expression}[expr] ( 'AS' {alias}[alias] )? +---- + +image::n1ql-language-reference/generic-expr.png["Syntax diagram", align=left] + +[[join-clause,join-clause]] +== JOIN Clause + +[subs="normal"] +---- +join-clause ::= <> | <> | <> +---- + +image::n1ql-language-reference/join-clause.png["Syntax diagram", align=left] + +[[ansi-join-clause,ansi-join-clause]] +=== ANSI JOIN + +[subs="normal"] +---- +ansi-join-clause ::= <>? 'JOIN' <> <> +---- + +image::n1ql-language-reference/ansi-join-clause.png["Syntax diagram", align=left] + +[#ansi-join-type,reftext="ansi-join-type",subs="normal"] +---- +ansi-join-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) | ( 'RIGHT' 'OUTER'? ) +---- + +image::n1ql-language-reference/ansi-join-type.png["Syntax diagram", align=left] + +[#ansi-join-rhs,reftext="ansi-join-rhs",subs="normal"] +---- +ansi-join-rhs ::= <> | <> | <> +---- + +image::n1ql-language-reference/ansi-join-rhs.png["Syntax diagram", align=left] + +[#rhs-keyspace,reftext="rhs-keyspace",subs="normal"] +---- +rhs-keyspace ::= <> ( 'AS'? {alias}[alias] )? <>? +---- + +image::n1ql-language-reference/rhs-keyspace.png["Syntax diagram", align=left] + +[#rhs-subquery,reftext="rhs-subquery",subs="normal"] +---- +rhs-subquery ::= <> 'AS'? {alias}[alias] +---- + +image::n1ql-language-reference/rhs-subquery.png["Syntax diagram", align=left] + +[#rhs-generic,reftext="rhs-generic",subs="normal"] +---- +rhs-generic ::= {expression}[expr] ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/rhs-generic.png["Syntax diagram", align=left] + +[#ansi-join-hints,reftext="ansi-join-hints",subs="normal"] +---- +ansi-join-hints ::= <> | <> | <> +---- + +image::n1ql-language-reference/ansi-join-hints.png["Syntax diagram", align=left] + +[#use-hash-hint,reftext="use-hash-hint",subs="normal"] +---- +use-hash-hint ::= 'USE' <> +---- + +image::n1ql-language-reference/use-hash-hint.png["Syntax diagram", align=left] + +[#use-hash-term,reftext="use-hash-term",subs="normal"] +---- +use-hash-term ::= 'HASH' '(' ( 'BUILD' | 'PROBE' ) ')' +---- + +image::n1ql-language-reference/use-hash-term.png["Syntax diagram", align=left] + +[#use-nl-hint,reftext="use-nl-hint",subs="normal"] +---- +use-nl-hint ::= 'USE' <> +---- + +image::n1ql-language-reference/use-nl-hint.png["Syntax diagram", align=left] + +[#use-nl-term,reftext="use-nl-term",subs="normal"] +---- +use-nl-term ::= 'NL' +---- + +image::n1ql-language-reference/use-nl-term.png["Syntax diagram", align=left] + +[#multiple-hints,reftext="multiple-hints",subs="normal"] +---- +multiple-hints ::= 'USE' ( <> <> ) | ( <> <> ) +---- + +image::n1ql-language-reference/multiple-hints.png["Syntax diagram", align=left] + +[#ansi-hint-terms,reftext="ansi-hint-terms",subs="normal"] +---- +ansi-hint-terms ::= <> | <> +---- + +image::n1ql-language-reference/ansi-hint-terms.png["Syntax diagram", align=left] + +[#other-hint-terms,reftext="other-hint-terms",subs="normal"] +---- +other-hint-terms ::= <> | <> +---- + +image::n1ql-language-reference/other-hint-terms.png["Syntax diagram", align=left] + +[#ansi-join-predicate,reftext="ansi-join-predicate",subs="normal"] +---- +ansi-join-predicate ::= 'ON' {expression}[expr] +---- + +image::n1ql-language-reference/ansi-join-predicate.png["Syntax diagram", align=left] + +[[lookup-join-clause,lookup-join-clause]] +=== Lookup JOIN + +[subs="normal"] +---- +lookup-join-clause ::= <>? 'JOIN' <> <> +---- + +image::n1ql-language-reference/lookup-join-clause.png["Syntax diagram", align=left] + +[#lookup-join-type,reftext="lookup-join-type",subs="normal"] +---- +lookup-join-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +---- + +image::n1ql-language-reference/lookup-join-type.png["Syntax diagram", align=left] + +[#lookup-join-rhs,reftext="lookup-join-rhs",subs="normal"] +---- +lookup-join-rhs ::= <> ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/lookup-join-rhs.png["Syntax diagram", align=left] + +[#lookup-join-predicate,reftext="lookup-join-predicate",subs="normal"] +---- +lookup-join-predicate ::= 'ON' 'PRIMARY'? 'KEYS' {expression}[expr] +---- + +image::n1ql-language-reference/lookup-join-predicate.png["Syntax diagram", align=left] + +[[index-join-clause,index-join-clause]] +=== Index JOIN + +[subs="normal"] +---- +index-join-clause ::= <>? 'JOIN' <> <> +---- + +image::n1ql-language-reference/index-join-clause.png["Syntax diagram", align=left] + +[#index-join-type,reftext="index-join-type",subs="normal"] +---- +index-join-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +---- + +image::n1ql-language-reference/index-join-type.png["Syntax diagram", align=left] + +[#index-join-rhs,reftext="index-join-rhs",subs="normal"] +---- +index-join-rhs ::= <> ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/index-join-rhs.png["Syntax diagram", align=left] + +[#index-join-predicate,reftext="index-join-predicate",subs="normal"] +---- +index-join-predicate ::= 'ON' 'PRIMARY'? 'KEY' {expression}[expr] 'FOR' {alias}[alias] +---- + +image::n1ql-language-reference/index-join-predicate.png["Syntax diagram", align=left] + +[[nest-clause,nest-clause]] +== NEST Clause + +[subs="normal"] +---- +nest-clause ::= <> | <> | <> +---- + +image::n1ql-language-reference/nest-clause.png["Syntax diagram", align=left] + +[[ansi-nest-clause,ansi-nest-clause]] +=== ANSI NEST + +[subs="normal"] +---- +ansi-nest-clause ::= <>? 'NEST' <> <> +---- + +image::n1ql-language-reference/ansi-nest-clause.png["Syntax diagram", align=left] + +[#ansi-nest-type,reftext="ansi-nest-type",subs="normal"] +---- +ansi-nest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +---- + +image::n1ql-language-reference/ansi-nest-type.png["Syntax diagram", align=left] + +[#ansi-nest-rhs,reftext="ansi-nest-rhs",subs="normal"] +---- +ansi-nest-rhs ::= <> ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/ansi-nest-rhs.png["Syntax diagram", align=left] + +[#ansi-nest-predicate,reftext="ansi-nest-predicate",subs="normal"] +---- +ansi-nest-predicate ::= 'ON' {expression}[expr] +---- + +image::n1ql-language-reference/ansi-nest-predicate.png["Syntax diagram", align=left] + +[[lookup-nest-clause,lookup-nest-clause]] +=== Lookup NEST + +[subs="normal"] +---- +lookup-nest-clause ::= <>? 'NEST' <> <> +---- + +image::n1ql-language-reference/lookup-nest-clause.png["Syntax diagram", align=left] + +[#lookup-nest-type,reftext="lookup-nest-type",subs="normal"] +---- +lookup-nest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +---- + +image::n1ql-language-reference/lookup-nest-type.png["Syntax diagram", align=left] + +[#lookup-nest-rhs,reftext="lookup-nest-rhs",subs="normal"] +---- +lookup-nest-rhs ::= <> ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/lookup-nest-rhs.png["Syntax diagram", align=left] + +[#lookup-nest-predicate,reftext="lookup-nest-predicate",subs="normal"] +---- +lookup-nest-predicate ::= 'ON' 'KEYS' {expression}[expr] +---- + +image::n1ql-language-reference/lookup-nest-predicate.png["Syntax diagram", align=left] + +[[index-nest-clause,index-nest-clause]] +=== Index NEST + +[subs="normal"] +---- +index-nest-clause ::= <>? 'NEST' <> <> +---- + +image::n1ql-language-reference/index-nest-clause.png["Syntax diagram", align=left] + +[#index-nest-type,reftext="index-nest-type",subs="normal"] +---- +index-nest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +---- + +image::n1ql-language-reference/index-nest-type.png["Syntax diagram", align=left] + +[#index-nest-rhs,reftext="index-nest-rhs",subs="normal"] +---- +index-nest-rhs ::= <> ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/index-nest-rhs.png["Syntax diagram", align=left] + +[#index-nest-predicate,reftext="index-nest-predicate",subs="normal"] +---- +index-nest-predicate ::= 'ON' 'KEY' {expression}[expr] 'FOR' {alias}[alias] +---- + +image::n1ql-language-reference/index-nest-predicate.png["Syntax diagram", align=left] + +[[unnest-clause,unnest-clause]] +== UNNEST Clause + +[subs="normal"] +---- +unnest-clause ::= <>? ( 'UNNEST' | 'FLATTEN' ) {expression}[expr] ( 'AS'? {alias}[alias] )? +---- + +image::n1ql-language-reference/unnest-clause.png["Syntax diagram", align=left] + +[#unnest-type,reftext="unnest-type",subs="normal"] +---- +unnest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +---- + +image::n1ql-language-reference/unnest-type.png["Syntax diagram", align=left] + +[[comma-separated-join,comma-separated-join]] +== Comma-Separated Join + +[subs="normal"] +---- +comma-separated-join ::= ',' ( <> | <> | <> ) +---- + +image::n1ql-language-reference/comma-separated-join.png["Syntax diagram", align=left] + +[[use-clause,use-clause]] +== USE Clause + +[subs="normal"] +---- +use-clause ::= <> | <> +---- + +image::n1ql-language-reference/use-clause.png["Syntax diagram", align=left] + +[#use-keys-clause,reftext="use-keys-clause",subs="normal"] +---- +use-keys-clause ::= 'USE' <> +---- + +image::n1ql-language-reference/use-keys-clause.png["Syntax diagram", align=left] + +[#use-keys-term,reftext="use-keys-term",subs="normal"] +---- +use-keys-term ::= 'PRIMARY'? 'KEYS' {expression}[expr] +---- + +image::n1ql-language-reference/use-keys-term.png["Syntax diagram", align=left] + +[#use-index-clause,reftext="use-index-clause",subs="normal"] +---- +use-index-clause ::= 'USE' <> +---- + +image::n1ql-language-reference/use-index-clause.png["Syntax diagram", align=left] + +[#use-index-term,reftext="use-index-term",subs="normal"] +---- +use-index-term ::= 'INDEX' '(' <> ( ',' <> )* ')' +---- + +image::n1ql-language-reference/use-index-term.png["Syntax diagram", align=left] + +[#index-ref,reftext="index-ref",subs="normal"] +---- +index-ref ::= <>? <>? +---- + +image::n1ql-language-reference/index-ref.png["Syntax diagram", align=left] + +[#index-name,reftext="index-name",subs="normal"] +---- +index-name ::= {identifier}[identifier] +---- + +image::n1ql-language-reference/index-name.png["Syntax diagram", align=left] + +[#index-type,reftext="index-type",subs="normal"] +---- +index-type ::= 'USING' ( 'GSI' | 'FTS' ) +---- + +image::n1ql-language-reference/index-type.png["Syntax diagram", align=left] + +[[let-clause,let-clause]] +== LET Clause + +[subs="normal"] +---- +let-clause ::= 'LET' {alias}[alias] '=' {expression}[expr] ( ',' {alias}[alias] '=' {expression}[expr] )* +---- + +image::n1ql-language-reference/let-clause.png["Syntax diagram", align=left] + +[[where-clause,where-clause]] +== WHERE Clause + +[subs="normal"] +---- +where-clause ::= 'WHERE' <> +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram", align=left] + +[#cond,reftext="cond",subs="normal"] +---- +cond ::= {expression}[expr] +---- + +image::n1ql-language-reference/cond.png["Syntax diagram", align=left] + +[[group-by-clause,group-by-clause]] +== GROUP BY Clause + +[subs="normal"] +---- +group-by-clause ::= 'GROUP' 'BY' {expression}[expr] ( ',' {expression}[expr] )* <>? <>? | <> +---- + +image::n1ql-language-reference/group-by-clause.png["Syntax diagram", align=left] + +[#letting-clause,reftext="letting-clause",subs="normal"] +---- +letting-clause ::= 'LETTING' {alias}[alias] '=' {expression}[expr] ( ',' {alias}[alias] '=' {expression}[expr] )* +---- + +image::n1ql-language-reference/letting-clause.png["Syntax diagram", align=left] + +[#having-clause,reftext="having-clause",subs="normal"] +---- +having-clause ::= 'HAVING' <> +---- + +image::n1ql-language-reference/having-clause.png["Syntax diagram", align=left] + +[[window-clause,window-clause]] +== WINDOW Clause + +[subs="normal"] +---- +window-clause ::= 'WINDOW' <> ( ',' <> )* +---- + +image::n1ql-language-reference/window-clause.png["Syntax diagram", align=left] + +[#window-declaration,reftext="window-declaration",subs="normal"] +---- +window-declaration ::= <> 'AS' '(' <> ')' +---- + +image::n1ql-language-reference/window-declaration.png["Syntax diagram", align=left] + +[#window-name,reftext="window-name",subs="normal"] +---- +window-name ::= {identifier}[identifier] +---- + +image::n1ql-language-reference/window-name.png["Syntax diagram", align=left] + +[#window-definition,reftext="window-definition",subs="normal"] +---- +window-definition ::= <>? <>? <>? + <>? +---- + +image::n1ql-language-reference/window-definition.png["Syntax diagram", align=left] + +[#window-ref,reftext="window-ref",subs="normal"] +---- +window-ref ::= {identifier}[identifier] +---- + +image::n1ql-language-reference/window-ref.png["Syntax diagram", align=left] + +[#window-partition-clause,reftext="window-partition-clause",subs="normal"] +---- +window-partition-clause ::= 'PARTITION' 'BY' {expression}[expr] ( ',' {expression}[expr] )* +---- + +image::n1ql-language-reference/window-partition-clause.png["Syntax diagram", align=left] + +[#window-order-clause,reftext="window-order-clause",subs="normal"] +---- +window-order-clause ::= 'ORDER' 'BY' <> ( ',' <> )* +---- + +image::n1ql-language-reference/window-order-clause.png["Syntax diagram", align=left] + +[#window-frame-clause,reftext="window-frame-clause",subs="normal"] +---- +window-frame-clause ::= ( 'ROWS' | 'RANGE' | 'GROUPS' ) <> <>? +---- + +image::n1ql-language-reference/window-frame-clause.png["Syntax diagram", align=left] + +[#window-frame-extent,reftext="window-frame-extent",subs="normal"] +---- +window-frame-extent ::= 'UNBOUNDED' 'PRECEDING' | {number}[valexpr] 'PRECEDING' | 'CURRENT' 'ROW' | + 'BETWEEN' ( 'UNBOUNDED' 'PRECEDING' | 'CURRENT' 'ROW' | + {number}[valexpr] ( 'PRECEDING' | 'FOLLOWING' ) ) + 'AND' ( 'UNBOUNDED' 'FOLLOWING' | 'CURRENT' 'ROW' | + {number}[valexpr] ( 'PRECEDING' | 'FOLLOWING' ) ) +---- + +image::n1ql-language-reference/window-frame-extent.png["Syntax diagram", align=left] + +[#window-frame-exclusion,reftext="window-frame-exclusion",subs="normal"] +---- +window-frame-exclusion ::= 'EXCLUDE' ( 'CURRENT' 'ROW' | 'GROUP' | 'TIES' | 'NO' 'OTHERS' ) +---- + +image::n1ql-language-reference/window-frame-exclusion.png["Syntax diagram", align=left] + +[[order-by-clause,order-by-clause]] +== ORDER BY Clause + +[subs="normal"] +---- +order-by-clause ::= 'ORDER' 'BY' <> ( ',' <> )* +---- + +image::n1ql-language-reference/order-by-clause.png["Syntax diagram", align=left] + +[#ordering-term,reftext="ordering-term",subs="normal"] +---- +ordering-term ::= {expression}[expr] ( 'ASC' | 'DESC' )? ( 'NULLS' ( 'FIRST' | 'LAST' ) )? +---- + +image::n1ql-language-reference/ordering-term.png["Syntax diagram", align=left] + +[[limit-clause,limit-clause]] +== LIMIT Clause + +[subs="normal"] +---- +limit-clause ::= 'LIMIT' {expression}[expr] +---- + +image::n1ql-language-reference/limit-clause.png["Syntax diagram", align=left] + +[[offset-clause,offset-clause]] +== OFFSET Clause + +[subs="normal"] +---- +offset-clause ::= 'OFFSET' {expression}[expr] +---- + +image::n1ql-language-reference/offset-clause.png["Syntax diagram", align=left] + +== Related Links + +* {conventions}[Conventions] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/selectclause.adoc b/modules/n1ql/pages/n1ql-language-reference/selectclause.adoc new file mode 100644 index 000000000..bd3f6e033 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/selectclause.adoc @@ -0,0 +1,643 @@ += SELECT Clause +:description: The SELECT clause determines the result set. +:imagesdir: ../../assets/images +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +The `SELECT` clause determines the result set. + +[#section_Purpose] +== Purpose + +In a `SELECT` statement, the `SELECT` clause determines the projection (result set). + +[#section_Prerequisites] +== Prerequisites + +For you to select data from a document or keyspace, you must have the [.param]`query_select` privilege on the document or keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +[#section_Syntax] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=select-clause] +---- + +image::n1ql-language-reference/select-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +hint-comment:: <> icon:caret-down[] +projection:: <> icon:caret-down[] + +[#hint-comment] +=== Optimizer Hints + +In Couchbase Capella, you can supply hints to the optimizer within a specially-formatted hint comment. +For further details, refer to xref:n1ql-language-reference/optimizer-hints.adoc[]. + +[#sec_Arguments] +=== Projection + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=projection] +---- + +image::n1ql-language-reference/projection.png["Syntax diagram", align=left] + +The projection consists of an optional `ALL` or `DISTINCT` <>, followed by one of the following alternatives: + +* One or more <>, separated by commas. +* A single <>, including a <> and an optional <>. + +[[all-distinct]] +==== ALL / DISTINCT + +(Optional; default is ALL.) + +SELECT ALL retrieves all of the data specified and will result in all of the specified columns, including all duplicates. + +SELECT DISTINCT removes duplicate result objects from the query's result set. + +NOTE: The DISTINCT clause is not blocking in nature, since it streams the input and produces the output in parallel, while consuming less memory. + +In general, `SELECT ALL` results in more returned documents than `SELECT DISTINCT` due to [.code]``DISTINCT``'s extra step of removing duplicates. +Since `DISTINCT` is purely run in memory, it executes quickly, making the overhead of removing duplicates more noticeable as your recordset gets larger. +Refer to <>. + +[[result-expr]] +==== Result Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=result-expr] +---- + +image::n1ql-language-reference/result-expr.png["Syntax diagram", align=left] + +[source#path,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=path] +---- + +image::n1ql-language-reference/path.png["Syntax diagram", align=left] + +The result expression may contain one of the following alternatives: + +* A <>, preceded by an optional path. +* A <>, including an optional <>. + +[[raw-element-value]] +==== RAW / ELEMENT / VALUE + +(Optional; RAW and ELEMENT and VALUE are synonyms.) + +When you specify one or more <> in the query projection, each result is wrapped in an object, and an implicit or explicit <> is given for each result expression. +This extra layer might not be desirable, since it requires extra output parsing. + +SELECT RAW reduces the amount of data returned by eliminating the field attribute. +The RAW qualifier specifies that the expression that follows should not be wrapped in an object, and the alias for that expression should be suppressed, as shown in <> and <>. + +The RAW qualifier only enables you to specify a single <>. +You cannot use the RAW qualifier with a <> or with multiple select expressions. + +[[keyspace-name]] +==== Star Expression ({asterisk}) + +The star expression `{asterisk}` enables you to select _all_ the fields from the source specified by the xref:n1ql-language-reference/from.adoc[FROM clause]. + +The star expression may be preceded by a xref:n1ql:n1ql-language-reference/nestedops.adoc[path], to select all the nested fields from within an array. + +[NOTE] +==== +Omitting the keyspace name before a star expression adds the keyspace name to the result set; whereas if you include the keyspace name before a star expression, the keyspace name will not appear in the result set. +Refer to <>. +==== + +[[field-expression]] +==== Select Expression + +The select expression is any expression that evaluates to a field to be included in the query's result set. +At its simplest, this may be the name of a field in the data source, such as `id`, `airline`, or `stops`. +Refer to <>. + +The select expression may include a xref:n1ql:n1ql-language-reference/nestedops.adoc[path], to select a nested field from within an array, such as `schedule[0].day`. +Refer to <>. + +If no field name is specified, the select expression allows you to perform calculations, such as `SELECT 10+20 AS Total;` or any other {sqlpp} expression. +For details with examples, see xref:n1ql-language-reference/index.adoc#N1QL_Expressions[{sqlpp} Expressions]. + +[[alias]] +==== AS Alias + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=alias] +---- + +image::n1ql-language-reference/alias.png["Syntax diagram", align=left] + +A temporary name of a keyspace name or field name to make names more readable or unique. +Refer to <>. + +(((implicit alias))) +If you do not explicitly give a field an alias, it is given an _implicit alias_. + +* For a field, the implicit alias is the same as the name of the field in the input. +* For a nested path, the implicit alias is defined as the last component in the path. +* For any expression which does not refer to a field, the implicit alias is a dollar sign followed by a number, based on the position of the expression in the projection; for example, `$1`, `$2`, and so on. + +An implicit or explicit alias is returned in the result set, unless you suppress it using the <>. + +[#sec_BestPractices] +== Best Practices + +When possible, explicitly list all fields you want in your result set instead of using a star expression `{asterisk}` to select all fields, since the `{asterisk}` requires an extra trip over your network -- one to get the list of field names and one to select the fields. + +[#sec_Examples] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-field]] +.Select fields by name +==== +.Query +[source,sqlpp] +---- +SELECT id, airline, stops FROM route LIMIT 1; +---- + +.Result +[source,json] +---- +[ + { + "airline": "AF", + "id": 10000, + "stops": 0 + } +] +---- +==== + +[[ex-path]] +.Select field with path +==== +.Query +[source,sqlpp] +---- +SELECT schedule[0].day FROM route; +---- + +.Result +[source,json] +---- +[ + { + "day": 0 + } +] +---- +==== + +[[ex-alias]] +.Select field with explicit alias +==== +.Query +[source,sqlpp] +---- +SELECT schedule[0].day AS Weekday FROM route LIMIT 1; +---- + +.Result +[source,json] +---- +[ + { + "Weekday": 0 + } +] +---- +==== + +[[ex-all-distinct]] +.SELECT ALL and SELECT DISTINCT +==== +Note that the queries in this example may take some time to run. + +[cols=2*a] +|=== +| +[[q1]] +.Query 1 +[source,sqlpp] +---- +SELECT ALL city FROM landmark; +---- + +slightly slower +| +[[q2]] +.Query 2 +[source,sqlpp] +---- +SELECT DISTINCT city FROM landmark; +---- + +slightly faster +|=== + +When used on a field such as `city`, which contains non-unique values, `SELECT DISTINCT` reduces the recordset to a small fraction of its original size; and while removing so many of the documents takes time, projecting the remaining small fraction is actually slightly faster than the overhead of removing duplicates. + +[cols=2*a] +|=== +| +[[q3]] +.Query 3 +[source,sqlpp] +---- +SELECT ALL META().id FROM landmark; +---- + +much faster +| +[[q4]] +.Query 4 +[source,sqlpp] +---- +SELECT DISTINCT META().id FROM landmark; +---- + +much slower +|=== + +On the other extreme, when used on a field such as `META().id` which contains only unique values, `SELECT DISTINCT` does not reduce the recordset at all, and the overhead of looking for duplicates is wasted effort. +In this case, `SELECT DISTINCT` takes about twice as long to execute as `SELECT ALL`. +==== + +[[ex-distinct-plan]] +.Query plan using the `DISTINCT` operator +==== +.Query +[source,sqlpp] +---- +EXPLAIN SELECT DISTINCT city FROM landmark; +---- + +.Results +[source,json] +---- +[ + { + "plan": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "PrimaryScan3", + "bucket": "travel-sample", + "index": "def_inventory_landmark_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "bucket": "travel-sample", + "keyspace": "landmark", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "Parallel", + "~child": { + "#operator": "Sequence", + "~children": [ + { + "#operator": "InitialProject", + "distinct": true, + "result_terms": [ + { + "expr": "(`landmark`.`city`)" + } + ] + }, + { + "#operator": "Distinct" // <1> + } + ] + } + }, + { + "#operator": "Distinct" // <1> + } + ] + }, + "text": "SELECT DISTINCT city FROM landmark;" + } +] +---- +<1> Lines using the `DISTINCT` operator +==== + +[[ex-raw-expr]] +.SELECT and SELECT RAW with a simple expression +==== +[cols=2*a] +|=== +| +.Query +[source,sqlpp] +---- +SELECT {"a":1, "b":2}; +---- +| +.Query +[source,sqlpp] +---- +SELECT RAW {"a":1, "b":2}; +---- + +| +.Results +[source,json] +---- +[ + { + "$1": { // <1> + "a": 1, + "b": 2 + } + } +] +---- +| +.Results +[source,json] +---- +[ + { // <2> + "a": 1, + "b": 2 + } +] +---- +|=== + +<1> Added implicit alias +<2> No implicit alias +==== + +[[ex-raw-field]] +.SELECT, SELECT RAW, and SELECT DISTINCT RAW with a field +==== +[cols="5a,5a,5a"] +|=== +| +.Query +[source,sqlpp] +---- +SELECT city +FROM airport +ORDER BY city LIMIT 5; +---- +| +.Query +[source,sqlpp] +---- +SELECT RAW city +FROM airport +ORDER BY city LIMIT 5; +---- +| +.Query +[source,sqlpp] +---- +SELECT DISTINCT RAW city +FROM airport +ORDER BY city LIMIT 5; +---- + +| +.Results +[source,json] +---- +[ + { + "city": "Abbeville" + }, + { + "city": "Aberdeen" + }, + { + "city": "Aberdeen" + }, + { + "city": "Aberdeen" + }, + { + "city": "Abilene" + } +] +---- +| +.Results +[source,json] +---- +[ + "Abbeville", + "Aberdeen", + "Aberdeen", + "Aberdeen", + "Abilene" +] +---- +| +.Results +[source,json] +---- +[ + "Abbeville", + "Aberdeen", + "Abilene", + "Adak Island", + "Addison" +] +---- +|=== +==== + +[[ex1]] +.Select all the fields of 1 document from the `airline` keyspace +==== +.Query +[source,sqlpp] +---- +SELECT * FROM airline LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "airline": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + } + } +] +---- +==== + +[[ex2]] +.Select all the fields of 1 document from the `landmark` keyspace +==== +.Query +[source,sqlpp] +---- +SELECT * FROM landmark LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "landmark": { + "activity": "see", + "address": "Prince Arthur Road, ME4 4UG", + "alt": null, + "city": "Gillingham", + "content": "Adult - £6.99 for an Adult ticket that allows you to come back for further visits within a year (children's and concessionary tickets also available). Museum on military engineering and the history of the British Empire. A quite extensive collection that takes about half a day to see. Of most interest to fans of British and military history or civil engineering. The outside collection of tank mounted bridges etc can be seen for free. There is also an extensive series of themed special event weekends, admission to which is included in the cost of the annual ticket.", + "country": "United Kingdom", + "directions": null, + "email": null, + "geo": { + "accuracy": "RANGE_INTERPOLATED", + "lat": 51.39184, + "lon": 0.53616 + }, + "hours": "Tues - Fri 9.00am to 5.00pm, Sat - Sun 11.30am - 5.00pm", + "id": 10019, + "image": null, + "name": "Royal Engineers Museum", + "phone": "+44 1634 822839", + "price": null, + "state": null, + "title": "Gillingham (Kent)", + "tollfree": null, + "type": "landmark", + "url": "http://www.remuseum.org.uk" + } + } +] +---- +==== + +[[ex-star]] +.Star expressions and select expressions with path +==== +[[q3]] +.Query A +[source,sqlpp] +---- +SELECT * FROM hotel LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "hotel": { // <.> + "address": "Capstone Road, ME7 3JE", + "alias": null, + "checkin": null, +// ... + } + } +] +---- + +<.> As the star expression does not include the keyspace name, the results are wrapped in an extra object, and the keyspace name is added to each result. + +[[q4]] +.Query B +[source,sqlpp] +---- +SELECT hotel.* FROM hotel LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { // <.> + "address": "Capstone Road, ME7 3JE", + "alias": null, + "checkin": null, +// ... + } +] +---- + +<.> As the star expression includes the keyspace name, the keyspace name is not added to the results. + +[[q5]] +.Query C +[source,sqlpp] +---- +SELECT meta().id, email, city, phone, hotel.reviews[0].ratings +FROM hotel LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { // <.> + "city": "Medway", + "email": null, + "id": "hotel_10025", + "phone": "+44 870 770 5964", + "ratings": { + "Cleanliness": 5, + "Location": 4, + "Overall": 4, + "Rooms": 3, + "Service": 5, + "Value": 4 + } + }, +// ... +] +---- + +<.> With a select expression, you may optionally include the keyspace name; in either case, the keyspace name is not added to the results. +==== + +[#sec_RelatedLinks] +== Related Links + +* xref:n1ql-language-reference/from.adoc[FROM clause] +* xref:n1ql-language-reference/hints.adoc[USE clause] +* xref:n1ql-language-reference/let.adoc[LET Clause] +* xref:n1ql-language-reference/where.adoc[WHERE Clause] +* xref:n1ql-language-reference/groupby.adoc[GROUP BY Clause] +* xref:n1ql-language-reference/union.adoc[UNION, INTERSECT, and EXCEPT Clause] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/selectintro.adoc b/modules/n1ql/pages/n1ql-language-reference/selectintro.adoc new file mode 100644 index 000000000..147b7fbb1 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/selectintro.adoc @@ -0,0 +1,804 @@ += SELECT Overview +:imagesdir: ../../assets/images +:page-toclevels: 2 +:keywords: sargable +:description: With the SELECT statement, you can query and manipulate JSON data. \ +You can select, join, project, nest, unnest, group, and sort in a single SELECT statement. +:page-topic-type: reference + +// Cross-references +:query-select: xref:clusters:manage-database-users.adoc#about-database-user-permissions + +// TEMP +include::partial$n1ql-language-reference/collapsible-style.adoc[] + +[abstract] +{description} + +The SELECT statement takes a set of JSON documents from keyspaces as its input, manipulates it and returns a set of JSON documents in the result array. +Since the schema for JSON documents is flexible, JSON documents in the result set have flexible schema as well. + +A simple query in {sqlpp} consists of three parts: + +* SELECT: specifies the projection, which is the part of the document that is to be returned. +* FROM: specifies the keyspaces to work with. +* WHERE: specifies the query criteria (filters or predicates) that the results must satisfy. + +.Examples on this Page +**** +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Prerequisites + +The user executing the SELECT statement must have {query-select}[read] access to all keyspaces referred in the query. +Note that the SELECT statement may refer to one keyspace, multiple keyspaces, or no keyspaces at all. +For more details about user roles, see xref:clusters:manage-database-users.adoc[]. + +.RBAC Examples +[%collapsible] +==== +====== +To execute the following statement, the user does not need any special privileges. + +[source,sqlpp] +---- +SELECT 1 +---- + +To execute the following statement, the user must have {query-select}[read] access to `airline`. + +[source,sqlpp] +---- +SELECT * FROM airline; +---- + +To execute the following statement, the user must have {query-select}[read] access to `route` and `airline`. + +[source,sqlpp] +---- +SELECT * FROM route +JOIN airline +ON KEYS route.airlineid +WHERE route.airlineid IN ["airline_330", "airline_225"] +---- + +To execute the following statement, the user must have {query-select}[read] access to `airport` and `landmark`. + +[source,sqlpp] +---- +SELECT * FROM airport +WHERE city IN (SELECT RAW city FROM landmark); +---- + +To execute the following statement, the user must have {query-select}[read] access to `hotel` and `landmark`. + +[source,sqlpp] +---- +SELECT * FROM hotel WHERE city = "Gillingham" +UNION +SELECT * FROM landmark WHERE city = "Gillingham"; +---- +====== +==== + +[#projection] +== Projection and Data Source + +To query on a keyspace, you must either specify the document keys or use an index on the keyspace. + +The following example uses an index to query the keyspace for airports that are in the America/Anchorage timezone and at an altitude of 2100ft or higher, and returns an array with the airport name and city name for each airport that satisfies the conditions. + +==== +.Query +[source,sqlpp] +---- +include::example$select/query-keyspace-idx.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/query-keyspace-idx.jsonc[] +---- +==== + +The next example queries the keyspace using the document key `"airport_3469"`. + +==== +.Query +[source,sqlpp] +---- +SELECT * FROM airport USE KEYS "airport_3469"; +---- + +.Results +[source,JSON] +---- +[ + { + "airport": { + "airportname": "San Francisco Intl", + "city": "San Francisco", + "country": "United States", + "faa": "SFO", + "geo": { + "alt": 13, + "lat": 37.618972, + "lon": -122.374889 + }, + "icao": "KSFO", + "id": 3469, + "type": "airport", + "tz": "America/Los_Angeles" + } + } +] +---- +==== + +With projections, you retrieve just the fields that you need and not the entire document. +This is especially useful when querying for a large dataset as it results in shorter processing times and better performance. + +In clusters running Couchbase Server 7.6 or later, the projection is returned in the order specified by the query. +In prior versions, the projection was sorted alphabetically. +To revert to this behavior, use the xref:n1ql:n1ql-manage/query-settings.adoc#sort_projection[sort_projection] request-level parameter. + +The SELECT statement provides a variety of data processing capabilities such as <>, <> using JOINs or subqueries, <>, <>, <> using operators, <>, <>, and more. +Follow the links for examples that demonstrate each capability. + +== SELECT Statement Processing + +The SELECT statement queries a keyspace and returns a JSON array that contains zero or more objects. + +The following diagram shows the query execution workflow at a high level and illustrates the interaction with the query, index, and data services. + +.Query Execution Workflow +[plantuml,query-execution,svg] +.... +include::learn:partial$diagrams/query-execution.puml[] +.... + +The SELECT statement is executed as a sequence of steps. +Each step in the process produces result objects that are then used as inputs in the next step until all steps in the process are complete. +While the workflow diagram shows all the possible phases a query goes through before returning a result, the clauses and predicates in a query decide the phases and the number of times that the query goes through. +For example, sort phase can be skipped when there is no ORDER BY clause in the query; scan-fetch-join phase will execute multiple times for correlated subqueries. + +The following diagram shows the possible elements and operations during query execution. + +.Query Execution Phases +[plantuml,query-service,svg] +.... +include::learn:partial$diagrams/query-service.puml[] +.... + +Some phases are done serially while others are done in parallel, as specified by their parent operator. + +The below table summarizes all the Query Phases that might be used in an Execution Plan: + +[cols="1,4"] +|=== +| Query Phase | Description + +| Parse +| Analyzes the query and available access path options for each keyspace in the query to create a query plan and execution infrastructure. + +| Plan +| Selects the access path, determines the Join order, determines the type of Joins, and then creates the infrastructure needed to execute the plan. + +| Scan +| Scans the data from the Index Service. + +| Fetch +| Fetches the data from the Data Service. + +| Join +| Joins the data from the Data Service. + +| Filter +| Filters the result objects by specifying conditions in the WHERE clause. + +| Pre-Aggregate +| Internal set of tools to prepare the Aggregate phase. + +| Aggregate +| Performs aggregating functions and window functions. + +| Sort +| Orders and sorts items in the resultset in the order specified by the ORDER BY clause + +| Offset +| Skips the first _n_ items in the result object as specified by the OFFSET clause. + +| Limit +| Limits the number of results returned using the LIMIT clause. + +| Project +| Receives only the fields needed for final displaying to the user. +|=== + +The possible elements and operations in a query include: + +* Specifying the keyspace that is queried. +* Specifying the document keys or using indexes to access the documents. +* Fetching the data from the data service. +* Filtering the result objects by specifying conditions in the WHERE clause. +* Removing duplicate result objects from the resultset by using the DISTINCT clause. +* Grouping and aggregating the result objects. +* Ordering (sorting) items in the resultset in the order specified by the ORDER BY expression list. +* Skipping the first [.var]`n` items in the result object as specified by the OFFSET clause. +* Limiting the number of results returned using the LIMIT clause. + +== Data Processing Capabilities + +[#filtering] +=== Filtering +You can filter the query results using the WHERE clause. +Consider the following example which queries for all airports in the America/Anchorage timezone that are at an altitude of 2000ft or more. +The WHERE clause specifies the conditions that must be satisfied by the documents to be included in the resultset, and the resultset is returned as an array of airports that satisfy the condition. + +NOTE: The keys in the result object are ordered alphabetically at each level. + +==== +.Query +[source,sqlpp] +---- +SELECT * +FROM airport +WHERE tz = "America/Anchorage" + AND geo.alt >= 2000; +---- + +.Result +[source,JSON] +---- +[ + { + "airport": { + "airportname": "Arctic Village Airport", + "city": "Arctic Village", + "country": "United States", + "faa": "ARC", + "geo": { + "alt": 2092, + "lat": 68.1147, + "lon": -145.579 + }, + "icao": "PARC", + "id": 6729, + "type": "airport", + "tz": "America/Anchorage" + } + }, + { + "airport": { + "airportname": "Anaktuvuk Pass Airport", + "city": "Anaktuvuk Pass", + "country": "United States", + "faa": "AKP", + "geo": { + "alt": 2103, + "lat": 68.1336, + "lon": -151.743 + }, + "icao": "PAKP", + "id": 6712, + "type": "airport", + "tz": "America/Anchorage" + } + } +] +---- +==== + +[#query-across-relationships] +=== Querying Across Relationships +You can use the SELECT statement to query across relationships using the JOIN clause or subqueries. + +==== JOIN Clause +Before delving into examples, take a look at a simplified representation of the data model of the `inventory` scope in the `travel-sample` bucket, which is used in the following examples. +For more details about the data model, see xref:java-sdk:ref:travel-app-data-model.adoc[Travel App Data Model]. + +.Data model of inventory scope, simplified +[plantuml,travel-app-data-model,svg] +.... +@startuml + +left to right direction + +together { + package "Route documents" as route $route { + map "**route_5966**" as route_5966 { + id => 5966 + type => route + airlineid => airline_24 + sourceairport => SEA + } + } +} + +together { + package "Airline documents" as airline $airline { + map "**airline_24**" as airline_24 { + id => 24 + type => airline + callsign => AMERICAN + iata => AA + } + } + + package "Airport documents" as airport $airport { + map "**airport_3577**" as airport_3577 { + id => 3577 + type => airport + faa => SEA + icao => KSEA + } + } + + package "Landmark documents" as landmark $landmark { + map "**landmark_21661**" as landmark_21661 { + id => 21661 + type => landmark + country => France + email => null + } + } +} + +route_5966::airlineid --> airline_24 : Foreign Key ID +airport_3577::faa .. route_5966::sourceairport + +remove $landmark + +@enduml +.... + + +The <> uses a JOIN clause to find the distinct airline details which have routes that start from SFO. +This example JOINS the document from the `route` keyspace with documents from the `airline` keyspace using the KEY "airlineid". + +* Documents from the `route` keyspace are on the left side of the JOIN, and documents from the `airline` keyspace are on the right side of the JOIN. +* The documents from the `route` keyspace (on the left) contain the foreign key "airlineid" of documents from the `airline` keyspace (on the right). + +[[example_1]] +==== +.Query +[source,sqlpp] +---- +SELECT DISTINCT airline.name, airline.callsign, + route.destinationairport, route.stops, route.airline +FROM route + JOIN airline + ON KEYS route.airlineid +WHERE route.sourceairport = "SFO" +LIMIT 2; +---- + +.Results +[source,JSON] +---- +[ + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "AUS", + "name": "JetBlue Airways", + "stops": 0 + }, + { + "airline": "B6", + "callsign": "JETBLUE", + "destinationairport": "BOS", + "name": "JetBlue Airways", + "stops": 0 + } +] +---- +==== + +Let's consider <> which finds the number of distinct airports where AA has routes. +In this example: + +* Documents from the `airline` keyspace are on the left side of the JOIN, and documents from the `route` keyspace are on the right side. +* The WHERE clause predicate `airline.iata = "AA"` is on the left side keyspace `airline`. + +This example illustrates a special kind of JOIN where the documents on the right side of JOIN contain the foreign key reference to the documents on the left side. +Such JOINs are referred to as index JOIN. +For details, see xref:n1ql-language-reference/from.adoc#index-join-clause[Index JOIN Clause]. + +[[example_2]] +==== +Index JOIN requires a special inverse index [.param]`route_airlineid` on the JOIN key `route.airlineid`. +Create this index using the following command: + +[source,sqlpp] +---- +CREATE INDEX route_airlineid ON route(airlineid); +---- + +Now we can execute the following query. + +.Query +[source,sqlpp] +---- +SELECT Count(DISTINCT route.sourceairport) AS distinctairports1 +FROM airline + JOIN route + ON KEY route.airlineid FOR airline +WHERE airline.iata = "AA"; +---- + +.Results +[source,JSON] +---- +[ + { + "distinctairports1": 429 + } +] +---- +==== + +==== Subqueries +A subquery is an expression that is evaluated by executing an inner SELECT query. +Subqueries can be used in most places where you can use an expression such as projections, FROM clauses, and WHERE clauses. + +A subquery is executed once for every input document to the outer statement and it returns an array every time it is evaluated. +See xref:n1ql-language-reference/subqueries.adoc[Subqueries] for more details. + +==== +.Query +[source,sqlpp] +---- +SELECT * +FROM (SELECT t.airportname + FROM (SELECT * + FROM airport t + WHERE country = "United States" + LIMIT 1) AS s1) AS s2; +---- + +.Results +[source,JSON] +---- +[ + { + "s2": { + "airportname": "Barter Island Lrrs" + } + } +] +---- +==== + +[#deep-traversal-nested-docs] +=== Deep Traversal for Nested Documents +When querying a keyspace with nested documents, SELECT provides an easy way to traverse deep nested documents using the dot notation and NEST and UNNEST clauses. + +==== Dot Notation +The following query looks for the schedule, and accesses the flight id for the destination airport "ALG". +Since a given flight has multiple schedules, the attribute `schedule` is an array containing all schedules for the specified flight. +You can access the individual array elements using the array indexes. +For brevity, we’re limiting the number of results in the query to 1. + +==== +.Query +[source,sqlpp] +---- +SELECT t.schedule[0].flight AS flightid +FROM route t +WHERE destinationairport="ALG" +LIMIT 1; +---- + +.Results +[source,JSON] +---- +[ + { + "flightid": "AH631" + } +] +---- +==== + +==== NEST and UNNEST +Note that an array is created with the matching nested documents. +In this example: + +* The `airline` field in the result is an array of the `airline` documents that are matched with the key `route.airlineid`. +* Hence, the projection is accessed as `airline[0]` to pick the first element of the array. + +==== +.Query +[source,sqlpp] +---- +SELECT DISTINCT route.sourceairport, + route.airlineid, + airline[0].callsign +FROM route +NEST airline + ON KEYS route.airlineid +WHERE route.airline = "AA" +LIMIT 4; +---- + +.Results +[source,JSON] +---- +[ + { + "airlineid": "airline_24", + "callsign": "AMERICAN", + "sourceairport": "ABE" + }, + { + "airlineid": "airline_24", + "callsign": "AMERICAN", + "sourceairport": "ABI" + }, + { + "airlineid": "airline_24", + "callsign": "AMERICAN", + "sourceairport": "ABQ" + }, + { + "airlineid": "airline_24", + "callsign": "AMERICAN", + "sourceairport": "ABZ" + } +] +---- +==== + +The following example uses the UNNEST clause to retrieve the author names from the `reviews` object. + +==== +.Query +[source,sqlpp] +---- +SELECT r.author +FROM hotel t +UNNEST t.reviews r +LIMIT 4; +---- + +.Results +[source,JSON] +---- +[ + { + "author": "Ozella Sipes" + }, + { + "author": "Barton Marks" + }, + { + "author": "Blaise O'Connell IV" + }, + { + "author": "Nedra Cronin" + } +] +---- +==== + +[#aggregation] +=== Aggregation +As part of a single SELECT statement, you can also perform aggregation using the SUM, COUNT, AVG, MIN, MAX, or ARRAY_AVG functions. + +The following example counts the total number of flights to SFO: + +==== +.Query +[source,sqlpp] +---- +SELECT count(schedule[*]) AS totalflights +FROM route t +WHERE destinationairport="SFO"; +---- + +.Results +[source,JSON] +---- +[ + { + "totalflights": 250 + } +] +---- +==== + +[#combine-resultsets] +=== Combining Resultsets Using Operators +You can combine the result sets using the UNION or INTERSECT operators. + +Consider the following example which looks for the first schedule for flights to "SFO" and "BOS": + +==== +.Query +[source,sqlpp] +---- +(SELECT t.schedule[0] + FROM route t + WHERE destinationairport = "SFO" + LIMIT 1) +UNION ALL +(SELECT t.schedule[0] + FROM route t + WHERE destinationairport = "BOS" + LIMIT 1); +---- + +.Results +[source,JSON] +---- +[ + { + "$1": { + "day": 0, + "flight": "AI339", + "utc": "23:05:00" + } + }, + { + "$1": { + "day": 0, + "flight": "AM982", + "utc": "09:11:00" + } + } +] +---- +==== + +[#group-sort-limit] +=== Grouping, Sorting, and Limiting Results +You can perform further processing on the data in your result set before the final projection is generated. +You can group data using the GROUP BY clause, sort data using the ORDER BY clause, and you can limit the number of results included in the result set using the LIMIT clause. + +The following example looks for the number of airports at an altitude of 5000ft or higher and groups the results by country and timezone. +It then sorts the results by country names and timezones (ascending order by default). + +==== +.Query +[source,sqlpp] +---- +SELECT COUNT(*) AS count, + t.country AS country, + t.tz AS timezone +FROM airport t +WHERE geo.alt >= 5000 +GROUP BY t.country, t.tz +ORDER BY t.country, t.tz; +---- + +.Results +[source,JSON] +---- +[ + { + "count": 2, + "country": "France", + "timezone": "Europe/Paris" + }, + { + "count": 57, + "country": "United States", + "timezone": "America/Denver" + }, + { + "count": 7, + "country": "United States", + "timezone": "America/Los_Angeles" + }, + { + "count": 4, + "country": "United States", + "timezone": "America/Phoenix" + }, + { + "count": 1, + "country": "United States", + "timezone": "Pacific/Honolulu" + } +] +---- +==== + +[[index-selection]] +=== Index Selection + +The optimizer attempts to select an appropriate secondary index for a query based on the filters in the WHERE clause. +If it cannot select a secondary query, the query service falls back on the primary index for the keyspace. + +By default, secondary indexes don't index a document if the leading index key is MISSING in the document. +This means that when a query selects a field which is MISSING in some documents, the optimizer will not be able to choose a secondary index which uses that field as a leading key. +There are two ways to resolve this: + +* In the query, use a WHERE clause to filter out any documents where the required field is MISSING. +The minimum filter you can use to do this is `IS NOT MISSING`. +This is usually only necessary in queries which do not otherwise have a WHERE clause; for example, some GROUP BY and aggregate queries. + +* In the index definition, use the `INCLUDE MISSING` modifier in the leading index key, to index documents where the specified key is missing. +For more information, see xref:n1ql:n1ql-language-reference/createindex.adoc#include-missing[INCLUDE MISSING Clause]. + +(((sargable))) +A query is said to be _sargable_ if the optimizer is able to select an index to speed up the execution of the query. + +[#ex-missing] +.Field with MISSING values -- cannot choose the secondary index +==== +This example uses an index `idx_airport_missing` that is defined by following statement. + +.Index +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-missing.n1ql[] +---- + +.Query +[source,sqlpp] +---- +include::example$n1ql-language-reference/explain-idx-missing.n1ql[] +---- + +The query selects the `district` field, which is MISSING for many documents in the `airport` keyspace. + +.Result +[source,json] +---- +include::example$n1ql-language-reference/explain-idx-missing.jsonc[tags=include;ellipsis] +---- + +<.> Therefore the optimizer falls back on the `def_inventory_airport_primary` index. +==== + +[#ex-filter] +.Filter out MISSING values -- correct secondary index is chosen +==== +[source,sqlpp] +---- +include::example$n1ql-language-reference/explain-idx-filter.n1ql[] +---- + +The WHERE clause filters out documents where `district` is not MISSING. + +[source,json] +---- +include::example$n1ql-language-reference/explain-idx-filter.jsonc[tags=include;ellipsis] +---- + +<.> The optimizer correctly chooses the `idx_airport_missing` index. +==== + +[#ex-include] +.Index includes MISSING values -- correct secondary index is chosen +==== +This example uses an index `idx_airport_include` that is defined by following statement. + +.Index +[source,sqlpp] +---- +include::example$n1ql-language-reference/create-idx-include.n1ql[] +---- + +.Query +[source,sqlpp] +---- +include::example$n1ql-language-reference/explain-idx-missing.n1ql[] +---- + +As in <>, the query selects the `district` field, which is MISSING for many documents in the `airport` keyspace. + +.Result +[source,json] +---- +include::example$n1ql-language-reference/explain-idx-include.jsonc[tags=include;ellipsis] +---- + +<.> In this case, since the lead key in the index includes MISSING values, the optimizer correctly chooses the `idx_airport_include` index. +==== + +For further examples, refer to xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[Group By and Aggregate Performance]. diff --git a/modules/n1ql/pages/n1ql-language-reference/sequenceops.adoc b/modules/n1ql/pages/n1ql-language-reference/sequenceops.adoc new file mode 100644 index 000000000..7fbfc8dcc --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/sequenceops.adoc @@ -0,0 +1,427 @@ += Sequence Operators +:page-topic-type: reference +:page-partial: +:imagesdir: ../../assets/images +:description: Sequence operators enable you to return a value from a sequence. + +// Cross-references +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:query-context: xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context +:identifiers: xref:n1ql-language-reference/identifiers.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Sequences + +// tag::overview[] +A sequence is a construct that returns a sequence of integer values, one at a time, rather like a counter. +Each time you request the next value for a sequence, an increment is added to the previous value, and the resulting value is returned. +This is useful for generating values such as sequential ID numbers, where you need the Query service to keep track of the current value from one query to the next. +// end::overview[] + +// tag::attributes[] +You can define any of the following attributes when you create a sequence. +You can alter an existing sequence in order to restart it, or to change any of the sequence attributes. + +=== Start Value, Increment, and Direction + +By default, a sequence starts at `0` and goes up by `1` at each step. +You can specify the start value of the sequence, the incremental value for the sequence, and the direction of the sequence: ascending or descending. + +=== Maximum and Minimum Value + +The highest possible value for a sequence is the highest signed 64-bit integer, `2^63^-1`. +This is the default maximum value. + +The lowest possible value for a sequence is the lowest signed 64-bit integer, `-2^63^`. +This is the default minimum value. + +You can specify a different maximum or minimum value for a sequence. + +=== Cycling + +A sequence may permit cycling. +In this case, the sequence behaves as follows: + +* If the sequence is ascending, then when it reaches the maximum value, it continues from the minimum value -- which may be different to the sequence's specified starting value. + +* If the sequence is descending, then when it reaches the minimum value, it continues from the maximum value -- which may be different to the sequence's specified starting value. + +If a sequence does not permit cycling, then when it reaches the maximum or minimum value, it generates an error. +// end::attributes[] + +[[next-val-for]] +== Next Value Operator + +The next value operator increments a given sequence and returns the next value. + +=== Prerequisites + +.RBAC Privileges +To use this operator, you must have the _Query Use Sequences_ privilege granted on the scope. +For more details about user roles, see {authorization-overview}[Authorization]. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=next-val-expr] +---- + +image::n1ql-language-reference/next-val-expr.png["Syntax diagram: refer to source code listing", align=left] + +Synonym: `NEXT VALUE FOR` and `NEXTVAL FOR` are synonyms. + +[horizontal] +sequence:: (Required) A name that identifies the sequence within a namespace, bucket, and scope. +See <> below. + +[[next-sequence]] +==== Sequence Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=sequence] +---- + +image::n1ql-language-reference/sequence.png["Syntax diagram: refer to source code listing", align=left] + +Each sequence is associated with a given namespace, bucket, and scope. +You must specify the namespace, bucket, and scope to refer to the sequence correctly. + +[horizontal] +namespace:: +(Optional) The {logical-hierarchy}[namespace] of the bucket which contains the sequence. + +bucket:: +(Optional) The bucket which contains the sequence. + +scope:: +(Optional) The scope which contains the sequence. + +identifier:: +(Required) The name of the sequence. +The sequence name is case-sensitive. + +Currently, only the `default` namespace is available. +If you omit the namespace, the default namespace in the current session is used. + +If the {query-context}[query context] is set, you can omit the bucket and scope from the statement. +In this case, the bucket and scope for the sequence are taken from the query context. + +The namespace, bucket, scope, and sequence name must follow the rules for {identifiers}[identifiers]. +If the namespace, bucket, scope, or sequence name contain any special characters such as hyphens (-), you must wrap that part of the expression in backticks ({backtick} {backtick}). + +=== Return Value + +For a new sequence, the next value operator returns the starting value in the sequence. + +For a sequence that has been referenced already, the next value operator increments the sequence and returns the new value. +However, the sequence is only incremented once per document. + +Subqueries operate on independent documents from their containing queries, so subqueries increment the sequence independently. + +[NOTE] +==== +A sequence is not guaranteed to generate unique values. +For example, in the following circumstances, it may generate a value that it has generated before: + +* If the sequence cycles. +* If the sequence is restarted with a value that overlaps with previously-generated values. +* If the sequence is restarted to change the direction of the increment: for example, descending instead of ascending. +==== + +=== Restrictions + +You cannot use this operator in a WHERE or ON clause. +This generates a semantic error 3100. + +=== Examples + +To try the examples in this section, set the query context to the `tenant_agent_00` scope in the travel sample dataset. +For more information, see {query-context}[Query Context]. + +[[ex-nextval-start]] +.Start a sequence +==== +This statement starts a sequence called `ordNum` for use in the following examples. + +.Query +[source,sqlpp] +---- +CREATE SEQUENCE ordNum START WITH 1000; +---- +==== + +[[ex-nextval-doc]] +.Insert a sequential value in a document body +==== +The following statement uses the `ordNum` sequence to generate a booking number within the body of the document. + +.Query +[source,sqlpp] +---- +INSERT INTO bookings + VALUES (UUID(), + {"num": NEXT VALUE FOR ordNum, "user": 0}) + RETURNING *; +---- + +.Results +[source,json] +---- +[ + { + "bookings": { + "num": 1000, + "user": 0 + } + } +] +---- +==== + +[[ex-nextval-key]] +.Insert a sequential value in a document key and body +==== +The following statement uses the `ordNum` sequence to generate the document key and a booking number within the body of the document. + +.Query +[source,sqlpp] +---- +INSERT INTO bookings + VALUES (TO_STRING(NEXTVAL FOR ordNum), + {"num": NEXTVAL FOR ordNum, "user": 1}) + RETURNING META().id, *; +---- + +This query gives different results, depending on the version of Couchbase Server. + +''' + +[.status]##Couchbase Server 7.6–7.6.3## + +.Results +[source,json] +---- +[ + { + "id": "1001", + "bookings": { + "num": 1002, + "user": 1 + } + } +] +---- + +In versions of Couchbase Server prior to 7.6.5, the key is not regarded as part of the document, so this query increments the sequence twice. +This gives a different sequence number for the document key and the document value. + +''' + +[.status]#Couchbase Server 7.6.5# + +.Results +[source,json] +---- +[ + { + "id": "1001", + "bookings": { + "num": 1001, + "user": 1 + } + } +] +---- + +In Couchbase Server 7.6.5 and later, the entire VALUES clause (key, value, and options) is regarded as a single document, so the query only increments the sequence once. +This gives the same sequence number in the document key and the document value. +==== + +[[ex-nextval-same]] +.Insert a sequential value with INSERT SELECT +==== +The following statement uses an INSERT SELECT statement. +With this query, the document key and document value are both generated within the same document. + +.Query +[source,sqlpp] +---- +INSERT INTO bookings (KEY k, VALUE v) + SELECT TO_STRING(NEXTVAL FOR ordNum) k, + {"num": NEXTVAL FOR ordNum, "user": 1} v + RETURNING META().id, *; +---- + +.Result +[source,json] +---- +[ + { + "id": "1003", + "bookings": { + "num": 1003, + "user": 1 + } + } +] +---- + +The next value operator only increments a sequence once within the context of a document. +This gives the same sequence number in the document key and the document value. +==== + +[[prev-val-for]] +== Previous Value Operator + +The previous value operator returns the current value in a sequence, without incrementing or decrementing the sequence. +This is useful when you need to refer to the same value again without generating a new value. + +=== Prerequisites + +.RBAC Privileges +To use this operator, you must have the _Query Use Sequences_ privilege granted on the scope. +For more details about user roles, see {authorization-overview}[Authorization]. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=prev-val-expr] +---- + +image::n1ql-language-reference/prev-val-expr.png["Syntax diagram: refer to source code listing", align=left] + +Synonym: `PREVIOUS VALUE FOR`, `PREV VALUE FOR`, and `PREVVAL FOR` are synonyms. + +[horizontal] +sequence:: (Required) A name that identifies the sequence within a namespace, bucket, and scope. +See <> below. + +[[prev-sequence]] +==== Sequence Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=sequence] +---- + +image::n1ql-language-reference/sequence.png["Syntax diagram: refer to source code listing", align=left] + +Each sequence is associated with a given namespace, bucket, and scope. +You must specify the namespace, bucket, and scope to refer to the sequence correctly. + +[horizontal] +namespace:: +(Optional) The {logical-hierarchy}[namespace] of the bucket which contains the sequence. + +bucket:: +(Optional) The bucket which contains the sequence. + +scope:: +(Optional) The scope which contains the sequence. + +identifier:: +(Required) The name of the sequence. +The sequence name is case-sensitive. + +Currently, only the `default` namespace is available. +If you omit the namespace, the default namespace in the current session is used. + +If the {query-context}[query context] is set, you can omit the bucket and scope from the statement. +In this case, the bucket and scope for the sequence are taken from the query context. + +The namespace, bucket, scope, and sequence name must follow the rules for {identifiers}[identifiers]. +If the namespace, bucket, scope, or sequence name contain any special characters such as hyphens (-), you must wrap that part of the expression in backticks ({backtick} {backtick}). + +=== Return Value + +The previous value operator returns one of the following, in order of precedence: + +. If a value has been generated for the current document, the operator returns the current value generated for the document. +. If in a transaction, and a value has been generated for the transaction, the operator returns the current value generated in the transaction. +. Otherwise, the operator returns the current value generated for the sequence on the node. + +The previous value operator does not increment or decrement the sequence. + +If no value has been generated for the sequence, the previous value operator returns an error. + +=== Restrictions + +You cannot use this operator in a WHERE or ON clause. +This generates a semantic error 3100. + +=== Examples + +To try the examples in this section, set the query context to the `tenant_agent_00` scope in the travel sample dataset. +For more information, see {query-context}[Query Context]. + +[[ex-prevval-multi]] +.Insert the same sequential value in multiple statements +==== +This example assumes that you have created a sequence called `ordNum` as described in <>. + +.Query +[source,sqlpp] +---- +BEGIN TRANSACTION; +INSERT INTO bookings VALUES(UUID(), + {"num": NEXT VALUE FOR ordNum, + "user": 0, + "type": "order"}); +INSERT INTO bookings VALUES(UUID(), + {"order_num": PREVVAL FOR ordNum, + "hotel": "hotel_17413", + "type": "item"}); +INSERT INTO bookings VALUES(UUID(), + {"order_num": PREVVAL FOR ordNum, + "hotel": "hotel_15912", + "type": "item"}); +COMMIT; +---- +==== + +[[ex-prevval-test]] +.Check the result of <> +==== +.Query +[source,sqlpp] +---- +SELECT o.num, o.user, ARRAY_AGG(i.hotel) items +FROM bookings o, + bookings i +WHERE o.type = "order" + AND i.type = "item" + AND o.num = i.order_num +GROUP BY o.num, o.user; +---- + +.Result +[source,json] +---- +[ + { + "num": 1004, + "user": 0, + "items": [ + "hotel_15912", + "hotel_17413" + ] + } +] +---- +==== + +== Related Links + +* To create a sequence, see xref:n1ql-language-reference/createsequence.adoc[]. +* To alter a sequence, see xref:n1ql-language-reference/altersequence.adoc[]. +* To drop a sequence, see xref:n1ql-language-reference/dropsequence.adoc[]. +* To monitor sequences, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-sequences[Monitor Sequences]. diff --git a/modules/n1ql/pages/n1ql-language-reference/set-transaction.adoc b/modules/n1ql/pages/n1ql-language-reference/set-transaction.adoc new file mode 100644 index 000000000..cc16373fe --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/set-transaction.adoc @@ -0,0 +1,87 @@ += SET TRANSACTION +:description: The SET TRANSACTION statement enables you to specify settings for a transaction. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:insert: xref:n1ql:n1ql-language-reference/insert.adoc +:upsert: xref:n1ql:n1ql-language-reference/upsert.adoc +:delete: xref:n1ql:n1ql-language-reference/delete.adoc +:update: xref:n1ql:n1ql-language-reference/update.adoc +:merge: xref:n1ql:n1ql-language-reference/merge.adoc +:select: xref:n1ql:n1ql-language-reference/selectintro.adoc +:execfunction: xref:n1ql:n1ql-language-reference/execfunction.adoc +:prepare: xref:n1ql:n1ql-language-reference/prepare.adoc +:execute: xref:n1ql:n1ql-language-reference/execute.adoc +:transactions: xref:n1ql:n1ql-language-reference/transactions.adoc +:preparation: xref:n1ql:n1ql-language-reference/transactions.adoc#preparation + +// Related links +:overview: xref:server:learn:data/transactions.adoc +:begin-transaction: xref:n1ql-language-reference/begin-transaction.adoc +:set-transaction: xref:n1ql-language-reference/set-transaction.adoc +:savepoint: xref:n1ql-language-reference/savepoint.adoc +:commit-transaction: xref:n1ql-language-reference/commit-transaction.adoc +:rollback-transaction: xref:n1ql-language-reference/rollback-transaction.adoc + +[abstract] +{description} + +== Purpose + +The `SET TRANSACTION` statement enables you to specify settings for an ACID transaction. +Refer to {transactions}[] for further information. + +This statement may only be used within a transaction. + +ifdef::flag-devex-rest-api[] +include::partial$n1ql-language-reference/transaction-id.adoc[] +endif::flag-devex-rest-api[] + +You may also optionally specify settings when you start the transaction using the `BEGIN TRANSACTION` command. + +NOTE: Currently, the only available transaction setting is "isolation level read committed". +This setting is enabled by default. +The `SET TRANSACTION` statement is therefore optional and may be omitted. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/tcl.ebnf[tag=set-transaction] +---- + +image::n1ql-language-reference/set-transaction.png["Syntax diagram: refer to source code listing", align=left] + +== Example + +If you want to try this example, first refer to {preparation}[Preparation] to set up your environment. + +.Specify transaction settings +==== +// Line highlighting doesn't work with highlight.js. +// Markup for future use [source,n1ql,highlight=17..19] + +.Transaction +[source,sqlpp,subs=macros] +---- +include::example$transactions/multiple.n1ql[tags=transaction;set-mark;!begin-mark;!set-plain;!savepoint-mark;!rollback-mark;!commit-mark] +---- + +.Results +[source,json] +---- +include::example$transactions/results.jsonc[tags=extract;ellipsis] +---- + +<.> Beginning a transaction returns a transaction ID. +==== + +== Related Links + +* For an overview of Couchbase transactions, refer to {overview}[]. +* To begin a transaction, refer to {begin-transaction}[]. +* To set a savepoint, refer to {savepoint}[]. +* To rollback a transaction, refer to {rollback-transaction}[]. +* To commit a transaction, refer to {commit-transaction}[]. +* Blog post: https://blog.couchbase.com/transactions-n1ql-couchbase-distributed-nosql/[Couchbase Transactions: Elastic, Scalable, and Distributed^]. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/statistics-delete.adoc b/modules/n1ql/pages/n1ql-language-reference/statistics-delete.adoc new file mode 100644 index 000000000..adf585c4b --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/statistics-delete.adoc @@ -0,0 +1,193 @@ += Delete Statistics +:description: You can use the UPDATE STATISTICS statement to delete statistics. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross references +:n1ql: xref:n1ql-language-reference +:cbo: {n1ql}/cost-based-optimizer.adoc +:expression: {n1ql}/index.adoc +:array-expr: {n1ql}/indexing-arrays.adoc#array-expr +:meta-info-expr: {n1ql}/indexing-meta-info.adoc#metakeyspace_expr-property +:keyspace-ref: {n1ql}/createindex.adoc#keyspace-ref +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +//Related links +:updatestatistics: {n1ql}/updatestatistics.adoc +:statistics-expressions: {n1ql}/statistics-expressions.adoc +:statistics-index: {n1ql}/statistics-index.adoc +:statistics-indexes: {n1ql}/statistics-indexes.adoc +:statistics-delete: {n1ql}/statistics-delete.adoc + +// TODO: Links in EBNF files +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +The `UPDATE STATISTICS` statement provides a syntax which enables you to delete statistics for a set of index expressions, or for an entire keyspace. + +Since the {cbo}[cost-based optimizer] uses statistics for cost calculations, deleting statistics for a set of index expressions effectively turns off the cost-based optimizer for queries which utilize predicates on those expressions. +Deleting all statistics for a keyspace turns off the cost-based optimizer for all queries referencing that keyspace. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=update-statistics-delete] +---- + +image::n1ql-language-reference/update-statistics-delete.png["Syntax diagram: refer to source code listing", align=left] + +For this syntax, `UPDATE STATISTICS` and `ANALYZE` are synonyms. +The statement must begin with one of these alternatives. + +When using the `UPDATE STATISTICS` keywords, the `FOR` keyword is optional. +Including this keyword makes no difference to the operation of the statement. + +When using the `ANALYZE` keyword, the `COLLECTION` or `KEYSPACE` keywords are optional. +Including either of these keywords makes no difference to the operation of the statement. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +delete-clause:: <> icon:caret-down[] + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace-path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace-partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of the keyspace for which you want to delete statistics. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +[[delete-clause]] +=== DELETE Clause + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=delete-clause] +---- + +image::n1ql-language-reference/delete-clause.png["Syntax diagram: refer to source code listing", align=left] + +The `DELETE` clause enables you to provide a comma-separated list of index expressions for which you want to delete statistics, or to specify that you want to delete all statistics for the keyspace. + +[horizontal.compact] +delete-expr:: <> icon:caret-down[] +delete-all:: <> icon:caret-down[] + +[[delete-expressions]] +==== Delete Expressions + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=delete-expr] +---- + +image::n1ql-language-reference/delete-expr.png["Syntax diagram: refer to source code listing", align=left] + +Constraint: if you used the `UPDATE STATISTICS` keywords at the beginning of the statement, you may not use the `STATISTICS` keyword in this clause. + +Conversely, if you used the `ANALYZE` keyword at the beginning of the statement, you must include the `STATISTICS` keyword in this clause. + +[horizontal] +index-key:: +[Required] The expression for which you want to delete statistics. +This may be any expression that is supported as an index key, including, but not limited to: + +* A {sqlpp} {expression}[expression] over any fields in the document, as used in a secondary index. + +* An {array-expr}[array expression], as used when creating an array index. + +* An {meta-info-expr}[expression with the META() function], as used in a metadata index. + +[[delete-all]] +==== Delete All Statistics + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=delete-all] +---- + +image::n1ql-language-reference/delete-all.png["Syntax diagram: refer to source code listing", align=left] + +Constraint: If you used the `UPDATE STATISTICS` keywords at the beginning of the statement, you must use the `ALL` keyword in this clause. + +Conversely, if you used the `ANALYZE` keyword at the beginning of the statement, you must use the `STATISTICS` keyword in this clause. + +== Result + +The statement returns an empty array. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-1]] +.Delete statistics with UPDATE STATISTICS +==== +[source,sqlpp] +---- +include::example$utility/statistics-delete.n1ql[] +---- +==== + +[[ex-2]] +.Delete statistics with ANALYZE +==== +[source,sqlpp] +---- +include::example$utility/analyze-delete.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +[[ex-3]] +.Delete all statistics with UPDATE STATISTICS +==== +[source,sqlpp] +---- +include::example$utility/statistics-delete-all.n1ql[] +---- +==== + +[[ex-4]] +.Delete all statistics with ANALYZE +==== +[source,sqlpp] +---- +include::example$utility/analyze-delete-all.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +== Related Links + +* {updatestatistics}[UPDATE STATISTICS] overview +* {statistics-expressions}[Updating Statistics for Index Expressions] +* {statistics-index}[Updating Statistics for a Single Index] +* {statistics-indexes}[Updating Statistics for Multiple Indexes] +* {cbo}[Cost-Based Optimizer] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/statistics-expressions.adoc b/modules/n1ql/pages/n1ql-language-reference/statistics-expressions.adoc new file mode 100644 index 000000000..dd43bca56 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/statistics-expressions.adoc @@ -0,0 +1,248 @@ += Update Statistics for Index Expressions +:description: You can use the UPDATE STATISTICS statement to gather statistics for an index key expression. +:page-topic-type: reference +:page-partial: +:imagesdir: ../../assets/images + +// Cross-references +:n1ql: xref:n1ql-language-reference +:cbo: {n1ql}/cost-based-optimizer.adoc +:expression: {n1ql}/index.adoc +:keyspace-ref: {n1ql}/createindex.adoc#keyspace-ref +:array-expr: {n1ql}/indexing-arrays.adoc#array-expr +:adaptive-expr: {n1ql}/adaptive-indexing.adoc#index-key +:meta-info-expr: {n1ql}/indexing-meta-info.adoc#metakeyspace_expr-property +:distribution-stats: {cbo}#distribution-stats +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +//Related links +:updatestatistics: {n1ql}/updatestatistics.adoc +:statistics-expressions: {n1ql}/statistics-expressions.adoc +:statistics-index: {n1ql}/statistics-index.adoc +:statistics-indexes: {n1ql}/statistics-indexes.adoc +:statistics-delete: {n1ql}/statistics-delete.adoc + +// TODO: Links in EBNF files +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +The `UPDATE STATISTICS` statement provides a syntax which enables you to gather statistics for an index key expression. + +// tag::overview[] +When you use an index with a query, you typically create the index on the fields which the query uses to filter. +To use the cost-based optimizer with that query, you must collect statistics on the same fields that you used to create the index. + +A query may have predicates on non-indexed fields, and you can collect statistics on those fields also to help the optimizer. + +For a query which filters on an array or array of objects, you must collect the statistics using exactly the same expression that you used to create the index. +// end::overview[] + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=update-statistics-expr] +---- + +image::n1ql-language-reference/update-statistics-expr.png["Syntax diagram: refer to source code listing", align=left] + +For this syntax, `UPDATE STATISTICS` and `ANALYZE` are synonyms. +The statement must begin with one of these alternatives. + +When using the `UPDATE STATISTICS` keywords, the `FOR` keyword is optional. +Including this keyword makes no difference to the operation of the statement. + +When using the `ANALYZE` keyword, the `COLLECTION` or `KEYSPACE` keywords are optional. +Including either of these keywords makes no difference to the operation of the statement. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +index-key:: <> icon:caret-down[] +index-with:: <> icon:caret-down[] + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace-path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace-partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of the keyspace for which you want to gather statistics. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +[[index-expr]] +=== Index Expression + +The expression for which you want to gather statistics. +This may be any expression that is supported as an index key, including, but not limited to: + +* A {sqlpp} {expression}[expression] over any fields in the document, as used in a secondary index. + +* An {array-expr}[array expression], as used when creating an array index. + +* An {meta-info-expr}[expression with the META() function], as used in a metadata index. + +[[index-with,WITH Clause]] +include::partial$n1ql-language-reference/statistics-options.adoc[] + +== Result + +The statement returns an empty array. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex1]] +.Single predicate +==== +.Create indexes +[source,sqlpp] +---- +include::example$utility/statistics-expr.n1ql[tag=indexes] +---- + +.Update statistics +[source,sqlpp] +---- +include::example$utility/statistics-expr.n1ql[tag=update] +---- + +.Query +[source,sqlpp] +---- +include::example$utility/statistics-expr.n1ql[tag=explain] +---- + +.Result +[source,JSON] +---- +include::example$utility/statistics-expr.jsonc[] +---- +==== + +<1> The overall cardinality estimate for the query. +<2> The overall cost estimate for the query. +<3> Cardinality and cost estimates for the index scan operator. +<4> Cardinality and cost estimates for the initial project operator. + +[[ex2]] +.Multiple predicates +==== +This example uses the same indexes as <>. + +.Update statistics +[source,sqlpp] +---- +include::example$utility/statistics-expr-predicate.n1ql[tag=update] +---- + +There is no index on the `free_breakfast` field. +However, the query below refers to this field as a predicate, so we collect statistics on this field also. + +.Query +[source,sqlpp] +---- +include::example$utility/statistics-expr-predicate.n1ql[tag=explain] +---- + +.Result +[source,JSON] +---- +include::example$utility/statistics-expr-predicate.jsonc[] +---- +==== + +<1> Overall cardinality and cost estimates for the query. +<2> Cardinality and cost estimates for the index scan operator. +<3> Cardinality and cost estimates for the fetch operator. +<4> Cardinality and cost estimates for the filter operator. +<5> Cardinality and cost estimates for the initial group operator. +<6> Cardinality and cost estimates for the intermediate group operator. +<7> Cardinality and cost estimates for the final group operator. +<8> Cardinality and cost estimates for the initial project operator. + +[[ex3]] +.Filter on an array +==== +.Create index +[source,sqlpp] +---- +include::example$utility/statistics-expr-array.n1ql[tag=indexes] +---- + +.Update statistics +[source,N1Ql] +---- +include::example$utility/statistics-expr-array.n1ql[tag=update] +---- + +.Query +[source,N1Ql] +---- +include::example$utility/statistics-expr-array.n1ql[tag=explain] +---- + +.Results +[source,JSON] +---- +include::example$utility/statistics-expr-array.jsonc[] +---- +==== + +[[ex4]] +.Filter on an array of objects +==== +.Create index +[source,sqlpp] +---- +include::example$utility/statistics-expr-nested.n1ql[tag=indexes] +---- + +.Update statistics +[source,N1Ql] +---- +include::example$utility/statistics-expr-nested.n1ql[tag=update] +---- + +.Query +[source,N1Ql] +---- +include::example$utility/statistics-expr-nested.n1ql[tag=explain] +---- + +.Results +[source,JSON] +---- +include::example$utility/statistics-expr-nested.jsonc[] +---- +==== + +== Related Links + +* {updatestatistics}[UPDATE STATISTICS] overview +* {statistics-index}[Updating Statistics for a Single Index] +* {statistics-indexes}[Updating Statistics for Multiple Indexes] +* {statistics-delete}[Deleting Statistics] +* {cbo}[Cost-Based Optimizer] diff --git a/modules/n1ql/pages/n1ql-language-reference/statistics-index.adoc b/modules/n1ql/pages/n1ql-language-reference/statistics-index.adoc new file mode 100644 index 000000000..a5e4d550c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/statistics-index.adoc @@ -0,0 +1,202 @@ += Update Statistics for a Single Index +:description: You can use the UPDATE STATISTICS statement to gather statistics on a single index. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross references +:n1ql: xref:n1ql-language-reference +:cbo: {n1ql}/cost-based-optimizer.adoc +:keyspace-ref-alter: {n1ql}/alterindex.adoc#keyspace-ref +:keyspace-ref-drop: {n1ql}/dropindex.adoc#keyspace-ref +:index-path-alter: {n1ql}/alterindex.adoc#index-path +:index-path-drop: {n1ql}/dropindex.adoc#index-path +:distribution-stats: {cbo}#distribution-stats +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +//Related links +:updatestatistics: {n1ql}/updatestatistics.adoc +:statistics-expressions: {n1ql}/statistics-expressions.adoc +:statistics-index: {n1ql}/statistics-index.adoc +:statistics-indexes: {n1ql}/statistics-indexes.adoc +:statistics-delete: {n1ql}/statistics-delete.adoc + +// TODO: Links in EBNF files +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +The `UPDATE STATISTICS` statement provides a syntax which enables you to analyze a single index. +With this syntax, the statement gathers statistics for all the index key expressions in the specified index. +This provides a shorthand so that you do not need to list all the index key expressions explicitly. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=update-statistics-index] +---- + +image::n1ql-language-reference/update-statistics-index.png["Syntax diagram: refer to source code listing", align=left] + +For this syntax, `UPDATE STATISTICS FOR` and `ANALYZE` are synonyms. +The statement must begin with one of these alternatives. + +[horizontal.compact] +index-clause:: <> icon:caret-down[] +index-using:: <> icon:caret-down[] +index-with:: <> icon:caret-down[] + +[[index-clause]] +=== INDEX Clause + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=index-clause] +---- + +image::n1ql-language-reference/index-clause.png["Syntax diagram: refer to source code listing", align=left] + +For this syntax, the `INDEX` clause enables you to specify the index name and a keyspace. + +[horizontal.compact] +index-name:: A unique name that identifies the index. +index-path:: <> icon:caret-down[] +keyspace-ref:: <> icon:caret-down[] + +[[index-path]] +==== Index Path + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-path] +---- + +image::n1ql-language-reference/index-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-full-index,ebnf,reftext="keyspace-full"] +---- +include::partial$grammar/ddl.ebnf[tag=keyspace-full] +---- + +image::n1ql-language-reference/keyspace-full.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-prefix-index,ebnf,reftext="keyspace-prefix"] +---- +include::partial$grammar/ddl.ebnf[tag=keyspace-prefix] +---- + +image::n1ql-language-reference/keyspace-prefix.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial-index,ebnf,reftext="keyspace-partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +You can use a dotted notation to specify the index and the keyspace on which the index is built. +Refer to the {index-path-alter}[ALTER INDEX] or {index-path-drop}[DROP INDEX] statements for details of the syntax. + +[[keyspace-ref]] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace-path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace-partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Alternatively, you can use the index name with the `ON` keyword and a keyspace reference to specify the keyspace on which the index is built. +Refer to the {keyspace-ref-alter}[ALTER INDEX] or {keyspace-ref-drop}[DROP INDEX] statements for details of the syntax. + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +In Couchbase Capella, the index type for a secondary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +[[index-with,WITH Clause]] +include::partial$n1ql-language-reference/statistics-options.adoc[] + +== Result + +The statement returns an empty array. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-1]] +.UPDATE STATISTICS with index identifier +==== +[source,sqlpp] +---- +include::example$utility/statistics-index.n1ql[] +---- +==== + +[[ex-2]] +.UPDATE STATISTICS with ON clause +==== +[source,sqlpp] +---- +include::example$utility/statistics-index-on.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +[[ex-3]] +.ANALYZE with index identifier +==== +[source,sqlpp] +---- +include::example$utility/analyze-index.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +[[ex-4]] +.ANALYZE with ON clause +==== +[source,sqlpp] +---- +include::example$utility/analyze-index-on.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +== Related Links + +* {updatestatistics}[UPDATE STATISTICS] overview +* {statistics-expressions}[Updating Statistics for Index Expressions] +* {statistics-indexes}[Updating Statistics for Multiple Indexes] +* {statistics-delete}[Deleting Statistics] +* {cbo}[Cost-Based Optimizer] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/statistics-indexes.adoc b/modules/n1ql/pages/n1ql-language-reference/statistics-indexes.adoc new file mode 100644 index 000000000..4cc2cbbfa --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/statistics-indexes.adoc @@ -0,0 +1,219 @@ += Update Statistics for Multiple Indexes +:description: You can use the UPDATE STATISTICS statement to gather statistics for multiple indexes at once. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:n1ql: xref:n1ql-language-reference +:cbo: {n1ql}/cost-based-optimizer.adoc +:selectclause: {n1ql}/selectclause.adoc +:keyspace-ref: {n1ql}/createindex.adoc#keyspace-ref +:distribution-stats: {cbo}#distribution-stats +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy + +//Related links +:updatestatistics: {n1ql}/updatestatistics.adoc +:statistics-expressions: {n1ql}/statistics-expressions.adoc +:statistics-index: {n1ql}/statistics-index.adoc +:statistics-indexes: {n1ql}/statistics-indexes.adoc +:statistics-delete: {n1ql}/statistics-delete.adoc + +// TODO: Links in EBNF files +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +The `UPDATE STATISTICS` statement provides a syntax which enables you to analyze multiple indexes at once. +With this syntax, the statement gathers statistics for all the index key expressions from all specified indexes. +This provides a shorthand so that you do not need to list all the index key expressions explicitly. + +If the same index expression is included in multiple indexes, duplicate index expressions are removed, so each index expression is only analyzed once. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=update-statistics-indexes] +---- + +image::n1ql-language-reference/update-statistics-indexes.png["Syntax diagram: refer to source code listing", align=left] + +For this syntax, `UPDATE STATISTICS` and `ANALYZE` are synonyms. +The statement must begin with one of these alternatives. + +When using the `UPDATE STATISTICS` keywords, the `FOR` keyword is optional. +Including this keyword makes no difference to the operation of the statement. + +When using the `ANALYZE` keyword, the `COLLECTION` or `KEYSPACE` keywords are optional. +Including either of these keywords makes no difference to the operation of the statement. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +indexes-clause:: <> icon:caret-down[] +index-using:: <> icon:caret-down[] +index-with:: <> icon:caret-down[] + +[[keyspace-ref]] +=== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace-path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace-partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +The simple name or fully-qualified name of the keyspace on which the indexes are built. +Refer to the {keyspace-ref}[CREATE INDEX] statement for details of the syntax. + +[[indexes-clause]] +=== INDEX Clause + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=indexes-clause] +---- + +image::n1ql-language-reference/indexes-clause.png["Syntax diagram: refer to source code listing", align=left] + +For this syntax, the `INDEX` clause enables you to specify a comma-separated list of index names, a subquery which returns an array of index names, or all the indexes in the specified keyspace. + +[horizontal.compact] +index-name:: A unique name that identifies an index. +subquery-expr:: <> icon:caret-down[] + +[[subquery-expr]] +==== Subquery Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=subquery-expr] +---- + +image::n1ql-language-reference/subquery-expr.png["Syntax diagram: refer to source code listing", align=left] + +Use parentheses to specify a subquery. + +The subquery must return an array of strings, each string representing the name of an index. +The subquery should look for GSI indexes that are in the online state. +Refer to <> and <> for details. + +==== INDEX ALL + +The `INDEX ALL` keywords enable you to analyze all the indexes in the specified keyspace, without having to use a subquery. +Refer to <> and <> for details. + +[[index-using]] +=== USING Clause + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-using] +---- + +image::n1ql-language-reference/index-using.png["Syntax diagram: refer to source code listing", align=left] + +In Couchbase Capella, the index type for a secondary index must be Global Secondary Index (GSI). +The `USING GSI` keywords are optional and may be omitted. + +[[index-with,WITH Clause]] +include::partial$n1ql-language-reference/statistics-options.adoc[] + +== Result + +The statement returns an empty array. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-1]] +.UPDATE STATISTICS with indexes +==== +[source,sqlpp] +---- +include::example$utility/statistics-indexes.n1ql[] +---- +==== + +[[ex-2]] +.ANALYZE with indexes +==== +[source,sqlpp] +---- +include::example$utility/analyze-indexes.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +[[ex-3]] +.UPDATE STATISTICS with subquery +==== +[source,sqlpp] +---- +include::example$utility/statistics-indexes-subquery.n1ql[] +---- + +<1> One set of parentheses delimits the whole group of index terms, and the other set of parentheses delimits the subquery, leading to a double set of parentheses. + +<2> The `RAW` keyword forces the subquery to return a flattened array of strings, each of which refers to an index name. + +<3> Since `USING` is a reserved keyword, you need to surround it in backticks in the query. +==== + +[[ex-4]] +.ANALYZE with subquery +==== +[source,sqlpp] +---- +include::example$utility/analyze-indexes-subquery.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +[[ex-5]] +.UPDATE STATISTICS with all indexes +==== +[source,sqlpp] +---- +include::example$utility/statistics-indexes-all.n1ql[] +---- +==== + +[[ex-6]] +.ANALYZE with all indexes +==== +[source,sqlpp] +---- +include::example$utility/analyze-indexes-all.n1ql[] +---- + +This query is equivalent to the query in <>. +==== + +== Related Links + +* {updatestatistics}[UPDATE STATISTICS] overview +* {statistics-expressions}[Updating Statistics for Index Expressions] +* {statistics-index}[Updating Statistics for a Single Index] +* {statistics-delete}[Deleting Statistics] +* {cbo}[Cost-Based Optimizer] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/stringfun.adoc b/modules/n1ql/pages/n1ql-language-reference/stringfun.adoc new file mode 100644 index 000000000..851ddb5fc --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/stringfun.adoc @@ -0,0 +1,1605 @@ += String Functions +:description: String functions perform operations on a string input value and returns a string or other value. +:page-topic-type: reference +:example-caption!: + +{description} + +NOTE: If any arguments to any of the following functions are [.out]`MISSING` then the result is also [.out]`MISSING` -- that is, no result is returned. +Similarly, if any of the arguments passed to the functions are `NULL` or are of the wrong type, such as an integer instead of a string, then `NULL` is returned as the result. + +[[fn-str-concat,CONCAT()]] +== CONCAT([.var]`string1`, [.var]`string2`, …) + +=== Description +This function takes two or more strings and returns a new string after concatenating the input strings. +If there are fewer than two arguments, then it returns an error. + +=== Arguments +string1, string2, \...:: [At least 2 are required] The strings, or valid xref:n1ql-language-reference/index.adoc[expressions] which evaluate to strings, to be concatenated together. + +=== Return Value +A new string, concatenated from the input strings. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT CONCAT("abc", "def", "ghi") AS concat; +---- + +.Result +[source,json] +---- +[ + { + "concat": "abcdefghi" + } +] +---- +==== + +[[fn-str-concat2,CONCAT2()]] +== CONCAT2([.var]`separator`, [.var]`arg1`, [.var]`arg2`, …) + +=== Description +This function takes the input strings, or arrays of strings, and concatenates them with the specified separator between each input string. +If there are fewer than two arguments, then it returns an error. + +=== Arguments +separator:: [Required] The string to separate the input strings. +If no separator is required, specify the empty string "". + +arg1, arg2, \...:: [At least 1 is required] The strings, or arrays of strings, to be concatenated together. + +=== Return Value +A new string, concatenated from the inputs, with the separator between each input. +Arrays of strings are flattened and concatenated in the same order. +If there is only one string argument, the separator is not used. + +If any argument or array element is MISSING, returns MISSING. +If any argument or array element is non-string, returns NULL. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT CONCAT2('-','a','b',['c','d'],['xyz']) AS c1, +CONCAT2('-','a') AS c2, +CONCAT2('-',['b']) AS c3; +---- + +.Result +[source,json] +---- +[ + { + "c1": "a-b-c-d-xyz", + "c2": "a", + "c3": "b" + } +] +---- +==== + +[[fn-str-contains,CONTAINS()]] +== CONTAINS(in_str, search_str) + +=== Description +Checks whether or not the specified search string is a substring of the input string -- that is, exists within. +This returns `true` if the substring exists within the input string, otherwise `false` is returned. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search within. + +search_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search for. + +=== Return Value +A boolean, representing whether the search string exists within the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT CONTAINS("SQL++ is awesome", "N1QL") as n1ql, + CONTAINS("SQL++ is awesome", "SQL") as sql; +---- + +.Result +[source,json] +---- +[ + { + "n1ql": false, + "sql": true + } +] +---- +==== + +[[fn-str-initcap,INITCAP()]] +== INITCAP(in_str) + +=== Description +Converts the string so that the first letter of each word is uppercase and every other letter is lowercase (known as 'Title Case'). + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to title case. + +=== Return Value +A string, representing the input string converted to title case. + +=== Limitations +This function capitalizes the initial letter of every word in the sentence, this means that even short words such as "the" and "or" will be capitalized. +This does not strictly follow title case conventions used in the writing domain. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT INITCAP("SQL++ is awesome") as sqlpp; +---- + +.Result +[source,json] +---- +[ + { + "sqlpp": "Sql++ Is Awesome" + } +] +---- +==== + +[[fn-str-length,LENGTH()]] +== LENGTH(in_str) + +_Equivalent_: xref:n1ql-language-reference/metafun.adoc#len[LEN()] + +=== Description +Finds the length of a string, where length is defined as the number of code points within the string. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to find the length of. + +=== Return Value +An integer representing the length of the string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT LENGTH("SQL++ is awesome") AS ascii, + LENGTH("Café") AS diacritic, + LENGTH("🙂") AS emoji, + LENGTH("") AS zero; +---- + +.Result +[source,json] +---- +[ + { + "ascii": 16, + "diacritic": 5, // <.> + "emoji": 4, // <.> + "zero": 0 + } +] +---- + +<.> The letter with diacritic counts as two bytes. +<.> The emoji counts as four bytes. +==== + +[[fn-str-lower,LOWER()]] +== LOWER(in_str) + +=== Description +Converts all characters in the input string to lower case. +This is useful for canonical comparison of string values. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to lower case. + +=== Return Value +A string representing the input string converted to lower case. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT LOWER("SQL++ is awesome") as sqlpp; +---- + +.Result +[source,json] +---- +[ + { + "sqlpp": "sql++ is awesome" + } +] +---- +==== + +[[fn-str-lpad,LPAD()]] +== LPAD(in_str, size [, char]) + + +=== Description +Pads a string with leading characters. +The function adds characters to the beginning of the string to pad the string to a specified length. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to add the leading characters to. + +size:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that specifies the desired length of the result string. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to add to the input string. ++ +If omitted, the default is space `" "`, Unicode U+0020. + +=== Return Value +A string representing the input string with leading characters added. + +* If the specified size is smaller than the length of the input string, the input string is truncated and no padding is added. +* If the specified size is larger than the length of the input string, but shorter than the length of the input string plus the padding characters, the padding characters are truncated. +* If the specified size is greater than the length of the input string plus the padding characters, the padding characters are repeated in order until the specified size is reached. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT LPAD("SQL++ is awesome", 20) AS implicit_padding, + LPAD("SQL++ is awesome", 20, "🙂!") AS repeated_padding, + LPAD("SQL++ is awesome", 20, "987654321") AS truncate_padding, + LPAD("SQL++ is awesome", 5, "987654321") AS truncate_string; +---- + +.Result +[source,json] +---- +[ + { + "implicit_padding": " SQL++ is awesome", + "repeated_padding": "🙂SQL++ is awesome", // <.> + "truncate_padding": "9876SQL++ is awesome", + "truncate_string": "SQL++" + } +] +---- + +<.> The emoji counts as four bytes when calculating the size. +==== + +[[fn-str-ltrim,LTRIM()]] +== LTRIM(in_str [, char]) + +=== Description +Removes all leading characters from a string. +The function removes all consecutive characters from the beginning of the string that match the specified characters and stops when it encounters a character that does not match any of the specified characters. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to remove the leading characters from. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to trim from the input string. +Each character in this string is trimmed from the input string -- you don't need to delimit the characters to trim. +For example, specifying a character value of `"abc"` trims the characters "a", "b" and "c" from the start of the string. ++ +If omitted, the default is whitespace: space `" "`, tab `"\t"`, newline `"\n"`, formfeed `"\f"`, or carriage return `"\r"`. + +=== Return Value +A string representing the input string with leading characters removed. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT LTRIM("...SQL++ is awesome", ".") as dots, + LTRIM(" SQL++ is awesome", " ") as explicit_spaces, + LTRIM("\t SQL++ is awesome") as implicit_spaces, + LTRIM("SQL++ is awesome") as no_dots; +---- + +.Result +[source,json] +---- +[ + { + "dots": "SQL++ is awesome", + "explicit_spaces": "SQL++ is awesome", + "implicit_spaces": "SQL++ is awesome", + "no_dots": "SQL++ is awesome" + } +] +---- +==== + +[[fn-str-mask,MASK()]] +== MASK(in_str [, options]) + + +=== Description +Overlays specified characters in the string with masking characters. +This may be useful when returning sensitive information, such as credit card numbers or email addresses. + +=== Arguments + +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the string to mask. + +options:: An object containing the following possible parameters: + +mask;; A string containing masking characters that will be used to overlay the input string. +May optionally also contain _hole_ characters, representing gaps in the mask; and _inject_ characters, that are inserted into the output. +(Default: `pass:c[********]`) + +hole;; A string containing the character or characters used to indicate holes in the mask string. +(Default: space) + +inject;; A string containing the character or characters in the mask string that are inserted into the output, rather than overlaying the input. +(Default: none) + +length;; Determines the length of the output string. +(Default: missing) + +* If this property is missing, or set to anything other than `"source"`, the length of the output is dynamic. +Any characters in the input up to the anchor point (see below) are included in the output. +The mask then starts at the anchor point, and continues for the length of the specified mask string. +Any characters in the input beyond the end of the mask are deleted. +This method may therefore obscure the number of characters in the input. + +* If the value is `"source"`, the length of the output is the same as the length of the input. +Any characters in the input up to the anchor point are included in the output. +The mask then starts at the anchor point. +If the mask is _longer than_ the remaining length of the input, the mask is truncated to fit. +If the mask string is _shorter than or the same length as_ the remaining length of the input, the mask continues for the length of the specified mask string. +Any characters in the input beyond the end of the mask are included in the output. + +anchor;; Determines where in the input string the mask should start. +Possible values are `"start"`, `"end"`, a regular expression string, a positive integer, or a negative integer. +(Default: `"start"`) + +* `"start"` -- the mask begins at the start of the input and is applied towards the end. + +* `"end"` -- the mask begins at the end of the input and is applied from the end towards the start. + +* Regular expression -- the mask begins at the first point in the input which matches the regular expression, and is applied towards the end. +If you need to match the strings `"start"` or `"end"`, use patterns such as `"[s]tart"` or `"[e]nd"`. + +* Positive integer -- the mask begins the specified number of characters after the start of the input, and is applied towards the end. + +* Negative integer -- the mask begins the specified number of characters before the end of the input, and is applied towards the start. + ++ ++ +If an anchor places the mask outside the boundaries of the input string, the input string is returned unchanged. + +=== Return Value +A string representing the masked input string. + +=== Examples +==== +Default mask, custom mask, custom mask demonstrating holes. + +.Query +[source,sqlpp] +---- +SELECT MASK('SomeTextToMask') AS mask, + MASK('SomeTextToMask', {"mask": "++++"}) AS mask_custom, + MASK('SomeTextToMask', {"mask": "++++ ++++"}) AS mask_hole; +---- + +.Result +[source,json] +---- +[ + { + "mask": "********", + "mask_custom": "++++", + "mask_hole": "++++Text++++" + } +] +---- +==== + +==== +Mask with character injection. + +.Query +[source,sqlpp] +---- +SELECT MASK('1234abcd5678efgh', {"mask": "****-****-****-####", + "hole": "#", + "inject": "-"}) AS mask_inject; +---- + +.Result +[source,json] +---- +[ + { + "mask_inject": "****-****-****-efgh" + } +] +---- +==== + +==== +Mask anchored to the end of the source, with the output length determined by the source. + +.Query +[source,sqlpp] +---- +SELECT MASK('1234abcd5678efgh', {"mask": "****", "anchor": "end", "length": "source"}) +AS end_anchor; +---- + +.Result +[source,json] +---- +[ + { + "end_anchor": "1234abcd5678****" + } +] +---- +==== + +==== +Mask anchored at the pattern `d5`. + +.Query +[source,sqlpp] +---- +SELECT MASK('1234abcd5678efgh', {"mask": "****", "anchor": "d5"}) AS regex_anchor; +---- + +.Result +[source,json] +---- +[ + { + "regex_anchor": "1234abc****" + } +] +---- +==== + +==== +Mask anchored 2 characters from the end of the source, with length determined by the input string. + +.Query +[source,sqlpp] +---- +SELECT MASK('1234abcd5678efgh', {"mask": "****", "anchor": -2, "length": "source"}) +AS negative_anchor; +---- + +.Result +[source,json] +---- +[ + { + "negative_anchor": "1234abcd56****gh" + } +] +---- +==== + +==== +Mask anchored at the 14th character, with length determined by the input string. + +.Query +[source,sqlpp] +---- +SELECT MASK('1234abcd5678efgh', {"mask": "****", "anchor": 14, "length": "source"}) +AS positive_anchor; +---- + +.Result +[source,json] +---- +[ + { + "positive_anchor": "1234abcd5678ef**" + } +] +---- +==== + +[[fn-mb-length,MB_LENGTH()]] +== MB_LENGTH(in_str) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Finds the length of a string, where length is defined as the number of characters within the string. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to find the length of. + +=== Return Value +An integer representing the length of the string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_LENGTH("SQL++ is awesome") AS ascii, + MB_LENGTH("Café") AS diacritic, + MB_LENGTH("🙂") AS emoji, + MB_LENGTH("") AS zero; +---- + +.Result +[source,json] +---- +[ + { + "ascii": 16, + "diacritic": 4, // <.> + "emoji": 1, // <.> + "zero": 0 + } +] +---- + +<.> The letter with diacritic counts as a single character. +<.> The emoji counts as a single character. +==== + +[[fn-mb-lpad,MB_LPAD()]] +== MB_LPAD(in_str, size [, char]) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Pads a string with leading characters. +The function adds characters to the beginning of the string to pad the string to a specified length. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to add the leading characters to. + +size:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that specifies the desired length of the result string. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to add to the input string. ++ +If omitted, the default is space `" "`, Unicode U+0020. + +=== Return Value +A string representing the input string with leading characters added. + +* If the specified size is smaller than the length of the input string, the input string is truncated and no padding is added. +* If the specified size is larger than the length of the input string, but shorter than the length of the input string plus the padding characters, the padding characters are truncated. +* If the specified size is greater than the length of the input string plus the padding characters, the padding characters are repeated in order until the specified size is reached. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_LPAD("SQL++ is awesome", 20) AS implicit_padding, + MB_LPAD("SQL++ is awesome", 20, "🙂!") AS repeated_padding, + MB_LPAD("SQL++ is awesome", 20, "987654321") AS truncate_padding, + MB_LPAD("SQL++ is awesome", 5, "987654321") AS truncate_string; +---- + +.Result +[source,json] +---- +[ + { + "implicit_padding": " SQL++ is awesome", + "repeated_padding": "🙂!🙂!SQL++ is awesome", // <.> + "truncate_padding": "9876SQL++ is awesome", + "truncate_string": "SQL++" + } +] +---- + +<.> The emoji counts as a single character when calculating the size. +==== + +[[fn-mb-rpad,MB_RPAD()]] +== MB_RPAD(in_str, size [, char]) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Pads a string with trailing characters. +The function adds characters to the end of the string to pad the string to a specified length. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to add the trailing characters to. + +size:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that specifies the desired length of the result string. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to add to the input string. ++ +If omitted, the default is space `" "`, Unicode U+0020. + +=== Return Value +A string representing the input string with trailing characters added. + +* If the specified size is smaller than the length of the input string, the input string is truncated and no padding is added. +* If the specified size is larger than the length of the input string, but shorter than the length of the input string plus the padding characters, the padding characters are truncated. +* If the specified size is greater than the length of the input string plus the padding characters, the padding characters are repeated in order until the specified size is reached. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_RPAD("SQL++ is awesome", 20) AS implicit_padding, + MB_RPAD("SQL++ is awesome", 20, "🙂!") AS repeated_padding, + MB_RPAD("SQL++ is awesome", 20, "123456789") AS truncate_padding, + MB_RPAD("SQL++ is awesome", 5, "123456789") AS truncate_string; +---- + +.Result +[source,json] +---- +[ + { + "implicit_padding": "SQL++ is awesome ", + "repeated_padding": "SQL++ is awesome🙂!🙂!", // <.> + "truncate_padding": "SQL++ is awesome1234", + "truncate_string": "SQL++" + } +] +---- + +<.> The emoji counts as a single character when calculating the size. +==== + +[[fn-mb-substr,MB_SUBSTR()]] +== MB_SUBSTR(in_str, start_pos [, length]) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Returns the substring (of given length) counting forward from the provided position. +The position is zero-based -- that is, the first position is 0. +If position is negative, it is counted from the end of the string; -1 is the last position in the string. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to extract the substring from. + +start_pos:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the start position of the substring. + +length:: [Optional; default is to capture to the end of the string] ++ +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the length of the substring to extract. + +=== Return Value +A string representing the substring extracted from the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_SUBSTR("🙂 SQL++ is awesome", 11) as rest_of_string, + MB_SUBSTR("🙂 SQL++ is awesome", 11, 1) as single_letter, + MB_SUBSTR("🙂 SQL++ is awesome", 0, 10) as ten_from_start; +---- + +.Result +[source,json] +---- +[ + { + "rest_of_string": "awesome", + "single_letter": "a", + "ten_from_start": "🙂 SQL++ is" + } +] +---- + +The emoji counts as a single character for the starting position and the substring length. +==== + +[[fn-mb-substr1,MB_SUBSTR1()]] +== MB_SUBSTR1(in_str, start_pos [, length]) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Returns the substring (of given length) counting forward from the provided position. +The position is one-based -- that is, the first position is 1. +If position is negative, it is counted from the end of the string; 0 is the last position in the string. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to extract the substring from. + +start_pos:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the start position of the substring. + +length:: [Optional; default is to capture to the end of the string] ++ +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the length of the substring to extract. + +=== Return Value +A string representing the substring extracted from the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_SUBSTR1("🙂 SQL++ is awesome", 12) as rest_of_string, + MB_SUBSTR1("🙂 SQL++ is awesome", 12, 1) as single_letter, + MB_SUBSTR1("🙂 SQL++ is awesome", 0, 10) as ten_from_start; +---- + +.Result +[source,json] +---- +[ + { + "rest_of_string": "awesome", + "single_letter": "a", + "ten_from_start": "🙂 SQL++ is" + } +] +---- + +The emoji counts as a single character for the starting position and the substring length. +==== + +[[fn-mb-pos,MB_POS()]] +== MB_POS(in_str, search_str) + +Alias for <>. + +[[fn-mb-pos1,MB_POS1()]] +== MB_POS1(in_str, search_str) + +Alias for <>. + +[[fn-mb-position,MB_POSITION()]] +== MB_POSITION(in_str, search_str) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Finds the first position of the search string within the string. +This position is zero-based -- that is, the first position is 0. +If the search string does not exist within the input string then the function returns -1. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search within. + +search_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search for. + +=== Return Value +An integer representing the first position of the search string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_POSITION("🙂 SQL++ is awesome", "awesome") as awesome, + MB_POSITION("🙂 SQL++ is awesome", "N1QL") as n1ql, + MB_POSITION("🙂 SQL++ is awesome", "SQL") as sql; +---- + +.Result +[source,json] +---- +[ + { + "awesome": 11, + "n1ql": -1, + "sql": 2 + } +] +---- + +The emoji counts as a single character when calculating the position. +==== + +[[fn-mb-position1,MB_POSITION1()]] +== MB_POSITION1(in_str, search_str) + +This function is available in clusters using Couchbase Server 7.6 or later. + +=== Description +Finds the first position of the search string within the string. +This position is one-based -- that is, the first position is 1. +If the search string does not exist within the input string then the function returns 0. + +This function works with multi-byte characters, not single bytes. +For a variant of this function that works with single bytes, see <>. + +Because this function works with multi-byte characters, it may be slower than its single byte variant. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search within. + +search_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search for. + +=== Return Value +An integer representing the first position of the search string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT MB_POSITION1("🙂 SQL++ is awesome", "awesome") as awesome, + MB_POSITION1("🙂 SQL++ is awesome", "N1QL") as n1ql, + MB_POSITION1("🙂 SQL++ is awesome", "SQL") as sql; +---- + +.Result +[source,json] +---- +[ + { + "awesome": 12, + "n1ql": 0, + "sql": 3 + } +] +---- + +The emoji counts as a single character when calculating the position. +==== + +[[fn-str-pos,POS()]] +== POS(in_str, search_str) + +Alias for <>. + +[[fn-str-pos1,POS1()]] +== POS1(in_str, search_str) + +Alias for <>. + +[[fn-str-position,POSITION()]] +== POSITION(in_str, search_str) + +=== Description +Finds the first position of the search string within the string. +This position is zero-based -- that is, the first position is 0. +If the search string does not exist within the input string then the function returns -1. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search within. + +search_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search for. + +=== Return Value +An integer representing the first position of the search string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT POSITION("🙂 SQL++ is awesome", "awesome") as awesome, + POSITION("🙂 SQL++ is awesome", "N1QL") as n1ql, + POSITION("🙂 SQL++ is awesome", "SQL") as sql; +---- + +.Result +[source,json] +---- +[ + { + "awesome": 14, + "n1ql": -1, + "sql": 5 + } +] +---- + +The emoji counts as four bytes when calculating the position. +==== + +[[fn-str-position1,POSITION1()]] +== POSITION1(in_str, search_str) + +=== Description +Finds the first position of the search string within the string. +This position is one-based -- that is, the first position is 1. +If the search string does not exist within the input string then the function returns 0. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search within. + +search_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search for. + +=== Return Value +An integer representing the first position of the search string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT POSITION1("🙂 SQL++ is awesome", "awesome") as awesome, + POSITION1("🙂 SQL++ is awesome", "N1QL") as n1ql, + POSITION1("🙂 SQL++ is awesome", "SQL") as sql; +---- + +.Result +[source,json] +---- +[ + { + "awesome": 15, + "n1ql": 0, + "sql": 6 + } +] +---- + +The emoji counts as four bytes when calculating the position. +==== + +[[fn-str-repeat,REPEAT()]] +== REPEAT(in_str, n) + +=== Description +Creates a new string which is the input string repeated the specified number of times. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to repeat. + +n:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the number of times to repeat the string. + +=== Return Value +A string representing the string generated by repeating the input string. + +=== Limitations +It is possible to generate very large strings using this function. +In some cases the query engine may be unable to process all of these and cause excessive resource consumption. +It is therefore recommended that you first validate the inputs to this function to ensure that the generated result is a reasonable size. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT REPEAT("SQL++", 0) as empty_string, + REPEAT("SQL++", 3) as repeat_3; +---- + +.Result +[source,json] +---- +[ + { + "empty_string": "", + "repeat_3": "SQL++SQL++SQL++" + } +] +---- +==== + +[[fn-str-replace,REPLACE()]] +== REPLACE(in_str, search_str, replace [, n ]) + +=== Description +Replaces occurrences of a given substring in an input string. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to search for replacements in. + +search_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to replace. + +replace:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to replace the search string with. + +n:: [Optional; default is all instances of the search string are replaced] ++ +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, which represents the number of instances of the search string to replace. +If a negative value is specified then all instances of the search string are replaced. + +=== Return Value +A string representing the input string with the specified substring replaced. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT REPLACE("SQL SQL SQL", "L", "L++", -2) as negative_n, + REPLACE("SQL SQL SQL", "L", "L++", 2) as replace_2, + REPLACE("SQL SQL SQL", "L", "L++") as replace_all; +---- + +.Result +[source,json] +---- +[ + { + "negative_n": "SQL++ SQL++ SQL++", + "replace_2": "SQL++ SQL++ SQL", + "replace_all": "SQL++ SQL++ SQL++" + } +] +---- +==== + +[[fn-str-reverse,REVERSE()]] +== REVERSE(in_str) + +=== Description +Reverses the order of the characters in a given string. +That is, the first character becomes the last character and the last character becomes the first character, and so on. +Among other things, you can use this function to test whether or not a string is a palindrome. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to reverse. + +=== Return Value +A string representing the input string with its characters reversed. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT REVERSE("SQL++ is awesome") as sqlpp, + REVERSE("racecar") as palindrome; +---- + +.Result +[source,json] +---- +[ + { + "sqlpp": "emosewa si ++LQS", + "palindrome": "racecar" + } +] +---- +==== + +[[fn-str-rpad,RPAD()]] +== RPAD(in_str, size [, char]) + +=== Description +Pads a string with trailing characters. +The function adds characters to the end of the string to pad the string to a specified length. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to add the trailing characters to. + +size:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that specifies the desired length of the result string. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to add to the input string. ++ +If omitted, the default is space `" "`, Unicode U+0020. + +=== Return Value +A string representing the input string with trailing characters added. + +* If the specified size is smaller than the length of the input string, the input string is truncated and no padding is added. +* If the specified size is larger than the length of the input string, but shorter than the length of the input string plus the padding characters, the padding characters are truncated. +* If the specified size is greater than the length of the input string plus the padding characters, the padding characters are repeated in order until the specified size is reached. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT RPAD("SQL++ is awesome", 20) AS implicit_padding, + RPAD("SQL++ is awesome", 20, "🙂!") AS repeated_padding, + RPAD("SQL++ is awesome", 20, "123456789") AS truncate_padding, + RPAD("SQL++ is awesome", 5, "123456789") AS truncate_string; +---- + +.Result +[source,json] +---- +[ + { + "implicit_padding": "SQL++ is awesome ", + "repeated_padding": "SQL++ is awesome🙂", // <.> + "truncate_padding": "SQL++ is awesome1234", + "truncate_string": "SQL++" + } +] +---- + +<.> The emoji counts as four bytes when calculating the size. +==== + +[[fn-str-rtrim,RTRIM()]] +== RTRIM(in_str [, char]) + +=== Description +Removes all trailing characters from a string. +The function removes all consecutive characters from the end of the string that match the specified characters and stops when it encounters a character that does not match any of the specified characters. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to remove trailing characters from. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to trim from the input string. +Each character in this string is trimmed from the input string -- you don't need to delimit the characters to trim. +For example, specifying a character value of `"abc"` trims the characters `"a"`, `"b"` and `"c"` from the start of the string. ++ +If omitted, the default is whitespace: space `" "`, tab `"\t"`, newline `"\n"`, formfeed `"\f"`, or carriage return `"\r"`. + +=== Return Value +A string representing the input string with its trailing characters removed. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT RTRIM("SQL++ is awesome...", ".") as dots, + RTRIM("SQL++ is awesome ", " ") as explicit_spaces, + RTRIM("SQL++ is awesome \t") as implicit_spaces, + RTRIM("SQL++ is awesome") as no_dots; +---- + +.Result +[source,json] +---- +[ + { + "dots": "SQL++ is awesome", + "explicit_spaces": "SQL++ is awesome", + "implicit_spaces": "SQL++ is awesome", + "no_dots": "SQL++ is awesome" + } +] +---- +==== + +[[fn-str-split,SPLIT()]] +== SPLIT(in_str [, in_substr]) + +=== Description +Splits the string into an array of substrings, based on the specified separator string. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to split. + +in_substr:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the substring to split the input string on. + +=== Return Value +An array of strings containing the strings created by splitting the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT SPLIT("SQL++ is awesome", " ") as explicit_spaces, + SPLIT("SQL++ is awesome") as implicit_spaces, + SPLIT("SQL++ is awesome", "is") as split_is; +---- + +.Result +[source,json] +---- +[ + { + "explicit_spaces": [ + "SQL++", + "is", + "awesome" + ], + "implicit_spaces": [ + "SQL++", + "is", + "awesome" + ], + "split_is": [ + "SQL++ ", + " awesome" + ] + } +] +---- +==== + +[[fn-str-substr,SUBSTR()]] +== SUBSTR(in_str, start_pos [, length]) + +=== Description +Returns the substring (of given length) counting forward from the provided position. +The position is zero-based -- that is, the first position is 0. +If position is negative, it is counted from the end of the string; -1 is the last position in the string. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to extract the substring from. + +start_pos:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the start position of the substring. + +length:: [Optional; default is to capture to the end of the string] ++ +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the length of the substring to extract. + +=== Return Value +A string representing the substring extracted from the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT SUBSTR("🙂 SQL++ is awesome", 11) as rest_of_string, + SUBSTR("🙂 SQL++ is awesome", 11, 1) as single_letter, + SUBSTR("🙂 SQL++ is awesome", 0, 10) as ten_from_start; +---- + +.Result +[source,json] +---- +[ + { + "rest_of_string": "is awesome", + "single_letter": "i", + "ten_from_start": "🙂 SQL++" + } +] +---- + +The emoji counts as four bytes for the starting position and the substring length. +==== + +[[fn-str-substr1,SUBSTR1()]] +== SUBSTR1(in_str, start_pos [, length]) + +=== Description +Returns the substring (of given length) counting forward from the provided position. +The position is one-based -- that is, the first position is 1. +If position is negative, it is counted from the end of the string; 0 is the last position in the string. + +This function works with single bytes, not multi-byte characters. +For a variant of this function that works with multi-byte characters, see <>. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to extract the substring from. + +start_pos:: An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the start position of the substring. + +length:: [Optional; default is to capture to the end of the string] ++ +An integer, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to an integer, that is the length of the substring to extract. + +=== Return Value +A string representing the substring extracted from the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT SUBSTR1("🙂 SQL++ is awesome", 12) as rest_of_string, + SUBSTR1("🙂 SQL++ is awesome", 12, 1) as single_letter, + SUBSTR1("🙂 SQL++ is awesome", 0, 10) as ten_from_start; +---- + +.Result +[source,json] +---- +[ + { + "rest_of_string": "is awesome", + "single_letter": "i", + "ten_from_start": "🙂 SQL++" + } +] +---- + +The emoji counts as four bytes for the starting position and the substring length. +==== + +[[fn-str-suffixes,SUFFIXES()]] +== SUFFIXES(in_str) + +=== Description +Generates an array of all the suffixes of the input string. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to generate the suffixes of. + +=== Return Value +An array of strings containing all of the suffixes of the input string. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT SUFFIXES("SQL++ is awesome") as sqlpp; +---- + +.Result +[source,json] +---- +[ + { + "sqlpp": [ + "SQL++ is awesome", + "QL++ is awesome", + "L++ is awesome", + "++ is awesome", + "+ is awesome", + " is awesome", + "is awesome", + "s awesome", + " awesome", + "awesome", + "wesome", + "esome", + "some", + "ome", + "me", + "e" + ] + } +] +---- +==== + +The following example uses the `SUFFIXES()` function to index and query the airport names when a partial airport name is given. + +==== +include::ROOT:partial$query-context.adoc[tag=example] + +.Query +[source,sqlpp] +---- +CREATE INDEX autocomplete_airport_name +ON airport ( DISTINCT ARRAY array_element FOR array_element +IN SUFFIXES(LOWER(airportname)) END ); +---- + +.Query +[source,sqlpp] +---- +SELECT airportname +FROM airport +WHERE ANY array_element +IN SUFFIXES(LOWER(airportname)) SATISFIES array_element LIKE 'washing%' END; +---- + +.Result +[source,json] +---- +[ + { + "airportname": "Washington Dulles Intl" + }, + { + "airportname": "Baltimore Washington Intl" + }, + { + "airportname": "Ronald Reagan Washington Natl" + }, + { + "airportname": "Washington Union Station" + } +] +---- +==== + +This https://dzone.com/articles/a-couchbase-index-technique-for-like-predicates-wi[blog^] provides more information about this example. + +[[fn-str-title,TITLE()]] +== TITLE(in_str) + +Alias for <>. + +[#fn-str-token] +include::partial$n1ql-language-reference/fun-token.adoc[] + +[[fn-str-trim,TRIM()]] +== TRIM(in_str [, char]) + +=== Description +Removes all leading and trailing characters from a string. +The function removes all consecutive characters from the beginning and end of the string that match the specified characters and stops when it encounters a character that does not match any of the specified characters. +This function is equivalent to calling <> and <> successively. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to remove trailing and leading characters from. + +char:: +[Optional] A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that represents the characters to trim from the input string. +Each character in this string is trimmed from the input string -- you don't need to delimit the characters to trim. +For example, specifying a character value of `"abc"` trims the characters `"a"`, `"b"` and `"c"` from the start of the string. ++ +If omitted, the default is whitespace: space `" "`, tab `"\t"`, newline `"\n"`, formfeed `"\f"`, or carriage return `"\r"`. + +=== Return Value +A string representing the input string with trailing and leading characters removed. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT TRIM("...SQL++ is awesome...", ".") as dots, + TRIM(" SQL++ is awesome ", " ") as explicit_spaces, + TRIM("\t SQL++ is awesome ") as implicit_spaces, + TRIM("SQL++ is awesome") as no_dots; +---- + +.Result +[source,json] +---- +[ + { + "dots": "SQL++ is awesome", + "explicit_spaces": "SQL++ is awesome", + "implicit_spaces": "SQL++ is awesome", + "no_dots": "SQL++ is awesome" + } +] +---- +==== + +[[fn-str-upper,UPPER()]] +== UPPER(in_str) + +=== Description +Converts all characters in the input string to upper case. + +=== Arguments +in_str:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to convert to upper case. + +=== Return Value +A string representing the input string converted to upper case. + +=== Examples +==== +.Query +[source,sqlpp] +---- +SELECT UPPER("SQL++ is awesome") as sqlpp; +---- + +.Result +[source,json] +---- +{ + "results": [ + { + "sqlpp": "SQL++ IS AWESOME" + } + ] +} +---- +==== + +[[fn-str-urldecode,URLDECODE()]] +== URLDECODE(encoded_string) + +=== Description +Decodes the URL-encoded input string and returns the resulting plain string. + +=== Arguments +encoded_string:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to URL-decode. + +=== Return Value +The input string, with any percent encoding replaced by reserved characters. + +If the input argument is MISSING, returns MISSING. +If the input argument is non-string, or if the argument is a string containing a single percent character `%`, returns NULL. + +=== Example +==== +.Query +[source,sqlpp] +---- +SELECT URLDECODE("SELECT%20name%20FROM%20%60travel-sample%60.inventory.hotel%20LIMIT%201%3B") AS decoded; +---- + +.Result +[source,json] +---- +[ + { + "decoded": "SELECT name FROM `travel-sample`.inventory.hotel LIMIT 1;" + } +] +---- +==== + +[[fn-str-urlencode,URLENCODE()]] +== URLENCODE(plain_string) + +=== Description +Returns the input string encoded for use in a URL. + +=== Arguments +plain_string:: A string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is the string to URL-encode. + +=== Return Value +The input string, with any reserved characters replaced by percent encoding. + +If the input argument is MISSING, returns MISSING. +If the input argument is non-string, returns NULL. + +=== Example +.Query +==== +[source,sqlpp] +---- +SELECT URLENCODE("SELECT name FROM `travel-sample`.inventory.hotel LIMIT 1;") AS encoded; +---- + +.Result +[source,json] +---- +[ + { + "encoded": "SELECT%20name%20FROM%20%60travel-sample%60.inventory.hotel%20LIMIT%201%3B" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/stringops.adoc b/modules/n1ql/pages/n1ql-language-reference/stringops.adoc new file mode 100644 index 000000000..556a92ef8 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/stringops.adoc @@ -0,0 +1,64 @@ += String Operators +:description: {sqlpp} provides the concatenation string operator. +:page-topic-type: reference +:imagesdir: ../../assets/images + +{description} + +== Concatenation + +The concatenation operator joins two strings. +The result of the concatenation operator is also a string. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=concatenation-term] +---- + +image::n1ql-language-reference/concatenation-term.png["Syntax diagram", align=left] + +=== Example + +The following example shows concatenation of two strings. + +==== +.Query +[source,sqlpp] +---- +SELECT fname || " " || lname AS full_name + FROM tutorial +---- + +.Result +[source,json] +---- + { + "results": [ + { + "full_name": "Dave Smith" + }, + { + "full_name": "Earl Johnson" + }, + { + "full_name": "Fred Jackson" + }, + { + "full_name": "Harry Jackson" + }, + { + "full_name": "Ian Taylor" + }, + { + "full_name": "Jane Edwards" + } + ] +} +---- +==== + +== Related Links + +Refer to xref:n1ql:n1ql-language-reference/comparisonops.adoc[Comparison Operators] for string comparisons. \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/subqueries.adoc b/modules/n1ql/pages/n1ql-language-reference/subqueries.adoc new file mode 100644 index 000000000..7dc273370 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/subqueries.adoc @@ -0,0 +1,711 @@ += Subqueries +:description: In {sqlpp}, a subquery is a SELECT query that is a constituent part of another {sqlpp} query or subquery. +:page-topic-type: reference +:imagesdir: ../../assets/images + +[abstract] +{description} + +Using subqueries, you can create multiple levels of nesting of queries. +The outer levels of queries are called outer or parent queries, and inner level subqueries are called inner or child queries, or simply subqueries. + +.Examples on this Page +**** +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=subquery-expr] +---- + +image::n1ql-language-reference/subquery-expr.png["Syntax diagram", align=left] + +* A subquery in {sqlpp} is limited to a xref:n1ql-language-reference/select-syntax.adoc[SELECT] query, whereas the outermost parent query can be any DML statement such as SELECT, INSERT, UPDATE, DELETE or MERGE. +* Subquery *must* be enclosed in parenthesis. +* When subquery is used in `FROM` clause, it must be aliased. +* Subqueries are {sqlpp} expressions and {sqlpp} evaluates them like any other {sqlpp} xref:n1ql-language-reference/index.adoc#N1QL_Expressions[language expressions]. +When an expression is contained in a {sqlpp} statement, the expression is evaluated once for every input document to the statement, and same applies to a subquery-expression -- the inner SELECT or subquery is executed once for every input document considered in the outer query. +* A subquery expression returns an array every time it is evaluated, and the array contains the results of the inner SELECT subquery. + +== Subqueries in DML Statement Clauses + +A subquery can occur as part of various clauses of the parent query where generic {sqlpp} expressions can be used. +For instance, a SELECT statement can have a subquery in the projection list, WHERE clause, FROM clause, LET clause, and GROUP BY clause. +Similarly, an UPDATE, INSERT, DELETE can have a subquery in the WHERE clause. +For example, consider the following query which finds all the cities with landmarks that have airports. + +[#Q1] +==== +.Q1 +[source,sqlpp] +---- +include::example$n1ql-language-reference/subquery-1.n1ql[] +---- + +.Results +[source,json] +---- +[ + { + "city": "Abbeville" + }, + { + "city": "Avignon" + }.. +] +---- +==== + +In the above example, the subquery is used as a part of WHERE condition of the parent query and it returns an array of cities that have airports. + +Note that the IN or WITHIN predicate needs an array on right-side expression as the subquery evaluates to. +Further, the usage of keyword `RAW` in the subquery projection ensures just the `city` attribute values in the result without JSON wrapping. +The outer query browses through each of the landmark cities and returns the city name if it is in the array of cities returned by the inner subquery. + +When subquery is used in the FROM clause, that must be aliased, to be able to access and refer to the results documents of the subquery. +In the following example <>, the subquery is named as `t1`, and it returns the aggregated value of airport names by city and country. +The outer query further processes the result of the subquery to find total number of airports by country where each city has more than 5 airports. + +[#Q2] +==== +.Q2 +[source,sqlpp] +---- +SELECT t1.country, array_agg(t1.city), sum(t1.city_cnt) as apnum +FROM (SELECT city, city_cnt, array_agg(airportname) as apnames, country + FROM airport + GROUP BY city, country LETTING city_cnt = count(city) ) AS t1 +WHERE t1.city_cnt > 5 +GROUP BY t1.country; +---- + +.Results +[source,json] +---- +[ + { + "$1": [ + "Paris" + ], + "apnum": 9, + "country": "France" + }, + { + "$1": [ + "London" + ], + "apnum": 13, + "country": "United Kingdom" + }, + { + "$1": [ + "Houston", + "New York", + "San Diego" + ], + "apnum": 22, + "country": "United States" + } +] +---- +==== + +For more examples, see the <> section. + +[#subquery-n1ql-exp] +== Subqueries in {sqlpp} Expressions + +Subqueries can appear as independent SELECT queries or can be combined as a constituent part of other {sqlpp} language expressions. + +For example, in the above queries <> and <>, the subquery is a full independent SELECT query. +In the following example <>, the subquery is part of a {sqlpp} expression. + +[#Q3] +==== +.Q3 +[source,sqlpp] +---- +SELECT array_max((SELECT count(city) as cnt + FROM airport + GROUP BY city)[*].cnt); +---- + +.Results +[source,json] +---- +[ + { + "$1": 14 + } +] +---- +==== + +In this example, the subquery is wrapped in a parenthesis ( ) and it occurs as part of the expression `[*].cnt` which treats the result of the subquery as an array of JSON documents (with one attribute `cnt`) and extracts the `cnt` values from all the subquery result array elements. +Finally, the `array_max()` function is applied to this to get the maximum number of airports in any of the cities. + +[#section_onz_3tj_mz] +== Variables in Scope of a Subquery + +The scope of subquery is defined as the set of names, identifiers, and variables that are accessible to the subquery. +Variables include all keyspace names, aliases, LET or LETTING variables that can be referenced by the subquery. +For a multilevel nested subquery, the scope includes scope of the subquery and all the scopes of its parent queries. + +A subquery cannot access variables from its sibling subqueries or its parents’ sibling subqueries. +For example, in the following nested query structure, the subquery SQ13 can only access the variables from SQ13, SQ1, and Q0, but not from SQ12, or SQ2. + +---- +Q0: SELECT ... + (SELECT .. + (SELECT ...) AS SQ12 + (SELECT ...) AS SQ13 ) AS SQ1 + (SELECT ... + (SELECT ...) AS SQ21 + (SELECT ...) AS SQ22 ) AS SQ2 +---- + +Note that the keyspace name identifiers themselves are NOT variables, whereas any aliases of the keyspace name identifiers are variables in the scope. +For example, in the above query <>, the keyspace identifier `landmark` in the outer query is not considered a variable for the subquery. +In fact, that is the reason the subquery can also use the same keyspace name independently and still be a non-correlated subquery. +However, the alias `t1` defined in the outer query is considered a variable in scope for the subquery. + +The following example <> is a correlated subquery that uses the variable `t1` from the outer query: + +[#Q4] +==== +.Q4: Find the landmarks that are named with corresponding city name +[source,sqlpp] +---- +SELECT t1.city, t1.name +FROM landmark t1 +WHERE t1.city IN SPLIT((SELECT RAW t2.name + FROM t1 AS t2)[0]); +---- + +.Results +[source,json] +---- +[ + { + "city": "Aberdour", + "name": "Aberdour Castle" + }, + { + "city": "Aberdour", + "name": "Aberdour Railway Station" + }, + { + "city": "Aberdulais", + "name": "Aberdulais Falls and Tin Works" + } + // ... +] +---- +==== + +This above example <> uses the alias `t1` from outer query in the FROM clause of subquery. +The subquery aliases `t1` to `t2` to avoid conflict in same variable name `t1` being present in both outer and inner queries scope. +The reference to `t2` in the subquery is actually referring to the same document from `landmark` that is being processed as `t1` in the outer query. +In other words, the same query can be simply rewritten (without using subqueries) as follows: + +[#Q4A] +==== +.Q4A +[source,sqlpp] +---- +SELECT t1.city, t1.name +FROM landmark t1 +WHERE t1.city IN SPLIT(t1.name); +---- + +.Results +[source,json] +---- +[ + { + "city": "Aberdour", + "name": "Aberdour Castle" + }, + { + "city": "Aberdour", + "name": "Aberdour Railway Station" + }, + { + "city": "Aberdulais", + "name": "Aberdulais Falls and Tin Works" + } + // ... +] +---- +==== + +Typically, subqueries may refer to any variables and aliases available in the scope to build correlated subqueries and to perform subqueries specific to some context of outer query. +See xref:n1ql-language-reference/correlated-subqueries.adoc[Correlated Subqueries] for more details and xref:n1ql-language-reference/subquery-examples.adoc[Examples]. + +[#from-clause] +== FROM clause in Subqueries + +=== Keyspace Identifier versus Expression + +As described in the xref:n1ql-language-reference/from.adoc[FROM clause], the from-term can be a keyspace name or identifier or a {sqlpp} expression: + +* Keyspace identifiers are independent sources of data for a query. +* {sqlpp} xref:n1ql-language-reference/index.adoc#N1QL_Expressions[expressions] can be constructed using various {sqlpp} language constructs including subqueries. + ** Constant expressions are independent sources of data for a query. + ** Variable expressions depend on variables in scope and are evaluated to resolve as input data for the query. +These are applicable to subqueries. + ** This applies irrespective of whether it is a simple identifier such as `alias`, `var` or a nested path identifier such as `keyspace.subdoc1.subdoc2.field`, `alias.subdoc.field`, or `var.subdoc.field`. + +An expression can be a simple identifier or variable such as `alias`, `var` or more complex with various {sqlpp} language constructs. +Either way, {sqlpp} evaluates `from-term` to resolve to keyspace identifiers or expressions as follows: + +* A `from-term` is considered as an expression if it is not a keyspace name identifier. +* If simple identifier can be considered as identifier or expression depending on various factors. +An identifier `var` is considered as an expression if it is variable in scope defined through LET or LETTING, or explicit keyspace alias in parent queries. + +In the following equivalent queries, explicit alias `t` of `airport` or LET variable `x` is treated as an expression and hence a nested path like `t.geo.lat` is allowed in the subquery FROM clause. + +[#Q5A] +==== +.Q5A +[source,sqlpp] +---- +SELECT count(*) FROM airport t +WHERE (SELECT RAW t.geo.alt FROM t t1)[0] > 6000 ; +---- +==== + +[#Q5B] +==== +.Q5B +[source,sqlpp] +---- +SELECT count(*) FROM airport t +WHERE (SELECT RAW alt FROM t.geo.alt)[0] > 6000; +---- +==== + +[#Q5C] +==== +.Q5C +[source,sqlpp] +---- +SELECT count(*) FROM `travel-sample` .inventory.airport t +LET x = t.geo +WHERE (SELECT RAW y.alt FROM x y)[0] > 6000; +---- +==== + +[#Q5D] +==== +.Q5D +[source,sqlpp] +---- +SELECT count(*) FROM airport t +WHERE (SELECT RAW geo.alt FROM t.geo)[0] > 6000; +---- +==== + +=== Implicit Alias + +When explicit alias is not defined, every identifier will have an implicit alias predefined with the same name as the identifier. +Implicit alias of a nested path is defined as the last component in the path. +In above example <>, the implicit alias of the nested path `t.geo` in subquery is `geo`, and in example <> the implicit alias of `t.geo.alt` is `alt`. + +For example, the following example <> has no explicit alias for ``travel-sample``. +So the `airport` used in the subquery FROM clause is considered a keyspace identifier, but not an expression. +That makes the subquery non-correlated by the FROM clause, and the subquery returns all documents from keyspace `airport`. + +[#Q6] +==== +.Q6 +[source,sqlpp] +---- +SELECT array_length((SELECT RAW t1.geo.alt + FROM airport t1)) +FROM airport LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "$1": 1968 + }, + // ... +] +---- +==== + +Contrast Q6 with Q6A below, the subquery is correlated by using the keyspace alias in the FROM clause. +The result is only `1` because the subquery is applicable to only the current document `t` being processed in the parent query. + +[#Q6A] +==== +.Q6A +[source,sqlpp] +---- +SELECT array_length((SELECT RAW t1.geo.alt FROM t t1)) +FROM airport t; +---- + +.Results +[source,json] +---- +[ + { + "$1": 1 + }, + // ... +] +---- +==== + +Further, the subquery is required to alias its `from-term` to avoid conflict with the same identifier in both outer and inner queries. +For example, the following example Q6B shows an error: + +[#Q6B] +==== +.Q6B +[source,sqlpp] +---- +SELECT array_length((SELECT RAW t1.geo.alt + FROM airport)) +FROM airport; +---- + +.Results +[source,json] +---- +[ + { + "code": 4020, + "msg": "Duplicate subquery alias airport", + "query": "SELECT array_length((SELECT RAW t1.geo.alt\nFROM airport))\nFROM airport;" + } +] +---- +==== + +An implicit keyspace alias is not considered as an expression, as in the above example Q6. +However, the nested paths are expressions. +In the following example Q6C, the FROM term has the nested path `airport.geo` as an expression, where `airport` refers to the implicit alias of the keyspace in the parent query. +Hence this is a correlated subquery, and the result is `1` corresponds to the current document in the parent query. + +[#Q6C] +==== +.Q6C +[source,sqlpp] +---- +SELECT array_length((SELECT RAW t1.alt + FROM airport.geo t1)) +FROM airport +LIMIT 1; +---- + +.Results +[source,json] +---- +[ + { + "$1": 1 + } +] +---- +==== + +If the expression does not resolve to any of the variables in scope for the subquery, then that is treated as keyspace identifier and subsequently if the keyspace is not found, an error is raised. +For example, in the following query `hotel` is not defined in the scope and is treated as a new keyspace identifier. + +[#Q7] +==== +.Q7 +[source,sqlpp] +---- +SELECT * FROM landmark t1 +WHERE t1.city IN (SELECT RAW city + FROM hotel + LIMIT 3 + ); +---- + +.Results +[source,json] +---- +[ + { + "t1": { + "activity": "see", + "address": "Prince Arthur Road, ME4 4UG", + "alt": null, + "city": "Gillingham", + "content": "Adult - £6.99 for an Adult ticket that allows you to come back for further visits within a year (children's and concessionary tickets also available). Museum on military engineering and the history of the British Empire. A quite extensive collection that takes about half a day to see. Of most interest to fans of British and military history or civil engineering. The outside collection of tank mounted bridges etc can be seen for free. There is also an extensive series of themed special event weekends, admission to which is included in the cost of the annual ticket.", + "country": "United Kingdom", + "directions": null, + "email": null, + "geo": { + "accuracy": "RANGE_INTERPOLATED", + "lat": 51.39184, + "lon": 0.53616 + }, + "hours": "Tues - Fri 9.00am to 5.00pm, Sat - Sun 11.30am - 5.00pm", + "id": 10019, + "image": null, + "name": "Royal Engineers Museum", + "phone": "+44 1634 822839", + "price": null, + "state": null, + "title": "Gillingham (Kent)", + "tollfree": null, + "type": "landmark", + "url": "http://www.remuseum.org.uk" + } + } + // ... +] +---- +==== + +[[nested-path-expr]] +=== Nested Path Expressions in Subqueries + +As mentioned in the xref:n1ql-language-reference/from.adoc[FROM clause], the `from-term` of both parent and subqueries allow nested path expressions over constants and subqueries. +However, only subqueries allow variable expressions (including paths), that are referenced through any <> of the subquery. +This is very powerful for language expressibility, simplicity and flexibility to {sqlpp} queries. +Especially, when combined with subqueries, nested path expressions over variables extend full power of {sqlpp} syntax to array attributes/sub-documents without losing the structure of the array elements in results, or requiring tricky processing (with UNNEST, GROUP BY, ORDER BY and so). +See the <> below. + +NOTE: The usage of nested paths over keyspace identifiers is NOT allowed in the from-terms, and it results in a syntax error. +Nested paths are always considered expressions in {sqlpp}. + +[#section_cjh_pck_mz] +== Examples + +.{blank} +==== +The following query is valid because the nested path in the subquery is based on the explicit alias variable `k1` in scope. + +[source,sqlpp] +---- +SELECT * FROM keyspace1 AS k1 +WHERE (SELECT … FROM k1.subdoc1.subdoc2.field3 …); +---- +==== + +.{blank} +==== +The following query is invalid and raises an error because the nested path is in the outermost query: + +[source,sqlpp] +---- +SELECT * FROM keyspace1.subdoc1.subdoc2.field3 … ; +---- + +The subquery is based on the keyspace identifiers. +Note that, the outer query has explicit alias defined, and hence the keyspace1/keyspace2 in subquery `from-term` are treated as identifiers. + +[source,sqlpp] +---- +SELECT * FROM keyspace1 AS k1 +WHERE (SELECT … FROM keyspace1.subdoc1.field3 …); + +SELECT * FROM keyspace1 AS k1 +WHERE (SELECT … FROM keyspace2.subdoc2 …); +---- +==== + +.{blank} +==== +The following example shows usage of nested path over subquery expression. + +[source,sqlpp] +---- +SELECT x.alt +FROM (SELECT geo from airport + )[*].geo AS x +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "alt": 12 + }, + { + "alt": 295 + } +] +---- +==== + +.{blank} +==== +The following example shows usage of nested path over constant expression. + +[source,sqlpp] +---- +SELECT x +FROM [{"a" : 1, "b" : {"c" : 2}}, + {"a" : 3, "b" : {"d" : 4}}][*].b AS x +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "x": { + "c": 2 + } + }, + { + "x": { + "d": 4 + } + } +] +---- +==== + +.{blank} +==== +The following two queries show valid and invalid examples with the `airport` collection. +Note the nested paths used in the FROM clause of the subquery. + +.Q8: Find airports that are at altitudes more than 4000ft +[source#Q8,n1ql] +---- +SELECT t1.city, t1.geo.alt +FROM airport t1 +WHERE (SELECT RAW t2.alt + FROM airport.geo t2)[0] > 4000; +---- + +.Results +[source,json] +---- +[ + { + "code": 3000, + "msg": "Ambiguous reference to field travel-sample.", + "query_from_user": "SELECT t1.city, t1.geo.alt\nFROM `travel-sample` t1\nWHERE t1.type = \"airport\" AND \n(SELECT RAW t2.alt \n FROM `travel-sample`.geo t2)[0] > 4000;" + } +] +---- + +.Q8A: Q8 rewritten to use nested path using outer query variable t1 +[source#Q8A,n1ql] +---- +SELECT t1.city, t1.geo.alt +FROM airport t1 +WHERE (SELECT RAW t2.alt FROM t1.geo t2)[0] > 4000; +---- + +.Results +[source,json] +---- +[ + { + "alt": 6537, + "city": "Grants" + }, + { + "alt": 5045, + "city": "Prescott" + }, + // ... +] +---- +==== + +.{blank} +==== +The following query demonstrates the power of using nested path expressions in xref:n1ql-language-reference/correlated-subqueries.adoc[correlated subqueries] over the array subdocument `hotel.reviews`. +The query Q9 finds the top 10 hotels and number of reviewers which have Overall rating at least 4 and rated by minimum 6 people. + +.Q9 +[source#Q9,n1ql] +---- +SELECT name, cnt_reviewers +FROM hotel AS t +LET cnt_reviewers = (SELECT raw count(*) + FROM t.reviews AS s + WHERE s.ratings.Overall >= 4)[0] +WHERE cnt_reviewers >= 6 +ORDER BY cnt_reviewers DESC +LIMIT 10; +---- + +.Results +[source,json] +---- +[ + { + "cnt_reviewers": 9, + "name": "Holiday Inn London Kensington Forum" + }, + { + "cnt_reviewers": 9, + "name": "Campanile" + }, + { + "cnt_reviewers": 9, + "name": "Drop in Chalets" + }, + { + "cnt_reviewers": 9, + "name": "Cadogan Hotel" + }, + { + "cnt_reviewers": 9, + "name": "Negresco" + }, + { + "cnt_reviewers": 9, + "name": "Suites at Fisherman's Wharf" + }, + { + "cnt_reviewers": 9, + "name": "Wyndham Parc 55 Hotel" + }, + { + "cnt_reviewers": 8, + "name": "Lochmaddy Hotel" + }, + { + "cnt_reviewers": 8, + "name": "Kensington West" + }, + { + "cnt_reviewers": 8, + "name": "Ibis Hotel Stratford" + } +] +---- + +.Q9A +[source#Q9A,n1ql] +---- +SELECT name, cnt_reviewers +FROM hotel AS t +LET cnt_reviewers = (SELECT raw count(*) + FROM hotel tmp + USE KEYS meta(t).id + UNNEST tmp.reviews s + WHERE s.ratings.Overall >= 4)[0] +WHERE cnt_reviewers >= 6 +ORDER BY cnt_reviewers DESC +LIMIT 10; +---- + +The above query Q9A is an equivalent of query <> that does not use nested paths in the subquery FROM clause. +Therefore, it requires a USE KEYS clause on the same document as in the outer query, that is `meta(t).id` where `t` refers to the outer query document. +Nested paths cannot be used in the FROM clause and hence UNNEST is used on nested structures. +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/subquery-examples.adoc b/modules/n1ql/pages/n1ql-language-reference/subquery-examples.adoc new file mode 100644 index 000000000..9ded5e9a2 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/subquery-examples.adoc @@ -0,0 +1,480 @@ += Examples +:page-topic-type: reference + +.Examples on this Page +**** +include::ROOT:partial$query-context.adoc[tag=statement] +**** + +WARNING: Please note that some of the examples below will alter the data in your sample buckets. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +== Example 1 + +Here is an example of aggregating using correlated subquery expression in projection. +This query finds the top 3 overall rated hotels. +The subquery in the projection finds the average overall rating across all rating of the given hotel document `t`. +Note that the subquery uses nested paths in the FROM clause. + +==== +[source,sqlpp] +---- +SELECT name, (SELECT raw avg(s.ratings.Overall) + FROM t.reviews as s)[0] AS overall_avg_rating +FROM hotel AS t +ORDER BY overall_avg_rating DESC +LIMIT 3; +---- + +.Results +[source,json] +---- +[ + { + "name": "Culloden House Hotel", + }, + { + "name": "The Bulls Head", + "overall_avg_rating": 5 + }, + { + "name": "La Pradella", + "overall_avg_rating": 5 + } +] +---- +==== + +== Example 2 + +The following query shows how to use correlated subquery expression in projection with predicates and sorted results on specific nested fields. +This query finds flight schedules starting after 10PM from SFO airport. + +==== +[source,sqlpp] +---- +SELECT id, sourceairport, destinationairport, + (SELECT s.* + FROM route.schedule s + WHERE s.utc > "22:00:00" + ORDER BY s.utc) after_10pm +FROM route +WHERE sourceairport = "SFO" +LIMIT 2; +---- + +.Results +[source,json] +---- +[ + { + "after_10pm": [ + { + "day": 2, + "flight": "AI712", + "utc": "23:44:00" + } + ], + "destinationairport": "HKG", + "id": 10624, + "sourceairport": "SFO" + }, + { + "after_10pm": [ + { + "day": 6, + "flight": "AI588", + "utc": "22:14:00" + }, + { + "day": 5, + "flight": "AI886", + "utc": "22:53:00" + }, + { + "day": 1, + "flight": "AI678", + "utc": "23:50:00" + } + ], + "destinationairport": "ICN", + "id": 10625, + "sourceairport": "SFO" + } +] +---- +==== + +== Example 3 + +The following query uses correlated subquery expression as predicate in the WHERE clause, and finds the source airports from which more than 4 flights are scheduled on day 1. + +==== +[source,sqlpp] +---- +SELECT airline, sourceairport +FROM route +WHERE (SELECT raw count(*) + FROM route.schedule as s WHERE s.day = 1)[0] > 4 +LIMIT 3; +---- + +.Results +[source,json] +---- +[ + { + "airline": "AF", + "sourceairport": "TLV" + }, + { + "airline": "AF", + "sourceairport": "TPE" + }, + { + "airline": "AF", + "sourceairport": "TRI" + } +] +---- +==== + +== Example 4 + +The following query finds the top 3 hotels and number of reviewers, which have Overall rating at least 4, and rated by minimum 6 people. +Note that it is a correlated subquery expression in the LET clause, with nested paths (that is `t.ratings`) in the subquery FROM path. + +==== +[source,sqlpp] +---- +SELECT name, cnt_reviewers +FROM hotel AS t +LET cnt_reviewers = (SELECT raw count(*) + FROM t.reviews AS s + WHERE s.ratings.Overall >= 4)[0] +WHERE cnt_reviewers >= 6 +ORDER BY cnt_reviewers DESC +LIMIT 3; +---- + +.Results +[source,json] +---- +[ + { + "cnt_reviewers": 9, + "name": "Negresco" + }, + { + "cnt_reviewers": 9, + "name": "Cadogan Hotel" + }, + { + "cnt_reviewers": 9, + "name": "Holiday Inn London Kensington Forum" + } +] +---- +==== + +== Example 5 + +This example shows usage of subquery expressions in MERGE statement. +This query uses constant expression as the MERGE source data, and updates the vacancy to false for matching documents. +For the sake of demonstrating update operation, this query saves the current value of vacancy to a new attribute old_vacancy. + +==== +[source,sqlpp] +---- +MERGE INTO hotel t USING [{"id":"21728"},{"id":"21730"}] source +ON KEY "hotel_"|| source.id +WHEN MATCHED THEN UPDATE SET t.old_vacancy = t.vacancy, t.vacancy = false +RETURNING meta(t).id, t.old_vacancy, t.vacancy; +---- + +.Results +[source,json] +---- +[ + { + "id": "hotel_21728", + "old_vacancy": false, + "vacancy": false + }, + { + "id": "hotel_21730", + "old_vacancy": true, + "vacancy": false + } +] +---- +==== + +== Example 6 + +Here is an example of LET variable in the FROM clause. + +==== +[source,sqlpp] +---- +SELECT count(*) FROM airport t +LET x = t.geo +WHERE (SELECT RAW y.alt FROM x y)[0] > 6000; +---- + +.Results +[source,json] +---- +[ + { + "$1": 38 + } +] +---- +==== + +== Example 7 + +An example of using same keyspace name in subquery FROM clause that is used in the parent query. + +In this example, the subquery is not correlated with the parent query, so it returns all of the airports in the `airport` collection. + +==== +[source,sqlpp] +---- +SELECT array_length((SELECT RAW t1.geo.alt + FROM airport t1)) +FROM airport LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "$1": 1968 + }, + { + "$1": 1968 + }, + { + "$1": 1968 + }, + { + "$1": 1968 + } +] +---- +==== + +== Example 8 + +An example of using alias name in the subquery FROM clause. + +In this example, the subquery is correlated with the parent query, so it only returns the single airport found by the parent query. + +==== +[source,sqlpp] +---- +SELECT array_length((SELECT RAW t1.geo.alt FROM t t1)) +FROM airport t; +---- + +.Results +[source,json] +---- +[ + { + "$1": 1 + }, + ... +] +---- +==== + +== Example 9 + +A non-correlated subquery with UPDATE. + +==== +[source,sqlpp] +---- +UPDATE airport t1 SET airportname_dup = "high_altitude_" || airportname +WHERE t1.geo.alt IN (SELECT RAW t2.geo.alt + FROM airport t2 + WHERE t2.geo.alt > 6000) +RETURNING t1.airportname_dup; +---- + +.Results +[source,json] +---- +[ + { + "airportname_dup": "high_altitude_Grants Milan Muni" + }, + { + "airportname_dup": "high_altitude_Durango La Plata Co" + }, + { + "airportname_dup": "high_altitude_Black Rock" + }, + ... + { + "airportname_dup": "high_altitude_Colorado Springs East" + } +] +---- +==== + +== Example 10 + +A correlated subquery with UPDATE with nested paths. + +==== +[source,sqlpp] +---- +UPDATE airport t1 +SET airportname_dup = "high_altitude_2 " || airportname +WHERE (SELECT RAW geo.alt + FROM t1.geo + WHERE geo.alt > 6000)[0] = t1.geo.alt +RETURNING t1.airportname_dup; +---- + +.Results +[source,json] +---- +[ + { + "airportname_dup": "high_altitude_2 Grants Milan Muni" + }, + { + "airportname_dup": "high_altitude_2 Durango La Plata Co" + }, + { + "airportname_dup": "high_altitude_2 Black Rock" + }, + ... + { + "airportname_dup": "high_altitude_2 Colorado Springs East" + } +] +---- +==== + +== Example 11 + +The following correlated subquery with UPDATE. +In this example, the subquery filters for 5 rated reviews and sorts them by reviewer name. +The result of the subquery is assigned to a new field `reviews_5star` in the hotel document. + +If you are warned that the query contains no WHERE clause or USE KEYS, choose btn:[Continue]. + +==== +[source,sqlpp] +---- +UPDATE hotel t1 +SET reviews_5star = (SELECT raw t2 + FROM t1.reviews t2 + WHERE t2.ratings.Overall = 5 + ORDER BY t2.author) +LIMIT 1 +RETURNING t1.reviews[*].author; +---- + +.Results +[source,json] +---- +[ + { + "author": [ + "Ozella Sipes", + "Barton Marks" + ] + } +] +---- +==== + +== Example 12 + +A non-correlated subquery with INSERT. + +==== +[source,sqlpp] +---- +INSERT INTO hotel (KEY UUID()) + SELECT x.name, x.city, "landmark_hotels" AS type + FROM hotel x + WHERE x.city WITHIN + ( SELECT DISTINCT t.city + FROM landmark t) + LIMIT 4 +RETURNING *; +---- + +.Results +[source,json] +---- +[ + { + "hotel": { + "city": "Aberdeenshire", + "name": "Castle Hotel", + "type": "landmark_hotels" + } + }, + { + "hotel": { + "city": "Aberdeenshire", + "name": "Two Bears Cottage", + "type": "landmark_hotels" + } + }, + { + "hotel": { + "city": "Agoura Hills", + "name": "Malibu Creek Campground", + "type": "landmark_hotels" + } + }, + { + "hotel": { + "city": "Altrincham", + "name": "Cresta Court Hotel", + "type": "landmark_hotels" + } + } +] +---- +==== + +== Example 13 + +A correlated subquery with DELETE all hotel records which got the minimum overall rating by more than 4 reviewers. + +==== +[source,sqlpp] +---- +DELETE FROM hotel t +WHERE (SELECT RAW count(*) + FROM t.reviews t2 + WHERE t2.ratings.Overall = 1 )[0] > 4 +RETURNING t.name; +---- + +.Results +[source,json] +---- +[ + { + "name": "Beverly Laurel Motor Hotel" + }, + { + "name": "Tan yr Eglwys Cottages" + }, +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/time-series.adoc b/modules/n1ql/pages/n1ql-language-reference/time-series.adoc new file mode 100644 index 000000000..ca81fb54c --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/time-series.adoc @@ -0,0 +1,530 @@ += Store and Process Time Series Data +:page-topic-type: concept +:imagesdir: ../../assets/images +:description: Couchbase Capella can store and process time series data. + +// Links +:url-unix-epoch: https://en.wikipedia.org/wiki/Unix_time +:url-maxint64: https://docs.gtk.org/glib/const.MAXINT64.html +:url-ts-blog: https://blog.couchbase.com + +// Cross-references +:cbimport: xref:connect:cli-import-export.adoc +:collection-manage: xref:cli:cbcli/couchbase-cli-collection-manage.adoc +:import-documents: xref:clusters:data-service/import-data-documents.adoc +:bucket-expiration: xref:server:learn:data/expiration.adoc +:document-expiration: xref:java-sdk:howtos:kv-operations.adoc#document-expiration +:preserve_expiry: xref:n1ql:n1ql-manage/query-settings.adoc#preserve_expiry +:n1ql-language-reference: xref:n1ql-language-reference +:update: {n1ql-language-reference}/update.adoc +:insert: {n1ql-language-reference}/insert.adoc +:timeseries: {n1ql-language-reference}/timeseries.adoc +:upsert: {n1ql-language-reference}/upsert.adoc +:datefun: {n1ql-language-reference}/datefun.adoc + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +Time series data is any data which changes over time. +In the case of data management, it refers to data collected frequently, in regular or irregular intervals, from a device or a process. +The changing data is typically numerical, and changes incrementally. + +IMPORTANT: This feature is only available on clusters using Couchbase Server 7.2 or later. + +[[document-type]] +== Types of Time Series + +A time series may be regular or irregular. + +* In a regular time series, the data points are collected at regular intervals. +For example, stock ticker prices, or climate data. +If no data is available to collect at that time, data can be stored as `null`. ++ +.... +include::attachment$regular-time-series.csv[lines=1..3] +... +.... + +* In an irregular time series, the data points occur at irregular intervals: that is, you do not know in advance when a data point will be collected. +For example, historical earthquake data, or house sales and prices in an area over time. ++ +.... +include::attachment$irregular-time-series.csv[lines=1..6] +... +.... + +[[document-structure]] +== Structure of Time Series Documents + +In Couchbase Capella, time series data must be stored in time series documents with a specific format, which ensures compact storage and quick processing. +Couchbase time series documents have the following general characteristics. + +* All date and time values associated with the time series are stored as integers, representing the number of milliseconds since the {url-unix-epoch}[Unix epoch]. +The maximum date and time is {url-maxint64}[MaxInt64] milliseconds -- that is, `(2^63)-1`, or approximately 292.5 million years. + +* The data values stored at each time point are stored as values in arrays, not as named fields in objects. +If there are multiple data values at each time point, the order of values must be consistent for all time points. + +Each time series document must contain the following fields: + +[options="header", cols="1a,3a,1a"] +|=== +| Default name | Description | Schema + +| **ts_start** + +_Required_ +| The start date and time of the data in this document. +You can use a different name for this field, but you must then specify the path to the field when you query the data. + +The start date and time is usually the same as the first time point in the document. +However, this depends on the data, and your data storage strategy. +For example, if each time series document contains a month's data, then the start date and time may be exactly at the start of the month, rather than the first time point in the document. + +If this field is omitted, the document is ignored by time series queries. +| Integer (milliseconds since the {url-unix-epoch}[Unix epoch]) + +| **ts_end** + +_Required_ +| The end date and time of the data in this document. +You can use a different name for this field, but you must then specify the path to the field when you query the data. + +The end date and time is usually the same as the last time point in the document. +However, this depends on the data, and your data storage strategy. +For example, if each time series document contains a month's data, then the end date and time may be exactly at the end of the month, rather than the last time point in the document. + +If this field is omitted, the document is ignored by time series queries. +| Integer (milliseconds since the {url-unix-epoch}[Unix epoch]) + +| **ts_interval** + +_Required_ for regular time series +| The interval between data points, in milliseconds. +You can use a different name for this field, but you must then specify the path to the field when you query the data. + +If this field is omitted, the document is assumed to contain an irregular time series. +| Integer (milliseconds) + +| **ts_data** + +_Required_ +| The time series data. +This field must be an array. +Each element in the array represents a single time point. + +For a regular time series, each element may be a literal representing a single value at that time point, or a nested array containing multiple values for that time point. + +For an irregular time series, each element must be a nested array. +The first value in the nested array represents the time at that time point, in milliseconds since the {url-unix-epoch}[Unix epoch]. +The other values in the nested array represent the data values at that time point. + +If this field is omitted, the document is ignored by time series queries. +| Array, or array of arrays +|=== + +The document may contain any other fields you require. + +As `ts_data` is usually the largest field, you may consider storing it after other commonly-used fields in the document for faster access. + +TIP: The date-time values in a time series document may represent values smaller than milliseconds, if required. +You are recommended to use milliseconds for easy compatibility with {sqlpp} date and time functions. +If you need to use date-time values smaller than milliseconds, you must use a multiplication factor to use the date-time values with date and time functions. + +=== Examples of Time Series Documents + +.Regular time series data with a single data point +==== +This document contains invented stock ticker data. + +[source,json] +---- +{ + "ticker": "BASE", + "ts_start": 1677730930000, + "ts_end": 1677730939000, + "ts_interval": 1000, + "ts_data": [ 16.30, 16.31, 16.32, 16.33, 16.34, + 16.35, 16.36, 16.37, 16.38, 16.39 ] +} +---- + +Note that the document contains a time series start, a time series end, and a time series interval. +The time series interval is 1,000 milliseconds, which means the time points are 1 second apart. + +Within the time series data, each time point has a single value. +The date and time for each time point is determined by the time series start and the time series interval. +==== + +.Regular time series data with multiple data points +==== +This document contains invented stock ticker data. + +[source,json] +---- +{ + "ticker": "XYZ", + "ts_interval": 86400000, + "ts_start": 1359676800000, + "ts_end": 1362009600000, + "ts_data": [ + [ 27.285, 27.595, 27.24, 27.295 ], + [ 27.64, 27.95, 27.365, 27.61 ], + // ... + [ 27.45, 27.605, 27.395, 27.545 ] + ] +} +---- + +Note that the document contains a time series start, a time series end, and a time series interval. +The time series interval is 86,400,000 milliseconds, which means the time points are 1 day apart. + +Within the time series data, each time point has four values, representing the daily opening, high, low, and closing stock prices. +The order of values must be consistent for each time point. +The date and time for each time point is determined by the time series start and the time series interval. +==== + +.Irregular time series data +==== +This document contains historical house price data for a neighborhood. +footnote:ogl[Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.] + +[source,json] +---- +{ + "ts_start": 631152000000, + "ts_end": 946641600000, + "ts_data": [ + // ... + [867715200000, 69950], + [875664000000, 67000], + [896659200000, 71500], + [899251200000, 73000], + [901929600000, 72000] + ] +} +---- + +Note that the document contains a time series start and end, but no time series interval. + +Within the time series data, for each time point, the first value is a date-time stamp. +The second value is the house price. +==== + +[[storage-strategy]] +== Time Series Data Storage Strategy + +To reduce index sizes and increase performance, store your time series data using the largest possible arrays in the smallest number of documents. + +The optimum size for each time series document depends on the type of queries you need to perform. +If you plan to query the time series data using ranges measured in days, it's most efficient to store the time series data in documents which contain a day's data. +Likewise, if you plan to query the time series data using ranges measured in hours, you should store the time series data in documents which contain an hour's data, and so on. + +To expand on this: if most of your queries use ranges of 2 to 4 hours, storing your time series data in documents which contain a day's data can have an overhead of 80–90% data discard per document. +In this case, it would be more efficient to store the time series data in documents containing 4 hours' data. + +The maximum size of a time series document is 20MB. + +You should also consider data expiration when planning the optimum size for time series documents. +To minimize your storage requirements, you can set the {bucket-expiration}[expiration] for your time series documents. +You can specify expiration at the bucket, collection, or document level, but it applies at the document level -- when a document expires, all the time series data in that document is deleted. + +[[ingestion]] +== Ingesting Time Series Data + +Ingesting time series data into Couchbase is usually a multi-stage process, depending on the format of the original data. + +. Import the raw dataset from a supported format: CSV or JSON. +To do this, you can use the {cbimport}[cbimport] command line tool, the {import-documents}[import] feature in the Couchbase UI, or an SDK data parsing library. + +. When the data is imported, transform the imported data to one or more documents with the <>. +To do this, use an {insert}[INSERT SELECT] query or an SDK insert operation. + +** Convert any dates and times to milliseconds since the {url-unix-epoch}[Unix epoch]. +To do this, use {sqlpp} {datefun}[date-time functions], or date-time functions at the application level. + +** If necessary, set the expiration for the document, according to your data storage strategy. + +[[incremental-ingestion]] +== Incremental Time Series Data + +As more time series data is generated, you can ingest new data incrementally. +You can import the raw data just as you imported the initial data. + +To transform the new data into time series documents, use one of these strategies: + +* If the new data does not overlap the date range of any existing time series documents, import the new data into new time series documents. +To do this, use an {insert}[INSERT SELECT] query or an SDK insert operation, just as you did with the initial data. + +* If the new data falls within the date range of an existing document, update an existing time series document. +There are two ways to do this: + +** Use an {upsert}[UPSERT SELECT] query or an SDK upsert operation to replace an existing time series document. + +** Use an {update}[UPDATE] query or an array-append SDK call using the sub-document API to append the new data to an existing time series document. + +[[indexes]] +== Indexing Time Series Data + +To index time series data, you only need to create an index on the time series documents, not on the nested time series data within the documents. +This ensures that indexes of time series data are lean and efficient. + +If your time series documents are as large as possible, the expiration of time series documents has a minimal impact on index maintenance and index scan. +Conversely, if your time series documents are smaller, index maintenance and scans may be much slower. +For more information, see <>. + +An index on time series documents should include the `ts_end` field and the `ts_start` field, along with any other fields you need to index. + +[[queries]] +== Querying Time Series Data + +To query time series data, Couchbase Capella provides the _TIMESERIES function. +For full details and examples, see {timeseries}[]. + +== Examples + +For these examples, use the following links to download raw time series data to your local system. + +* link:{attachmentsdir}/regular-time-series.csv[regular-time-series.csv, window=_blank] -- invented temperature data +* link:{attachmentsdir}/irregular-time-series.csv[irregular-time-series.csv, window=_blank] -- historical house price data +footnote:ogl[] + +[[ex-import]] +.Import time series data from CSV files +==== +Create a scope for the time series data. + +[source,sqlpp] +---- +CREATE SCOPE `travel-sample`.time IF NOT EXISTS; +---- + +Create collections for the raw time series data within the new scope. + +[source,sqlpp] +---- +CREATE COLLECTION `travel-sample`.time.regular IF NOT EXISTS; +CREATE COLLECTION `travel-sample`.time.irregular IF NOT EXISTS; +---- + +Use the {import-documents}[Import] tool to import the irregular time series data: + +. Go to menu:Data Tools[Import]. +. In the *Import* tab, select *A Single Collection*. +. In the *travel-sample* bucket, select the *time* scope and the *irregular* collection. +. Click btn:[Select a file] and select `irregular-time-series.csv`. +. In *File Type*, make sure *CSV* is selected. +. In *Document IDs*, make sure *UUID* is selected. +. Click btn:[Import Data File]. + +Use the {import-documents}[Import] tool to import the regular time series data: + +. In the *Import* tab, select *A Single Collection*. +. In the *travel-sample* bucket, select the *time* scope and the *regular* collection. +. Click btn:[Select a file] and select `regular-time-series.csv`. +. In *File Type*, make sure *CSV* is selected. +. In *Document IDs*, make sure *UUID* is selected. +. Click btn:[Import Data File]. +==== + +[[ex-regular-insert]] +.Convert regular time series data to a time series document +==== +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +First, create a primary index on the imported regular time series data so that you can query it. + +[source,sqlpp] +---- +CREATE PRIMARY INDEX ON regular; +---- + +Create a collection to contain the converted regular time series data. + +[source,sqlpp] +---- +CREATE COLLECTION weather; +---- + +The following query takes the imported regular time series data and converts it to a time series document. + +[source,sqlpp] +---- +INSERT INTO weather + (KEY _k, VALUE _v, OPTIONS {"expiration": 60*60*24*30}) +SELECT "temp:mean:2013" _k, + {"region": r.Region, + "ts_start": MIN(timestamp), + "ts_end": MAX(timestamp), + "ts_interval": 1000*60*60*24, + "ts_data": ARRAY t[1] FOR t IN + ARRAY_AGG([timestamp, r.Mean]) + END} _v +FROM regular AS r +LET timestamp = STR_TO_MILLIS(r.Date, "YYYY-MM-DD") +WHERE timestamp + BETWEEN STR_TO_MILLIS("2013-01-01", "YYYY-MM-DD") + AND STR_TO_MILLIS("2013-11-30", "YYYY-MM-DD") +GROUP BY r.Region +RETURNING *; +---- + +The raw data is regular, with an interval of +1 day. +The query sets the time series interval accordingly. + +The ARRAY_AGG function aggregates the required time series into a single time series data array. +Within the time series data array, each time point is constructed as a nested array, containing the date-time stamp and the mean temperature data. + +As this is a regular time series, the ARRAY operator then strips out the date-time stamps to save storage space. +This two-step process ensures that the time series data points are preserved in the correct order. +==== + +[[ex-irregular-insert]] +.Convert irregular time series data to a time series document +==== +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +First, create a primary index on the imported irregular time series data so that you can query it. + +[source,sqlpp] +---- +CREATE PRIMARY INDEX ON irregular; +---- + +Create a collection to contain the converted irregular time series data. + +[source,sqlpp] +---- +CREATE COLLECTION housing; +---- + +The following query takes the imported irregular time series data and converts it to a time series document. + +[source,sqlpp] +---- +INSERT INTO housing + (KEY _k, VALUE _v, OPTIONS {"expiration": 60*60*24*30}) +SELECT "sales:prices:2000s" _k, + {"district": i.District, + "ts_start": MIN(timestamp), + "ts_end": MAX(timestamp), + "ts_data": ARRAY_AGG([timestamp, i.Price])} _v +FROM irregular AS i +LET timestamp = STR_TO_MILLIS(i.Date, "2/1/06") +WHERE timestamp + BETWEEN STR_TO_MILLIS("2000", "YYYY") + AND STR_TO_MILLIS("2009", "YYYY") +GROUP BY i.District +RETURNING *; +---- + +The raw data is irregular, so the query does not set the time series interval. + +Within the time series data array, each time point is constructed as a nested array, containing the date-time stamp and the house price data. +==== + +[[ex-index]] +.Create indexes for time series data +==== +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +The following query creates an index for the time series data created in <>. + +[source,sqlpp] +---- +CREATE INDEX idx_mean_temp ON weather(region, ts_end, ts_start); +---- + +The following query creates an index for the time series data created in <>. + +[source,sqlpp] +---- +CREATE INDEX idx_sales_prices ON housing(district, ts_end, ts_start); +---- +==== + +[[ex-update]] +.Add time series data to an existing time series document +==== +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +The following query appends new data to an existing regular time series document. + +[source,sqlpp] +---- +UPDATE weather AS w +USE KEYS "temp:mean:2013" +SET w.ts_data = ARRAY_CONCAT(w.ts_data, ARRAY_FLATTEN(( + SELECT RAW ARRAY t[1] FOR t IN + ARRAY_AGG([timestamp, r.Mean]) + END + FROM import AS r + LET timestamp = STR_TO_MILLIS(r.Date, "YYYY-MM-DD") + WHERE timestamp + BETWEEN STR_TO_MILLIS("2013-12-01", "YYYY-MM-DD") + AND STR_TO_MILLIS("2013-12-31", "YYYY-MM-DD")), 1)), + w.ts_end = STR_TO_MILLIS("2013-12-31", "YYYY-MM-DD"), + meta(w).expiration = meta(w).expiration +RETURNING *; +---- + +The ARRAY_CONCAT and ARRAY_FLATTEN functions append the newly imported data to the existing time series data. + +The newly imported data is converted by a subquery, which aggregates the mean temperature figures into a single time series data array, as in <>. + +The query sets the end date and time for the time series to the end of the year 2013. +See <> and <> for other ways to set the end date and time for the time series. + +The query specifies that the updated time series document should keep its current time-to-live. +Note that it is also possible to preserve the document time-to-live using the request-level {preserve_expiry}[preserve_expiry] parameter. +==== + +[[ex-regular-end]] +.Update regular time series end date and time +==== +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +The following query updates the end date and time of a regular time series document to match the date-time stamp of the last time point. + +[source,sqlpp] +---- +UPDATE weather AS w +USE KEYS "temp:mean:2013" +SET w.ts_end = w.ts_start + + (w.ts_interval * ARRAY_LENGTH(w.ts_data)) +RETURNING w.ts_end; +---- + +To calculate the end date and time, the query multiplies the time series interval by the number of time points in the time series data, and adds the result to the start date and time. +==== + +[[ex-irregular-end]] +.Update irregular time series end date and time +==== +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +The following query updates the end date and time of an irregular time series document to match the date-time stamp of the last time point. + +[source,sqlpp] +---- +UPDATE housing AS h +USE KEYS "sales:prices:2000s" +SET h.ts_end = h.ts_data[-1][0] +RETURNING h.ts_end; +---- + +To determine the end date and time, the query takes the first element (the date-time stamp) from the last time point in the time series data. +==== + +== Related Links + +* Querying time series data: {timeseries}[] + +* How-to guide: xref:guides:import.adoc[] + +// * Blog post: {url-ts-blog}[Couchbase Time Series^] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/timeseries.adoc b/modules/n1ql/pages/n1ql-language-reference/timeseries.adoc new file mode 100644 index 000000000..6b73ff2b9 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/timeseries.adoc @@ -0,0 +1,665 @@ += _TIMESERIES Function +:description: The _TIMESERIES function enables you to query time series data. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Links +:url-unix-epoch: https://en.wikipedia.org/wiki/Unix_time +:url-maxint64: https://docs.gtk.org/glib/const.MAXINT64.html +:url-ts-blog: https://blog.couchbase.com + +:time-series: xref:n1ql-language-reference/time-series.adoc +:unnest: xref:n1ql-language-reference/unnest.adoc + +{description} + +The time series data must be stored in Couchbase time series documents. +For more information, see {time-series}[]. + +The function dynamically generates data point objects from the array of time series data in the input document. +For a regular time series, the function uses the time series interval to generate a date-time stamp for each time point automatically. + +IMPORTANT: This feature is only available on clusters using Couchbase Server 7.2 or later. + +== Syntax + +[subs=normal] +.... +_TIMESERIES(__document__, __options__) +.... + +=== Arguments + +document:: +An expression resolving to a time series document. + +options:: +A JSON object specifying options for the function. + +=== Options + +[options="header", cols="1a,3a,1a"] +|=== +| Name | Description | Schema + +| **ts_data** + +__optional__ +| The path to the time series data in the document. + +If omitted, the function uses the `ts_data` field in the document. + +If the function cannot find the time series data, the document is ignored. + +*Default:* `ts_data` +| String + +| **ts_interval** + +__optional__ +| The path to the time series interval in the document. + +If omitted, the function uses the `ts_interval` field in the document. + +If the function cannot find the time series interval, the time series is assumed to be irregular. + +*Default:* `ts_interval` +| String + +| **ts_start** + +__optional__ +| The path to the start date and time for the document. + +If omitted, the function uses the `ts_start` field in the document. + +If the function cannot find the start date and time, the document is ignored. + +*Default:* `ts_start` +| String + +| **ts_end** + +__optional__ +| The path to the end date and time for the document. + +If omitted, the function uses the `ts_end` field in the document. + +If the function cannot find the end date and time, the document is ignored. + +*Default:* `ts_end` +| String + +| **ts_keep** + +__optional__ +| Whether the timeline should be removed to save memory. +If `true`, the timeline is kept. + +*Default:* `false` +| Boolean + +| **ts_ranges** + +__optional__ +| One or more date-time ranges, which are used to filter the time series data. +Time series data outside the specified range or ranges is filtered out. + +For a single predicate range, this is an expression resolving to an array containing two integers, both representing milliseconds since the {url-unix-epoch}[Unix epoch]. +The first value is the start of the filtered time series range, and the second is the end of the filtered time series range. + +Both values are inclusive. +If you need the start of the range to be exclusive, increase the start value by one. +If you need the end of the range to be exclusive, decrease the end value by one. + +Both values must be present. +If you need the start of the range to be unbounded, use `0`. +If you need the end of the range to be unbounded, use {url-maxint64}[MaxInt64] -- that is, `(2^63)-1`. + +To filter on multiple predicate ranges, this option can be an array of arrays, in which each nested array contains a pair of millisecond integers as above. + +If omitted, the time series data is not filtered. +| Array of integers, or array of arrays of integers + +| **ts_project** + +__optional__ +| An integer, or an array of integers, indicating which values should be returned for each data point. +`0` indicates the first value, `1` the second value, and so on. + +If omitted, all values are returned for every data point. +| Numeric expression, or array of numeric expressions +|=== + +== Return Values + +The function returns an array of objects, with one object for each data point in the selected range. +Each object has the following fields: + +_t:: An integer representing the time at that data point, in milliseconds since the {url-unix-epoch}[Unix epoch]. + +_v0, _v1, ...:: The value or values at that time point. + +== Usage + +You can use the _TIMESERIES function anywhere in a query, but typically you use it as the right-hand side of an {unnest}[UNNEST] clause. + +You cannot use the _TIMESERIES function in an index definition. + +If your query contains predicates on date-time ranges, and you are using an index for your time series documents, you should include the range predicates in the WHERE clause of the query, as well as the `ts_ranges` option of the _TIMESERIES function. +This pushes the range predicates to the index scan. + +A query containing date-time range predicates in both the _TIMESERIES function and the WHERE clause may become repetitive and hard to understand, especially with complex range predicates. +To make your queries easier to read, use a query parameter or common table expression to store the date-time range predicates. + +== Examples + +[[ex-regular-single]] +.Query regular time series data +==== +The following query selects time series data for mean temperatures in the specified time range. +Each time series document contains a month's data. + +[source,sqlpp] +---- +WITH docs AS ( + [ + { + "region": "UK", + "ts_data": [18.5, 18.5, 18.5, 18.5, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 16.5, 16.5, 16.5, 16.5, 16.5, + 16.5, 16.5, 16.5, 16.5, 16.5], + "ts_end": 1375228800000, + "ts_start": 1372636800000, + "ts_interval": 86400000 + }, + { + "region": "UK", + "ts_data": [19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5, + 17, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, + 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 14, 14, 14, 14], + "ts_end": 1377907200000, + "ts_start": 1375315200000, + "ts_interval": 86400000 + } + ] +), +range_start AS (1375056000000), +range_end AS (1375574400000) +SELECT t.* FROM docs AS d +UNNEST _timeseries(d, {"ts_ranges": [range_start, range_end]}) AS t +WHERE d.region = 'UK' + AND (d.ts_start <= range_end AND d.ts_end >= range_start); +---- + +Note that the specified range predicate cuts across more than one time series document. + +For each time point, the _TIMESERIES function calculates the date-time stamp `_t` and returns a single value `_v0`. + +.Results +[source,json] +---- +[ + { + "_t": 1375056000000, + "_v0": 16.5 + }, + { + "_t": 1375142400000, + "_v0": 16.5 + }, + { + "_t": 1375228800000, + "_v0": 16.5 + }, + { + "_t": 1375315200000, + "_v0": 19.5 + }, + { + "_t": 1375401600000, + "_v0": 19.5 + }, + { + "_t": 1375488000000, + "_v0": 19.5 + }, + { + "_t": 1375574400000, + "_v0": 19.5 + } +] +---- +==== + +[[ex-regular-multiple]] +.Query regular time series data with multiple data points +==== +The following query selects time series data for daily low and high temperatures in the specified time range. +Each time series document contains a month's data. + +[source,sqlpp] +---- +WITH docs AS ( + [ + { + "region": "UK", + "ts_data": [ + [10, 27], [10, 27], [10, 27], [10, 27], [10, 30], [10, 30], [10, 30], + [10, 30], [10, 30], [10, 30], [10, 30], [10, 30], [10, 30], [10, 30], + [10, 30], [10, 30], [10, 30], [10, 30], [10, 30], [10, 30], [10, 30], + [10, 23], [10, 23], [10, 23], [10, 23], [10, 23], [10, 23], [10, 23], + [10, 23], [10, 23], [10, 23] + ], + "ts_end": 1375228800000, + "ts_start": 1372636800000, + "ts_interval": 86400000 + }, + { + "region": "UK", + "ts_data": [ + [12, 27], [12, 27], [12, 27], [12, 27], [12, 27], [12, 27], [12, 27], + [12, 27], [12, 27], [12, 27], [12, 22], [9, 22], [9, 22], [9, 22], + [9, 22], [9, 22], [9, 22], [9, 22], [9, 22], [9, 22], [9, 22], + [9, 22], [9, 22], [9, 22], [9, 22], [9, 22], [9, 22], [9, 19], + [9, 19], [9, 19], [9, 19] + ], + "ts_end": 1377907200000, + "ts_start": 1375315200000, + "ts_interval": 86400000 + } + ] +), +range_start AS (1375056000000), +range_end AS (1375574400000) +SELECT MILLIS_TO_TZ(t._t,"UTC") AS day, t._v0 AS low, t._v1 AS high +FROM docs AS d +UNNEST _timeseries(d, {"ts_ranges": [range_start, range_end]}) AS t +WHERE d.region = 'UK' + AND (d.ts_start <= range_end AND d.ts_end >= range_start); +---- + +Note that the specified time range predicate cuts across more than one time series document. + +For each time point, the _TIMESERIES function calculates the date-time stamp `_t` and returns the values `_v0` and `_v1`. + +The query adds aliases to the data returned by the _TIMESERIES function and converts the date-time stamp to a readable date-time string. + +.Results +[source,json] +---- +[ + { + "day": "2013-07-29T00:00:00Z", + "high": 23, + "low": 10 + }, + { + "day": "2013-07-30T00:00:00Z", + "high": 23, + "low": 10 + }, + { + "day": "2013-07-31T00:00:00Z", + "high": 23, + "low": 10 + }, + { + "day": "2013-08-01T00:00:00Z", + "high": 27, + "low": 12 + }, + { + "day": "2013-08-02T00:00:00Z", + "high": 27, + "low": 12 + }, + { + "day": "2013-08-03T00:00:00Z", + "high": 27, + "low": 12 + }, + { + "day": "2013-08-04T00:00:00Z", + "high": 27, + "low": 12 + } +] +---- + +To view the results as a chart: + +. Click btn:[Chart]. + +. In *Chart Type*, select `Multi-Connected Points by Column`. + +. In *X-Axis*, select `day`. + +. In *Y-Values*, select both `high` and `low`. + +image::time-series-regular.svg["Line chart showing high and low temperatures over 7 days"] +==== + +[[ex-irregular]] +.Query irregular time series data +==== +The following query selects time series data for house sales and prices in the specified time range. +Each time series document contains a decade's data. +footnote:[Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.] + +[source,sqlpp] +---- +WITH docs AS ( + [ + { + "district": "South", + "ts_data": [ + [852595200000, 69950], + [852854400000, 67000], + [884044800000, 71500], + [884131200000, 73000], + [884217600000, 72000] + ], + "ts_end": 884217600000, + "ts_start": 852595200000 + }, + { + "district": "South", + "ts_data": [ + [978912000000,115000], + [1010534400000,139950], + [1073347200000,195000], + [1105056000000,225000], + [1136678400000,210000] + ], + "ts_end": 1136678400000, + "ts_start": 978912000000 + }, + { + "district": "South", + "ts_data": [ + [1294531200000,200000], + [1326326400000,212000], + [1357430400000,171000], + [1420675200000,252500], + [1452384000000,330000], + [1483660800000,290000], + [1514764800000,325000] + ], + "ts_end": 1514764800000, + "ts_start": 1294531200000 + } + ] +), +range_start AS (1104537600000), +range_end AS (1419984000000) +SELECT MILLIS_TO_TZ(t._t,"UTC") AS date, t._v0 AS price +FROM docs AS d +UNNEST _timeseries(d, {"ts_ranges": [range_start, range_end]}) AS t +WHERE d.district = 'South' + AND (d.ts_start <= range_end AND d.ts_end >= range_start); +---- + +Note that the specified time range cuts across more than one time series document. + +For each time point, the _TIMESERIES function returns the date-time stamp `_t` and a single value `_v0`. + +The query adds aliases to the data returned by the _TIMESERIES function and converts the date-time stamp to a readable date-time string. + +.Results +[source,json] +---- +[ + { + "date": "2005-01-07T00:00:00Z", + "price": 225000 + }, + { + "date": "2006-01-08T00:00:00Z", + "price": 210000 + }, + { + "date": "2011-01-09T00:00:00Z", + "price": 200000 + }, + { + "date": "2012-01-12T00:00:00Z", + "price": 212000 + }, + { + "date": "2013-01-06T00:00:00Z", + "price": 171000 + } +] +---- + +To view the results as a chart: + +. Click btn:[Chart]. + +. In *Chart Type*, select `Line`. + +. In *X-Axis*, select `date`. + +. In *Y-Axis*, select `price`. + +image::time-series-irregular.svg["Line chart showing house prices over 10 years"] +==== + +[[ex-window]] +.Use window functions with time series data +==== +Before you try this example, you must follow all the examples in {time-series}[] to import time series data. + +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +The following query returns the weekly average and four-week moving average for temperature over a two-month range. + +[source,sqlpp] +---- +WITH range_start AS (STR_TO_MILLIS ("2013-07-01", "YYYY-MM-DD")), + range_end AS (STR_TO_MILLIS ("2013-08-31", "YYYY-MM-DD")) +SELECT MILLIS_TO_TZ(week*1000*60*60*24*7, "UTC") AS week_of, + week_avg, + AVG(week_avg) OVER (ORDER BY week ROWS 4 PRECEDING) AS four_week_mov_avg +FROM weather AS d +UNNEST _timeseries(d, {"ts_ranges": [range_start, range_end]}) AS t +WHERE d.region = 'UK' + AND (d.ts_start <= range_end AND d.ts_end >= range_start) +GROUP BY IDIV(t._t, 1000*60*60*24*7) AS week +LETTING week_avg = AVG(t._v0); +---- + +.Results +[source,json] +---- +[ + { + "four_week_mov_avg": 18.5, + "week_avg": 18.5, + "week_of": "2013-06-27T00:00:00Z" + }, + { + "four_week_mov_avg": 19.142857142857142, + "week_avg": 19.785714285714285, + "week_of": "2013-07-04T00:00:00Z" + }, + { + "four_week_mov_avg": 19.428571428571427, + "week_avg": 20, + "week_of": "2013-07-11T00:00:00Z" + }, + { + "four_week_mov_avg": 19.19642857142857, + "week_avg": 18.5, + "week_of": "2013-07-18T00:00:00Z" + }, + { + "four_week_mov_avg": 18.657142857142855, + "week_avg": 16.5, + "week_of": "2013-07-25T00:00:00Z" + }, + { + "four_week_mov_avg": 18.857142857142854, + "week_avg": 19.5, + "week_of": "2013-08-01T00:00:00Z" + }, + { + "four_week_mov_avg": 18.385714285714286, + "week_avg": 17.428571428571427, + "week_of": "2013-08-08T00:00:00Z" + }, + { + "four_week_mov_avg": 17.485714285714288, + "week_avg": 15.5, + "week_of": "2013-08-15T00:00:00Z" + }, + { + "four_week_mov_avg": 16.842857142857145, + "week_avg": 15.285714285714286, + "week_of": "2013-08-22T00:00:00Z" + }, + { + "four_week_mov_avg": 16.342857142857145, + "week_avg": 14, + "week_of": "2013-08-29T00:00:00Z" + } +] +---- + +To view the results as a chart: + +. Click btn:[Chart]. + +. In *Chart Type*, select `Multi-Connected Points by Column`. + +. In *X-Axis*, select `week_of`. + +. In *Y-Values*, select both `four_week_mov_avg` and `week_avg`. + +image::time-series-window.svg["Line chart showing weekly average temperature and four-week moving average over 2 months"] +==== + +[[ex-ranges]] +.Query time series data with multiple predicate ranges +==== +Before you try this example, you must follow all the examples in {time-series}[] to import time series data. + +For this example, set the query context to the `time` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +The following query returns the weekly average and four-week moving average for temperature over March, April, and May. + +[source,sqlpp] +---- +WITH datarange AS ( + [ + [STR_TO_MILLIS("2013-03-01", "YYYY-MM-DD"), + STR_TO_MILLIS("2013-03-31", "YYYY-MM-DD")], + [STR_TO_MILLIS("2013-05-01", "YYYY-MM-DD"), + STR_TO_MILLIS("2013-05-31", "YYYY-MM-DD")], + [STR_TO_MILLIS("2013-07-01", "YYYY-MM-DD"), + STR_TO_MILLIS("2013-07-31", "YYYY-MM-DD")] + ]), + docs AS ( + SELECT DISTINCT RAW META(d).id + FROM datarange AS tr + JOIN weather AS d + ON d.region = 'UK' AND (d.ts_start <= tr[1] AND d.ts_end>= tr[0])) +SELECT MILLIS_TO_TZ(week*1000*60*60*24*7, "UTC") AS week_of, + week_avg, + AVG(week_avg) OVER (ORDER BY week ROWS 4 PRECEDING) AS four_week_mov_avg +FROM weather AS d +USE KEYS docs +UNNEST _timeseries(d, {"ts_ranges": datarange }) AS t +GROUP BY IDIV(t._t, 1000*60*60*24*7) AS week +LETTING week_avg = AVG(t._v0); +---- + +.Results +[source,json] +---- +[ + { + "four_week_mov_avg": 5.5, + "week_avg": 5.5, + "week_of": "2013-02-28T00:00:00Z" + }, + { + "four_week_mov_avg": 5.5, + "week_avg": 5.5, + "week_of": "2013-03-07T00:00:00Z" + }, + { + "four_week_mov_avg": 5.5476190476190474, + "week_avg": 5.642857142857143, + "week_of": "2013-03-14T00:00:00Z" + }, + { + "four_week_mov_avg": 5.785714285714286, + "week_avg": 6.5, + "week_of": "2013-03-21T00:00:00Z" + }, + { + "four_week_mov_avg": 5.928571428571429, + "week_avg": 6.5, + "week_of": "2013-03-28T00:00:00Z" + }, + { + "four_week_mov_avg": 7.028571428571428, + "week_avg": 11, + "week_of": "2013-04-25T00:00:00Z" + }, + { + "four_week_mov_avg": 8.128571428571428, + "week_avg": 11, + "week_of": "2013-05-02T00:00:00Z" + }, + { + "four_week_mov_avg": 9.585714285714285, + "week_avg": 12.928571428571429, + "week_of": "2013-05-09T00:00:00Z" + }, + { + "four_week_mov_avg": 10.985714285714284, + "week_avg": 13.5, + "week_of": "2013-05-16T00:00:00Z" + }, + { + "four_week_mov_avg": 12.385714285714284, + "week_avg": 13.5, + "week_of": "2013-05-23T00:00:00Z" + }, + { + "four_week_mov_avg": 12.885714285714283, + "week_avg": 13.5, + "week_of": "2013-05-30T00:00:00Z" + }, + { + "four_week_mov_avg": 14.385714285714283, + "week_avg": 18.5, + "week_of": "2013-06-27T00:00:00Z" + }, + { + "four_week_mov_avg": 15.757142857142856, + "week_avg": 19.785714285714285, + "week_of": "2013-07-04T00:00:00Z" + }, + { + "four_week_mov_avg": 17.057142857142857, + "week_avg": 20, + "week_of": "2013-07-11T00:00:00Z" + }, + { + "four_week_mov_avg": 18.057142857142857, + "week_avg": 18.5, + "week_of": "2013-07-18T00:00:00Z" + }, + { + "four_week_mov_avg": 18.657142857142855, + "week_avg": 16.5, + "week_of": "2013-07-25T00:00:00Z" + } +] +---- +==== + +== Related Links + +* Overview: {time-series}[] + +// * Blog post: {url-ts-blog}[Couchbase Time Series^] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/tokenfun.adoc b/modules/n1ql/pages/n1ql-language-reference/tokenfun.adoc new file mode 100644 index 000000000..29465ad71 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/tokenfun.adoc @@ -0,0 +1,193 @@ += Token Functions +:description: Tokenization is the process of breaking a stream of text up into words, phrases, symbols, or other meaningful elements called tokens. +:page-topic-type: reference +:example-caption!: + +{description} +The list of tokens becomes input for further processing such as parsing or text mining. +Token functions are not limited to string input since they work with generic JSON objects and documents. + +NOTE: If any arguments to any of the following functions are [.out]`MISSING` then the result is also [.out]`MISSING` (i.e. +no result is returned). +Similarly, if any of the arguments passed to the functions are `NULL` or are of the wrong type (e.g. +an integer instead of a string), then `NULL` is returned as the result. + +[#section_kqy_hj4_qz] +== CONTAINS_TOKEN(input_obj, token_expr [, options ]) + +=== Description +Checks whether or not the specified search token `token_expr` is a sub-string of the input object `input_obj`. + +=== Arguments +input_obj:: Any JSON object, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, to search within. + +token_expr:: A token string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is being searched for. + +options:: +An optional JSON object to control tokenization. +Within options: +names;; A boolean to include object names (default: true) +case;; Either "lower" or "upper" for case folding (default: no change to the original text) +specials;; A boolean to include strings with special characters, such as email addresses and URLs (default: false) +split;; A boolean to split string values into words (default: true) +trim;; A boolean to trim spaces around unsplit string values (default: true) + +=== Return Value +A boolean, representing whether the search expression exists within the input object. + +This returns `true` if the sub-string exists within the input string, otherwise `false` is returned. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Finding hotels with the word "Inn" within their name +==== +[source,sqlpp] +---- +SELECT name +FROM hotel +WHERE CONTAINS_TOKEN(name, "Inn",{"specials":true}) +LIMIT 4; +---- + +[source,json] +---- +[ + { + "name": "Sportsman Inn" + }, + { + "name": "Keefer's Inn" + }, + { + "name": "Quality Inn King City Hotel" + }, + { + "name": "Premier Inn, Albert Dock" + } +] +---- +==== + +== CONTAINS_TOKEN_LIKE(input_obj, token_expr [, options ]) + +=== Description +Checks whether or not the specified search token `token_expr` is a sub-string of the input object `input_obj`. + +=== Arguments +input_obj:: Any JSON object, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, to search within. + +token_expr:: A token string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is being searched for. + +options:: +An optional JSON object to control tokenization. +Within options: +names;; A boolean to include object names (default: true) +case;; Either "lower" or "upper" for case folding (default: no change to the original text) +specials;; A boolean to include strings with special characters, such as email addresses and URLs (default: false) +split;; A boolean to split string values into words (default: true) +trim;; A boolean to trim spaces around unsplit string values (default: true) + +=== Return Value +A boolean, representing whether the search expression exists within the input object. + +This returns `true` if the sub-string exists within the input string, otherwise `false` is returned. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Finding email addresses of UK hotels +==== +[source,sqlpp] +---- +SELECT email +FROM hotel +WHERE CONTAINS_TOKEN_LIKE(email, "%uk",{"specials":true}) +LIMIT 4; +---- + +[source,json] +---- +[ + { + "email": "glencoe@syha.org.uk" + }, + { + "email": "owner@hillhousellanrhidian.co.uk" + }, + { + "email": "julia@number38thegower.co.uk" + }, + { + "email": "stay@holiday-harlech.co.uk" + } +] +---- +==== + +== CONTAINS_TOKEN_REGEXP(input_obj, token_expr [, options ]) + +=== Description +Checks whether or not the specified search token `token_expr` is a sub-string of the input object `input_obj`. + +=== Arguments +input_obj:: Any JSON object, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, to search within. + +token_expr:: A token string, or any valid xref:n1ql-language-reference/index.adoc[expression] which evaluates to a string, that is being searched for. + +options:: +An optional JSON object to control tokenization. +Within options: +names;; A boolean to include object names (default: true) +case;; Either "lower" or "upper" for case folding (default: no change to the original text) +specials;; A boolean to include strings with special characters, such as email addresses and URLs (default: false) +split;; A boolean to split string values into words (default: true) +trim;; A boolean to trim spaces around unsplit string values (default: true) + +=== Return Value +A boolean, representing whether the search expression exists within the input object. + +This returns `true` if the sub-string exists within the input string, otherwise `false` is returned. + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Finding hotels with the word "Inn" within their name +==== +[source,sqlpp] +---- +SELECT name +FROM hotel +WHERE CONTAINS_TOKEN_REGEXP(name, "In+.*",{"specials":true}) +LIMIT 4; +---- + +[source,json] +---- +[ + { + "name": "Sportsman Inn" + }, + { + "name": "Inveraray Youth Hostel" + }, + { + "name": "Inverness Youth Hostel" + }, + { + "name": "Indian Cove Campground" + } +] +---- +==== + +[#fn-str-title] +== HAS_TOKEN(input_obj, token_expr [, options ]) + +Alias for <>. + +[#fn-str-token] +include::partial$n1ql-language-reference/fun-token.adoc[] diff --git a/modules/n1ql/pages/n1ql-language-reference/transactions.adoc b/modules/n1ql/pages/n1ql-language-reference/transactions.adoc new file mode 100644 index 000000000..0f9348b0e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/transactions.adoc @@ -0,0 +1,425 @@ += {sqlpp} Support for Couchbase Transactions +:page-topic-type: concept +:imagesdir: ../../assets/images +:description: {sqlpp} offers full support for Couchbase ACID transactions based on optimistic concurrency. +:tabs: +:page-partial: + +// N1QL cross-references +:insert: xref:n1ql:n1ql-language-reference/insert.adoc +:upsert: xref:n1ql:n1ql-language-reference/upsert.adoc +:delete: xref:n1ql:n1ql-language-reference/delete.adoc +:update: xref:n1ql:n1ql-language-reference/update.adoc +:merge: xref:n1ql:n1ql-language-reference/merge.adoc +:select: xref:n1ql:n1ql-language-reference/selectintro.adoc +:execfunction: xref:n1ql:n1ql-language-reference/execfunction.adoc +:prepare: xref:n1ql:n1ql-language-reference/prepare.adoc +:execute: xref:n1ql:n1ql-language-reference/execute.adoc + +// Learn cross-references +:transactions: xref:server:learn:data/transactions.adoc +:roles: xref:server:learn:security/roles.adoc + +// Manage cross-references +:install-sample-buckets: xref:clusters:data-service/import-data-documents.adoc#import-sample-data +:sys-transactions: xref:n1ql:n1ql-intro/sysinfo.adoc#sys-transactions + +// Tools cross-references +:query-workbench: xref:clusters:query-service/query-workbench.adoc +:cbq-shell: xref:n1ql:n1ql-intro/cbq.adoc +:n1ql-rest-api: xref:n1ql-rest-query:index.adoc + +// Settings cross-references +:txid: xref:n1ql:n1ql-manage/query-settings.adoc#txid +:tximplicit: xref:n1ql:n1ql-manage/query-settings.adoc#tximplicit +:txstmtnum: xref:n1ql:n1ql-manage/query-settings.adoc#txstmtnum +:kvtimeout: xref:n1ql:n1ql-manage/query-settings.adoc#kvtimeout +:txtimeout_req: xref:n1ql:n1ql-manage/query-settings.adoc#txtimeout_req +:txtimeout-srv: xref:n1ql:n1ql-manage/query-settings.adoc#txtimeout-srv +:queryTxTimeout: xref:n1ql:n1ql-manage/query-settings.adoc#queryTxTimeout +:atrcollection_req: xref:n1ql:n1ql-manage/query-settings.adoc#atrcollection_req +:atrcollection-srv: xref:n1ql:n1ql-manage/query-settings.adoc#atrcollection-srv +:cleanupclientattempts: xref:n1ql:n1ql-manage/query-settings.adoc#cleanupclientattempts +:cleanuplostattempts: xref:n1ql:n1ql-manage/query-settings.adoc#cleanuplostattempts +:cleanupwindow: xref:n1ql:n1ql-manage/query-settings.adoc#cleanupwindow +:queryCleanupClientAttempts: xref:n1ql:n1ql-manage/query-settings.adoc#queryCleanupClientAttempts +:queryCleanupLostAttempts: xref:n1ql:n1ql-manage/query-settings.adoc#queryCleanupLostAttempts +:queryCleanupWindow: xref:n1ql:n1ql-manage/query-settings.adoc#queryCleanupWindow +:numatrs_req: xref:n1ql:n1ql-manage/query-settings.adoc#numatrs_req +:numatrs-srv: xref:n1ql:n1ql-manage/query-settings.adoc#numatrs-srv +:queryNumAtrs: xref:n1ql:n1ql-manage/query-settings.adoc#queryNumAtrs +:scan_consistency: xref:n1ql:n1ql-manage/query-settings.adoc#scan_consistency +:durability_level: xref:n1ql:n1ql-manage/query-settings.adoc#durability_level +:transactional-scan-consistency: xref:n1ql:n1ql-manage/query-settings.adoc#transactional-scan-consistency + +// Related links +:begin-transaction: xref:n1ql-language-reference/begin-transaction.adoc +:set-transaction: xref:n1ql-language-reference/set-transaction.adoc +:savepoint: xref:n1ql-language-reference/savepoint.adoc +:commit-transaction: xref:n1ql-language-reference/commit-transaction.adoc +:rollback-transaction: xref:n1ql-language-reference/rollback-transaction.adoc + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +A transaction is a group of operations that are either committed to the database together, or are all undone from the database if there's a failure. +Refer to {transactions}[Transactions] for an overview of Couchbase transactions. + +include::partial$n1ql-language-reference/transaction-restrictions.adoc[] + +== Statements + +{sqlpp} provides the following statements in support of Couchbase transactions. +Refer to the documentation for each statement for more information and examples. + +* To begin a transaction, refer to {begin-transaction}[BEGIN TRANSACTION]. +* To specify transaction settings, refer to {set-transaction}[SET TRANSACTION]. +* To set a savepoint, refer to {savepoint}[SAVEPOINT]. +* To rollback a transaction, refer to {rollback-transaction}[ROLLBACK TRANSACTION]. +* To commit a transaction, refer to {commit-transaction}[COMMIT TRANSACTION]. + + +== Settings and Parameters + +The Query service provides settings and parameters in support of Couchbase transactions. +Refer to the documentation for each parameter for more information and examples. + +|=== +| Setting{nbsp}/ Parameter | Description + +| {txid}[txid] request-level parameter +| Specifies the transaction to which a statement belongs. + +| {tximplicit}[tximplicit] request-level parameter +| Specifies that a statement is a single transaction. + +| {txstmtnum}[txstmtnum] request-level parameter +| Specifies the transaction statement number. + +| {kvtimeout}[kvtimeout] request-level parameter +| Specifies the maximum time to spend on a KV operation within a transaction before timing out. + +| {durability_level}[durability_level] request-level parameter +| Specifies the transactional durability level. + +| {txtimeout_req}[txtimeout] request-level parameter + +ifdef::flag-devex-rest-api[] +{txtimeout-srv}[txtimeout] node-level setting + +{queryTxTimeout}[queryTxTimeout] cluster-level setting +endif::flag-devex-rest-api[] +| Specify the maximum time to spend on a transaction before timing out. + +| {atrcollection_req}[atrcollection] request-level parameter + +ifdef::flag-devex-rest-api[] +{atrcollection-srv}[atrcollection] node-level setting +endif::flag-devex-rest-api[] +| Specify where the active transaction record is stored. + +ifdef::flag-devex-rest-api[] +| {cleanupclientattempts}[cleanupclientattempts] node-level setting + +{queryCleanupClientAttempts}[queryCleanupClientAttempts] cluster-level setting + +{cleanuplostattempts}[cleanuplostattempts] node-level setting + +{queryCleanupLostAttempts}[queryCleanupLostAttempts] cluster-level setting +| Specify how expired transactions are cleaned up. + +| {cleanupwindow}[cleanupwindow] node-level setting + +{queryCleanupWindow}[queryCleanupWindow] cluster-level setting +| Specify how frequently active transaction records are checked for cleanup. + +| {numatrs_req}[numatrs] request-level parameter + +{numatrs-srv}[numatrs] node-level setting + +{queryNumAtrs}[queryNumAtrs] cluster-level setting +| Specify the total number of active transaction records. +endif::flag-devex-rest-api[] +|=== + +In addition, the {scan_consistency}[scan-consistency] request-level parameter is used to specify the transactional scan consistency. +Refer to {transactional-scan-consistency}[Transactional Scan Consistency] for details. + +== Query Tools + +To create a Couchbase transaction using {sqlpp}, you can use: + +* The {query-workbench}[Query tab] +* The {cbq-shell}[cbq shell] +ifdef::flag-devex-rest-api[] +* The {n1ql-rest-api}[Query REST API] +endif::flag-devex-rest-api[] + +There are slight differences in the way these tools operate when creating Couchbase transactions. +These are explained in the sections below. + +Note that some Couchbase SDKs provide APIs to support Couchbase transactions. +For further details, refer to {transactions}[Transactions] in the Server documentation. + +=== Couchbase Transactions with the Query Tab + +* To execute a transaction containing multiple statements, compose the sequence of statements in the Query editor. +Each statement must be terminated with a semicolon. +After each statement, you must press kbd:[Shift+Enter] to start a new line _without_ executing the query. +You can then click btn:[Execute] to execute the transaction. + +//// +* To execute a single statement as a transaction, simply enter the statement in the Query Editor and click btn:[Run as TX]. +//// + +* You do not need to specify the `txid` parameter or the `tximplicit` parameter. +If you need to specify any other parameters for the Couchbase transaction, you can use the Query Options window. + +=== Couchbase Transactions with the cbq shell + +* To execute a transaction containing multiple statements, you can create the transaction one statement at a time. +Once you have started a transaction, all statements within the cbq shell session are assumed to be part of the same transaction until you rollback or commit the transaction. +In this case, you don't need to set the `txid` parameter. +footnote:[You must be using cbq shell version 2.0 or above to use the automatic transaction ID functionality.] + +* Alternatively, you can use the `tximplicit` parameter to run a single statement as a transaction. +In this case, you do not need to specify the `txid` parameter either. + +* You can specify parameters for the Couchbase transaction using the `\SET` command. + +ifdef::flag-devex-rest-api[] +=== Couchbase Transactions with the Query REST API + +* To execute a transaction containing multiple statements, you can create the transaction one statement at a time. +Once you have started the transaction, you must set the `txid` parameter to specify the transaction to which each subsequent statement belongs. + +* Alternatively, you can use the `tximplicit` parameter to run a single statement as a transaction. +In this case, you do not need to specify the `txid` parameter. + +* You can specify parameters for the Couchbase transaction as body parameters or query parameters alongside the query statement. +endif::flag-devex-rest-api[] + + +== Monitoring + +You can monitor active Couchbase transactions using the `system:transactions` catalog. +For more information, refer to {sys-transactions}[system:transactions]. + +== Permissions + +When developing a transaction with an SDK, the transaction may contain a mixture of key-value operations and query statements. + +To execute key-value operations or query statements within a transaction, users must have the relevant cluster access privileges, with permissions on the relevant buckets, scopes and collections. + +See xref:clusters:manage-database-users.adoc[] for details. + +== Worked Example + +This worked example guides you through a complete Couchbase transaction session using {sqlpp}. + +[[preparation]] +=== Preparation + +The worked example assumes that the supplied `travel-sample` bucket is installed. +Refer to {install-sample-buckets}[Import Sample Data] for installation details. + +.Context +For this worked example, set the query context to the `tenant_agent_00` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +image::guides:transactions-context.png["The query context drop-down menu, with the tenant_agent_00 scope selected"] + +.Index +For the purposes of this worked example, you must create a primary index in the keyspace you will be using. + +==== +Create a primary index on `{backtick}travel-sample{backtick}.tenant_agent_00.bookings`, so that you can query and update the documents in this keyspace. + +[source,sqlpp] +---- +include::example$transactions/multiple.n1ql[tag=index] +---- +==== + +.Parameters +If necessary, set the transaction parameters for this worked example. +In particular, you will turn off durability for the purposes of this example, in order to make sure that there are no problems meeting the transaction durability requirements. + +[tabs] +==== +Query Tab:: ++ +-- +. Click *Query Options* to display the Query Options window. + +. Open the *Scan Consistency* drop-down list and select *not_bounded*. + +. In the *Transaction Timeout* box, enter `120`. + +. In the *Named Parameters* section, click the btn:[+] button to add a named parameter. + +. When the new named parameter appears, enter `durability_level` in the *name* box and `"none"` (with double quotes) in the *value* box. + +. Choose btn:[Save] to save the preferences and return to the Query tab. +-- + +CBQ Shell:: ++ +-- +Enter the following parameters. + +[source,sqlpp] +---- +include::example$transactions/multiple.n1ql[tag=settings] +---- + +<.> The transaction timeout. +<.> The transaction scan consistency. +No scan consistency is set for individual statements within the transaction; they inherit from the transaction scan consistency. +<.> Durability level of all the mutations within the transaction. +-- +==== + +=== Transaction + +[[ex-1]] + +.Transaction using the Query tab or cbq shell +==== +Copy the entire sequence below and paste it into either the {query-workbench}[Query tab] or the {cbq-shell}[cbq shell]. +Note that you must be using cbq shell version 2.0 or above. + +.Transaction +[source,sqlpp] +---- +include::example$transactions/multiple.n1ql[tags=transaction;!begin-mark;!set-mark;!savepoint-mark;!rollback-mark;!commit-mark] +---- + + +The results of running the transaction in the Query tab are shown below. +If you are using the cbq shell, the results are formatted differently, but contain the same information. + +.Results +[source.no-callouts,json] +---- +include::example$transactions/results.jsonc[tags=extract-1] +---- +Beginning a transaction returns a unique transaction ID `txid`. + +[source.no-callouts,json] +---- +include::example$transactions/results.jsonc[tags=extract-2;!ellipsis] +---- +Before setting the second savepoint, the booking document has user `"0"`, name `"Keon Hoppe"`. + +[source.no-callouts,json] +---- +include::example$transactions/results.jsonc[tags=extract-3] +---- +After setting the second savepoint and performing an update, the booking document has user `"1"`, name `"Rigoberto Bernier"`. + +[source.no-callouts,json] +---- +include::example$transactions/results.jsonc[tags=extract-4] +---- +After rolling back to the second savepoint, the booking document again has user `"0"`, name `"Keon Hoppe"`. +==== + +[[ex-2]] +.Check the results of <> +==== +Check the result of committing the transaction. + +.Query +[source,sqlpp] +---- +include::example$transactions/multiple.n1ql[tag=check-3] +---- + +.Results +[source.no-callouts,json,indent=0] +---- +include::example$transactions/results.jsonc[tag=check-3] +---- + +The booking document has been added with the attributes that were present when the transaction was committed. +==== + +ifdef::flag-devex-rest-api[] +.Transaction using the Query REST API +==== +For reference, this example shows the equivalent of <> using the Query REST API. + +.Begin transaction and set parameters +[source,console] +---- +include::example$transactions/multiple.sh[tag=begin] +---- + +.Specify transaction settings +[source,console] +---- +include::example$transactions/multiple.sh[tag=set] +---- + +.Create a booking document +[source,console] +---- +include::example$transactions/multiple.sh[tag=upsert] +---- + +.Set a savepoint +[source,console] +---- +include::example$transactions/multiple.sh[tag=savepoint-1] +---- + +.Update the booking document to include a user +[source,console] +---- +include::example$transactions/multiple.sh[tag=update-1] +---- + +.Check the content of the booking and user +[source,console] +---- +include::example$transactions/multiple.sh[tag=check-1] +---- + +.Set a second savepoint +[source,console] +---- +include::example$transactions/multiple.sh[tag=savepoint-2] +---- + +.Update the booking documents to change the user +[source,console] +---- +include::example$transactions/multiple.sh[tag=update-2] +---- + +.Check the content of the booking and user +[source,console] +---- +include::example$transactions/multiple.sh[tag=check-2] +---- + +.Roll back the transaction to the second savepoint +[source,console] +---- +include::example$transactions/multiple.sh[tag=rollback] +---- + +.Check the content of the booking and user again +[source,console] +---- +include::example$transactions/multiple.sh[tag=check-3] +---- + +.Commit the transaction +[source,console] +---- +include::example$transactions/multiple.sh[tag=commit] +---- + +<.> After beginning the transaction, each subsequent statement in the transaction must specify the transaction ID that was generated when the transaction began. +==== +endif::flag-devex-rest-api[] + +== Related Links + +* Blog post: https://blog.couchbase.com/transactions-n1ql-couchbase-distributed-nosql/[Couchbase Transactions: Elastic, Scalable, and Distributed^]. diff --git a/modules/n1ql/pages/n1ql-language-reference/typefun.adoc b/modules/n1ql/pages/n1ql-language-reference/typefun.adoc new file mode 100644 index 000000000..084bd19a4 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/typefun.adoc @@ -0,0 +1,668 @@ += Type Functions +:description: Type functions perform operations that check or convert expressions. +:page-topic-type: reference + +[abstract] +{description} + +NOTE: If any arguments to any of the following functions are [.out]`MISSING` then the result is also [.out]`MISSING` (i.e. +no result is returned). +Similarly, if any of the arguments passed to the functions are `NULL` or are of the wrong type (e.g. +an integer instead of a string), then `NULL` is returned as the result. + + +[#fn-type-isarray] +== ISARRAY(expression) + +=== Description + +Checks if the supplied expression is an array. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns True if expression is an array, otherwise returns MISSING, NULL or false. + +=== Examples +==== +[source,sqlpp] +---- +SELECT ISARRAY(true) AS `boolean`, + ISARRAY(MISSING) AS `missing`, + ISARRAY(NULL) AS `null`, + ISARRAY(123) AS `number`, + ISARRAY("hello world") AS `string`, + ISARRAY([1, 2, 3]) AS `array`, + ISARRAY({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": true, + "boolean": false, + "null": null, + "number": false, + "object": false, + "string": false + } +] +---- +==== + +[#fn-type-isatom] +== ISATOM(expression) + +=== Description + +Checks if the supplied expression is a Boolean, number, or string. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns True if expression is a Boolean, number, or string, otherwise returns MISSING, NULL or false. + +=== Examples +==== +[source,sqlpp] +---- +SELECT ISATOM(true) AS `boolean`, + ISATOM(MISSING) AS `missing`, + ISATOM(NULL) AS `null`, + ISATOM(123) AS `number`, + ISATOM("hello world") AS `string`, + ISATOM([1, 2, 3]) AS `array`, + ISATOM({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": false, + "boolean": true, + "null": null, + "number": true, + "object": false, + "string": true + } +] +---- +==== + +[#fn-type-isboolean] +== ISBOOLEAN(expression) + +=== Description + +Checks if the supplied expression is a Boolean. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns True if expression is a Boolean, otherwise returns MISSING, NULL or false. + +=== Examples +==== +[source,sqlpp] +---- +SELECT ISBOOLEAN(true) AS `boolean`, + ISBOOLEAN(MISSING) AS `missing`, + ISBOOLEAN(NULL) AS `null`, + ISBOOLEAN(123) AS `number`, + ISBOOLEAN("hello world") AS `string`, + ISBOOLEAN([1, 2, 3]) AS `array`, + ISBOOLEAN({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": false, + "boolean": true, + "null": null, + "number": false, + "object": false, + "string": false + } +] +---- +==== + +[#fn-type-isnumber] +== ISNUMBER(expression) + +=== Description + +Checks if the supplied expression is a number. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns True if expression is a number, otherwise returns MISSING, NULL or false. + +=== Examples +==== +[source,sqlpp] +---- +SELECT ISNUMBER(true) AS `boolean`, + ISNUMBER(MISSING) AS `missing`, + ISNUMBER(NULL) AS `null`, + ISNUMBER(123) AS `number`, + ISNUMBER("hello world") AS `string`, + ISNUMBER([1, 2, 3]) AS `array`, + ISNUMBER({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": false, + "boolean": false, + "null": null, + "number": true, + "object": false, + "string": false + } +] +---- +==== + +[#fn-type-isobject] +== ISOBJECT(expression) + +=== Description + +Checks if the supplied expression is an object. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns True if expression is an object, otherwise returns MISSING, NULL or false. + +=== Examples +==== +[source,sqlpp] +---- +SELECT ISOBJECT(true) AS `boolean`, + ISOBJECT(MISSING) AS `missing`, + ISOBJECT(NULL) AS `null`, + ISOBJECT(123) AS `number`, + ISOBJECT("hello world") AS `string`, + ISOBJECT([1, 2, 3]) AS `array`, + ISOBJECT({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": false, + "boolean": false, + "null": null, + "number": false, + "object": true, + "string": false + } +] +---- +==== + +[#fn-type-isstring] +== ISSTRING(expression) + +=== Description + +Checks if the supplied expression is a string. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns True if expression is a string, otherwise returns MISSING, NULL or false. + +=== Examples +==== +[source,sqlpp] +---- +SELECT ISSTRING(true) AS `boolean`, + ISSTRING(MISSING) AS `missing`, + ISSTRING(NULL) AS `null`, + ISSTRING(123) AS `number`, + ISSTRING("hello world") AS `string`, + ISSTRING([1, 2, 3]) AS `array`, + ISSTRING({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": false, + "boolean": false, + "null": null, + "number": false, + "object": false, + "string": true + } +] +---- +==== + +[#fn-type-type] +== TYPE(expression) + +=== Description + +Checks the type of the supplied expression. + +=== Arguments + +expression:: [Required] The expression to check. + +=== Return Value + +Returns one of the following strings, based on the value of expression: + +* "missing" +* "null" +* "boolean" +* "number" +* "string" +* "array" +* "object" +* "binary" + +=== Examples +==== +[source,sqlpp] +---- +SELECT TYPE(true) AS `boolean`, + TYPE(MISSING) AS `missing`, + TYPE(NULL) AS `null`, + TYPE(123) AS `number`, + TYPE("hello world") AS `string`, + TYPE([1, 2, 3]) AS `array`, + TYPE({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": "array", + "boolean": "boolean", + "missing": "missing", + "null": "null", + "number": "number", + "object": "object", + "string": "string" + } +] +---- +==== + +[#fn-type-toarray] +== TOARRAY(expression) + +=== Description + +Converts the supplied expression to an array. + +=== Arguments + +expression:: [Required] The expression to convert. + +=== Return Value + +Returns one of the following strings, based on the value of expression: + +Returns array as follows: + +* MISSING is MISSING. +* NULL is NULL. +* Arrays are themselves. +* All other values are wrapped in an array. + +=== Examples +==== +[source,sqlpp] +---- +SELECT TOARRAY(true) AS `boolean`, + TOARRAY(MISSING) AS `missing`, + TOARRAY(NULL) AS `null`, + TOARRAY(123) AS `number`, + TOARRAY("hello world") AS `string`, + TOARRAY([1, 2, 3]) AS `array`, + TOARRAY({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": [ + 1, + 2, + 3 + ], + "boolean": [ + true + ], + "null": null, + "number": [ + 123 + ], + "object": [ + { + "hello": "world" + } + ], + "string": [ + "hello world" + ] + } +] +---- +==== + +[#fn-type-toatom] +== TOATOM(expression) + +=== Description + +Converts the supplied expression to Boolean, number, or string. + +=== Arguments + +expression:: [Required] The expression to convert. + +=== Return Value + +Returns atomic value as follows: + +* MISSING is MISSING. +* NULL is NULL. +* Arrays of length 1 are the result of TOATOM() on their single element. +* Objects of length 1 are the result of TOATOM() on their single value. +* Booleans, numbers, and strings are themselves. +* All other values are NULL. + +=== Examples +==== +[source,sqlpp] +---- +SELECT TOATOM(true) AS `boolean`, + TOATOM(MISSING) AS `missing`, + TOATOM(NULL) AS `null`, + TOATOM(123) AS `number`, + TOATOM("hello world") AS `string`, + TOATOM([1, 2, 3]) AS `array`, + TOATOM({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": null, + "boolean": true, + "null": null, + "number": 123, + "object": "world", + "string": "hello world" + } +] +---- +==== + +[#fn-type-toboolean] +== TOBOOLEAN(expression) + +=== Description + +Converts the supplied expression to a Boolean. + +=== Arguments + +expression:: [Required] The expression to convert. + +=== Return Value + +Returns Boolean as follows: + +* MISSING is MISSING. +* NULL is NULL. +* False is false. +* Numbers +0, -0, and NaN are false. +* Empty strings, arrays, and objects are false. +* All other values are true. + +=== Examples +==== +[source,sqlpp] +---- +SELECT TOBOOLEAN(true) AS `boolean`, + TOBOOLEAN(MISSING) AS `missing`, + TOBOOLEAN(NULL) AS `null`, + TOBOOLEAN(123) AS `number`, + TOBOOLEAN("hello world") AS `string`, + TOBOOLEAN([1, 2, 3]) AS `array`, + TOBOOLEAN({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": true, + "boolean": true, + "null": null, + "number": true, + "object": true, + "string": true + } +] +---- +==== + +[#fn-type-tonumber] +== TONUMBER(expression [, string-expression]) + +=== Description + +Converts the supplied expression to a number. + +=== Arguments + +expression:: [Required] The expression to convert. + +string-expression:: [Optional] Characters to strip from the input expression before conversion, if the input expression is a string. + +=== Return Value + +Returns number as follows: + +* MISSING is MISSING. +* NULL is NULL. +* False is 0. +* True is 1. +* Numbers are themselves. +* Strings that parse as numbers are those numbers. +* All other values are NULL. + +If `string-expression` is supplied, and the input expression is a string, then the following operations are carried out before conversion: + +* All whitespace is stripped from the input expression string. + +* All characters listed in `string-expression` are stripped from the input expression string. + +* If a decimal comma is detected, it is replaced with a decimal point -- all other points must be removed from the input expression string. + +If `string-expression` is not supplied, then the input expression string is parsed as-is. + +=== Examples +==== +[source,sqlpp] +---- +SELECT TONUMBER(true) AS `boolean`, + TONUMBER(MISSING) AS `missing`, + TONUMBER(NULL) AS `null`, + TONUMBER(123) AS `number`, + TONUMBER("hello world") AS `string`, + TONUMBER([1, 2, 3]) AS `array`, + TONUMBER({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": null, + "boolean": 1, + "null": null, + "number": 123, + "object": null, + "string": null + } +] +---- +==== + +==== +[source,sqlpp] +---- +SELECT TONUMBER("AU$123456.78", "AU$") AS `aud`, + TONUMBER("€123.456,78 ", "€.") AS `eur`, + TONUMBER("$ 123,456.78", "$,") AS `usd`, + TONUMBER("¥123 456 789.00", "¥") AS `yen`; +---- +[source,json] +---- +[ + { + "aud": 123456.78, + "eur": 123456.78, + "usd": 123456.78, + "yen": 123456789 + } +] +---- +==== + +[#fn-type-toobject] +== TOOBJECT(expression) + +=== Description + +Converts the supplied expression to an object. + +=== Arguments + +expression:: [Required] The expression to convert. + +=== Return Value + +Returns object as follows: + +* MISSING is MISSING. +* NULL is NULL. +* Objects are themselves. +* All other values are the empty object. + +=== Examples + +[source,sqlpp] +---- +SELECT TOOBJECT(true) AS `boolean`, + TOOBJECT(MISSING) AS `missing`, + TOOBJECT(NULL) AS `null`, + TOOBJECT(123) AS `number`, + TOOBJECT("hello world") AS `string`, + TOOBJECT([1, 2, 3]) AS `array`, + TOOBJECT({"hello": "world"}) AS `object`; +---- + +[source,json] +---- +[ + { + "array": {}, + "boolean": {}, + "null": null, + "number": {}, + "object": { + "hello": "world" + }, + "string": {} + } +] +---- + +[#fn-type-tostring] +== TOSTRING(expression) + +=== Description + +Converts the supplied expression to a string. + +=== Arguments + +expression:: [Required] The expression to convert. + +=== Return Value + +Returns string as follows: + +- MISSING is MISSING. +- NULL is NULL. +- False is "false". +- True is "true". +- Numbers are their string representation. +- Strings are themselves. +- All other values are NULL. + +=== Examples + +[source,sqlpp] +---- +SELECT TOSTRING(true) AS `boolean`, + TOSTRING(MISSING) AS `missing`, + TOSTRING(NULL) AS `null`, + TOSTRING(123) AS `number`, + TOSTRING("hello world") AS `string`, + TOSTRING([1, 2, 3]) AS `array`, + TOSTRING({"hello": "world"}) AS `object`; +---- + +[source,json] +[ + { + "array": null, + "boolean": "true", + "null": null, + "number": "123", + "object": null, + "string": "hello world" + } +] diff --git a/modules/n1ql/pages/n1ql-language-reference/union.adoc b/modules/n1ql/pages/n1ql-language-reference/union.adoc new file mode 100644 index 000000000..9a955333d --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/union.adoc @@ -0,0 +1,186 @@ += UNION, INTERSECT, and EXCEPT +:description: The set operators UNION, INTERSECT, and EXCEPT combine the resultsets of two or more SELECT statements. +:imagesdir: ../../assets/images +:page-topic-type: reference + +[abstract] +The set operators <>, <>, and <> combine the resultsets of two or more `SELECT` statements. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=set-op] +---- + +image::n1ql-language-reference/set-op.png["Syntax diagram", align=left] + +=== UNION + +Returns all values from both the first and second `SELECT` statements. + +=== INTERSECT + +Returns only values present in both the first and second `SELECT` statements. + +=== EXCEPT + +Returns values from the first `SELECT` statement that are absent from the second `SELECT` statement. + +== Return Values + +`UNION`, `INTERSECT`, and `EXCEPT` return distinct results, such that there are no duplicates. + +`UNION ALL`, `INTERSECT ALL`, and `EXCEPT ALL` return all applicable values, including duplicates. +These queries are faster, because they do not compute distinct results. + +You can improve the performance of a query by using covering indexes, where the index includes all the information needed to satisfy the query. +For more information, see xref:indexes:covering-indexes.adoc[Covering Indexes]. + +To order all the results of a set operator together, refer to the examples for the xref:n1ql-language-reference/orderby.adoc#Ex2[ORDER BY] clause. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +For the following examples, consider these queries and the number of results they return. + +.Q1 +[source,sqlpp] +---- +SELECT DISTINCT city FROM airport; +---- +(1641 results) + +.Q2 +[source,sqlpp] +---- +SELECT DISTINCT city FROM hotel; +---- +(274 results) + +NOTE: The `SELECT` statements in the following examples do not need to use the DISTINCT keyword, since the set operators return distinct results when used without the ALL keyword. + +.UNION of Q1 and Q2 +==== +[source,sqlpp] +---- +SELECT city FROM airport +UNION +SELECT city FROM hotel; +---- + +This gives 1871 results: + +[source,json] +---- +[ + { + "city": "Calais" + }, + { + "city": "Peronne" + }, + { + "city": "Nangis" + }, + { + "city": "Bagnole-de-l'orne" + }, +// ... +] +---- +==== + +.INTERSECT of Q1 and Q2 +==== +[source,sqlpp] +---- +SELECT city FROM airport +INTERSECT +SELECT city FROM hotel; +---- + +This gives 44 results: + +[source,json] +---- +[ + { + "city": "Cannes" + }, + { + "city": "Nice" + }, + { + "city": "Orange" + }, + { + "city": "Avignon" + }, +// ... +] +---- +==== + +.EXCEPT of Q1 and Q2 +==== +[source,sqlpp] +---- +SELECT city FROM airport +EXCEPT +SELECT city FROM hotel; +---- + +This gives 1597 results: + +[source,json] +---- +[ + { + "city": "Calais" + }, + { + "city": "Peronne" + }, + { + "city": "Nangis" + }, + { + "city": "Bagnole-de-l'orne" + }, +// ... +] +---- +==== + +.EXCEPT of Q2 and Q1 +==== +[source,sqlpp] +---- +SELECT city FROM hotel +EXCEPT +SELECT city FROM airport; +---- + +This gives 230 results: + +[source,json] +---- +[ + { + "city": "Medway" + }, + { + "city": "Gillingham" + }, + { + "city": "Giverny" + }, + { + "city": "Highland" + }, +// ... +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/unnest.adoc b/modules/n1ql/pages/n1ql-language-reference/unnest.adoc new file mode 100644 index 000000000..360c9450e --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/unnest.adoc @@ -0,0 +1,138 @@ += UNNEST clause +:description: The UNNEST clause creates an input object by flattening an array in the parent document. +:imagesdir: ../../assets/images +:from-term: pass:q[`UNNEST` clause] +:page-topic-type: reference + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +The `UNNEST` clause is used within the xref:n1ql-language-reference/from.adoc[FROM] clause. +If a document or object contains a nested array, UNNEST conceptually performs a join of the nested array with its parent object. +Each resulting joined object becomes an output of the query. +Unnests can be chained. + +TIP: To return the position of the elements in an unnested array after you use `UNNEST`, use the xref:n1ql-language-reference/metafun.adoc#unnest-pos[UNNEST_POS function]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=unnest-clause] +---- + +image::n1ql-language-reference/unnest-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +unnest-type:: <> icon:caret-down[] +expr:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[#from-term] +include::partial$n1ql-language-reference/from-term.adoc[] + +[#unnest-type] +=== Unnest Type + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=unnest-type] +---- + +image::n1ql-language-reference/unnest-type.png["Syntax diagram", align=left] + +This clause represents the type of unnest. + +`INNER`:: +For each result object produced, the array object in the left-hand side keyspace must be non-empty. + +`LEFT [OUTER]`:: +{startsb}Query Service interprets `LEFT` as `LEFT OUTER`{endsb} ++ +A left-outer unnest is performed, and at least one result object is produced for each left source object. + +This clause is optional. +If omitted, the default is `INNER`. + +[#unnest-path] +=== Unnest Path + +expr:: The path to the nested array. + +The path expression in each UNNEST clause must reference some preceding path. + +[#unnest-as-alias] +=== AS Alias + +Assigns another name to the right-hand side of the unnest. +For details, see xref:n1ql-language-reference/from.adoc#section_ax5_2nx_1db[AS Clause]. + +Assigning an alias to the path is optional. +If you assign an alias to the path, the `AS` keyword may be omitted. + +[NOTE] +==== +If you want to use an xref:n1ql-language-reference/indexing-arrays.adoc[ARRAY index] for the UNNEST query, you can use any arbitrary alias for the right side of the UNNEST -- the alias does not have to be the same as the ARRAY index variable name in order to use that index. +==== + +== Limitations + +You may chain UNNEST clauses with comma-separated joins; however, the comma-separated joins must come after any JOIN, NEST, or UNNEST clauses. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[#UNNEST-Example-1] +.UNNEST an array to select an item +==== +In the `route` keyspace, flatten the schedule array to get details of the flights on Monday (`1`). + +[source,sqlpp] +---- +include::example$select/unnest.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/unnest.jsonc[] +---- + +Another way to get similar results is by using a quantified expression to find array items that meet our criteria: + +[source,sqlpp] +---- +include::example$select/unnest-array.n1ql[] +---- + +However, without the `UNNEST` clause, the unflattened list results in 3 sets of flights instead of only 3 individual flights: + +[source,JSON] +---- +include::example$select/unnest-array.jsonc[] +---- +==== + +[#UNNEST-Example-2] +.Use `UNNEST` to collect items from one array to use in another query +==== +In this example, the `UNNEST` clause iterates over the `reviews` array and collects the `author` names of the reviewers who rated the rooms less than a 2 to be contacted for ways to improve. +`r` is an element of the array generated by the UNNEST operation. + +[source,sqlpp] +---- +include::example$select/unnest-raw.n1ql[] +---- + +.Results +[source,JSON] +---- +include::example$select/unnest-raw.jsonc[] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/update.adoc b/modules/n1ql/pages/n1ql-language-reference/update.adoc new file mode 100644 index 000000000..1bc0ba3aa --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/update.adoc @@ -0,0 +1,411 @@ += UPDATE +:description: UPDATE replaces a document that already exists with updated values. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:clusters:manage-database-users.adoc +:bucket-expiration: xref:server:learn:data/expiration.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:document-expiration: xref:java-sdk:howtos:kv-operations.adoc#document-expiration +:meta: xref:n1ql-language-reference/metafun.adoc#meta +:returning-clause: xref:n1ql-language-reference/insert.adoc#returning-clause +:use-keys-clause: xref:n1ql-language-reference/hints.adoc#use-keys-clause +:preserve_expiry: xref:n1ql:n1ql-manage/query-settings.adoc#preserve_expiry + +:from: xref:n1ql-language-reference/from.adoc +:from-keyspace-ref: {from}#from-keyspace-ref +:as-clause: {from}#section_ax5_2nx_1db + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] +include::partial$n1ql-language-reference/collapsible-style.adoc[] + +[abstract] +{description} + +WARNING: Please note that the examples on this page will alter the data in your sample buckets. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +== Prerequisites + +=== RBAC Privileges + +User executing the UPDATE statement must have the _Query Update_ privilege on the target keyspace. +If the statement has any clauses that needs data read, such as SELECT clause, or RETURNING clause, then _Query Select_ privilege is also required on the keyspaces referred in the respective clauses. +For more details about user roles, see {authorization-overview}[]. + +[NOTE] +A user with the _Data Writer_ privilege may set documents to expire. +When the document expires, the data service deletes the document, even though the user may not have the _Query Delete_ privilege. + +.RBAC Examples +[%collapsible] +==== +====== +include::ROOT:partial$query-context.adoc[tag=example] + +To execute the following statement, you must have the _Query Update_ privilege on `airport`. + +[source,sqlpp] +---- +include::example$dml/update-rbac.n1ql[] +---- + +To execute the following statement, you must have the _Query Update_ privilege on `airport` and _Query Select_ privilege on `pass:c[`beer-sample`]`. + +[source,sqlpp] +---- +include::example$dml/update-rbac-sub.n1ql[] +---- + +To execute the following statement, you must have the _Query Update_ and _Query Select_ privileges on `airport`. + +[source,sqlpp] +---- +include::example$dml/update-rbac-return.n1ql[] +---- +====== +==== + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=update] +---- + +image::n1ql-language-reference/update.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links from EBNF + +[horizontal.compact] +target-keyspace:: <> icon:caret-down[] +use-keys:: <> icon:caret-down[] +set-clause:: <> icon:caret-down[] +unset-clause:: <> icon:caret-down[] +where-clause:: <> icon:caret-down[] +limit-clause:: <> icon:caret-down[] +returning-clause:: <> icon:caret-down[] + +[[update-target]] +=== Update Target + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=target-keyspace] +---- + +image::n1ql-language-reference/target-keyspace.png["Syntax diagram: refer to source code listing", align=left] + +The update target is the keyspace which you want to update. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[keyspace-ref]] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Keyspace reference for the update target. +For more details, refer to {from-keyspace-ref}[Keyspace Reference]. + +[id="update-alias"] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[[update-hint]] +=== Update Hint + +You can use a `USE KEYS` hint on the update target to specify the keys of the data items to be updated. +For details, refer to {use-keys-clause}[USE KEYS Clause]. + +[[set-clause]] +=== SET Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=set-clause] +---- + +image::n1ql-language-reference/set-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the value for an attribute to be changed. + +[horizontal] +path:: +A <> specifying the attribute to be changed. + +expr:: +The value may be a generic expression term, a subquery, or an expression that resolves to nested array elements. + +update-for:: <> icon:caret-down[] + +The SET clause also supports alternative arguments which enable you to set the expiration of the document. + +[horizontal] +meta:: +A {meta}[META().expiration] expression specifying the expiration property of the document being updated. + +expiration:: +An integer, or an expression resolving to an integer, representing the {document-expiration}[document expiration] in seconds. + +[NOTE] +If the document expiration is not specified, the document expiration is set according to the request-level {preserve_expiry}[preserve_expiry] parameter. +If this is `true`, the existing document expiration is preserved; if `false`, the document expiration defaults to `0`, meaning the document expiration is the same as the {bucket-expiration}[bucket or collection expiration]. + +[[unset-clause]] +=== UNSET Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=unset-clause] +---- + +image::n1ql-language-reference/unset-clause.png["Syntax diagram: refer to source code listing", align=left] + +Removes the specified attribute from the document. + +[horizontal.compact] +path:: +A <> specifying the attribute to be removed. + +update-for:: <> icon:caret-down[] + +[NOTE] +You cannot use the UNSET clause to unset the document expiration. +To unset the document expiration, set the document expiration to `0`. +Alternatively, if the request-level {preserve_expiry}[preserve_expiry] parameter is set to `false`, simply update the document without specifying the document expiration. + +[[update-for]] +=== FOR Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=update-for] +---- + +image::n1ql-language-reference/update-for.png["Syntax diagram: refer to source code listing", align=left] + +[source#path,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=path] +---- + +image::n1ql-language-reference/path.png["Syntax diagram: refer to source code listing", align=left] + +Uses the FOR statement to iterate over a nested array to SET or UNSET the given attribute for every matching element in the array. +The FOR clause can evaluate functions and expressions, and the UPDATE statement supports multiple nested FOR expressions to access and update fields in nested arrays. +Additional array levels are supported by chaining the FOR clauses. + +[[where-clause]] +=== WHERE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the condition that needs to be met for data to be updated. +Optional. + +[[limit-clause]] +=== LIMIT Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=limit-clause] +---- + +image::n1ql-language-reference/limit-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the greatest number of objects that can be updated. +This clause must have a non-negative integer as its upper bound. +Optional. + +[[returning-clause]] +=== RETURNING Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=returning-clause] +---- + +image::n1ql-language-reference/returning-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the information to be returned by the operation as a query result. +For more details, refer to {returning-clause}[RETURNING Clause]. + +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +NOTE: For some of these examples, the Query tab may warn you that the query has no WHERE clause and will update all documents. +In this case, you can ignore the warning: the USE KEYS hint in these examples ensures that the query updates only one document. + +[[example-1]] +.Set an attribute +==== +The following statement sets the nickname of the landmark "Tradeston Pedestrian Bridge" to "Squiggly Bridge". + +[source,sqlpp] +---- +include::example$dml/update-set.n1ql[] +---- + +[source,json] +---- +include::example$dml/update-set.jsonc[] +---- +==== + +[[example-2]] +.Unset an attribute +==== +This statement removes the `nickname` attribute from the `landmark` keyspace for the document with the key `landmark_10090`. + +[source,sqlpp] +---- +include::example$dml/update-unset.n1ql[] +---- + +[source,json] +---- +include::example$dml/update-unset.jsonc[] +---- +==== + +[[example-3]] +.Set attributes in an array +==== +This statement sets the `codeshare` attribute for each element in the `schedule` array for document `route_10003` in the `route` keyspace. + +[source,sqlpp] +---- +include::example$dml/update-set-array.n1ql[] +---- + +[source,json] +---- +include::example$dml/update-set-array.jsonc[tags=extract;ellipsis] +---- +==== + +[[example-4]] +.Set nested array elements +==== +[source,sqlpp] +---- +include::example$dml/update-set-nested.n1ql[] +---- + +[source,json] +---- +include::example$dml/update-set-nested.jsonc[] +---- +==== + +[[example-5]] +.Access nested arrays +==== +.Query +[source,sqlpp] +---- +include::example$dml/update-unset-nested.n1ql[] +---- + +.Result +[source,json] +---- +include::example$dml/update-unset-nested.jsonc[] +---- +==== + +[[example-6]] +.Update a document with the results of a subquery +==== +.Query +[source,sqlpp] +---- +include::example$dml/update-set-sub.n1ql[] +---- + +.Result +[source,json] +---- +include::example$dml/update-set-sub.jsonc[] +---- +==== + +[[example-7]] +.Update a document and set expiration +==== +Update a document and set the expiration to 1 week. + +.Query +[source,sqlpp] +---- +include::example$dml/update-set-expire.n1ql[] +---- +==== + +[[example-8]] +.Update a document and preserve expiration +==== +.Query +[source,sqlpp] +---- +include::example$dml/update-preserve-expire.n1ql[] +---- + +Note that it is possible to preserve the document expiration using the request-level {preserve_expiry}[preserve_expiry] parameter. +==== + +[[example-9]] +.Update a document and unset expiration +==== +Set the document expiration to 0 to unset the document expiration. +(In this case, the document expiration defaults to be the same as the bucket or collection expiration.) + +.Query +[source,sqlpp] +---- +include::example$dml/update-unset-expire.n1ql[] +---- + +Alternatively, if the request-level {preserve_expiry}[preserve_expiry] parameter is set to `false`, and you update the document without specifying the document expiration, the document expiration defaults to 0. + +.Query +[source,sqlpp] +---- +include::example$dml/update-unset-expire-alt.n1ql[] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/updatestatistics.adoc b/modules/n1ql/pages/n1ql-language-reference/updatestatistics.adoc new file mode 100644 index 000000000..a9e6aff9a --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/updatestatistics.adoc @@ -0,0 +1,127 @@ += UPDATE STATISTICS +:description: The UPDATE STATISTICS statement collects statistics on expressions over a named keyspace. +:page-topic-type: reference +:imagesdir: ../../assets/images + +// Cross-references +:monitor: xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc +:n1ql: xref:n1ql-language-reference +:cbo: {n1ql}/cost-based-optimizer.adoc +:select: {n1ql}/selectintro.adoc +:update: {n1ql}/update.adoc +:delete: {n1ql}/delete.adoc +:merge: {n1ql}/merge.adoc +:insert: {n1ql}/insert.adoc + +//Related links +:updatestatistics: {n1ql}/updatestatistics.adoc +:statistics-expressions: {n1ql}/statistics-expressions.adoc +:statistics-index: {n1ql}/statistics-index.adoc +:statistics-indexes: {n1ql}/statistics-indexes.adoc +:statistics-delete: {n1ql}/statistics-delete.adoc + +[abstract] +{description} +These statistics are used by the cost-based optimizer when choosing the optimal plan to execute a query. + +[[purpose]] +== Purpose + +The {cbo}[cost-based optimizer] uses statistics to generate a query plan with the lowest processing cost, for {select}[SELECT], {update}[UPDATE], {delete}[DELETE], {merge}[MERGE], and {insert}[INSERT INTO with SELECT] queries. + +After creating the indexes, and before running a query, you must gather distribution statistics for the expressions used in the query. +The cost-based optimizer uses these distribution statistics, together with keyspace and index statistics, to select the optimal indexes and generate the query plan. + +In Couchbase Server 7.6 and later, the Query service automatically gathers statistics whenever an index is created or built. +You can use the `UPDATE STATISTICS` statement to gather statistics at any time. + +[[syntax]] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/utility.ebnf[tag=update-statistics] +---- + +image::n1ql-language-reference/update-statistics.png["Syntax diagram: refer to source code listing", align=left] + +The `UPDATE STATISTICS` statement provides several different syntaxes to enable you to manage statistics. +For further details, refer to the following links. + +* {statistics-expressions}[Update Statistics for Index Expressions] +* {statistics-index}[Update Statistics for a Single Index] +* {statistics-indexes}[Update Statistics for Multiple Indexes] +* {statistics-delete}[Delete Statistics] + +[[usage]] +== Usage + +When you use an index with a query, you typically create the index on the fields which the query uses to filter. +To use the cost-based optimizer with that query, you must collect statistics on the same fields that you used to create the index. + +A query may have predicates on non-indexed fields, and you can collect statistics on those fields also to help the optimizer. + +For a query which filters on an array or array of objects, you must collect the statistics using exactly the same expression that you used to create the index. + +=== When to Gather Statistics + +How frequently you should run the `UPDATE STATISTICS` statement to gather statistics depends on the rate of data change. +For data that does not change frequently, there is no need to run `UPDATE STATISTICS`. +For data that changes constantly, you should run `UPDATE STATISTICS` more frequently. + +To gather statistics automatically, consider running a `cron` job at regular intervals to execute the `UPDATE STATISTICS` statement via the xref:n1ql:n1ql-intro/cbq.adoc#executing-a-script[cbq shell]. + +[[result]] +== Result + +If successful, the statement returns an empty array. + +=== Index Residency + +Optimizer statistics for an index can only be gathered when the index is at least partially memory-resident. +The optimizer statistics are gathered from the memory-resident portion of an index. +A higher memory-resident ratio produces more accurate optimizer statistics for that index. + +If an index has a memory-resident ratio of zero, then the statement returns the following warning: + +[source,json] +---- +[ + { + "code": 5390, + "msg": "Index def_inventory_airport_faa is not in memory" + } +] +---- + +Depending on the index storage settings, if an index has been scanned recently, it is more likely to be memory-resident; whereas if an index is not used for a long while, then it is more likely to be ejected from memory. +You may be able to improve the memory-resident ratio for an index (and avoid error 5390) by running one or more queries which use that index. +For further details, refer to xref:learn:services-and-indexes/indexes/storage-modes.adoc[Storage Settings]. + +== Optimizer Statistics + +For each bucket, the `UPDATE STATISTICS` command stores statistics in a collection called `_query` within a scope called `_system`. +The `_system` scope and its collections, including `_query`, are created automatically when you create a bucket, or when you migrate a bucket from a previous version of Couchbase Server. + +=== Security for Optimizer Statistics + +Regular users do not have access to the `_system` scope or any of its collections, including `_query`. + +Users with system administration privileges can access `_system` scope and its collections, including `_query`. +However, even with system administration privileges, you can't drop or create the `_system` scope or any of its collections. + +The `_system` scope and its collections are not listed in the *Explore Your Data* area in the Query tab. + +=== Optimizer Statistics for Multiple Query Nodes + +When a cluster has multiple Query nodes, statistics gathered from one Query node via the `UPDATE STATISTICS` statement are automatically propagated to the other Query nodes. +You don't need to run `UPDATE STATISTICS` with the same index expression for multiple query nodes. + +=== Monitoring Optimizer Statistics + +To monitor the optimizer statistics, query the `system:dictionary` and `system:dictionary_cache` keyspaces. +For further details, refer to {monitor}[]. + +== Related Links + +* {cbo}[Cost-Based Optimizer] \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/upsert.adoc b/modules/n1ql/pages/n1ql-language-reference/upsert.adoc new file mode 100644 index 000000000..5f97821e5 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/upsert.adoc @@ -0,0 +1,260 @@ += UPSERT +:description: UPSERT is used to insert a new record or update an existing one. +:page-topic-type: reference +:imagesdir: ../../assets/images + +:authorization-overview: xref:server:learn:security/authorization-overview.adoc +:bucket-expiration: xref:server:learn:data/expiration.adoc +:select-syntax: xref:n1ql-language-reference/select-syntax.adoc +:logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy +:paths: xref:n1ql-intro/queriesandresults.adoc#paths +:document-expiration: xref:java-sdk:howtos:kv-operations.adoc#document-expiration +:preserve_expiry: xref:n1ql:n1ql-manage/query-settings.adoc#preserve_expiry + +:from: xref:n1ql-language-reference/from.adoc +:from-keyspace-ref: {from}#from-keyspace-ref +:as-clause: {from}#section_ax5_2nx_1db + +:insert: xref:n1ql-language-reference/insert.adoc +:insert-values: {insert}#insert-values +:values-clause: {insert}#values-clause +:insert-select: {insert}#insert-select +:result-expression: {insert}#result-expr + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] +include::partial$n1ql-language-reference/collapsible-style.adoc[] + +[abstract] +{description} +If the document doesn't exist it will be created. +UPSERT is a combination of INSERT and UPDATE. + +WARNING: Please note that the examples on this page will alter the data in your sample buckets. +To restore your sample data, remove and reinstall the `travel-sample` bucket. +Refer to xref:clusters:data-service/import-data-documents.adoc#import-sample-data[Import Sample Data] for details. + +== Prerequisites + +=== RBAC Privileges + +User executing the UPSERT statement must have the _Query Update_ and _Query Insert_ privileges on the target keyspace. +If the statement has any RETURNING clauses, then the _Query Select_ privilege is also required on the keyspaces referred in the respective clauses. +For more details about user roles, see +{authorization-overview}[Authorization]. + +[NOTE] +A user with the _Data Writer_ privilege may set documents to expire. +When the document expires, the data service deletes the document, even though the user may not have the _Query Delete_ privilege. + +.RBAC Examples +[%collapsible] +==== +====== +include::ROOT:partial$query-context.adoc[tag=example] + +To execute the following statement, you must have the _Query Update_ and _Query Insert_ privileges on `hotel`. + +[source,sqlpp] +---- +include::example$dml/upsert-rbac.n1ql[] +---- + +To execute the following statement, you must have the _Query Update_ and _Query Insert_ privileges on `hotel` and the _Query Select_ privilege on `hotel` also (for RETURNING clause). + +[source,sqlpp] +---- +include::example$dml/upsert-rbac-return.n1ql[] +---- + +.Result +[source,json] +---- +include::example$dml/upsert-rbac-return.jsonc[] +---- + +To execute the following statement, you must have the _Query Update_ and _Query Insert_ privileges on `landmark` and _Query Select_ privilege on `pass:c[`beer-sample`]`. + +[source,sqlpp] +---- +include::example$dml/upsert-rbac-select.n1ql[] +---- +====== +==== + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=upsert] +---- + +image::n1ql-language-reference/upsert.png["Syntax diagram: refer to source code listing", align=left] + +// TODO: Automatic links from EBNF + +[horizontal.compact] +target-keyspace:: <> icon:caret-down[] +insert-values:: <> icon:caret-down[] +insert-select:: <> icon:caret-down[] +returning-clause:: <> icon:caret-down[] + +[[insert-target]] +=== Insert Target + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=target-keyspace] +---- + +image::n1ql-language-reference/target-keyspace.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the keyspace into which to upsert documents. + +[horizontal.compact] +keyspace-ref:: <> icon:caret-down[] +alias:: <> icon:caret-down[] + +[[insert-target-ref]] +==== Keyspace Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-ref] +---- + +image::n1ql-language-reference/keyspace-ref.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-path,ebnf,reftext="keyspace path"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-path] +---- + +image::n1ql-language-reference/keyspace-path.png["Syntax diagram: refer to source code listing", align=left] + +[source#keyspace-partial,ebnf,reftext="keyspace partial"] +---- +include::partial$grammar/dql.ebnf[tag=keyspace-partial] +---- + +image::n1ql-language-reference/keyspace-partial.png["Syntax diagram: refer to source code listing", align=left] + +Keyspace reference for the insert target. +For more details, refer to {from-keyspace-ref}[Keyspace Reference]. + +[[insert-target-alias]] +==== AS Alias + +Assigns another name to the keyspace reference. +For details, refer to {as-clause}[AS Clause]. + +Assigning an alias to the keyspace reference is optional. +If you assign an alias to the keyspace reference, the `AS` keyword may be omitted. + +[[insert-values]] +=== Insert Values + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=insert-values] +---- +image::n1ql-language-reference/insert-values.png["Syntax diagram: refer to source code listing", align=left] + +Specifies one or more documents to be upserted using the VALUES clause. +For details, refer to {insert-values}[Insert Values]. + +[horizontal.compact] +values-clause:: <> icon:caret-down[] + +[[values-clause]] +==== VALUES Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=values-clause] +---- + +image::n1ql-language-reference/values-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specify the values as well-formed JSON. +Also enables you to set the {document-expiration}[expiration] of the upserted documents. +For details, refer to {values-clause}[VALUES Clause]. + +[NOTE] +When updating a document, if the document expiration is not specified, the document expiration is set according to the request-level {preserve_expiry}[preserve_expiry] parameter. +If this is `true`, the existing document expiration is preserved; if `false`, the document expiration defaults to `0`, meaning the document expiration is the same as the {bucket-expiration}[bucket or collection expiration]. + +[[insert-select]] +=== Insert Select + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=insert-select] +---- + +image::n1ql-language-reference/insert-select.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the documents to be upserted as a SELECT statement. +Also enables you to set the {document-expiration}[expiration] of the upserted documents. +For details, refer to {insert-select}[Insert Select]. + +[NOTE] +When updating a document, if the document expiration is not specified, the document expiration is set according to the request-level {preserve_expiry}[preserve_expiry] parameter. +If this is `true`, the existing document expiration is preserved; if `false`, the document expiration defaults to `0`, meaning the document expiration is the same as the {bucket-expiration}[bucket or collection expiration]. + +//// +[[select-statement]] +==== SELECT Statement + +SELECT statements let you retrieve data from specified keyspaces. +For details, refer to {select-syntax}[SELECT Syntax]. +//// + +[[returning-clause]] +=== RETURNING Clause + +[source,ebnf] +---- +include::partial$grammar/dml.ebnf[tag=returning-clause] +---- + +image::n1ql-language-reference/returning-clause.png["Syntax diagram: refer to source code listing", align=left] + +Specifies the fields that must be returned as part of the results object. + +[horizontal.compact] +result-expr:: <> icon:caret-down[] + +[[result-expr]] +==== Result Expression + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=result-expr] +---- + +image::n1ql-language-reference/result-expr.png["Syntax diagram: refer to source code listing", align=left] + +Specifies an expression on the data you upserted, to be returned as output. +For details, refer to {result-expression}[Result Expression]. + +== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +[[example-1]] +==== +The following statement upserts documents with type [.in]`landmark-pub` into the [.in]`landmark` keyspace. + +.Query +[source,sqlpp] +---- +include::example$dml/upsert-batch.n1ql[] +---- + +.Result +[source,json] +---- +include::example$dml/upsert-batch.jsonc[] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc new file mode 100644 index 000000000..c8f4e4341 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc @@ -0,0 +1,195 @@ += User-Defined Functions +:description: You can call a user-defined function in any expression where you can call a built-in function. +:page-topic-type: reference +:imagesdir: ../../assets/images +:page-partial: + +[abstract] +{description} + +== Description + +When you have created a user-defined function, you can call it in any expression, just like a built-in function. +User-defined functions have the same syntax as built-in functions, with brackets `()` to contain any arguments. + +The name of the function is usually an unqualified identifier, such as `func1` or `{backtick}func-1{backtick}`. +In this case, the path to the function is determined by the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +To call a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as `default:func1`. +Similarly, to call a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. +Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more details. + +NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. +You must call the user-defined function using the same case that was used when it was created. + +It is not possible to call a user-defined function in an expression if the function has side effects, such as performing mutations. +When you do this, an error is generated. + +== Prerequisites + +[cols="2,3"] +|=== +| To execute ... | You must have ... + +| Global inline functions +| *Execute Global Functions* role. + +| Scoped inline functions +| *Execute Scope Functions* role, with permissions on the specified bucket and scope. + +| Global external functions +| *Execute Global External Functions* role. + +| Scoped external functions +| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. +|=== + +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Arguments + +A user-defined function has zero, one, or more arguments, separated by commas, just like a built-in function. +Each argument is a {sqlpp} expression required by the function. + +If the function was created with named parameters, you must supply all the arguments that were specified when the function was created. +If the function was created without named parameters, you cannot supply an argument. +If the function is variadic, you can supply as many arguments as needed, or none. + +include::partial$n1ql-language-reference/udf-output.adoc[] + +== Examples + +Refer to xref:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] for details on creating user-defined functions. + +For simplicity, none of these examples implement any data validation or error checking. +If necessary, you can use xref:n1ql:n1ql-language-reference/conditionalops.adoc[conditional operators] to check the parameters of a user-defined function, and the xref:n1ql:n1ql-language-reference/metafun.adoc#abort[ABORT()] function to generate an error if something is wrong. + +include::ROOT:partial$query-context.adoc[tag=statement] + +.Inline function with expression +==== +The following statement creates a function called `to_meters`, which converts feet to meters. + +[source,sqlpp] +---- +CREATE FUNCTION to_meters(...) { args[0] * 0.3048 }; +---- + +The following query uses the `to_meters` function to express the elevation of the selected airports in meters above mean sea level (mamsl). +The built-in ROUND function is used to round the output to zero decimal places. + +.Query +[source,sqlpp] +---- +SELECT airportname, ROUND(to_meters(geo.alt)) AS mamsl +FROM airport +LIMIT 5; +---- + +.Result +[source,json] +---- +[ + { + "airportname": "Calais Dunkerque", + "mamsl": 4 + }, + { + "airportname": "Peronne St Quentin", + "mamsl": 90 + }, + { + "airportname": "Les Loges", + "mamsl": 130 + }, + { + "airportname": "Couterne", + "mamsl": 219 + }, + { + "airportname": "Bray", + "mamsl": 111 + } +] +---- +==== + +.Inline function with subquery +==== +The following statement creates a function called `locations`, which selects name and address information from all documents with the specified activity in the `landmark` keyspace. + +[source,sqlpp] +---- +include::example$n1ql-language-reference/udf-locations-define.n1ql[] +---- + +The following query uses the `locations` function as the FROM term in a SELECT query. +Compare this query with xref:n1ql-language-reference/from.adoc#ex-subquery-1[Example 2 in FROM Subquery]. + +.Query +[source,sqlpp] +---- +include::example$n1ql-language-reference/udf-locations-query.n1ql[] +---- + +.Result +[source,json] +---- +include::example$n1ql-language-reference/udf-locations-query.jsonc[] +---- +==== + +.External functions +==== +For this example, it is assumed that you have created two external functions: + +. A function called `geohash`, which depends on the JavaScript `encodeGeoHash` function in the `geohash-js` library; +. A function called `adjacent`, which depends on the JavaScript `calculateAdjacent` function in the `geohash-js` library. + +Refer to xref:n1ql-language-reference/createfunction.adoc#ex-external[Example 7 in CREATE FUNCTION] for details. + +The following query uses the `geohash` and `adjacent` functions to find the 9-figure geohash of the selected hotel, and the geohashes immediately to the north, south, west, and east. + +.Query +[source,sqlpp] +---- +SELECT area, + adjacent(area, "top") AS north, + adjacent(area, "bottom") AS south, + adjacent(area, "left") AS west, + adjacent(area, "right") AS east +FROM hotel +LET area = SUBSTR(geohash(geo.lat, geo.lon), 0, 9) +WHERE name = "Sachas Hotel"; +---- + +.Result +[source,json] +---- +[ + { + "area": "gcw2m05h1", + "east": "gcw2m05h4", + "north": "gcw2m05h3", + "south": "gcw2m055c", + "west": "gcw2m05h0" + } +] +---- + +To view the first geohash on a map, go to http://geohash.org/gcw2m05h1 and follow one of the links provided. +You can view the other geohashes by editing the URL. +At the latitude of the selected hotel, each geohash represents an area of approximately 3 𐄂 5 meters. +==== + +== Related Links + +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +ifdef::flag-devex-rest-api[] +* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. +endif::flag-devex-rest-api[] +* To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. +* To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. +* To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/where.adoc b/modules/n1ql/pages/n1ql-language-reference/where.adoc new file mode 100644 index 000000000..83ff87077 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/where.adoc @@ -0,0 +1,143 @@ += WHERE clause +:description: The WHERE clause filters resultsets based specified conditions. +:imagesdir: ../../assets/images +:page-topic-type: reference + +[abstract] +The `WHERE` clause filters resultsets based specified conditions. + +== Purpose + +When you want to narrow down your resultset by one or more criteria, use the `WHERE` clause to filter your resultset. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=where-clause] +---- + +image::n1ql-language-reference/where-clause.png["Syntax diagram: refer to source code listing", align=left] + +== Arguments + +cond:: [Required] Conditional expression that represents a filter to be applied to the resultset. +Records for which the condition resolves to TRUE are propagated to the resultset. + +You can construct complex conditional expressions, for example by using the xref:n1ql-language-reference/logicalops.adoc[logical operators] `AND`, `OR`, and `NOT`. + +[#examples_section] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Use WHERE filter the resultset +==== +To list only airports that are in France, use the `WHERE` clause for the "country" field. + +[source,sqlpp] +---- +SELECT airportname, city, country +FROM airport +WHERE country = "France" +LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "airportname": "Calais Dunkerque", + "city": "Calais", + "country": "France" + }, + { + "airportname": "Peronne St Quentin", + "city": "Peronne", + "country": "France" + }, + { + "airportname": "Les Loges", + "city": "Nangis", + "country": "France" + }, + { + "airportname": "Couterne", + "city": "Bagnole-de-l'orne", + "country": "France" + } +] +---- +==== + +.Use WHERE and OR to filter the resultset +==== +List only the landmarks that start with the letter "C" or "K". +Note that the first position of the `SUBSTR` function is `0`. + +[source,sqlpp] +---- +SELECT name +FROM landmark +WHERE CONTAINS(SUBSTR(name,0,1),"C") + OR CONTAINS(SUBSTR(name,0,1),"K") +LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "name": "City Chambers" + }, + { + "name": "Kingston Bridge" + }, + { + "name": "Clyde Arc" + }, + { + "name": "Clyde Auditorium" + } +] +---- +==== + +.Use WHERE, AND and NOT to filter the resultset +==== +List landmark restaurants, except Thai restaurants. + +[source,sqlpp] +---- +SELECT name, activity +FROM landmark +WHERE activity = "eat" +AND NOT CONTAINS(name,"Thai") +LIMIT 4; +---- + +.Results +[source,json] +---- +[ + { + "activity": "eat", + "name": "Hollywood Bowl" + }, + { + "activity": "eat", + "name": "Spice Court" + }, + { + "activity": "eat", + "name": "Beijing Inn" + }, + { + "activity": "eat", + "name": "Ossie's Fish and Chips" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-language-reference/window.adoc b/modules/n1ql/pages/n1ql-language-reference/window.adoc new file mode 100644 index 000000000..ea14b48e6 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/window.adoc @@ -0,0 +1,595 @@ += WINDOW Clause +:page-topic-type: reference +:description: The WINDOW clause defines named windows for window functions and aggregate functions used as window functions. +:imagesdir: ../../assets/images + +:aggregatefun: xref:n1ql-language-reference/aggregatefun.adoc +:count: {aggregatefun}#count +:countn: {aggregatefun}#countn +:windowfun: xref:n1ql-language-reference/windowfun.adoc +:nth-value: {windowfun}#fn-window-nth-value +:first-value: {windowfun}#fn-window-first-value +:last-value: {windowfun}#fn-window-last-value +:lag: {windowfun}#fn-window-lag +:lead: {windowfun}#fn-window-lead +:row-number: {windowfun}#fn-window-row-number +:rank: {windowfun}#fn-window-rank +:dense-rank: {windowfun}#fn-window-dense-rank +:percent-rank: {windowfun}#fn-window-percent-rank +:cume-dist: {windowfun}#fn-window-cume-dist +:ratio-to-report: {windowfun}#fn-window-ratio-to-report +:groupby: xref:n1ql-language-reference/groupby.adoc +:letting-clause: {groupby}#letting-clause +:having-clause: {groupby}#having-clause +:expression: xref:n1ql-language-reference/index.adoc#N1QL_Expressions +:number: xref:n1ql-language-reference/literals.adoc#numbers +:identifier: xref:n1ql-language-reference/identifiers.adoc +:orderby: xref:n1ql-language-reference/orderby.adoc +:datefun: xref:n1ql-language-reference/datefun.adoc + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +== Purpose + +include::partial$n1ql-language-reference/window-intro.adoc[tag=windows] + +.Window partitions and the window frame +image::window-example.png[Table of query result set with numbered callouts] + +// workaround for callout list with no callout references + +[%hardbreaks] +➀ The query result set. +➁ Window partitions -- partitioned by `name`, ordered by `time`. +➂ The current object. +➃ The window frame -- between unbounded preceding and current object. + +include::partial$n1ql-language-reference/window-intro.adoc[tag=functions] + +include::partial$n1ql-language-reference/window-intro.adoc[tag=syntax] + +include::partial$n1ql-language-reference/select-privilege.adoc[] + +== Syntax + +This page gives the syntax of the WINDOW clause. +Refer to {aggregatefun}[Aggregate Functions] or {windowfun}[Window Functions] for the details of window function calls. + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-clause] +---- + +image::n1ql-language-reference/window-clause.png["Syntax diagram", align=left] + +[[window-declaration]] +=== Window Declaration + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-declaration] +---- + +image::n1ql-language-reference/window-declaration.png["Syntax diagram", align=left] + +[horizontal.compact] +window-name:: <> icon:caret-down[] +window-definition:: <> icon:caret-down[] + +The *window declaration* assigns a name to the window definition. + +[[window-name]] +==== Window Name + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-name] +---- + +// {identifier}[identifier] +image::n1ql-language-reference/window-name.png["Syntax diagram", align=left] + +The window name must be unique in the current query block. + +[[window-definition]] +=== Window Definition + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-definition] +---- + +image::n1ql-language-reference/window-definition.png["Syntax diagram", align=left] + +[horizontal.compact] +window-ref:: <> icon:caret-down[] +window-partition-clause:: <> icon:caret-down[] +window-order-clause:: <> icon:caret-down[] +window-frame-clause:: <> icon:caret-down[] + +The *window definition* specifies the partitioning, ordering, and framing for window functions. + +[[window-ref]] +==== Window Reference + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-ref] +---- + +// {identifier}[identifier] +image::n1ql-language-reference/window-ref.png["Syntax diagram", align=left] + +The *window reference* enables you to reuse the definition of an existing named window, and extend that definition if necessary. +For example, you may refer to an existing named window which specifies partitioning and ordering options, and extend that window definition with additional framing options. + +The referenced named window must be within the scope of the current window definition. +Furthermore, when one named window refers to another existing named window, the referenced named window must be declared earlier in the current query block. + +The following syntax restrictions apply when using a window reference: + +* The current window definition may not include a <>. + +* The current window definition may only include a <> if the referenced named window does _not_ specify a window order clause. + +* The referenced named window may not specify a <>. + +[[window-partition-clause]] +==== Window Partition Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-partition-clause] +---- + +// {expression}[expr] +image::n1ql-language-reference/window-partition-clause.png["Syntax diagram", align=left] + +The *window partition clause* groups the query results into partitions using one or more expressions. + +This clause may be used with any {windowfun}[window function], or any {aggregatefun}[aggregate functions] used as a window function. + +This clause is optional. +If omitted, all the query results are grouped into single partition. + +[[window-order-clause]] +==== Window Order Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-order-clause] +---- + +image::n1ql-language-reference/window-order-clause.png["Syntax diagram", align=left] + +The *window order clause* determines how objects are ordered within each partition. +The window function works on objects in the order specified by this clause. + +This clause may be used with any {windowfun}[window function], or any {aggregatefun}[aggregate functions] used as a window function. + +This clause is optional for some functions, and required for others. +See the {aggregatefun}[Aggregate Functions] page or {windowfun}[Window Functions] page for details of the syntax of individual functions. + +If this clause is omitted, all objects are considered peers, i.e. their order is tied. +When objects in the window partition are tied, each window function behaves differently. + +* The {row-number}[ROW_NUMBER()] function returns a distinct number for each object. +If objects are tied, the results may be unpredictable. + +* The {rank}[RANK()], {dense-rank}[DENSE_RANK()], {percent-rank}[PERCENT_RANK()], and {cume-dist}[CUME_DIST()] functions return the same result for each object. + +* For other functions, if the <> is defined by `ROWS`, the results may be unpredictable. +If the window frame is defined by `RANGE` or `GROUPS`, the results are same for each object. + +This clause may have multiple <>. +To reduce the number of ties, add additional <>. + +[NOTE] +==== +This clause does not guarantee the overall order of the query results. +To guarantee the order of the final results, use the query {orderby}[ORDER BY clause]. +==== + +[[ordering-term]] +==== Ordering Term + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=ordering-term] +---- + +// {expression}[expr] +image::n1ql-language-reference/ordering-term.png["Syntax diagram", align=left] + +The *ordering term* specifies an ordering expression, collation, and nulls ordering. + +This clause has the same syntax and semantics as the ordering term for queries. +Refer to {orderby}[ORDER BY clause] for details. + +[[window-frame-clause]] +=== Window Frame Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-frame-clause] +---- + +image::n1ql-language-reference/window-frame-clause.png["Syntax diagram", align=left] + +[horizontal.compact] +window-frame-extent:: <> icon:caret-down[] +window-frame-exclusion:: <> icon:caret-down[] + +The *window frame clause* defines the window frame. + +This clause can be used with all {aggregatefun}[Aggregate Functions] and some {windowfun}[Window Functions] -- see the descriptions of individual functions for more details. + +This clause is allowed only when the <> is present. + +This clause is optional. + +* If this clause is omitted and there is no <>, the window frame is the entire partition. + +* If this clause is omitted but there is a <>, the window frame becomes all objects in the partition preceding the current object and its peers -- the same as `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`. + +The window frame can be defined in the following ways: + +`ROWS`:: Counts the exact number of objects within the frame. +If window ordering doesn't result in unique ordering, the function may produce unpredictable results. +You can add a unique expression or more window ordering expressions to produce unique ordering. + +`RANGE`:: Looks for a value offset within the frame. +The function produces deterministic results. + +`GROUPS`:: Counts all groups of tied rows within the frame. +The function produces deterministic results. + +[NOTE] +==== +If this clause uses `RANGE` with either `_valexpr_ PRECEDING` or `_valexpr_ FOLLOWING`, the <> must have only a single ordering term. +The ordering term expression must evaluate to a number. + +If the ordering term expression does not evaluate to a number, the window frame will be empty, which means the window function will return its default value: in most cases this is NULL, except for {count}[COUNT()] or {countn}[COUNTN()], whose default value is 0. + +This restriction does not apply when the window frame uses `ROWS` or `GROUPS`. +==== + +[TIP] +==== +The `RANGE` window frame is commonly used to define a window frame based on date or time. +In JSON, dates and times are represented as a string in ISO-8601 standard. + +If you want to use `RANGE` with either `_valexpr_ PRECEDING` or `_valexpr_ FOLLOWING`, and you want to use an ordering expression based on date or time, use the appropriate {datefun}[date or time function] to convert the date or time into milliseconds, then use the resulting number in the ordering expression. +==== + +[[window-frame-extent]] +==== Window Frame Extent + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-frame-extent] +---- + +image::n1ql-language-reference/window-frame-extent.png["Syntax diagram", align=left] + +[horizontal.compact] +valexpr:: The `_valexpr_` must be a positive constant or an expression that evaluates as a positive {number}[number]. +For `ROWS` or `GROUPS`, the `_valexpr_` must be an integer. + +The *window frame extent* clause specifies the start point and end point of the window frame. + +The expression before `AND` is the start point and expression after `AND` is the end point. +If `BETWEEN` is omitted, you can only specify the start point; the end point becomes `CURRENT ROW`. + +The window frame end point can't be before the start point. +If this clause violates this restriction explicitly, an error will result. +If it violates this restriction implicitly, the window frame will be empty, which means the window function will return its default value: in most cases this is NULL, except for {count}[COUNT()] or {countn}[COUNTN()], whose default value is 0. + +Window frame extents that result in an explicit violation are: + +* `( ROWS | RANGE | GROUPS ) BETWEEN CURRENT ROW AND _valexpr_ PRECEDING` + +* `( ROWS | RANGE | GROUPS ) BETWEEN _valexpr_ FOLLOWING AND _valexpr_ PRECEDING` + +* `( ROWS | RANGE | GROUPS ) BETWEEN _valexpr_ FOLLOWING AND CURRENT ROW` + +Window frame extents that result in an implicit violation are: + +* `( ROWS | RANGE | GROUPS ) BETWEEN UNBOUNDED PRECEDING AND _valexpr_ PRECEDING` -- if `_valexpr_` is too high, some objects may generate an empty window frame. + +* `( ROWS | RANGE | GROUPS ) BETWEEN _valexpr_ PRECEDING AND _valexpr_ PRECEDING` -- if the second `_valexpr_` is greater than or equal to the first `_valexpr_`, all result sets will generate an empty window frame. + +* `( ROWS | RANGE | GROUPS ) BETWEEN _valexpr_ FOLLOWING AND _valexpr_ FOLLOWING` -- if the first `_valexpr_` is greater than or equal to the second `_valexpr_`, all result sets will generate an empty window frame. + +* `( ROWS | RANGE | GROUPS ) BETWEEN _valexpr_ FOLLOWING AND UNBOUNDED FOLLOWING` -- if `_valexpr_` is too high, some objects may generate an empty window frame. + +* If the <> is present, any window frame specification may result in empty window frame. + +[[window-frame-exclusion]] +==== Window Frame Exclusion + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=window-frame-exclusion] +---- + +image::n1ql-language-reference/window-frame-exclusion.png["Syntax diagram", align=left] + +The *window frame exclusion clause* enables you to exclude specified objects from the window frame. + +This clause can be used with all {aggregatefun}[aggregate functions] and some {windowfun}[window functions] -- see the descriptions of individual functions for more details. + +This clause is allowed only when the <> is present. + +This clause is optional. +If this clause is omitted, the default is no exclusion -- the same as `EXCLUDE NO OTHERS`. + +`EXCLUDE CURRENT ROW`:: If the current object is still part of the window frame, it is removed from the window frame. + +`EXCLUDE GROUP`:: The current object and any peers of the current object are removed from the window frame. + +`EXCLUDE TIES`:: Any peers of the current object, but not the current object itself, are removed from the window frame. + +`EXCLUDE NO OTHERS`:: No additional objects are removed from the window frame. + +If the current object is already removed from the window frame, then it remains removed from the window frame. + +== Usage + +If present, the WINDOW clause must be included after the {groupby}[GROUP BY], {letting-clause}[LETTING], and {having-clause}[HAVING] clauses, and before the {orderby}[ORDER BY] clause. + +When the WINDOW clause is present, {sqlpp} rewrites the query by replacing window names with inline window definitions. +If a window is declared by the WINDOW clause, but not actually used by any window function or aggregate function in the query, that window definition is ignored and not used for determining the query plan. + +[[examples]] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +[[ex-1]] +.Using a shared window definition +==== +For each airline, show each route operated by that airline, including the length of the route, the length of the next-longest route, and the length of the next-shortest route. + +Compare this example with the examples for {lag}[LAG()] and {lead}[LEAD()]. + +.Query +[source,sqlpp] +---- +SELECT r.airline, r.id, r.distance, +LEAD(r.distance, 1, "No next distance") OVER win AS `next-distance`, +LAG(r.distance, 1, "No previous distance") OVER win AS `previous-distance` +FROM route AS r +WINDOW win AS ( + PARTITION BY r.airline + ORDER BY r.distance NULLS LAST +) -- <.> +LIMIT 7; +---- + +<.> The two window functions in this example share the same window definition, so it makes sense to use a named window. + +.Results +[source,json] +---- +[ + { + "airline": "2L", + "distance": 770.9691328580009, + "id": 125, + "next-distance": 770.969132858001, + "previous-distance": "No previous distance" + }, + { + "airline": "2L", + "distance": 770.969132858001, + "id": 117, + "next-distance": 922.7579695456559, + "previous-distance": 770.9691328580009 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "id": 118, + "next-distance": 922.7579695456559, + "previous-distance": 770.969132858001 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "id": 126, + "next-distance": "No next distance", + "previous-distance": 922.7579695456559 + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "id": 274, + "next-distance": 23.957943869396804, + "previous-distance": "No previous distance" + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "id": 276, + "next-distance": 26.397914084363418, + "previous-distance": 23.957943869396804 + }, + { + "airline": "3F", + "distance": 26.397914084363418, + "id": 282, + "next-distance": 26.397914084363418, + "previous-distance": 23.957943869396804 + } +] +---- +==== + +[[ex-2]] +.Referencing an existing named window in a named window definition +==== +For each destination airport, number all routes in order of distance, and calculate the distance of each route as a fraction of the total distance of all routes. + +Compare this example with the examples for {ratio-to-report}[RATIO_TO_REPORT()] and {row-number}[ROW_NUMBER()]. + +.Query +[source,sqlpp] +---- +SELECT d.id, d.destinationairport, +RATIO_TO_REPORT(d.distance) OVER win1 AS `distance-ratio`, +ROW_NUMBER() OVER win2 AS `row` +FROM route AS d +WINDOW win1 AS (PARTITION BY d.destinationairport), -- <.> + win2 AS (win1 ORDER BY d.distance NULLS LAST) -- <.> +LIMIT 7; +---- + +<.> The two window functions in this example share similar window definitions, so it makes sense to use named windows. + +<.> The window named `win2` reuses the specification of the existing window `win1`, and extends the specification with a window order clause. +Note that the definition of `win2` must come _after_ the definition of `win1`. + +.Results +[source,json] +---- +[ + { + "destinationairport": "AAE", + "distance-ratio": 0.16690466642630636, + "id": 10201, + "row": 1 + }, + { + "destinationairport": "AAE", + "distance-ratio": 0.22082544177013463, + "id": 10190, + "row": 2 + }, + { + "destinationairport": "AAE", + "distance-ratio": 0.3033841055547952, + "id": 10240, + "row": 3 + }, + { + "destinationairport": "AAE", + "distance-ratio": 0.3088857862487639, + "id": 10136, + "row": 4 + }, + { + "destinationairport": "AAL", + "distance-ratio": 0.07236336293503035, + "id": 14392, + "row": 1 + }, + { + "destinationairport": "AAL", + "distance-ratio": 0.25521719160354467, + "id": 14867, + "row": 2 + }, + { + "destinationairport": "AAL", + "distance-ratio": 0.6724194454614251, + "id": 22505, + "row": 3 + } +] +---- +==== + +[[ex-3]] +.Referencing an existing named window in an inline window definition +==== +For each airport, show each route starting at that airport, including the distance of the route, the distance of the shortest route from that airport, and the distance of the longest route from that airport. + +Compare this example with the examples for {first-value}[FIRST_VALUE()] and {last-value}[LAST_VALUE()]. + +.Query +[source,sqlpp] +---- +SELECT r.sourceairport, r.destinationairport, r.distance, +FIRST_VALUE(r.distance) OVER win AS `shortest_distance`, -- <.> +LAST_VALUE(r.distance) OVER ( + win ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -- <.> +) AS `longest_distance` +FROM route AS r +WINDOW win AS ( + PARTITION BY r.sourceairport + ORDER BY r.distance +) +LIMIT 7; +---- + +<.> The two window functions in this example share similar window definitions, so it makes sense to use a named window. + +<.> The inline window definition reuses the specification of the existing window `win`, and extends the specification with a window frame clause. +Note that the inline window definition comes before the definition of `win`. + +.Results +[source,json] +---- +[ + { + "destinationairport": "MRS", + "distance": 767.6526005881392, + "longest_distance": 1420.6731433915318, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "LYS", + "distance": 1015.6529968903878, + "longest_distance": 1420.6731433915318, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "ORY", + "distance": 1395.3690007167947, + "longest_distance": 1420.6731433915318, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "CDG", + "distance": 1420.6731433915318, + "longest_distance": 1420.6731433915318, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "AAR", + "distance": 99.89861063028253, + "longest_distance": 928.284226131001, + "shortest_distance": 99.89861063028253, + "sourceairport": "AAL" + }, + { + "destinationairport": "OSL", + "distance": 352.33081791745275, + "longest_distance": 928.284226131001, + "shortest_distance": 99.89861063028253, + "sourceairport": "AAL" + }, + { + "destinationairport": "LGW", + "distance": 928.284226131001, + "longest_distance": 928.284226131001, + "shortest_distance": 99.89861063028253, + "sourceairport": "AAL" + } +] +---- +==== + +== Related Links + +* {windowfun}[Window Functions] +* {aggregatefun}[Aggregate Functions] diff --git a/modules/n1ql/pages/n1ql-language-reference/windowfun.adoc b/modules/n1ql/pages/n1ql-language-reference/windowfun.adoc new file mode 100644 index 000000000..09baade3a --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/windowfun.adoc @@ -0,0 +1,1573 @@ += Window Functions +:page-topic-type: reference +:example-caption!: +:imagesdir: ../../assets/images +:description: Window functions are used to compute cumulative, moving, and reporting aggregations. + +:expression: xref:n1ql-language-reference/index.adoc#N1QL_Expressions +:identifier: xref:n1ql-language-reference/identifiers.adoc +:aggregatefun: xref:n1ql-language-reference/aggregatefun.adoc +:aggregate-quantifier: {aggregatefun}#aggregate-quantifier +:window: xref:n1ql-language-reference/window.adoc +:window-partition-clause: {window}#window-partition-clause +:window-order-clause: {window}#window-order-clause +:window-definition: {window}#window-definition +:window-frame-clause: {window}#window-frame-clause +:window-ex-1: {window}#ex-1 +:window-ex-2: {window}#ex-2 +:window-ex-3: {window}#ex-3 +:groupby: xref:n1ql-language-reference/groupby.adoc +:selectclause: xref:n1ql-language-reference/selectclause.adoc +:orderby: xref:n1ql-language-reference/orderby.adoc +:let: xref:n1ql-language-reference/let.adoc +:with: xref:n1ql-language-reference/with.adoc +:subqueries: xref:n1ql-language-reference/subqueries.adoc +:join: xref:n1ql-language-reference/join.adoc +:where: xref:n1ql-language-reference/where.adoc + +:disclaimer-text: If the query contains the {groupby}[GROUP BY] clause or {aggregatefun}[aggregate functions], this expression must only depend on GROUP BY expressions or aggregate functions. +ifeval::["{asciidoctor-version}" < "2.0.0"] +:disclaimer-text: If the query contains the {groupby}[GROUP BY\] clause or {aggregatefun}[aggregate functions\], this expression must only depend on GROUP BY expressions or aggregate functions. +endif::[] + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + +[abstract] +{description} + +include::partial$n1ql-language-reference/window-intro.adoc[] + +== Syntax + +This section shows the generic syntax of window functions, including window options and the OVER clause. +See the sections below for details of the syntax of individual window functions. + +[[window-function,window-function]] +=== Window Function + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=window-function] +---- + +image::n1ql-language-reference/window-function.png["Syntax diagram", align=left] + +[horizontal.compact] +window-function-arguments:: <> icon:caret-down[] +window-function-options:: <> icon:caret-down[] +over-clause:: <> icon:caret-down[] + +[[window-function-arguments]] +=== Window Function Arguments + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=window-function-arguments] +---- + +image::n1ql-language-reference/window-function-arguments.png["Syntax diagram", align=left] + +Refer to individual functions below for details of the arguments. + +[[window-function-options]] +=== Window Function Options + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=window-function-options] +---- + +image::n1ql-language-reference/window-function-options.png["Syntax diagram", align=left] + +[horizontal.compact] +nthval-from:: <> icon:caret-down[] +nulls-treatment:: <> icon:caret-down[] + +Window function options can only be used with some window functions, as described below. + +[[nthval-from]] +==== From Modifier + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=nthval-from] +---- + +image::n1ql-language-reference/nthval-from.png["Syntax diagram", align=left] + +The *from modifier* determines whether the computation begins at the first or last object in the window. + +This clause can only be used with the <> function. + +This clause is optional. +If omitted, the default setting is `FROM FIRST`. + +[[nulls-treatment]] +==== Nulls Modifier + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=nulls-treatment] +---- + +image::n1ql-language-reference/nulls-treatment.png["Syntax diagram", align=left] + +The *nulls modifier* determines whether NULL values are included in the computation, or ignored. +MISSING values are treated the same way as NULL values. + +This clause can only be used with the <>, <>, <>, <>, and <> functions. + +This clause is optional. +If omitted, the default setting is `RESPECT NULLS`. + +[[over-clause]] +=== OVER Clause + +include::partial$n1ql-language-reference/over-clause.adoc[tag=body] + +With some window functions, the window specification may include a {window-partition-clause}[window partition clause], a {window-order-clause}[window order clause], and a {window-frame-clause}[window frame clause]. +With other window functions, the window specification may only include a subset of these clauses. +Refer to individual functions below for details of the clauses permitted within the window specification. + +Note that any restrictions on the clauses permitted in the window specification apply equally, whether the function has an inline window definition, or a reference to a named window. + +== Usage + +Window functions can only appear in the {selectclause}[SELECT] projection clause or query {orderby}[ORDER BY] clause. + +TIP: Any expression within a window function may be a subquery. +However, this will lead to repeated evaluation when the query is processed. +If required, use a {let}[LET clause], a {with}[WITH clause], or an intervening {subqueries}[subquery] to avoid repeated evaluation. + +NOTE: An expression within the window function may not contain another, nested window function. +If necessary, you can specify one window function in a {subqueries}[subquery], and another window function in the parent query. + +Window functions are processed after {join}[JOIN] clauses, the {let}[LET] clause, the {where}[WHERE] clause, and the {groupby}[GROUP BY], {groupby}[LETTING], and {groupby}[HAVING] clauses. +Window functions therefore operate on the query result set. + +[[fn-window-cume-dist,CUME_DIST()]] +== CUME_DIST() + +=== Description +Returns the percentile rank of the current object as part of the cumulative distribution -- that is, the number of objects ranked lower than or equal to the current object, including the current object, divided by the total number of objects in the window partition. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=cume-dist-function] +---- + +image::n1ql-language-reference/cume-dist-function.png["Syntax diagram", align=left] + +=== Arguments +None. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Value +A number greater than 0 and less than or equal to 1. +The higher the value, the higher the ranking. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each destination airport, find the cumulative distribution of all routes in order of distance: + +.Query +[source,sqlpp] +---- +SELECT d.id, d.destinationairport, CUME_DIST() OVER ( + PARTITION BY d.destinationairport + ORDER BY d.distance NULLS LAST +) AS `rank` +FROM route AS d +LIMIT 7; +---- + +.Results +[source,json] +---- +[ + { + "destinationairport": "AAE", + "id": 10201, + "rank": 0.25 + }, + { + "destinationairport": "AAE", + "id": 10190, + "rank": 0.5 + }, + { + "destinationairport": "AAE", + "id": 10240, + "rank": 0.75 + }, + { + "destinationairport": "AAE", + "id": 10136, + "rank": 1 + }, + { + "destinationairport": "AAL", + "id": 14392, + "rank": 0.3333333333333333 + }, + { + "destinationairport": "AAL", + "id": 14867, + "rank": 0.6666666666666666 + }, + { + "destinationairport": "AAL", + "id": 22505, + "rank": 1 + }, +] +---- +==== + +[[fn-window-dense-rank,DENSE_RANK()]] +== DENSE_RANK() + +=== Description +Returns the dense rank of the current object -- that is, the number of distinct objects preceding this object in the current window partition, plus one. + +The objects are ordered by the {window-order-clause}[window order clause]. +If any objects are tied, they will have the same rank. + +For this function, when any objects have the same rank, the rank of the next object will be consecutive, so there will not be a gap in the sequence of returned values. +For example, if there are three objects ranked 2, the next dense rank is 3. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=dense-rank-function] +---- + +image::n1ql-language-reference/dense-rank-function.png["Syntax diagram", align=left] + +=== Arguments +None. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Values +An integer, greater than or equal to 1. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each country, find the dense rank of all airports in order of altitude: + +.Query +[source,sqlpp] +---- +SELECT a.airportname, a.geo.alt, DENSE_RANK() OVER ( + PARTITION BY a.country + ORDER BY a.geo.alt NULLS LAST +) AS `rank` +FROM airport AS a +LIMIT 10; +---- + +.Results +[source,json] +---- +[ + { + "airportname": "Croisette Heliport", + "alt": 0, + "rank": 1 + }, + { + "airportname": "Andernos-Les-Bains", + "alt": 0, + "rank": 1 + }, + { + "airportname": "La Defense Heliport", + "alt": 0, + "rank": 1 + }, + { + "airportname": "Marigot Bus Stop", + "alt": 0, + "rank": 1 + }, + { + "airportname": "Lille", + "alt": 1, + "rank": 2 + }, + { + "airportname": "Le Palyvestre", + "alt": 7, + "rank": 3 + }, + { + "airportname": "Frejus Saint Raphael", + "alt": 7, + "rank": 3 + }, + { + "airportname": "Calais Dunkerque", + "alt": 12, + "rank": 4 + }, + { + "airportname": "Cote D\\'Azur", + "alt": 12, + "rank": 4 + }, + { + "airportname": "Propriano", + "alt": 13, + "rank": 5 + } +] +---- +==== + +[[fn-window-first-value,FIRST_VALUE()]] +== FIRST_VALUE(`expr`) + +=== Description +Returns the requested value from the first object in the current window frame, where the window frame is determined by the {window-definition}[window definition]. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=first-value-function] +---- + +image::n1ql-language-reference/first-value-function.png["Syntax diagram", align=left] + +[[fn-window-first-value-args]] +=== Arguments +expr:: [Required] The value that you want to return from the first object in the window frame. footnote:disclaimer[{disclaimer-text}] + +[[fn-window-first-value-nulls,nulls-treatment]] +==== Nulls Modifier +The <> determines how NULL or MISSING values are treated when finding the first object in the window frame: + +`IGNORE NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are not included when finding the first object. +In this case, the function returns the first non-NULL, non-MISSING value. + +`RESPECT NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are included when finding the first object. + +If the <> is omitted, the default is `RESPECT NULLS`. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +an optional {window-order-clause}[window order clause], +and an optional {window-frame-clause}[window frame clause]. + +=== Return Values +The specified value from the first object. + +If all values are NULL or MISSING it returns NULL. + +[NOTE] +-- +In the following cases, this function may return unpredictable results. + +* If the {window-order-clause}[window order clause] is omitted. + +* If the window frame is defined by `ROWS`, and there are tied objects in the window frame. + +To make the function return deterministic results, add a {window-order-clause}[window order clause], or add further ordering terms to the {window-order-clause}[window order clause] so that no objects are tied. + +If the window frame is defined by `RANGE` or `GROUPS`, and there are tied objects in the window frame, the function returns the lowest value of the input expression. +-- + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each airport, show each route starting at that airport, including the distance of the route and the distance of the shortest route from that airport: + +.Query +[source,sqlpp] +---- +SELECT r.sourceairport, r.destinationairport, r.distance, +FIRST_VALUE(r.distance) OVER ( + PARTITION BY r.sourceairport + ORDER BY r.distance +) AS `shortest_distance` +FROM route AS r +LIMIT 7; +---- + +.Results +[source,json] +---- +[ + { + "destinationairport": "MRS", + "distance": 767.6526005881392, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "LYS", + "distance": 1015.6529968903878, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "ORY", + "distance": 1395.3690007167947, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "CDG", + "distance": 1420.6731433915318, + "shortest_distance": 767.6526005881392, + "sourceairport": "AAE" + }, + { + "destinationairport": "AAR", + "distance": 99.89861063028253, + "shortest_distance": 99.89861063028253, + "sourceairport": "AAL" + }, + { + "destinationairport": "OSL", + "distance": 352.33081791745275, + "shortest_distance": 99.89861063028253, + "sourceairport": "AAL" + }, + { + "destinationairport": "LGW", + "distance": 928.284226131001, + "shortest_distance": 99.89861063028253, + "sourceairport": "AAL" + } +] +---- +==== + +Refer also to {window-ex-3}[WINDOW Clause example 3] for a query showing this function used with the WINDOW clause. + +[[fn-window-lag,LAG()]] +== LAG(`expr` {startsb}, `offset` {startsb}, `default` {endsb} {endsb} ) + +=== Description +Returns the value of an object at a given offset prior to the current object position. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=lag-function] +---- + +image::n1ql-language-reference/lag-function.png["Syntax diagram", align=left] + +[[fn-window-lag-args]] +=== Arguments +expr:: [Required] The value that you want to return from the offset object. footnote:disclaimer[] + +offset:: [Optional] A positive integer greater than 0. +If omitted, the default is 1. + +default:: [Optional] The value to return when the offset goes out of window scope. +If omitted, the default is NULL. + +[[fn-window-lag-nulls,nulls-treatment]] +==== Nulls Modifier +The <> determines how NULL or MISSING values are treated when counting the offset: + +`IGNORE NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are not included when counting the offset. + +`RESPECT NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are included when counting the offset. + +If the <> is omitted, the default is `RESPECT NULLS`. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Values +The specified value from the offset object. + +If the offset object is out of scope, it returns the default value, or NULL if no default is specified. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each airline, show each route operated by that airline, including the length of the route and the length of the next-shortest route: + +.Query +[source,sqlpp] +---- +SELECT r.airline, r.id, r.distance, +LAG(r.distance, 1, "No previous distance") OVER ( + PARTITION BY r.airline + ORDER BY r.distance NULLS LAST +) AS `previous-distance` +FROM route AS r +LIMIT 7; +---- + +.Results +[source,json] +---- +[ + { + "airline": "2L", + "distance": 770.9691328580009, + "id": 125, + "previous-distance": "No previous distance" + }, + { + "airline": "2L", + "distance": 770.969132858001, + "id": 117, + "previous-distance": 770.9691328580009 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "id": 118, + "previous-distance": 770.969132858001 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "id": 126, + "previous-distance": 922.7579695456559 + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "id": 274, + "previous-distance": "No previous distance" + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "id": 276, + "previous-distance": 23.957943869396804 + }, + { + "airline": "3F", + "distance": 26.397914084363418, + "id": 282, + "previous-distance": 23.957943869396804 + } +] +---- +==== + +Refer also to {window-ex-1}[WINDOW Clause example 1] for a query showing this function used with the WINDOW clause. + +[[fn-window-last-value,LAST_VALUE()]] +== LAST_VALUE(`expr`) + +=== Description +Returns the requested value from the last object in the current window frame, where the window frame is specified by the {window-definition}[window definition]. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=last-value-function] +---- + +image::n1ql-language-reference/last-value-function.png["Syntax diagram", align=left] + +[[fn-window-last-value-args]] +=== Arguments +expr:: [Required] The value that you want to return from the last object in the window frame. footnote:disclaimer[] + +[[fn-window-last-value-nulls,nulls-treatment]] +==== Nulls Modifier +The <> determines how NULL or MISSING values are treated when finding the last object in the window frame: + +`IGNORE NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are not included when finding the last object. +In this case, the function returns the last non-NULL, non-MISSING value. + +`RESPECT NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are included when finding the last object. + +If the <> is omitted, the default is `RESPECT NULLS`. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +an optional {window-order-clause}[window order clause], +and an optional {window-frame-clause}[window frame clause]. + +=== Return Values +The specified value from the last object. + +If all values are NULL or MISSING it returns NULL. + +[NOTE] +-- +In the following cases, this function may return unpredictable results. + +* If the {window-order-clause}[window order clause] is omitted. + +* If the {window-frame-clause}[window frame clause] is omitted. + +* If the window frame is defined by `ROWS`, and there are tied objects in the window frame. + +To make the function return deterministic results, add a {window-order-clause}[window order clause], or add further ordering terms to the {window-order-clause}[window order clause] so that no objects are tied. + +If the window frame is defined by `RANGE` or `GROUPS`, and there are tied objects in the window frame, the function returns the highest value of the input expression. +-- + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each airport, show each route starting at that airport, including the distance of the route and the distance of the longest route from that airport: + +.Query +[source,sqlpp] +---- +SELECT r.sourceairport, r.destinationairport, r.distance, +LAST_VALUE(r.distance) OVER ( + PARTITION BY r.sourceairport + ORDER BY r.distance + ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -- <1> +) AS `longest_distance` +FROM route AS r +LIMIT 7; +---- + +<1> This clause specifies that the window frame should extend to the end of the window partition. +Without this clause, the end point of the window frame would always be the current object. +This would mean that the longest distance would always be the same as the current distance. + +.Results +[source,json] +---- +[ + { + "destinationairport": "MRS", + "distance": 767.6526005881392, + "longest_distance": 1420.6731433915318, + "sourceairport": "AAE" + }, + { + "destinationairport": "LYS", + "distance": 1015.6529968903878, + "longest_distance": 1420.6731433915318, + "sourceairport": "AAE" + }, + { + "destinationairport": "ORY", + "distance": 1395.3690007167947, + "longest_distance": 1420.6731433915318, + "sourceairport": "AAE" + }, + { + "destinationairport": "CDG", + "distance": 1420.6731433915318, + "longest_distance": 1420.6731433915318, + "sourceairport": "AAE" + }, + { + "destinationairport": "AAR", + "distance": 99.89861063028253, + "longest_distance": 928.284226131001, + "sourceairport": "AAL" + }, + { + "destinationairport": "OSL", + "distance": 352.33081791745275, + "longest_distance": 928.284226131001, + "sourceairport": "AAL" + }, + { + "destinationairport": "LGW", + "distance": 928.284226131001, + "longest_distance": 928.284226131001, + "sourceairport": "AAL" + } +] +---- +==== + +Refer also to {window-ex-3}[WINDOW Clause example 3] for a query showing this function used with the WINDOW clause. + +[[fn-window-lead,LEAD()]] +== LEAD(`expr` {startsb}, `offset` {startsb}, `default` {endsb} {endsb} ) + +=== Description +Returns the value of an object at a given offset ahead of the current object position. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=lead-function] +---- + +image::n1ql-language-reference/lead-function.png["Syntax diagram", align=left] + +[[fn-window-lead-args]] +=== Arguments +expr:: [Required] The value that you want to return from the offset object. footnote:disclaimer[] + +offset:: [Optional] A positive integer greater than 0. +If omitted, the default is 1. + +default:: [Optional] The value to return when the offset goes out of window scope. +If omitted, the default is NULL. + +[[fn-window-lead-nulls,nulls-treatment]] +==== Nulls Modifier +The <> determines how NULL or MISSING values are treated when counting the offset: + +`IGNORE NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are not included when counting the offset. + +`RESPECT NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are included when counting the offset. + +If the <> is omitted, the default is `RESPECT NULLS`. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Values +The specified value from the offset object. + +If the offset object is out of scope, it returns the default value, or NULL if no default is specified. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each airline, show each route operated by that airline, including the length of the route and the length of the next-longest route: + +.Query +[source,sqlpp] +---- +SELECT r.airline, r.id, r.distance, +LEAD(r.distance, 1, "No next distance") OVER ( + PARTITION BY r.airline + ORDER BY r.distance NULLS LAST +) AS `next-distance` +FROM route AS r +LIMIT 7; +---- + +.Results +[source,json] +---- + [ + { + "airline": "2L", + "distance": 770.9691328580009, + "id": 125, + "next-distance": 770.969132858001 + }, + { + "airline": "2L", + "distance": 770.969132858001, + "id": 117, + "next-distance": 922.7579695456559 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "id": 118, + "next-distance": 922.7579695456559 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "id": 126, + "next-distance": "No next distance" + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "id": 274, + "next-distance": 23.957943869396804 + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "id": 276, + "next-distance": 26.397914084363418 + }, + { + "airline": "3F", + "distance": 26.397914084363418, + "id": 282, + "next-distance": 26.397914084363418 + } +] +---- +==== + +Refer also to {window-ex-1}[WINDOW Clause example 1] for a query showing this function used with the WINDOW clause. + +[[fn-window-nth-value,NTH_VALUE()]] +== NTH_VALUE(`expr`, `offset`) + +=== Description +Returns the requested value from an object in the current window frame, where the window frame is specified by the {window-definition}[window definition]. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=nth-value-function] +---- + +image::n1ql-language-reference/nth-value-function.png["Syntax diagram", align=left] + +[[fn-window-nth-value-args]] +=== Arguments +expr:: [Required] The value that you want to return from the offset object in the window frame. footnote:disclaimer[] + +offset:: [Required] The number of the offset object within the window frame, counting from 1. + +[[fn-window-nth-value-from,nthval-from]] +==== From Modifier +The <> determines where the function starts counting the offset. + +`FROM FIRST`:: Offset counting starts at the first object in the window frame. +In this case, an offset of 1 is the first object in the window frame, 2 is the second object, and so on. + +`FROM LAST`:: Offset counting starts at the last object in the window frame. +In this case, an offset of 1 is the last object in the window frame, 2 is the second-to-last object, and so on. + +[[fn-window-nth-value-nulls,nulls-treatment]] +==== Nulls Modifier +The <> determines how NULL or MISSING values are treated when counting the offset: + +`IGNORE NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are not included when counting the offset. + +`RESPECT NULLS`:: If the values for any objects evaluate to NULL or MISSING, those objects are included when counting the offset. + +If the <> is omitted, the default is `RESPECT NULLS`. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +an optional {window-order-clause}[window order clause], +and an optional {window-frame-clause}[window frame clause]. + +=== Return Values +The specified value from the offset object. + +[NOTE] +-- +In the following cases, this function may return unpredictable results. + +* If the {window-order-clause}[window order clause] is omitted. + +* If the {window-frame-clause}[window frame clause] is omitted. + +* If the window frame is defined by `ROWS`, and there are tied objects in the window frame. + +To make the function return deterministic results, add a {window-order-clause}[window order clause], or add further ordering terms to the {window-order-clause}[window order clause] so that no objects are tied. + +If the window frame is defined by `RANGE` or `GROUPS`, and there are tied objects in the window frame, the function returns the lowest value of the input expression when counting `FROM FIRST`, or the highest value of the input expression when counting `FROM LAST`. +-- + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each airport, show each route starting at that airport, including the distance of the route and the distance of the second shortest route from that airport: + +.Query +[source,sqlpp] +---- +SELECT r.sourceairport, r.destinationairport, r.distance, +NTH_VALUE(r.distance, 2) FROM FIRST OVER ( + PARTITION BY r.sourceairport + ORDER BY r.distance + ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -- <1> +) AS `shortest_distance_but_1` +FROM route AS r +LIMIT 7; +---- + +<1> This clause specifies that the window frame should extend to the end of the window partition. +Without this clause, the end point of the window frame would always be the current object. +This would mean that for the route with the shortest distance, the function would be unable to find the route with the second shortest distance. + +.Results +[source,json] +---- +[ + { + "destinationairport": "MRS", + "distance": 767.6526005881392, + "shortest_distance_but_1": 1015.6529968903878, + "sourceairport": "AAE" + }, + { + "destinationairport": "LYS", // <1> + "distance": 1015.6529968903878, + "shortest_distance_but_1": 1015.6529968903878, + "sourceairport": "AAE" + }, + { + "destinationairport": "ORY", + "distance": 1395.3690007167947, + "shortest_distance_but_1": 1015.6529968903878, + "sourceairport": "AAE" + }, + { + "destinationairport": "CDG", + "distance": 1420.6731433915318, + "shortest_distance_but_1": 1015.6529968903878, + "sourceairport": "AAE" + }, + { + "destinationairport": "AAR", + "distance": 99.89861063028253, + "shortest_distance_but_1": 352.33081791745275, + "sourceairport": "AAL" + }, + { + "destinationairport": "OSL", // <2> + "distance": 352.33081791745275, + "shortest_distance_but_1": 352.33081791745275, + "sourceairport": "AAL" + }, + { + "destinationairport": "LGW", + "distance": 928.284226131001, + "shortest_distance_but_1": 352.33081791745275, + "sourceairport": "AAL" + } +] +---- + +<1> This is the route with the second shortest distance from AAE. +<2> This is the route with the second shortest distance from AAL. +==== + +==== +For each airport, show each route starting at that airport, including the distance of the route and the distance of the second longest route from that airport: + +.Query +[source,sqlpp] +---- +SELECT r.sourceairport, r.destinationairport, r.distance, +NTH_VALUE(r.distance, 2) FROM LAST OVER ( + PARTITION BY r.sourceairport + ORDER BY r.distance + ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -- <1> +) AS `longest_distance_but_1` +FROM route AS r +LIMIT 7; +---- + +<1> This clause specifies that the window frame should extend to the end of the window partition. +Without this clause, the end point of the window frame would always be the current object. +This would mean the function would be unable to find the route with the second longest distance for routes with shorter distances. + +.Results +[source,json] +---- +[ + { + "destinationairport": "MRS", + "distance": 767.6526005881392, + "longest_distance_but_1": 1395.3690007167947, + "sourceairport": "AAE" + }, + { + "destinationairport": "LYS", + "distance": 1015.6529968903878, + "longest_distance_but_1": 1395.3690007167947, + "sourceairport": "AAE" + }, + { + "destinationairport": "ORY", + "distance": 1395.3690007167947, + "longest_distance_but_1": 1395.3690007167947, // <1> + "sourceairport": "AAE" + }, + { + "destinationairport": "CDG", + "distance": 1420.6731433915318, + "longest_distance_but_1": 1395.3690007167947, + "sourceairport": "AAE" + }, + { + "destinationairport": "AAR", + "distance": 99.89861063028253, + "longest_distance_but_1": 352.33081791745275, + "sourceairport": "AAL" + }, + { + "destinationairport": "OSL", + "distance": 352.33081791745275, + "longest_distance_but_1": 352.33081791745275, // <2> + "sourceairport": "AAL" + }, + { + "destinationairport": "LGW", + "distance": 928.284226131001, + "longest_distance_but_1": 352.33081791745275, + "sourceairport": "AAL" + } +] +---- + +<1> This is the route with the second longest distance from AAE. +<2> This is the route with the second longest distance from AAL. +==== + +[[fn-window-ntile,NTILE()]] +== NTILE(`num_tiles`) + +=== Description +Divides the window partition into the specified number of tiles, and allocates each object in the window partition to a tile, so that as far as possible each tile has an equal number of objects. +When the set of objects is not equally divisible by the number of tiles, the function puts more objects into the lower-numbered tiles. +For each object, the function returns the number of the tile into which that object was placed. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=ntile-function] +---- + +image::n1ql-language-reference/ntile-function.png["Syntax diagram", align=left] + +[[fn-window-ntile-args]] +=== Arguments +num_tiles:: [Required] The number of tiles into which you want to divide the window partition. +This argument can be an expression and must evaluate to a number. +If the number is not an integer, it will be truncated. +If the expression depends on an object, it evaluates from the first object in the window partition. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Values +An value greater than or equal to 1 and less than or equal to the number of tiles. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each airline, allocate each route to one of three tiles by distance: + +.Query +[source,sqlpp] +---- +SELECT r.airline, r.distance, NTILE(3) OVER ( + PARTITION BY r.airline + ORDER BY r.distance +) AS `ntile` +FROM route AS r +LIMIT 16; +---- + +.Results +[source,json] +---- +[ + { + "airline": "2L", + "distance": 770.9691328580009, + "ntile": 1 + }, + { + "airline": "2L", + "distance": 770.969132858001, + "ntile": 1 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "ntile": 2 + }, + { + "airline": "2L", + "distance": 922.7579695456559, + "ntile": 3 + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "ntile": 1 + }, + { + "airline": "3F", + "distance": 23.957943869396804, + "ntile": 1 + }, + { + "airline": "3F", + "distance": 26.397914084363418, + "ntile": 1 + }, + { + "airline": "3F", + "distance": 26.397914084363418, + "ntile": 1 + }, + { + "airline": "3F", + "distance": 31.613003135476145, + "ntile": 2 + }, + { + "airline": "3F", + "distance": 31.613003135476145, + "ntile": 2 + }, + { + "airline": "3F", + "distance": 60.49012512494272, + "ntile": 2 + }, + { + "airline": "3F", + "distance": 60.490125124942736, + "ntile": 2 + }, + { + "airline": "3F", + "distance": 63.640308584677314, + "ntile": 3 + }, + { + "airline": "3F", + "distance": 63.640308584677314, + "ntile": 3 + }, + { + "airline": "3F", + "distance": 91.53839302649642, + "ntile": 3 + }, + { + "airline": "3F", + "distance": 91.53839302649642, + "ntile": 3 + } +] +---- +==== + +[[fn-window-percent-rank,PERCENT_RANK()]] +== PERCENT_RANK() + +=== Description +Returns the percentile rank of the current object -- that is, the rank of the object minus one, divided by the total number of objects in the window partition minus one. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=percent-rank-function] +---- + +image::n1ql-language-reference/percent-rank-function.png["Syntax diagram", align=left] + +=== Arguments +None. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Values +A number between 0 and 1. +The higher the value, the higher the ranking. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each destination airport, find the percentile rank of all routes in order of distance: + +.Query +[source,sqlpp] +---- +SELECT d.id, d.destinationairport, PERCENT_RANK() OVER ( + PARTITION BY d.destinationairport + ORDER BY d.distance NULLS LAST +) AS `rank` +FROM route AS d +LIMIT 7; +---- + +.Results +[source,json] +---- +[ + { + "destinationairport": "AAE", + "id": 10201, + "rank": 0 + }, + { + "destinationairport": "AAE", + "id": 10190, + "rank": 0.3333333333333333 + }, + { + "destinationairport": "AAE", + "id": 10240, + "rank": 0.6666666666666666 + }, + { + "destinationairport": "AAE", + "id": 10136, + "rank": 1 + }, + { + "destinationairport": "AAL", + "id": 14392, + "rank": 0 + }, + { + "destinationairport": "AAL", + "id": 14867, + "rank": 0.5 + }, + { + "destinationairport": "AAL", + "id": 22505, + "rank": 1 + } +] +---- +==== + +[[fn-window-rank,RANK()]] +== RANK() + +=== Description +Returns the rank of the current object -- that is, the number of distinct objects preceding this object in the current window partition, plus one. + +The objects are ordered by the {window-order-clause}[window order clause]. +If any objects are tied, they will have the same rank. + +When any objects have the same rank, the rank of the next object will include all preceding objects, so there may be a gap in the sequence of returned values. +For example, if there are three objects ranked 2, the next rank is 5. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=rank-function] +---- + +image::n1ql-language-reference/rank-function.png["Syntax diagram", align=left] + +=== Arguments +None. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and must include a {window-order-clause}[window order clause]. + +=== Return Values +An integer, greater than or equal to 1. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each country, find the rank of all airports in order of altitude: + +.Query +[source,sqlpp] +---- +SELECT a.airportname, a.geo.alt, RANK() OVER ( + PARTITION BY a.country + ORDER BY a.geo.alt NULLS LAST +) AS `rank` +FROM airport AS a +LIMIT 10; +---- + +.Results +[source,json] +---- +[ + { + "airportname": "Croisette Heliport", + "alt": 0, + "rank": 1 + }, + { + "airportname": "Andernos-Les-Bains", + "alt": 0, + "rank": 1 + }, + { + "airportname": "La Defense Heliport", + "alt": 0, + "rank": 1 + }, + { + "airportname": "Marigot Bus Stop", + "alt": 0, + "rank": 1 + }, + { + "airportname": "Lille", + "alt": 1, + "rank": 5 + }, + { + "airportname": "Le Palyvestre", + "alt": 7, + "rank": 6 + }, + { + "airportname": "Frejus Saint Raphael", + "alt": 7, + "rank": 6 + }, + { + "airportname": "Calais Dunkerque", + "alt": 12, + "rank": 8 + }, + { + "airportname": "Cote D\\'Azur", + "alt": 12, + "rank": 8 + }, + { + "airportname": "Propriano", + "alt": 13, + "rank": 10 + } +] +---- +==== + +[[fn-window-ratio-to-report,RATIO_TO_REPORT()]] +== RATIO_TO_REPORT(`expr`) + +=== Description +Returns the fractional ratio of the specified value for each object to the sum of values for all objects in the window frame. +If the {window-frame-clause}[window frame clause] is not specified, the fractional ratio is calculated for the whole window partition. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=ratio-to-report-function] +---- + +image::n1ql-language-reference/ratio-to-report-function.png["Syntax diagram", align=left] + +[[fn-window-ratio-to-report-args]] +=== Arguments +expr:: [Required] The value for which you want to calculate the fractional ratio. footnote:disclaimer[] + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +an optional {window-order-clause}[window order clause], +and an optional {window-frame-clause}[window frame clause]. + +=== Return Values +A number between 0 and 1, representing the fractional ratio of the value for the current object to the sum of values for all objects in the current window frame. +The sum of values for all objects in the current window frame is 1. + +If the input expression does not evaluate to a number, or the sum of values for all objects is zero, it returns NULL. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each destination airport, calculate the distance of each route as a fraction of the total distance of all routes: + +.Query +[source,sqlpp] +---- +SELECT d.id, d.destinationairport, RATIO_TO_REPORT(d.distance) OVER ( + PARTITION BY d.destinationairport +) AS `distance-ratio` +FROM route AS d +LIMIT 7; +---- + +.Results +[source,json] +---- +[ + { + "destinationairport": "AAE", + "distance-ratio": 0.3088857862487639, + "id": 10136 + }, + { + "destinationairport": "AAE", + "distance-ratio": 0.22082544177013463, + "id": 10190 + }, + { + "destinationairport": "AAE", + "distance-ratio": 0.3033841055547952, + "id": 10240 + }, + { + "destinationairport": "AAE", + "distance-ratio": 0.16690466642630636, + "id": 10201 + }, + { + "destinationairport": "AAL", + "distance-ratio": 0.25521719160354467, + "id": 14867 + }, + { + "destinationairport": "AAL", + "distance-ratio": 0.6724194454614251, + "id": 22505 + }, + { + "destinationairport": "AAL", + "distance-ratio": 0.07236336293503035, + "id": 14392 + } +] +---- +==== + +Refer also to {window-ex-2}[WINDOW Clause example 2] for a query showing this function used with the WINDOW clause. + +[[fn-window-row-number,ROW_NUMBER()]] +== ROW_NUMBER() + +=== Description +Returns a unique row number for every object in every window partition. +In each window partition, the row numbering starts at 1. + +The {window-order-clause}[window order clause] determines the sort order of the objects. +If the {window-order-clause}[window order clause] is omitted, the return values may be unpredictable. + +=== Syntax + +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=row-number-function] +---- + +image::n1ql-language-reference/row-number-function.png["Syntax diagram", align=left] + +=== Arguments +None. + +=== Window Specification + +The window specification may include an optional {window-partition-clause}[window partition clause], +and an optional {window-order-clause}[window order clause]. + +=== Return Values +An integer, greater than or equal to 1. + +=== Example + +include::ROOT:partial$query-context.adoc[tag=section] + +==== +For each destination airport, number all routes in order of distance: + +.Query +[source,sqlpp] +---- +SELECT d.id, d.destinationairport, ROW_NUMBER() OVER ( + PARTITION BY d.destinationairport + ORDER BY d.distance NULLS LAST +) AS `row` +FROM route AS d +LIMIT 7; +---- + +.Results +[source,json] +---- +[ + { + "destinationairport": "AAE", + "id": 10201, + "row": 1 + }, + { + "destinationairport": "AAE", + "id": 10190, + "row": 2 + }, + { + "destinationairport": "AAE", + "id": 10240, + "row": 3 + }, + { + "destinationairport": "AAE", + "id": 10136, + "row": 4 + }, + { + "destinationairport": "AAL", + "id": 14392, + "row": 1 + }, + { + "destinationairport": "AAL", + "id": 14867, + "row": 2 + }, + { + "destinationairport": "AAL", + "id": 22505, + "row": 3 + } +] +---- +==== + +Refer also to {window-ex-2}[WINDOW Clause example 2] for a query showing this function used with the WINDOW clause. + +== Related Links + +* {aggregatefun}[Aggregate Functions] +* {window}[WINDOW Clause] diff --git a/modules/n1ql/pages/n1ql-language-reference/with-recursive.adoc b/modules/n1ql/pages/n1ql-language-reference/with-recursive.adoc new file mode 100644 index 000000000..cb0fab4b2 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/with-recursive.adoc @@ -0,0 +1,696 @@ += WITH RECURSIVE Clause +:description: Use the WITH RECURSIVE clause to enable recursive referencing in common table expressions. +:imagesdir: ../../assets/images +:page-topic-type: reference +:page-status: Couchbase Server 7.6 + +[abstract] +{description} + +[#purpose] +== Purpose + +The common table expressions (CTEs) created by the WITH clause simplify complex queries and create temporary result sets which can be used as data sources or as expressions for queries. + +The WITH RECURSIVE clause is an extension of the WITH clause which enables you to create recursive queries. +You can use recursive queries with hierarchical data, or data in a tree structure. +In these cases, the data may have an arbitrary number of levels, and you won't know in advance how deeply you need to traverse the data. + +The CTE for a recursive query includes a UNION or UNION ALL xref:n1ql:n1ql-language-reference/union.adoc[set operator]. + +* The left arm of UNION/UNION ALL contains an anchor clause, which is non-recursive. +The anchor clause produces an initial set of documents as an intermediate result set for the CTE keyspace. + +* The right arm of UNION/UNION ALL contains the recursive clause. +The recursive clause produces a new set of documents. + +The recursive clause is executed again, with the CTE keyspace now referring to the result produced by the initial recursive clause. +This process repeats until it results in an empty intermediate result set. +The intermediate result sets are appended to produce a final output. + +[#syntax] +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=with-recursive-clause] +---- + +image::n1ql-language-reference/with-recursive-clause.png["Syntax diagram", align=left] + +[[recursive-select]] +=== Recursive SELECT + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=recursive-select] +---- + +image::n1ql-language-reference/recursive-select.png["Syntax diagram", align=left] + +The definition for a recursive CTE must be a SELECT statement that includes a UNION or UNION ALL set operator. +If it isn't, the CTE is treated as a non-recursive CTE. + +anchor-select:: +A xref:n1ql:n1ql-language-reference/select-syntax.adoc[SELECT query] that represents the anchor clause of the CTE. + +recursive-select-term:: +A xref:n1ql:n1ql-language-reference/select-syntax.adoc#select-term[select term] that represents the recursive clause of the CTE. + +[[cycle-clause]] +=== CYCLE Clause + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=cycle-clause] +---- + +image::n1ql-language-reference/cycle-clause.png["Syntax diagram", align=left] + +The optional CYCLE clause provides one method for avoiding infinite recursions. +It enables you to specify one or more fields whose values are likely to repeat. + +expr:: +(Required) An xref:n1ql:n1ql-language-reference/identifiers.adoc[identifier] or a xref:n1ql:n1ql-language-reference/select-syntax.adoc#path[path] representing a field/nested-field. + +[.status]#Couchbase Server 7.6.2# + +In Couchbase Server 7.6.2, the CYCLE clause returns the following error if you enter an invalid expression: + +[source,json] +---- +{ + "errors": [ + { + "code": 3307, + "msg": "Cycle fields validation failed for with term: cyc - cause: invalid cycle field expression term: (1 + 1) only identifier/path expressions are allowed" + } + ] +} +---- + +[[options-clause]] +=== OPTIONS Clause +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=options-clause] +---- + +image::n1ql-language-reference/options-clause.png["Syntax diagram", align=left] + +The optional OPTIONS clause provides another method for avoiding infinite recursions. +It enables you to specify that the recursion should exit after a specified level, or after accumulating a specified number of documents. + +expr:: +(Required) An object with the following properties. + +[options="header", cols="~a,~a,~a"] +|=== +|Name|Description|Schema + +|**levels** + +__optional__ +|Recursion should exit after reaching this level. +This assumes the anchor is at level 0. +|Integer + +|**documents** + +__optional__ +|Recursion should exit after accumulating this many documents. +|Integer +|=== + +[#limitations] +== Limitations + +* The recursive reference is only allowed once in the FROM clause. +It's not allowed anywhere else. + +* ORDER BY, LIMIT, and OFFSET clauses are not allowed in the SELECT statement in the subquery used to define the anchor and the recursive clause. + +* The DISTINCT quantifier is not allowed in anchor and recursive clauses. + +* GROUP BY, WINDOW, and AGGREGATE functions are not allowed in recursive clauses. + +* OUTER JOINS are not allowed in recursive clauses because they can lead to potential infinite recursion. + +* Recursive clauses do not support NEST and UNNEST clauses. + +* If there is no UNION/UNION ALL separation for the recursive CTE, the query defaults to a normal CTE. + +* A syntax error is returned when optional subclauses are used without the RECURSIVE keyword. + +* In general, recursion is also limited by: +** The logic in the recursive statement. +** The stop in the options argument. +** Breaching the request timeout, if configured. +** Breaching the request memory quota, if configured. +** Exceeding the implicit document limit (10000) when a memory quota is not in use and when no explicit document limit is set in the options. +** Exceeding the implicit level limit (1000) when the level option is not in use and when no explicit document limit is set in the options. + +[#examples_section] +== Examples + +The following examples follow linear recursion. +Only one recursive reference is allowed in the FROM clause. +Self-joins or set-ops are not allowed in the recursive reference. + +.Simple recursive referencing +==== +[source,sqlpp] +---- +WITH RECURSIVE cte AS ( + SELECT 1 AS r + UNION + SELECT cte.r+1 AS r + FROM cte + WHERE cte.r<4 +) +SELECT cte.r FROM cte; +---- + +.Results +[source,json] +---- +[ + { + "r": 1 + }, + { + "r": 2 + }, + { + "r": 3 + }, + { + "r": 4 + } +] +---- +==== + +.Combine recursive and non-recursive CTEs with the WITH clause +==== +[source,sqlpp] +---- +WITH RECURSIVE cte AS (SELECT 1 r) , + rcte AS ( + SELECT cte.r FROM cte + UNION + SELECT rcte.r+2 r FROM rcte WHERE rcte.r<7 + ) +SELECT * FROM rcte; +---- + +.Results +[source,json] +---- +[ + { + "rcte": { + "r": 1 + } + }, + { + "rcte": { + "r": 3 + } + }, + { + "rcte": { + "r": 5 + } + }, + { + "rcte": { + "r": 7 + } + } +] +---- +==== + +.Handle hierarchical or tree-structured data +==== +For this example, set the query context to the `tenant_agent_00` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +.Create a dataset containing employee information +[source,sqlpp] +---- +CREATE COLLECTION employees IF NOT EXISTS; + +INSERT INTO employees + VALUES ("e1", { + "employee_id": 1, + "employee_name": "Carlos" + }), + VALUES ("e2", { + "employee_id": 2, + "employee_name": "Maya", + "manager_id": 1 + }), + VALUES ("e3", { + "employee_id": 3, + "employee_name": "Fatima", + "manager_id": 1 + }), + VALUES ("e4", { + "employee_id": 4, + "employee_name": "Yijing", + "manager_id": 2 + }), + VALUES ("e5", { + "employee_id": 5, + "employee_name": "Rahul", + "manager_id": 3 + }), + VALUES ("e6", { + "employee_id": 6, + "employee_name": "Lisa", + "manager_id": 2 + }) +RETURNING *; +---- + +.Create an index for the employees +[source,sqlpp] +---- +CREATE INDEX e_idx ON employees(manager_id INCLUDE MISSING, employee_id, employee_name); +---- + +.Find the level of each employee in the organization +[source,sqlpp] +---- +WITH RECURSIVE emplLevel AS ( + SELECT e.employee_id, e.employee_name, 0 lvl + FROM employees e + WHERE manager_id IS MISSING + UNION + SELECT e1.employee_id, e1.employee_name, e1.manager_id, emplLevel.lvl+1 + lvl + FROM employees e1 JOIN emplLevel + ON e1.manager_id = emplLevel.employee_id +) +SELECT * FROM emplLevel; +---- + +.Results +[source,json] +---- +[ + { + "emplLevel": { + "employee_id": 1, + "employee_name": "Carlos", + "lvl": 0 + } + }, + { + "emplLevel": { + "employee_id": 2, + "employee_name": "Maya", + "lvl": 1, + "manager_id": 1 + } + }, + { + "emplLevel": { + "employee_id": 3, + "employee_name": "Fatima", + "lvl": 1, + "manager_id": 1 + } + }, + { + "emplLevel": { + "employee_id": 4, + "employee_name": "Yijing", + "lvl": 2, + "manager_id": 2 + } + }, + { + "emplLevel": { + "employee_id": 6, + "employee_name": "Lisa", + "lvl": 2, + "manager_id": 2 + } + }, + { + "emplLevel": { + "employee_id": 5, + "employee_name": "Rahul", + "lvl": 2, + "manager_id": 3 + } + } +] +---- + +.Find the reporting hierarchy of the employees in the organization +[source,sqlpp] +---- +SELECT e.employee_id, e.employee_name, e.manager_id, +( + WITH RECURSIVE cte AS ( + SELECT e1.employee_id, e1.employee_name, e1.manager_id + FROM employees e1 WHERE e1.manager_id = e.employee_id + UNION + SELECT e2.employee_id, e2.employee_name, e2.manager_id + FROM employees e2, cte + WHERE e2.manager_id = cte.employee_id + ) + SELECT cte.* FROM cte +) as reports +FROM employees e; +---- + +.Results +[source,json] +---- +[ + { + "employee_id": 1, + "employee_name": "Carlos", + "reports": [ + { + "employee_id": 2, + "employee_name": "Maya", + "manager_id": 1 + }, + { + "employee_id": 3, + "employee_name": "Fatima", + "manager_id": 1 + }, + { + "employee_id": 4, + "employee_name": "Yijing", + "manager_id": 2 + }, + { + "employee_id": 6, + "employee_name": "Lisa", + "manager_id": 2 + }, + { + "employee_id": 5, + "employee_name": "Rahul", + "manager_id": 3 + } + ] + }, + { + "employee_id": 2, + "employee_name": "Maya", + "manager_id": 1, + "reports": [ + { + "employee_id": 4, + "employee_name": "Yijing", + "manager_id": 2 + }, + { + "employee_id": 6, + "employee_name": "Lisa", + "manager_id": 2 + } + ] + }, + { + "employee_id": 3, + "employee_name": "Fatima", + "manager_id": 1, + "reports": [ + { + "employee_id": 5, + "employee_name": "Rahul", + "manager_id": 3 + } + ] + }, + { + "employee_id": 4, + "employee_name": "Yijing", + "manager_id": 2, + "reports": [] + }, + { + "employee_id": 6, + "employee_name": "Lisa", + "manager_id": 2, + "reports": [] + }, + { + "employee_id": 5, + "employee_name": "Rahul", + "manager_id": 3, + "reports": [] + } +] +---- +==== + +.Use the OPTIONS clause and the CYCLE clause to avoid infinite recursion +==== +For this example, set the query context to the `tenant_agent_00` scope in the travel sample dataset. +For more information, see xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[Query Context]. + +.Create a dataset containing product information +[source,sqlpp] +---- +CREATE COLLECTION products IF NOT EXISTS; + +INSERT INTO products + VALUES (uuid(), { + "id": 1, + "name": "Bicycle", + "price": 299.99, + "description": "A sturdy and reliable bicycle.", + "category": "Sports", + "related_items": [2, 4] + }), + VALUES (uuid(), { + "id": 2, + "name": "Helmet", + "price": 49.99, + "description": "A safety helmet for cycling.", + "category": "Sports", + "related_items": [1, 3] + }), + VALUES (uuid(), { + "id": 3, + "name": "Water Bottle", + "price": 9.99, + "description": "A convenient water bottle for cycling.", + "category": "Accessories", + "related_items": [2, 4] + }), + VALUES (uuid(), { + "id": 4, + "name": "Gloves", + "price": 19.99, + "description": "Comfortable gloves for cycling.", + "category": "Sports", + "related_items": [1, 3] + }) +RETURNING *; +---- + +.Create an index for the products +[source,sqlpp] +---- +CREATE PRIMARY INDEX ON `default`:`travel-sample`.`tenant_agent_00`.`products` +---- + +.Query resulting in infinite recursion +[source,sqlpp] +---- +WITH RECURSIVE similar_items AS ( + SELECT p.*, 0 as lvl FROM products p WHERE p.id=1 + UNION + SELECT p1.*, similar_items.lvl+1 as lvl FROM products p1, + similar_items WHERE p1.id IN similar_items.related_items +) +SELECT * FROM similar_items; +---- + +.Results +[source,json] +---- +[ + { + "code": 5500, + "msg": "Request has exceeded memory quota" + } +] +---- + +.Solution using the OPTIONS clause to add a level limit +[source,sqlpp] +---- +WITH RECURSIVE similar_items AS ( + SELECT p.*, 0 as lvl FROM products p WHERE p.id=1 + UNION + SELECT p1.*, similar_items.lvl+1 as lvl FROM products p1, + similar_items WHERE p1.id IN similar_items.related_items +) +OPTIONS {"levels":2} +SELECT * FROM similar_items; +---- + +.Results +[source,json] +---- +[ + { + "similar_items": { + "category": "Sports", + "description": "A sturdy and reliable bicycle.", + "id": 1, + "lvl": 0, + "name": "Bicycle", + "price": 299.99, + "related_items": [ + 2, + 4 + ] + } + }, + { + "similar_items": { + "category": "Sports", + "description": "A safety helmet for cycling.", + "id": 2, + "lvl": 1, + "name": "Helmet", + "price": 49.99, + "related_items": [ + 1, + 3 + ] + } + }, + { + "similar_items": { + "category": "Sports", + "description": "Comfortable gloves for cycling.", + "id": 4, + "lvl": 1, + "name": "Gloves", + "price": 19.99, + "related_items": [ + 1, + 3 + ] + } + }, + { + "similar_items": { + "category": "Sports", + "description": "A sturdy and reliable bicycle.", + "id": 1, + "lvl": 2, + "name": "Bicycle", + "price": 299.99, + "related_items": [ + 2, + 4 + ] + } + }, + { + "similar_items": { + "category": "Accessories", + "description": "A convenient water bottle for cycling.", + "id": 3, + "lvl": 2, + "name": "Water Bottle", + "price": 9.99, + "related_items": [ + 2, + 4 + ] + } + } +] +---- + +.Solution using the CYCLE clause to track which fields are likely to repeat and cause a cycle +[source,sqlpp] +---- +WITH RECURSIVE similar_items AS ( + SELECT p.*, 0 as lvl FROM products p WHERE p.id=1 + UNION + SELECT p1.*, similar_items.lvl+1 as lvl FROM products p1, + similar_items WHERE p1.id IN similar_items.related_items +) +CYCLE id RESTRICT +SELECT * FROM similar_items; +---- + +.Results +[source,json] +---- +[ + { + "similar_items": { + "category": "Sports", + "description": "A sturdy and reliable bicycle.", + "id": 1, + "lvl": 0, + "name": "Bicycle", + "price": 299.99, + "related_items": [ + 2, + 4 + ] + } + }, + { + "similar_items": { + "category": "Sports", + "description": "A safety helmet for cycling.", + "id": 2, + "lvl": 1, + "name": "Helmet", + "price": 49.99, + "related_items": [ + 1, + 3 + ] + } + }, + { + "similar_items": { + "category": "Sports", + "description": "Comfortable gloves for cycling.", + "id": 4, + "lvl": 1, + "name": "Gloves", + "price": 19.99, + "related_items": [ + 1, + 3 + ] + } + }, + { + "similar_items": { + "category": "Accessories", + "description": "A convenient water bottle for cycling.", + "id": 3, + "lvl": 2, + "name": "Water Bottle", + "price": 9.99, + "related_items": [ + 2, + 4 + ] + } + } +] +---- +==== \ No newline at end of file diff --git a/modules/n1ql/pages/n1ql-language-reference/with.adoc b/modules/n1ql/pages/n1ql-language-reference/with.adoc new file mode 100644 index 000000000..187334260 --- /dev/null +++ b/modules/n1ql/pages/n1ql-language-reference/with.adoc @@ -0,0 +1,135 @@ += WITH clause +:description: Use WITH to create a common table expression. +:imagesdir: ../../assets/images +:page-topic-type: reference + +[abstract] +Use `WITH` to create a *common table expression*. +The common table expression may be temporary result set that can be used as a data source for the query, or an expression for later use within a query. + +== Purpose + +Common table expressions or CTEs can be used to simplify complex queries. +They can also be particularly useful when a value needs to be used several times in a query. + +The WITH clause has comparable functionality to the xref:n1ql-language-reference/let.adoc[LET] clause. +The major difference between the WITH clause and the LET clause is that the WITH clause can come before the SELECT clause, enabling an earlier definition of expressions; whereas the LET clause must come after the xref:n1ql-language-reference/from.adoc[FROM] clause. + +The WITH clause is evaluated once per query block, and LET is evaluated for every object produced by the FROM or JOIN clause. + +You can chain WITH clauses. +A CTE that you create in one WITH clause may be referenced in a later WITH clause. + +== Prerequisites + +The WITH clause can only be used preceding a SELECT statement, and in order for you to select data from a document or keyspace, you must have the [.param]`query_select` privilege on the document or keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + +== Syntax + +[source,ebnf] +---- +include::partial$grammar/dql.ebnf[tag=with-clause] +---- + +image::n1ql-language-reference/with-clause.png["Syntax diagram", align=left] + +[#arguments] +== Arguments + +alias:: [Required] String or xref:n1ql-language-reference/index.adoc[expression] that represents the name of the variable. + +select:: xref:n1ql-language-reference/selectclause.adoc[SELECT] statement that returns a temporary result set assigned to [.var]`alias`. + +expression:: String or xref:n1ql-language-reference/index.adoc[expression] that represents a value assigned to [.var]`alias`. + +[#examples_section] +== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.Use a common table expression to create an expression for use in a query +==== +Find the average number of public likes for each record. +Then find all hotels with a greater than average number of public likes. + +[source,sqlpp] +---- +WITH avgLikeCount AS ( + SELECT VALUE AVG(DISTINCT ARRAY_COUNT(cte.public_likes)) + FROM hotel AS cte +) +SELECT hotel.name, ARRAY_COUNT(hotel.public_likes) AS likeCount +FROM hotel +WHERE ARRAY_COUNT(hotel.public_likes) > avgLikeCount[0] +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "likeCount": 8, + "name": "Medway Youth Hostel" + }, + { + "likeCount": 7, + "name": "Le Clos Fleuri" + }, + { + "likeCount": 9, + "name": "Windy Harbour Farm Hotel" + }, + { + "likeCount": 5, + "name": "Avondale Guest House" + }, + { + "likeCount": 8, + "name": "The Bulls Head" + } +] +---- +==== + +.Use a common table expression to create a record subset for use in a query +==== +Create a recordset of hotel names and their Cleanliness ratings. +Then use this recordset to find the names all hotels whose average Cleanliness rating is greater than 4.5. + +[source,sqlpp] +---- +WITH hotels AS ( + SELECT name, reviews[*].ratings[*].Cleanliness + FROM hotel +) +SELECT hotels.name +FROM hotels +WHERE ARRAY_AVG(hotels.Cleanliness) > 4.5 +LIMIT 5; +---- + +.Results +[source,json] +---- +[ + { + "name": "The George Hotel" + }, + { + "name": "Windy Harbour Farm Hotel" + }, + { + "name": "Avondale Guest House" + }, + { + "name": "The Bulls Head" + }, + { + "name": "Hill House Holiday Cottage" + } +] +---- +==== diff --git a/modules/n1ql/pages/n1ql-manage/index.adoc b/modules/n1ql/pages/n1ql-manage/index.adoc new file mode 100644 index 000000000..5b6a0ffa5 --- /dev/null +++ b/modules/n1ql/pages/n1ql-manage/index.adoc @@ -0,0 +1,47 @@ += Administer Queries and Indexes +:page-role: tiles -toc +:!sectids: + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +include::ROOT:partial$component-signpost.adoc[] + +== Get System Information + +{sqlpp} has a system namespace that stores metadata about data containers, the Query service, and the system as a whole. +You can query the system namespace to get this information. + +* xref:n1ql:n1ql-intro/sysinfo.adoc[] + +== Manage Queries + +You can monitor and manage queries using {sqlpp}. + +* xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc[] + +== Manage Primary and Secondary Indexes + +You can monitor and manage primary and secondary indexes using the Couchbase Capella UI. + +* xref:clusters:index-service/manage-indexes.adoc[] + +== Settings and Parameters + +You can configure the Query service using +ifdef::flag-devex-rest-api[] +cluster-level query settings, node-level query settings, and +endif::flag-devex-rest-api[] +request-level query parameters. + +* xref:n1ql:n1ql-manage/query-settings.adoc[] diff --git a/modules/n1ql/pages/n1ql-manage/monitoring-n1ql-query.adoc b/modules/n1ql/pages/n1ql-manage/monitoring-n1ql-query.adoc new file mode 100644 index 000000000..01ee0336b --- /dev/null +++ b/modules/n1ql/pages/n1ql-manage/monitoring-n1ql-query.adoc @@ -0,0 +1,1567 @@ += Manage and Monitor Queries +:example-caption!: +:alt-markdown-links: +:description: Monitoring and profiling {sqlpp} queries, query service nodes, and corresponding system resources is very important for smoother operational performance and efficiency of the system. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} +In fact, often it is vital for diagnosing and troubleshooting issues such as query performance, resource bottlenecks, and overloading of various services. + +include::ROOT:partial$component-signpost.adoc[] + +System keyspaces provide various monitoring details and statistics about individual queries and the Query service. +When running on a cluster with multiple query nodes, stats about all queries on all query nodes are collected in the Query management and monitoring system keyspaces. + +For example, this can help identify: + +* The top 10 slow or fast queries running on a particular query node or the cluster. +* Resource usage statistics of the query service, or resources used for a particular query. +* Details about the active, completed, and prepared queries. +* Find long running queries that are running for more than 2 minutes. + +These system keyspaces are transient in nature, and are not persisted to disk or permanent storage. +Hence, the information in the keyspaces pertains to the current instantiation of the Query service. + +You can access the Query management and monitoring system keyspaces using any of the following: + +* {sqlpp} from the cbq shell or the Query tab +ifdef::flag-devex-rest-api[] +* The Query Admin REST API +endif::flag-devex-rest-api[] +* A monitoring SDK + +Using {sqlpp} enables you to obtain further insights from the keyspaces. + +== Authentication and Client Privileges + +Users must have permission to access restricted system keyspaces. +For more details about cluster credentials, see xref:clusters:manage-database-users.adoc[]. + +ifdef::flag-devex-rest-api[] +== Examples on this Page + +In the REST API examples: + +* `$BASE_URL` is the protocol, host name or IP address, and port -- for example, `+http://localhost:8093+`. +* `$USER` is the user name. +* `$PASSWORD` is the password. +endif::flag-devex-rest-api[] + +[#vitals] +== Monitor System Vitals + +The `system:vitals` catalog provides data about the running state and health of the query nodes, such as number of logical cores, active threads, queued threads, CPU utilization, memory usage, network utilization, garbage collection percentage, and so on. +This information can be very useful to assess the current workload and performance characteristics of a query node. + +[#sys-vitals-get] +=== Get System Vitals + +To view system vitals, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To view system vitals with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD $BASE_URL/admin/vitals +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To view system vitals with {sqlpp}: + +[source,sqlpp] +---- +SELECT * FROM system:vitals; +---- +-- +==== + +[[sys-vital-examples]] +=== System Vitals Details + +Getting system vitals, as described in <>, returns results similar to the following. + +==== +[source,json] +---- +{ + "uptime": "7h39m32.668577197s", + "local.time": "2021-04-30 18:42:39.517208807 +0000 UTC m=+27573.945319668", + "version": "7.0.0-N1QL", + "total.threads": 191, + "cores": 2, + "gc.num": 669810600, + "gc.pause.time": "57.586373ms", + "gc.pause.percent": 0, + "memory.usage": 247985184, + "memory.total": 11132383704, + "memory.system": 495554808, + "cpu.user.percent": 0, + "cpu.sys.percent": 0, + "request.completed.count": 140, + "request.active.count": 0, + "request.per.sec.1min": 0.0018, + "request.per.sec.5min": 0.0055, + "request.per.sec.15min": 0.0033, + "request_time.mean": "536.348163ms", + "request_time.median": "54.065567ms", + "request_time.80percentile": "981.869933ms", + "request_time.95percentile": "2.543128455s", + "request_time.99percentile": "4.627922799s", + "request.prepared.percent": 0 +} +---- +==== + +This catalog contains the following attributes: + +include::n1ql-rest-admin:index.adoc[tags=Vitals] + +[#sys-active-req] +== Monitor and Manage Active Requests + +The `system:active_requests` catalog lists all currently executing active requests or queries. + +[[sys-active-get]] +=== Get Active Requests + +To view active requests, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To view active requests with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD $BASE_URL/admin/active_requests +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To view active requests with {sqlpp}: + +[source,sqlpp] +---- +SELECT * FROM system:active_requests; +---- +-- +==== + +To get the query plan for active requests, include `meta().plan` in a {sqlpp} query. +See <>. + +[tabs] +==== +{sqlpp}:: ++ +-- +To view active requests with {sqlpp}, including the query plan: + +[source,sqlpp] +---- +SELECT *, meta().plan FROM system:active_requests; +---- +-- +==== + +[[sys-active-delete]] +=== Terminate an Active Request + +The DELETE command can be used to terminate an active request, for instance, a non-responding or a long-running query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To terminate an active request [.var]`uuid` with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD -X DELETE $BASE_URL/admin/active_requests/uuid +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To terminate an active request [.var]`uuid` with {sqlpp}: + +[source,sqlpp] +---- +DELETE FROM system:active_requests WHERE requestId = "uuid"; +---- +-- +==== + +[[sys-active-examples]] +=== Active Request Details + +Getting active requests, as described in <>, returns results similar to the following. + +==== +[source,json] +---- +[ + { + "active_requests": { + "clientContextID": "832adfa0-e9e6-464e-b5e6-b7ec7549d511", + "cpuTime": "111.877µs", + "elapsedTime": "77.631814ms", + "executionTime": "77.517185ms", + "n1qlFeatCtrl": 76, + "node": "127.0.0.1:8091", + "phaseOperators": { + "authorize": 1, + "fetch": 1, + "primaryScan": 1, + "project": 1, + "stream": 1 + }, + "phaseTimes": { + "authorize": "4.998µs", + "fetch": "69.519µs", + "instantiate": "16.28µs", + "parse": "597.435µs", + "plan": "24.141851ms", + "plan.index.metadata": "24.005473ms", + "plan.keyspace.metadata": "2.022µs", + "primaryScan": "23.496033ms", + "project": "824ns", + "stream": "2.242µs" + }, + "queryContext": "default:travel-sample.inventory", + "remoteAddr": "127.0.0.1:37506", + "requestId": "05cc1895-9986-4819-b4d3-8a4311e8f319", + "requestTime": "2024-05-21T13:29:16.864Z", + "scanConsistency": "unbounded", + "state": "running", + "statement": "SELECT * FROM system:active_requests;", + "statementType": "SELECT", + "useCBO": true, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0", + "users": "builtin:Administrator" + } + } +] +---- +==== + +This catalog contains the following attributes: + +include::n1ql-rest-admin:index.adoc[tags=Requests] + +For query plan field names and meanings, see <>. + +[#sys-prepared] +== Monitor and Manage Prepared Statements + +The `system:prepareds` catalog provides data about the known prepared statements and their state in a query node's prepared statement cache. +For each prepared statement, this catalog provides information such as name, statement, query plan, last use time, number of uses, and so on. + +A prepared statement is created and stored relative to the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. +You can create multiple prepared statements with the same name, each stored relative to a different query context. +This enables you to run multiple instances of the same application against different datasets. + +When there are multiple prepared statements with the same name in different query contexts, the name of the prepared statement in the `system:prepareds` catalog includes the associated query context in brackets. + +[[sys-prepared-get]] +=== Get Prepared Statements + +To get a list of all known prepared statements, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To get a list of all known prepared statements with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD $BASE_URL/admin/prepareds +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To get a list of all known prepared statements with a {sqlpp} query: + +[source,sqlpp] +---- +SELECT * FROM system:prepareds; +---- +-- +==== + +To get information about a specific prepared statement, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To get information about a specific prepared statement [.var]`example1` with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD $BASE_URL/admin/prepareds/example1 +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To get information about a specific prepared statement [.var]`example1` with a {sqlpp} query: + +[source,sqlpp] +---- +SELECT * FROM system:prepareds WHERE name = "example1"; +---- +-- +==== + +To get the query plan for prepared statements, include `meta().plan` in a {sqlpp} query. +See <>. + +[tabs] +==== +{sqlpp}:: ++ +-- +To view prepared statements with {sqlpp}, including the query plan: + +[source,sqlpp] +---- +SELECT *, meta().plan FROM system:prepareds; +---- +-- +==== + +[[sys-prepared-delete]] +=== Delete Prepared Statements + +To delete a specific prepared statement, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To delete a prepared statement [.var]`p1` with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD -X DELETE $BASE_URL/admin/prepareds/p1 +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To delete a prepared statement [.var]`p1` with a {sqlpp} query: + +[source,sqlpp] +---- +DELETE FROM system:prepareds WHERE name = "p1"; +---- +-- +==== + +To delete all the known prepared statements, use a {sqlpp} query. + +[tabs] +==== +{sqlpp}:: ++ +-- +To delete all known prepared statements: + +[source,sqlpp] +---- +DELETE FROM system:prepareds; +---- +-- +==== + +[[sys-prepared-examples]] +=== Prepared Statement Details + +To try the examples in this section, first create a couple of prepared statements. + +.Create a prepared statement with default query context +==== +include::ROOT:partial$query-context.adoc[tag=unset] + +.Query +[source,sqlpp] +---- +PREPARE p1 AS SELECT * FROM `travel-sample`.inventory.airline WHERE iata = "U2"; +---- +==== + +.Create a prepared statement with specified query context +==== +include::ROOT:partial$query-context.adoc[tag=example] + +.Query +[source,sqlpp] +---- +PREPARE p1 AS SELECT * FROM airline WHERE iata = "U2"; +---- +==== + +Getting prepared statements, as described in <>, returns results similar to the following. + +==== +[source,json] +---- +{ + "requestID": "d976e59a-d74e-4350-b0df-fa137099d594", + "signature": { + "*": "*", + "plan": "json" + }, + "results": [ + { + "prepareds": { + "encoded_plan": "H4sIAAAAAAAA/6RTUW/TPBT9K9H5XrbJ30QBMcmIhzJ1AjG0qh3wwKbEJLedmWt71061UIXfjpxkndYhENpbYt97z7nn+GxAtnQVVbk3ykICAgtSsWY6djayMwHy6JWAthXdjr3+TBy0s5Avh7N5qewHaoJXJQXIDSpaqNpEGVmtyfwf1MobOtR2TTY6bg6VZqMtQS6UCdQKWLUiSPgR+u9uFOTdIAg4T6yi4zT+v/sfjOt45Vj/IAh41mttaNmTONUhQn7d4FzxkuL9tL/SEpiyXkMepQ/nA+Sz9rIV+FleaVPtMpjTTU22TG19AZPtcP+5aMp6pbhJcr6AwLe6vO54P+CLQfR+n3zLPh/Y576fcleXe3bfqYydYxsMt/k1NZCR66T+9eAdJO4l+L0NoXQ+nWxhIVAHbZeQWAaNVjxc6YRiefWnXZ6EvYs2VayMIYMneXWiTSSGQOlspXvhsLdXDPyKw0KrqIr97E12gU/PL7D/iMh7q6NWZtpLDwGmUJuYR+JV6ADp1qfCQGaRVouKBzsu28s2vbYd4pFJrZDuBFJOtyE8Go0EbmriJqWVbmOfYKab86aTaz45nRyfJxC9tF2skyoHkDhAKzC0TGeT6Xg2yfwoG8+zvic7yE5mZx+z4oFpxePEZF/eTWaTLMmyFeV19zLo+O3ZsNivAAAA//+q+jhuaAQAAA==", + "featuresControl": 76, + "indexApiVersion": 4, + "indexScanKeyspaces": { + "default:travel-sample.inventory.airline": false + }, + "name": "p1", // <1> + "namespace": "default", + "node": "127.0.0.1:8091", + "statement": "PREPARE p1 AS SELECT * FROM `travel-sample`.inventory.airline WHERE iata = \"U2\";", + "uses": 0 + } + }, + { + "prepareds": { + "encoded_plan": "H4sIAAAAAAAA/6STT28TMRDFv8rqcWkrExFAVDLiEKpUIIoaJQUOtNqY3Ulq6tju2Bt1iZbPjry7TWmKQKg3/xnPvPk9zwZkC1dSmXujLCQgsCAVK6YjZyM7EyAPXwloW9LNyOvPxEE7C/myP5sVyn6gOnhVUIDcoKSFqkyUkdWazNOgVt7QQNs12ei4HijNRluCXCgTqBGwakWQ8EN06zYV5G0iCDhPrKLjlP7J3QajKl461j8IAp71WhtadiJOdIiQXzc4U7ykeJftn7IEJqzXkIdp4XyAfNZcNAI/i0ttyl0FM7quyBbpWRfAZNu6/x00Yb1SXCecLyDwrSquWt339KKH3vWTb9Xnvfrcd1lu43LP7jsVsXVsg/42v6IaMnKV6F/13kHiDsGfbQiF8+lkWxYCVdB2CYll0GjE/ZaOKRaXf+vlUbV3q00UK2PI4FFeHWsTiSFQOFvqDhz29ua9vvlgrlVU8/3sTXaOT8/Psf9AyHuro1Zm0qGHAFOoTMwj8Sq0BenGp8BAZpFai4p7Oy6aiyb9th3hkUmtkO4E0pxuh/BwOBS4rojrNK108wDy4HevmK7P6pbibHwyPjpLtfXSttOeYB1A4gCNQJ9pMh1PRtNx5ofZaJZ1b7KD7Hh6+jHreWRf3o2n4ywx2RJ53X4LOnp72nf1KwAA////9+bsZQQAAA==", + "featuresControl": 76, + "indexApiVersion": 4, + "indexScanKeyspaces": { + "default:travel-sample.inventory.airline": false + }, + "name": "p1(travel-sample.inventory)", // <2> + "namespace": "default", + "node": "127.0.0.1:8091", + "statement": "PREPARE p1 AS SELECT * FROM airline WHERE iata = \"U2\";", + "uses": 0 + } + } + ], + "status": "success", + "metrics": { + "elapsedTime": "25.323496ms", + "executionTime": "25.173646ms", + "resultCount": 2, + "resultSize": 7891, + "serviceLoad": 12 + } +} +---- + +In this example, the names of the prepared statements are identical, but they are associated with different query contexts. + +<.> The name of the prepared statement for the default query context +<.> The name of the prepared statement showing the associated query context +==== + +This catalog contains the following attributes: + +include::n1ql-rest-admin:index.adoc[tags=Statements] + +For query plan field names and meanings, see <>. + +[#sys-completed-req] +== Monitor and Manage Completed Requests + +By default, the `system:completed_requests` catalog maintains a list of the most recent completed requests that have run longer than a predefined threshold of time. +(You can also log completed requests that meet other conditions that you define.) + +For each completed request, this catalog maintains information such as requestId, statement text, prepared name (if prepared statement), request time, service time, and so on. +This information provides a general insight into the health and performance of the query node and the cluster. + +[[sys-completed-get]] +=== Get Completed Requests + +To get a list of all logged completed requests, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To get a list of all logged completed requests using the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD $BASE_URL/admin/completed_requests +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To get a list of all logged completed requests using {sqlpp}: + +[source,sqlpp] +---- +SELECT * FROM system:completed_requests; +---- +-- +==== + +Note that the `completed` state means that the request was started and completed by the Query service, but it does not mean that it was necessarily successful. +The request could have been successful, or completed with errors. + +To find requests that completed successfully, search for completed requests whose `state` is `completed` and whose `errorCount` field has the value `0`. + +[tabs] +==== +{sqlpp}:: ++ +-- +To get a list of all logged completed requests, including only successful requests: + +[source,sqlpp] +---- +SELECT * FROM system:completed_requests +WHERE state = "completed" AND errorCount = 0; +---- +-- +==== + +To get the query plan for completed requests, include `meta().plan` in a {sqlpp} query. +See <>. + +[tabs] +==== +{sqlpp}:: ++ +-- +To view completed requests with {sqlpp}, including the query plan: + +[source,sqlpp] +---- +SELECT *, meta().plan FROM system:completed_requests; +---- +-- +==== + +[[sys-completed-delete]] +=== Purge the Completed Requests + +To purge a specific completed request, use +ifdef::flag-devex-rest-api[] +the Admin REST API or +endif::flag-devex-rest-api[] +a {sqlpp} query. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To purge a completed request [.var]`uuid` with the Admin REST API: + +[source,sh] +---- +curl -u $USER:$PASSWORD -X DELETE $BASE_URL/admin/completed_requests/uuid +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To purge a completed request [.var]`uuid` with {sqlpp}: + +[source,sqlpp] +---- +DELETE FROM system:completed_requests WHERE requestId = "uuid"; +---- +-- +==== + +To purge completed requests for a given time period, use a {sqlpp} query. + +[tabs] +==== +{sqlpp}:: ++ +-- +To purge the completed requests for a given time period: + +[source,sqlpp] +---- +DELETE FROM system:completed_requests WHERE requestTime LIKE "2015-09-09%"; +---- +-- +==== + +[[sys-completed-examples]] +=== Completed Request Details + +To try the examples in this section, first run a query which takes at least 1000ms (the default value of the `completed-threshold` query setting) to get registered in the `system:completed_requests` keyspace. + +.Run a long query +==== +include::ROOT:partial$query-context.adoc[tag=example] + +.Query +[source,sqlpp] +---- +SELECT * FROM route ORDER BY sourceairport LIMIT 5; +---- +==== + +Getting completed requests, as described in <>, returns results similar to the following. + +==== +[source,json] +---- +[ + // ... + { + "completed_requests": { + "clientContextID": "a19a61ab-cd9e-46c9-be71-92623ff85741", + "cpuTime": "912.408423ms", + "elapsedTime": "3.762926948s", + "errorCount": 0, + "errors": [], + "n1qlFeatCtrl": 76, + "node": "127.0.0.1:8091", + "phaseCounts": { + "fetch": 24023, + "primaryScan": 24023, + "primaryScan.GSI": 24023, + "sort": 24028 + }, + "phaseOperators": { + "authorize": 1, + "fetch": 1, + "primaryScan": 1, + "primaryScan.GSI": 1, + "project": 1, + "sort": 2, + "stream": 1 + }, + "phaseTimes": { + "authorize": "15.111µs", + "fetch": "3.641125449s", + "instantiate": "332.963µs", + "parse": "1.04015ms", + "plan": "602.878µs", + "plan.index.metadata": "25.849µs", + "plan.keyspace.metadata": "11.586µs", + "primaryScan": "101.118572ms", + "primaryScan.GSI": "101.118572ms", + "project": "33.273783ms", + "run": "3.760767643s", + "sort": "666.364325ms", + "stream": "1.617688ms" + }, + "queryContext": "default:travel-sample.inventory", + "remoteAddr": "127.0.0.1:37684", + "requestId": "e170bf67-d364-4ed7-9698-784bbb779d18", + "requestTime": "2024-05-21T14:31:46.882Z", + "resultCount": 5, + "resultSize": 17714, + "scanConsistency": "unbounded", + "serviceTime": "3.762768429s", + "state": "completed", + "statement": "SELECT * FROM route ORDER BY sourceairport LIMIT 5;", + "statementType": "SELECT", + "useCBO": true, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0", + "users": "builtin:Administrator", + "~qualifier": "threshold" + } + } +] +---- +==== + +For field names and meanings, see <>. + +For query plan field names and meanings, see <>. + +ifdef::flag-devex-rest-api[] +[[sys-completed-config]] +== Configure the Completed Requests + +You can configure the `system:completed_requests` keyspace by specifying parameters through the Admin API `/admin/settings` endpoint. + +You can specify the conditions for completed request logging using the `completed` field. +This field takes a JSON object containing the names and values of logging qualifiers. +Completed requests that meet the defined qualifiers are logged. + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed": {"user": "marco", "error": 12003}}' +---- + +=== Logging Qualifiers + +You can specify the following logging qualifiers. +A completed request is logged if _any_ of the qualifiers are met (logical OR). + +[horizontal] +`threshold`:: The execution time threshold in milliseconds. +`aborted`:: Whether to log requests that generate a panic. +`error`:: Log requests returning this error number. +`client`:: Log requests from this IP address. +`user`:: Log requests with this user name. +`context`:: Log requests with this client context ID. + +For full details, see xref:n1ql-rest-admin:index.adoc#Logging_Parameters[Logging Parameters]. + +The basic syntax adds a qualifier to the logging parameters, i.e. any existing qualifiers are not removed. +You can change the value of a logging qualifier by specifying the same qualifier again with a new value. + +To add a new instance of an existing qualifier, use a plus sign (`+`) before the qualifier name, e.g. `+user`. +To remove a qualifier, use a minus sign (`-`) before the qualifier name, e.g. `-user`. + +For example, the following request will add user `simon` to those tracked, and remove error `12003`. + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed": {"+user": "simon", "-error": 12003}}' +---- + +Similarly, you could remove all logging by execution time with the following request, as long as the value matches the existing threshold. + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed": {"-threshold": 1000}}' +---- + +=== Tagged Sets + +You can also specify qualifiers that have to be met as a group for the completed request to be logged (logical AND). + +To do this, specify the `tag` field along with a set of qualifiers, like so: + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed": {"user": "marco", "error": 12003, "tag": "both_user_and_error"}}' +---- + +In this case, the request will be logged when both user and error match. + +The tag name can be any string that is meaningful and unique. +Requests that match a tagged set of conditions are logged with a field `~tag`, which is set to the name of the tag. + +To add a qualifier to a tagged set, specify the tag name again along with the new qualifier: + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed": {"client": "172.1.2.3", "tag": "both_user_and_error"}}' +---- + +You cannot add a new instance of an existing qualifier to a tagged set using a plus sign (`+`) before the qualifier name. +For example, you cannot add a `user` qualifier to a tagged set that already contains a `user` qualifier. +If you need to track two users with the same error, create two tagged sets, one per user. + +You can remove a qualifier from a tagged set using a minus sign (`-`) before the qualifier name, e.g. `-user`. +When you remove the last qualifier from a tagged set, the tagged set is removed. + +[NOTE] +-- +You can specify multiple tagged sets. +In this case, completed requests are logged if they match all of the qualifiers in any of the tagged sets. + +You can also specify a mixture of tagged sets and individual qualifiers. +In this case, completed requests are logged if they match any of the individual qualifiers, or all of the qualifiers in any of the tagged sets. +-- + +=== Completed Threshold + +The [.param]`completed-threshold` field provides another way of specifying the `threshold` qualifier within the `completed` field. + +This field sets the minimum request duration after which requests are added to the `system:completed_requests` catalog. +The default value is 1000ms. +Specify [.in]`0` to log all requests and [.in]`-1` to not log any requests to the keyspace. + +To specify a different value, use: + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed-threshold":0}' +---- + +=== Completed Limit + +The [.param]`completed-limit` field sets the number of most recent requests to be tracked in the `system:completed_requests` catalog. +The default value is 4000. +Specify [.in]`0` to not track any requests and [.in]`-1` to set no limit. + +To specify a different value, use: + +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"completed-limit":1000}' +---- +endif::flag-devex-rest-api[] + +[#query-monitoring-settings] +== [[Request]]Query Profiling + +Query profiling enables you to obtain more detailed monitoring information and finer execution timings for any query. +You can set query profiling to the following levels: + +* `off` -- query profiling is disabled. +* `phases` -- query profiling is enabled, including information about the phases of query execution. +* `timings` -- query profiling is enabled, including information about the phases of query execution, and detailed timing information. + +You can set query profiling: + +ifdef::flag-devex-rest-api[] +* At the <>, so that it is enabled for all queries on that node. +endif::flag-devex-rest-api[] +* At the <>, for individual queries. + +[[client_context_id]] +For more information about Query settings and parameters, see xref:n1ql:n1ql-manage/query-settings.adoc[]. + +ifdef::flag-devex-rest-api[] +[#enable-settings-for-a-query-engine] +=== Enable Query Profiling for a Query Node + +To activate query profiling at the node level, specify the `profile` setting using the xref:n1ql-rest-admin:index.adoc[Admin REST API] (`/admin/settings` endpoint). + +.See the current node-level query settings +==== +The following request gets the current node-level query settings. + +.Request +[source,sh] +---- +include::n1ql:example$settings/node-level-settings.sh[tag=curl] +---- + +.Results +[source,json] +---- +include::n1ql:example$settings/node-level-settings.jsonc[] +---- +==== + +.Save node-level query settings to a file +==== +The following request saves the current node-level query settings to the file `query_settings.json`. + +.Request +[source,sh] +---- +include::n1ql:example$settings/save-node-level-settings.sh[tag=curl] +---- +==== + +.Set node-level query settings from a file +==== +Assuming that you have edited the file `query_settings.json` to specify the query settings you want, the following request +sets the node-level query settings according to the file. + +.Request +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -X POST \ + -d@./query_settings.json +---- +==== + +.Set node-level query settings explicitly +==== +The following request explicitly sets query profiling at the node level. + +.Request +[source,sh] +---- +curl $BASE_URL/admin/settings -u $USER:$PASSWORD \ + -H 'Content-Type: application/json' \ + -d '{"profile": "phases"}' +---- + +.Results +[source,json] +---- +{ + // ... + "profile":"phases", + "request-size-cap": 67108864, + "scan-cap": 512, + "servicers": 4, + "timeout": 0, + "txtimeout": "0s", + "use-cbo": true +} +---- +==== +endif::flag-devex-rest-api[] + +[#enable-settings-per-session-or-per-query] +=== Enable Query Profiling for a Request + +To activate profiling at the request level, you can: + +ifdef::flag-devex-rest-api[] +* Specify the `profile` setting using the xref:n1ql-rest-query:index.adoc[Query REST API] (`/query/service` endpoint). +endif::flag-devex-rest-api[] +* Specify the `profile` setting using the xref:n1ql:n1ql-intro/cbq.adoc[cbq] command line tool. + +[tabs] +==== +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To set query settings using the REST API, specify the parameters in the request body. + +''' + +The following statement sets the profiling to phases: + +[source,sh] +---- +curl $BASE_URL/query/service -u $USER:$PASSWORD \ + -d 'profile=phases&statement=SELECT * FROM `travel-sample`.inventory.airline LIMIT 1' +---- + +The following statement sets the profiling to timings: + +[source,sh] +---- +curl $BASE_URL/query/service -u $USER:$PASSWORD \ + -d 'profile=timings&statement=SELECT * FROM `travel-sample`.inventory.airline LIMIT 1' +---- +-- +endif::flag-devex-rest-api[] + +{sqlpp}:: ++ +-- +To set query settings using the cbq shell, use the `\SET` command. + +''' + +The following statement sets the profiling to phases: + +[source,sqlpp] +---- +\set -profile "phases"; +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +---- + +The following statement sets the profiling to timings: + +[source,sqlpp] +---- +\set -profile "timings"; +SELECT * FROM `travel-sample`.inventory.airline LIMIT 1; +---- +-- +==== + +The Query tab automatically enables Query profiling, with detailed timing information. +To disable or enable Query profiling with the Query tab, specify the *Collect query timings* option using the xref:clusters:query-service/query-workbench.adoc#query-settings[Query Settings]. + +[#monitor-profile-details] +== Query Profiling Details + +You can access the profiling information: + +* In the <>. +* In the <>. + +When a query executes a user-defined function, profiling information is available for the {sqlpp} queries within the user-defined function as well. + +[[profile]] +=== Profiling Details in Query Responses + +When profiling is enabled: + +* If you are using +ifdef::flag-devex-rest-api[] +the Query REST API or +endif::flag-devex-rest-api[] +the cbq shell, query profiling information is returned with the query results. +* If you are using the Query tab, query profiling information is not returned with the query results. + +.Phases Profile +==== +If you are using +ifdef::flag-devex-rest-api[] +the Query REST API or +endif::flag-devex-rest-api[] +the cbq shell, the following statistics are returned when `profile` is set to `phases`: + +[source,json] +---- +{ + "requestID": "06d6c1c2-1a8a-4989-a856-7314f9eddee5", + "signature": { + "*": "*" + }, + "results": [ + { + "airline": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + } + } + ], + "status": "success", + "metrics": { + "elapsedTime": "12.77927ms", + "executionTime": "12.570648ms", + "resultCount": 1, + "resultSize": 254, + "serviceLoad": 12 + }, + "profile": { + "phaseTimes": { + "authorize": "19.629µs", + "fetch": "401.997µs", + "instantiate": "147.686µs", + "parse": "4.545234ms", + "plan": "409.364µs", + "primaryScan": "6.103775ms", + "run": "6.699056ms" + }, + "phaseCounts": { + "fetch": 1, + "primaryScan": 1 + }, + "phaseOperators": { + "authorize": 1, + "fetch": 1, + "primaryScan": 1 + }, + "requestTime": "2021-04-30T18:37:56.394Z", + "servicingHost": "127.0.0.1:8091" + } +} +---- +==== + +.Timings Profile +==== +If you are using +ifdef::flag-devex-rest-api[] +the Query REST API or +endif::flag-devex-rest-api[] +the cbq shell, the following statistics are returned when `profile` is set to `timings`: + +[source,json] +---- +{ + "requestID": "268a1240-6864-43a2-af13-ccb8d1e50abf", + "signature": { + "*": "*" + }, + "results": [ + { + "airline": { + "callsign": "MILE-AIR", + "country": "United States", + "iata": "Q5", + "icao": "MLA", + "id": 10, + "name": "40-Mile Air", + "type": "airline" + } + } + ], + "status": "success", + "metrics": { + "elapsedTime": "2.915245ms", + "executionTime": "2.755355ms", + "resultCount": 1, + "resultSize": 254, + "serviceLoad": 12 + }, + "profile": { + "phaseTimes": { + "authorize": "18.096µs", + "fetch": "388.122µs", + "instantiate": "31.702µs", + "parse": "646.157µs", + "plan": "120.427µs", + "primaryScan": "1.402918ms", + "run": "1.936852ms" + }, + "phaseCounts": { + "fetch": 1, + "primaryScan": 1 + }, + "phaseOperators": { + "authorize": 1, + "fetch": 1, + "primaryScan": 1 + }, + "requestTime": "2021-04-30T18:40:13.239Z", + "servicingHost": "127.0.0.1:8091", + "executionTimings": { + "#operator": "Authorize", + "#stats": { + "#phaseSwitches": 4, + "execTime": "1.084µs", + "servTime": "17.012µs" + }, + "privileges": { + "List": [ + { + "Target": "default:travel-sample.inventory.airline", + "Priv": 7, + "Props": 0 + } + ] + }, + "~child": { + "#operator": "Sequence", + "#stats": { + "#phaseSwitches": 1, + "execTime": "2.474µs" + }, + "~children": [ + { + "#operator": "PrimaryScan3", + "#stats": { + "#itemsOut": 1, + "#phaseSwitches": 7, + "execTime": "18.584µs", + "kernTime": "8.869µs", + "servTime": "1.384334ms" + }, + "bucket": "travel-sample", + "index": "def_inventory_airline_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "airline", + "limit": "1", + "namespace": "default", + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "#stats": { + "#itemsIn": 1, + "#itemsOut": 1, + "#phaseSwitches": 10, + "execTime": "25.64µs", + "kernTime": "1.427752ms", + "servTime": "362.482µs" + }, + "bucket": "travel-sample", + "keyspace": "airline", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "InitialProject", + "#stats": { + "#itemsIn": 1, + "#itemsOut": 1, + "#phaseSwitches": 9, + "execTime": "6.006µs", + "kernTime": "1.825917ms" + }, + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + }, + { + "#operator": "Limit", + "#stats": { + "#itemsIn": 1, + "#itemsOut": 1, + "#phaseSwitches": 4, + "execTime": "2.409µs", + "kernTime": "2.094µs" + }, + "expr": "1" + }, + { + "#operator": "Stream", + "#stats": { + "#itemsIn": 1, + "#itemsOut": 1, + "#phaseSwitches": 6, + "execTime": "46.964µs", + "kernTime": "1.844828ms" + } + } + ] + }, + "~versions": [ + "7.0.0-N1QL", + "7.0.0-4960-enterprise" + ] + } + } +} +---- +==== + +The `profile` object contains the following attributes: + +include::n1ql-rest-query:index.adoc[tags=Profile] + +[[Execution_Timings,Execution Timings]] +*Execution Timings* + +include::n1ql-rest-query:index.adoc[tags=Execution_Timings] + +[[Statistics,Statistics]] +*Statistics* + +include::n1ql-rest-query:index.adoc[tags=Statistics] + +include::n1ql-rest-query:partial$definitions/Statistics/definition-end.adoc[opts=optional] + +[[plan]] +=== Profiling Details in System Catalogs + +The <> and <> system catalogs always return profiling information regarding query phases: that is, phase times, phase counts, and phase operators. + +The <>, <>, and <> system catalogs also support the `meta().plan` virtual attribute. +This captures the whole query plan, and includes profiling information regarding execution timings. + +To get execution timing information from these system catalogs, you must explicitly specify `meta().plan` in the projection list for the SELECT query. + +Within these system catalogs, not all statements have a `meta().plan` attribute. + +* With <> and <>, the `meta().plan` attribute is only available for statements that you run when profile is set to `timings`. + +* With <>, the `meta().plan` attribute is available for all statements. + +[NOTE] +==== +When request profiling is set to `timings`, profiling information is likely to use 100KB+ per entry in the `system:completed_requests` keyspace. + +* Due to the added overhead of running both profiling and xref:clusters:monitoring/monitoring.adoc#activity-logs[logging], turn on both of them only when needed. +Running only one of them continuously has no noticeable affect on performance. +* Profiling does not carry any extra cost beyond memory for completed requests, so it's fine to run it continuously. +==== + +[[example-2]] +.Plan Details +==== +Getting the plan for a statement that you ran when the profile was set to `timings` returns results similar to the following. + +[source,json] +---- +[ + { + // ... + "plan": { + "#operator": "Authorize", + "#stats": { + "#phaseSwitches": 4, + "execTime": "1.725µs", + "servTime": "21.312µs" + }, + "privileges": { + "List": [ + { + "Priv": 7, + "Props": 0, + "Target": "default:travel-sample.inventory.route" + } + ] + }, + "~child": { + "#operator": "Sequence", + "#stats": { + "#phaseSwitches": 2, + "execTime": "1.499µs" + }, + "~children": [ + { + "#operator": "PrimaryScan3", + "#stats": { + "#heartbeatYields": 6, + "#itemsOut": 24024, + "#phaseSwitches": 96099, + "execTime": "84.366121ms", + "kernTime": "3.021901421s", + "servTime": "69.320752ms" + }, + "bucket": "travel-sample", + "index": "def_inventory_route_primary", + "index_projection": { + "primary_key": true + }, + "keyspace": "route", + "namespace": "default", + "scope": "inventory", + "using": "gsi" + }, + { + "#operator": "Fetch", + "#stats": { + "#heartbeatYields": 7258, + "#itemsIn": 24024, + "#itemsOut": 24024, + "#phaseSwitches": 99104, + "execTime": "70.34694ms", + "kernTime": "142.630196ms", + "servTime": "3.021959695s" + }, + "bucket": "travel-sample", + "keyspace": "route", + "namespace": "default", + "scope": "inventory" + }, + { + "#operator": "InitialProject", + "#stats": { + "#itemsIn": 24024, + "#itemsOut": 24024, + "#phaseSwitches": 96100, + "execTime": "15.331951ms", + "kernTime": "3.219612458s" + }, + "result_terms": [ + { + "expr": "self", + "star": true + } + ] + }, + { + "#operator": "Order", + "#stats": { + "#itemsIn": 24024, + "#itemsOut": 24024, + "#phaseSwitches": 72078, + "execTime": "147.889352ms", + "kernTime": "3.229055752s" + }, + "sort_terms": [ + { + "expr": "(`route`.`sourceairport`)" + } + ] + }, + { + "#operator": "Stream", + "#stats": { + "#itemsIn": 24024, + "#itemsOut": 24024, + "#phaseSwitches": 24025, + "execTime": "11.851634134s" + } + } + ] + }, + "~versions": [ + "7.0.0-N1QL", + "7.0.0-4960-enterprise" + ] + } + } +] +---- +==== + +For field names and meanings, see <>. + +== Query Profiling Summary + +The following table summarizes Query profiling behavior. + +[%header,cols=7*] +|=== +s| Profile is ... +3+s| Query returns ... +3+s| Catalog includes ... + +s| {blank} +s| Query + +workbench +s| +cbq +s| +ifdef::flag-devex-rest-api[REST API] +s| Active + +Requests +s| Completed + +Requests +s| Prepared + +Statements + +| `off` +a| — +a| — +a| ifdef::flag-devex-rest-api[—] +a| icon:check[fw] phases +a| icon:check[fw] phases +a| icon:check[fw] timings + +| `phases` +a| — +a| icon:check[fw] phases +a| +ifdef::flag-devex-rest-api[] +icon:check[fw] phases +endif::flag-devex-rest-api[] +a| icon:check[fw] phases +a| icon:check[fw] phases +a| icon:check[fw] timings + +| `timings` +a| — +a| [%hardbreaks] +icon:check[fw] phases +icon:check[fw] timings +a| [%hardbreaks] +ifdef::flag-devex-rest-api[] +icon:check[fw] phases +icon:check[fw] timings +endif::flag-devex-rest-api[] +a| [%hardbreaks] +icon:check[fw] phases +icon:check[fw] timings +a| [%hardbreaks] +icon:check[fw] phases +icon:check[fw] timings +a| icon:check[fw] timings +|=== + +== Related Links + +* Refer to xref:n1ql:n1ql-intro/sysinfo.adoc[Getting System Information] for more information on the system namespace. diff --git a/modules/n1ql/pages/n1ql-manage/query-settings.adoc b/modules/n1ql/pages/n1ql-manage/query-settings.adoc new file mode 100644 index 000000000..6d9a9b5c8 --- /dev/null +++ b/modules/n1ql/pages/n1ql-manage/query-settings.adoc @@ -0,0 +1,410 @@ += Configure Queries +:description: You can configure the Query service using request-level query parameters. +:page-partial: +:alt-markdown-links: + +// External cross-references +:rest-cluster-query-settings: xref:rest-api:rest-cluster-query-settings.adoc +:general-settings-query-settings: xref:manage:manage-settings/general-settings.adoc#query-settings +:couchbase-cli-setting-query: xref:cli:cbcli/couchbase-cli-setting-query.adoc +:n1ql-rest-api-admin: xref:n1ql-rest-admin:index.adoc +:n1ql-rest-api-index: xref:n1ql-rest-query:index.adoc +:cbq-shell: xref:n1ql:n1ql-intro/cbq.adoc +:rest-intro: xref:rest-api:rest-intro.adoc +:query-settings: xref:clusters:query-service/query-workbench.adoc#query-settings + +// Pass through HTML table styles for this page + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +// TODO: Removed all service-level settings for now. +// Add them back in as they become available, through the Management API or other methods. + +[#section_nnj_sjk_k1b] +== Request-Level Parameters + +To set a request-level parameter, do one of the following: + +* Use the {query-settings}[Query Options] window in the Query tab. +* Use the {cbq-shell}[cbq] shell at the command line. +ifdef::flag-devex-rest-api[] +* Make a REST API call to the {n1ql-rest-api-index}[] (`/query/service` endpoint). +endif::flag-devex-rest-api[] +* Use an SDK client program. + +Generally, use the `cbq` shell or the Query tab as a sandbox to test queries in your Capella cluster. +Use +ifdef::flag-devex-rest-api[] +a REST API call or +endif::flag-devex-rest-api[] +an SDK client program for your production queries. + +[tabs] +==== +Capella UI:: ++ +-- +To set request-level preferences in the Query tab: + +. Go to menu:Data Tools[Query] and click btn:[Query Options] to display the Query Options window. + +. Specify the preferences -- if a preference is not explicitly listed, click btn:[+] next to *Named Parameters* and add its name and value. + +. Click btn:[Save]. + +image::clusters:query-workbench-settings.png["The Query Options window.",334,284] + +For more examples, see the xref:guides:transactions.adoc#settings[Couchbase Transactions] guide. +-- + +Command Line:: ++ +-- +To set request-level parameters in `cbq`, use the `\SET` command. +The parameter name must be prefixed by a hyphen. + +''' + +The following example sets the request-level timeout, pretty-print, and max parallelism parameters, and runs a query: + +[source,sqlpp] +---- +\SET -timeout "30m"; +\SET -pretty true; +\SET -max_parallelism 3; +SELECT * FROM "world" AS hello; +---- + +For more examples, see {cbq-shell}#cbq-parameter-manipulation[Parameter Manipulation] in the cbq documentation. +-- + +ifdef::flag-devex-rest-api[] +REST API:: ++ +-- +To set request-level parameters with the REST API, specify the parameters in the request body or the query URI. + +''' + +The following example sets the request-level timeout, pretty-print, and max parallelism parameters, and runs a query: + +[source,sh] +---- +curl http://localhost:8093/query/service -u Administrator:password \ + -d 'statement=SELECT * FROM "world" AS hello; + & timeout=30m + & pretty=true + & max_parallelism=3' +---- + +For more examples, see the xref:n1ql:n1ql-rest-api/examplesrest.adoc[Query Service REST API examples]. +-- +endif::flag-devex-rest-api[] +==== + +The table below contains details of all request-level parameters, along with examples. + +.Request-Level Parameters +include::n1ql-rest-query:index.adoc[tag=Request] + +[discrete#transactional-scan-consistency] +===== Transactional Scan Consistency + +If the request contains a `BEGIN TRANSACTION` statement, or a DML statement with the <> parameter set to `true`, then the <> parameter sets the [def]__transactional scan consistency__. +If you specify a transactional scan consistency of `request_plus`, `statement_plus`, or `at_plus`, or if you specify no transactional scan consistency, the transactional scan consistency is set to `request_plus`; otherwise, the transactional scan consistency is set as specified. + +.Transactional scan consistency +[%header, cols="2"] +|=== +| Scan consistency at start of transaction +| Transactional scan consistency + +| Not set +| `request_plus` + +| `not_bounded` +| `not_bounded` + +| `request_plus` + + `statement_plus` + + `at_plus` +| `request_plus` +|=== + +Any DML statements within the transaction that have no scan consistency set will inherit from the transactional scan consistency. +Individual DML statements within the transaction may override the transactional scan consistency. +If you specify a scan consistency of `not_bounded` for a statement within the transaction, the scan consistency for the statement is set as specified. +When you specify a scan consistency of `request_plus`, `statement_plus`, or `at_plus` for a statement within the transaction, the scan consistency for the statement is set to `request_plus`. + +However, `request_plus` consistency is not supported for statements using a full-text index. +If any statement within the transaction uses a full-text index, by means of the SEARCH function or the Flex Index feature, the scan consistency is set to `not_bounded` for the duration of the full-text search. + +.Overriding the transactional scan consistency +[%header, cols="2"] +|=== +| Scan consistency for statement within transaction +| Inherited scan consistency + +| Not set +| Transactional scan consistency + + (`not_bounded` for full-text search) + +| `not_bounded` +| `not_bounded` + +| `request_plus` + + `statement_plus` + + `at_plus` +| `request_plus` + + (`not_bounded` for full-text search) +|=== + +[#section_srh_tlm_n1b] +== Named Parameters and Positional Parameters + +You can add placeholder parameters to a statement, so that you can safely supply variable values when you run the statement. +A placeholder parameter may be a named parameter or a positional parameter. + +* To add a named parameter to a query, enter a dollar sign `$` or an at sign `@` followed by the parameter name. + +* To add a positional parameter to a query, enter a dollar sign `$` or an at sign `@` followed by the number of the parameter, or enter a question mark `?`. + +To run a query containing placeholder parameters, you must supply values for the parameters. + +* You can use an <> request-level parameter to supply the value for a named parameter. +The name of this property is a dollar sign `$` or an at sign `@` followed by the parameter name. + +* The <> request-level parameter enables you to supply a list of values for positional parameters. + +You can supply the values for placeholder parameters using any of the methods used to specify <>. + +**** +[.status]#Couchbase Server 7.6# + +The at sign `@` syntax is only supported in clusters running Couchbase Server 7.6.0 or later. +The dollar sign `$` syntax is supported in all versions of Couchbase Server. +**** + +=== Examples + +include::ROOT:partial$query-context.adoc[tag=section] + +.{example-caption} {counter:example}. Named Parameters +{blank} + +[tabs] +==== +Capella UI:: ++ +-- +// tag::intro-names[] +The following query uses named parameter placeholders. +// end::intro-names[] +The parameter values are supplied using the Query Options window. + +[caption=] +.Named Parameters +[cols="1s,2,1s,2"] +|=== +| name +| `$country` +| value +| `"France"` + +| name +| `$altitude` +| value +| `500` +|=== + +[source,sqlpp] +---- +include::example$settings/param-names.n1ql[tags=statement] +---- + +// tag::note-names[] +The named parameters and named parameter placeholders in this example use a mixture of `@` and `$` symbol prefixes. +In clusters running Couchbase Server 7.6.0 and later, you can use either of these symbols as preferred. +In previous versions of Couchbase Server, you must use the `$` symbol prefix. +// end::note-names[] +-- + +Command Line:: ++ +-- +include::query-settings.adoc[tag=intro-names] +The parameter values are supplied using the cbq shell. + +[source,sqlpp] +---- +include::example$settings/param-names.n1ql[tags=**] +---- + +include::query-settings.adoc[tag=note-names] +-- +==== + +.{example-caption} {counter:example}. Numbered Positional Parameters +{blank} + +[tabs] +==== +Capella UI:: ++ +-- +// tag::intro-numbers[] +The following query uses numbered positional parameter placeholders. +// end::intro-numbers[] +The parameter values are supplied using the Query Options window. + +[caption=] +.Positional Parameters +[cols="1s,5"] +|=== +| $1 | `"France"` +| $2 | `500` +|=== + +[source,sqlpp] +---- +include::example$settings/param-numbers.n1ql[tags=statement] +---- + +// tag::note-numbers[] +In this case, the first positional parameter value is used for the placeholder numbered `$1`, the second positional parameter value is used for the placeholder numbered `@2`, and so on. + +The numbered positional parameter placeholders in this example use a mixture of `@` and `$` symbol prefixes. +In clusters running Couchbase Server 7.6.0 and later, you can use either of these symbols as preferred. +In previous versions of Couchbase Server, you must use the `$` symbol prefix. +// end::note-numbers[] +-- + +Command Line:: ++ +-- +include::query-settings.adoc[tag=intro-numbers] +The parameter values are supplied using the cbq shell. + +[source,sqlpp] +---- +include::example$settings/param-numbers.n1ql[tag=**] +---- + +include::query-settings.adoc[tag=note-numbers] +-- +==== + +.{example-caption} {counter:example}. Unnumbered Positional Parameters +{blank} + +[tabs] +==== +Capella UI:: ++ +-- +// tag::intro-positions[] +The following query uses unnumbered positional parameter placeholders. +// end::intro-positions[] +The parameter values are supplied using the Query Options window. + +[caption=] +.Positional Parameters +[cols="1s,5"] +|=== +| $1 | `"France"` +| $2 | `500` +|=== + +[source,sqlpp] +---- +include::example$settings/param-positions.n1ql[tags=statement] +---- + +// tag::note-positions[] +In this case, the first positional parameter value is used for the first `?` placeholder, the second positional parameter value is used for the second `?` placeholder, and so on. +// end::note-positions[] +-- + +Command Line:: ++ +-- +include::query-settings.adoc[tag=intro-positions] +The parameter values are supplied using the cbq shell. + +[source.no-callouts,sqlpp] +---- +include::example$settings/param-positions.n1ql[tag=**] +---- + +include::query-settings.adoc[tag=note-positions] +-- +==== + +For more details and examples, including examples using SDKs, see the xref:guides:prep-statements.adoc[] guide. + +ifdef::flag-devex-rest-api[] +== Related Links + +* For more details about the {sqlpp} REST API, refer to {n1ql-rest-api-index}[]. +* For more details about the Admin REST API, refer to {n1ql-rest-api-admin}[]. +* For more details about the Query Settings API, refer to {rest-cluster-query-settings}[]. +* For more details about API content and settings, refer to {rest-intro}[]. +endif::flag-devex-rest-api[] diff --git a/modules/n1ql/pages/query.adoc b/modules/n1ql/pages/query.adoc new file mode 100644 index 000000000..f2d172439 --- /dev/null +++ b/modules/n1ql/pages/query.adoc @@ -0,0 +1,80 @@ += Query Data with {sqlpp} +:page-aliases: n1ql:index,n1ql:n1ql-intro/data-access-using-n1ql,clusters:query-service/query-service.adoc +:page-role: tiles -toc +:imagesdir: ../assets/images +:!sectids: +:keywords: SQL++, N1QL, Query +:description: The Query Service supports the querying of data by means of the {sqlpp} query language. + +// Pass through HTML styles for this page. + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] + +[abstract] +{description} + +include::ROOT:partial$component-signpost.adoc[] + +As its primary function, the Query service enables you to issue queries to extract data from Couchbase Capella. +You can also issue queries for data definition (defining indexes) and data manipulation (adding or deleting data). +The Query Service needs both the Index Service and the Data Service to be running on Couchbase Capella. + +You can run queries from the Query tab in the Couchbase Capella UI, the cbq shell, +ifdef::flag-devex-rest-api[] +the REST API, +endif::flag-devex-rest-api[] +or the Couchbase SDKs. + +== When to Use Queries + +Use the Query service for query analysis and execution to help you build applications. + +Use the Analytics service for online analytical processing (OLAP) -- large datasets with complex analytical or ad hoc queries. + +Use the Search service for full-text search with natural language processing across multiple data types and languages -- custom text analysis, Geospatial search, and more. + +== {sqlpp} for Query + +To create queries, you must use a query language that is structured so that the Query Service understands what it needs to retrieve. +Couchbase Capella uses a query language called {sqlpp}. +The Couchbase implementation of {sqlpp} was formerly known as https://www.couchbase.com/products/n1ql[N1QL^] (pronounced "nickel"). + +{sqlpp} is an expressive, powerful, and complete SQL dialect for querying, transforming, and manipulating JSON data. +Based on SQL, it's immediately familiar to developers who can quickly start developing rich applications. + +== How-To Guides + +* xref:n1ql:n1ql-intro/index.adoc[] +* xref:guides:query.adoc[] +* xref:guides:indexes.adoc[] +* xref:guides:manipulate.adoc[] +ifdef::flag-devex-javascript-udfs[] +* xref:guides:javascript-udfs.adoc[] +endif::flag-devex-javascript-udfs[] +* xref:n1ql:advanced.adoc[] + +== Query Administration + +* xref:n1ql:n1ql-manage/index.adoc[] + +== Query References + +* xref:n1ql:n1ql-language-reference/index.adoc[] +* xref:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[] +ifdef::flag-devex-javascript-udfs[] +* xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] +endif::flag-devex-javascript-udfs[] + +== Related Links + +* xref:server:learn:services-and-indexes/services/query-service.adoc[Query Service architecture] +* xref:server:learn:data/data.adoc[] diff --git a/modules/n1ql/partials/grammar/dcl.ebnf b/modules/n1ql/partials/grammar/dcl.ebnf new file mode 100644 index 000000000..c98dbee46 --- /dev/null +++ b/modules/n1ql/partials/grammar/dcl.ebnf @@ -0,0 +1,17 @@ +/* Data Control Language */ + +dcl-statement ::= grant + | revoke + +/* tag::grant[] */ +grant ::= 'GRANT' role ( ',' role )* ( 'ON' keyspace-ref ( ',' keyspace-ref )* )? + 'TO' user ( ',' user )* +/* end::grant[] */ + +/* tag::revoke[] */ +revoke ::= 'REVOKE' role ( ',' role )* ( 'ON' keyspace-ref ( ',' keyspace-ref )* )? + 'FROM' user ( ',' user )* +/* end::revoke[] */ + +role ::= identifier +user ::= identifier \ No newline at end of file diff --git a/modules/n1ql/partials/grammar/ddl.ebnf b/modules/n1ql/partials/grammar/ddl.ebnf new file mode 100644 index 000000000..827efc4b9 --- /dev/null +++ b/modules/n1ql/partials/grammar/ddl.ebnf @@ -0,0 +1,290 @@ +/* Data Definition Language */ + +ddl-statement ::= create-statement + | drop-statement + | other-statement + +create-statement ::= create-scope + | create-collection + | create-primary-index + | create-index + | create-function + | create-sequence + +drop-statement ::= drop-scope + | drop-collection + | drop-primary-index + | drop-index + | drop-function + | drop-sequence + +other-statement ::= alter-index + | alter-sequence + | build-index + | execute-function + + +/************************** + * Scopes and Collections * + **************************/ + +/* tag::create-scope[] */ +create-scope ::= 'CREATE' 'SCOPE' ( namespace ':' )? bucket '.' scope ( 'IF' 'NOT' 'EXISTS' )? +/* end::create-scope[] */ + +/* tag::create-collection[] */ +create-collection ::= 'CREATE' 'COLLECTION' ( ( namespace ':' )? bucket '.' scope '.' )? + collection ( 'IF' 'NOT' 'EXISTS' )? ( 'WITH' expr )? +/* end::create-collection[] */ + +/* tag::drop-scope[] */ +drop-scope ::= 'DROP' 'SCOPE' ( namespace ':' )? bucket '.' scope ( 'IF' 'EXISTS' )? +/* end::drop-scope[] */ + +/* tag::drop-collection[] */ +drop-collection ::= 'DROP' 'COLLECTION' ( ( namespace ':' )? bucket '.' scope '.' )? + collection ( 'IF' 'EXISTS' )? +/* end::drop-collection[] */ + + +/*********** + * Indexes * + ***********/ + +/* tag::create-primary-index[] */ +create-primary-index ::= 'CREATE' 'PRIMARY' 'INDEX' index-name? ( 'IF' 'NOT' 'EXISTS' )? + 'ON' keyspace-ref index-using? index-with? +/* end::create-primary-index[] */ + +/* tag::index-using[] */ +index-using ::= 'USING' 'GSI' +/* end::index-using[] */ + +/* tag::index-with[] */ +index-with ::= 'WITH' expr +/* end::index-with[] */ + +/* tag::create-index[] */ +create-index ::= 'CREATE' 'INDEX' index-name ( 'IF' 'NOT' 'EXISTS' )? 'ON' keyspace-ref + '(' index-key lead-key-attribs? ( ( ',' index-key key-attribs? )+ )? ')' + index-partition? where-clause? index-using? index-with? +/* end::create-index[] */ + +/* tag::index-key[] */ +index-key ::= expr | array-expr +/* end::index-key[] */ + +/* tag::lead-key-attribs[] */ +lead-key-attribs ::= index-order include-missing? | include-missing index-order? +/* end::lead-key-attribs[] */ + +/* tag::key-attribs[] */ +key-attribs ::= index-order +/* end::key-attribs[] */ + +/* tag::include-missing[] */ +include-missing ::= 'INCLUDE' 'MISSING' +/* end::include-missing[] */ + +/* tag::index-order[] */ +index-order ::= 'ASC' | 'DESC' +/* end::index-order[] */ + +/* tag::array-expr[] */ +array-expr ::= full-array-expr | simple-array-expr +/* end::array-expr[] */ + +/* tag::full-array-expr[] */ +full-array-expr ::= ( 'ALL' | 'DISTINCT' ) 'ARRAY' var-expr + 'FOR' var ( 'IN' | 'WITHIN' ) expr + ( ',' var ( 'IN' | 'WITHIN' ) expr )* ( 'WHEN' cond )? 'END' +/* end::full-array-expr[] */ + +/* tag::simple-array-expr[] */ +simple-array-expr ::= ( 'ALL' | 'DISTINCT' ) expr +/* end::simple-array-expr[] */ + +/* tag::pairs-function[] */ +pairs-function ::= 'PAIRS' '(' ( 'SELF' | index-key-object ) ')' +/* end::pairs-function[] */ + +/* tag::index-key-object[] */ +index-key-object ::= expr +/* end::index-key-object[] */ + +/* tag::index-partition[] */ +index-partition ::= 'PARTITION' 'BY' 'HASH' '(' partition-key-expr + ( ',' partition-key-expr )* ')' +/* end::index-partition[] */ + +/* tag::partition-key-expr[] */ +partition-key-expr ::= expr +/* end::partition-key-expr[] */ + +/* tag::alter-index[] */ +alter-index ::= 'ALTER' 'INDEX' ( index-path '.' index-name | index-name 'ON' keyspace-ref ) + index-using? index-with +/* end::alter-index[] */ + +/* tag::build-index[] */ +build-index ::= 'BUILD' 'INDEX' 'ON' keyspace-ref '(' index-term (',' index-term)* ')' + index-using? +/* end::build-index[] */ + +/* tag::index-term[] */ +index-term ::= index-name | index-expr | subquery-expr +/* end::index-term[] */ + +/* tag::index-expr[] */ +index-expr ::= string | array +/* end::index-expr[] */ + +/* tag::drop-primary-index[] */ +drop-primary-index ::= 'DROP' 'PRIMARY' 'INDEX' ( 'IF' 'EXISTS' )? 'ON' keyspace-ref + index-using? +/* end::drop-primary-index[] */ + +/* tag::drop-index[] */ +drop-index ::= 'DROP' 'INDEX' ( index-path '.' index-name ( 'IF' 'EXISTS' )? | + index-name ( 'IF' 'EXISTS' )? 'ON' keyspace-ref ) index-using? +/* end::drop-index[] */ + +/* tag::index-path[] */ +index-path ::= keyspace-full | keyspace-prefix | keyspace-partial +/* end::index-path[] */ + +/* tag::keyspace-full[] */ +keyspace-full ::= namespace ':' bucket '.' scope '.' collection +/* end::keyspace-full[] */ + +/* tag::keyspace-prefix[] */ +keyspace-prefix ::= ( namespace ':' )? bucket +/* end::keyspace-prefix[] */ + + +/************* + * Functions * + *************/ + +/* tag::create-function[] */ +create-function ::= create-function-inline | create-function-external +/* end::create-function[] */ + +/* tag::create-function-inline[] */ +create-function-inline ::= 'CREATE' ( 'OR' 'REPLACE' )? 'FUNCTION' function '(' params? ')' + ( 'IF' 'NOT' 'EXISTS' )? + ( '{' body '}' | 'LANGUAGE' 'INLINE' 'AS' body ) +/* end::create-function-inline[] */ + +/* tag::create-function-external[] */ +create-function-external ::= 'CREATE' ( 'OR' 'REPLACE' )? 'FUNCTION' function '(' params? ')' + ( 'IF' 'NOT' 'EXISTS' )? + 'LANGUAGE' 'JAVASCRIPT' 'AS' ( obj 'AT' library | javascript ) +/* end::create-function-external[] */ + +/* tag::function[] */ +function ::= ( namespace ':' ( bucket '.' scope '.' )? )? identifier +/* end::function[] */ + +/* tag::params[] */ +params ::= identifier ( "," identifier )* | "..." +/* end::params[] */ + +/* tag::body[] */ +body ::= expr +/* end::body[] */ + +/* tag::obj[] */ +obj ::= string +/* end::obj[] */ + +/* tag::library[] */ +library ::= string +/* end::library[] */ + +/* tag::javascript[] */ +javascript ::= string +/* end::javascript[] */ + +/* tag::drop-function[] */ +drop-function ::= 'DROP' 'FUNCTION' function ( 'IF' 'EXISTS' )? +/* end::drop-function[] */ + +/* tag::execute-function[] */ +execute-function ::= 'EXECUTE' 'FUNCTION' function '(' ( expr ( ',' expr )* )? ')' +/* end::execute-function[] */ + + +/************* + * Sequences * + *************/ + +/* tag::create-sequence[] */ +create-sequence ::= 'CREATE' 'SEQUENCE' ( sequence ( 'IF' 'NOT' 'EXISTS' )? | + ( 'IF' 'NOT' 'EXISTS' )? sequence ) + ( create-sequence-options | sequence-with )? +/* end::create-sequence[] */ + +/* tag::sequence[] */ +sequence ::= ( ( namespace ':' )? bucket '.' scope '.' )? identifier +/* end::sequence[] */ + +/* tag::create-sequence-options[] */ +create-sequence-options ::= ( start-with + | increment-by + | maxvalue + | minvalue + | cycle + | cache )* +/* end::create-sequence-options[] */ + +/* tag::start-with[] */ +start-with ::= 'START' 'WITH' integer +/* end::start-with[] */ + +/* tag::increment-by[] */ +increment-by ::= 'INCREMENT' 'BY' integer +/* end::increment-by[] */ + +/* tag::maxvalue[] */ +maxvalue ::= 'MAXVALUE' integer | 'NO' 'MAXVALUE' +/* end::maxvalue[] */ + +/* tag::minvalue[] */ +minvalue ::= 'MINVALUE' integer | 'NO' 'MINVALUE' +/* end::minvalue[] */ + +/* tag::cycle[] */ +cycle ::= 'CYCLE' | 'NO' 'CYCLE' +/* end::cycle[] */ + +/* tag::cache[] */ +cache ::= 'CACHE' integer | 'NO' 'CACHE' +/* end::cache[] */ + +/* tag::sequence-with[] */ +sequence-with ::= 'WITH' expr +/* end::sequence-with[] */ + +/* tag::drop-sequence[] */ +drop-sequence ::= 'DROP' 'SEQUENCE' ( sequence ( 'IF' 'EXISTS' )? | + ( 'IF' 'EXISTS' )? sequence ) +/* end::drop-sequence[] */ + +/* tag::alter-sequence[] */ +alter-sequence ::= 'ALTER' 'SEQUENCE' sequence + ( alter-sequence-options | sequence-with )? +/* end::alter-sequence[] */ + +/* tag::alter-sequence-options[] */ +alter-sequence-options ::= ( restart-with + | increment-by + | maxvalue + | minvalue + | cycle + | cache )* +/* end::alter-sequence-options[] */ + +/* tag::restart-with[] */ +restart-with ::= 'RESTART' ( 'WITH' integer )? +/* end::restart-with[] */ diff --git a/modules/n1ql/partials/grammar/dml.ebnf b/modules/n1ql/partials/grammar/dml.ebnf new file mode 100644 index 000000000..423ee2a61 --- /dev/null +++ b/modules/n1ql/partials/grammar/dml.ebnf @@ -0,0 +1,163 @@ +/* Data Manipulation Language */ + +dml-statement ::= delete + | insert + | merge + | update + | upsert + +/******************** + * Delete Statement * + ********************/ + +/* tag::delete[] */ +delete ::= 'DELETE' 'FROM' target-keyspace use-keys-clause? where-clause? + limit-clause? offset-clause? returning-clause? +/* end::delete[] */ + +/******************** + * Insert Statement * + ********************/ + +/* tag::insert[] */ +insert ::= 'INSERT' 'INTO' target-keyspace ( insert-values | insert-select ) + returning-clause? +/* end::insert[] */ + +/* tag::insert-values[] */ +insert-values ::= ( '(' 'PRIMARY'? 'KEY' ',' 'VALUE' ( ',' 'OPTIONS' )? ')' )? values-clause +/* end::insert-values[] */ + +/* tag::values-clause[] */ +values-clause ::= 'VALUES' '(' key ',' value ( ',' options )? ')' + ( ',' 'VALUES'? '(' key ',' value ( ',' options )? ')' )* +/* end::values-clause[] */ + +/* tag::insert-select[] */ +insert-select ::= '(' 'PRIMARY'? 'KEY' key ( ',' 'VALUE' value )? + ( ',' 'OPTIONS' options )? ')' select +/* end::insert-select[] */ + +/******************* + * Merge Statement * + *******************/ + +/* tag::merge[] */ +merge ::= 'MERGE' 'INTO' ( ansi-merge | lookup-merge ) limit-clause? returning-clause? +/* end::merge[] */ + +/* tag::ansi-merge[] */ +ansi-merge ::= target-keyspace use-index-clause 'USING' ansi-merge-source + ansi-merge-predicate ansi-merge-actions +/* end::ansi-merge[] */ + +/* tag::ansi-merge-source[] */ +ansi-merge-source ::= ( merge-source-keyspace | merge-source-subquery | merge-source-expr ) + ansi-join-hints? +/* end::ansi-merge-source[] */ + +/* tag::ansi-merge-predicate[] */ +ansi-merge-predicate ::= 'ON' expr +/* end::ansi-merge-predicate[] */ + +/* tag::ansi-merge-actions[] */ +ansi-merge-actions ::= merge-update? merge-delete? ansi-merge-insert? +/* end::ansi-merge-actions[] */ + +/* tag::ansi-merge-insert[] */ +ansi-merge-insert ::= 'WHEN' 'NOT' 'MATCHED' 'THEN' 'INSERT' '(' 'KEY'? key + ( ',' 'VALUE'? value )? ( ',' 'OPTIONS'? options )? ')' where-clause? +/* end::ansi-merge-insert[] */ + +/* tag::lookup-merge[] */ +lookup-merge ::= target-keyspace 'USING' lookup-merge-source lookup-merge-predicate + lookup-merge-actions +/* end::lookup-merge[] */ + +/* tag::lookup-merge-source[] */ +lookup-merge-source ::= merge-source-keyspace use-clause? | + merge-source-subquery | + merge-source-expr +/* end::lookup-merge-source[] */ + +/* tag::lookup-merge-predicate[] */ +lookup-merge-predicate ::= 'ON' 'PRIMARY'? 'KEY' expr +/* end::lookup-merge-predicate[] */ + +/* tag::lookup-merge-actions[] */ +lookup-merge-actions ::= merge-update? merge-delete? lookup-merge-insert? +/* end::lookup-merge-actions[] */ + +/* tag::lookup-merge-insert[] */ +lookup-merge-insert ::= 'WHEN' 'NOT' 'MATCHED' 'THEN' 'INSERT' expr where-clause? +/* end::lookup-merge-insert[] */ + +/* tag::merge-source-keyspace[] */ +merge-source-keyspace ::= keyspace-ref ( 'AS'? alias )? +/* end::merge-source-keyspace[] */ + +/* tag::merge-source-subquery[] */ +merge-source-subquery ::= subquery-expr 'AS'? alias +/* end::merge-source-subquery[] */ + +/* tag::merge-source-expr[] */ +merge-source-expr ::= expr ( 'AS'? alias )? +/* end::merge-source-expr[] */ + +/* tag::merge-update[] */ +merge-update ::= 'WHEN' 'MATCHED' 'THEN' 'UPDATE' set-clause? unset-clause? where-clause? +/* end::merge-update[] */ + +/* tag::merge-delete[] */ +merge-delete ::= 'WHEN' 'MATCHED' 'THEN' 'DELETE' where-clause? +/* end::merge-delete[] */ + +/******************** + * Update Statement * + ********************/ + +/* tag::update[] */ +update ::= 'UPDATE' target-keyspace use-keys? set-clause? unset-clause? + where-clause? limit-clause? returning-clause? +/* end::update[] */ + +/******************** + * Upsert Statement * + ********************/ + +/* tag::upsert[] */ +upsert ::= 'UPSERT' 'INTO' target-keyspace ( insert-values | insert-select ) + returning-clause? +/* end::upsert[] */ + +/****************** + * Common Clauses * + ******************/ + +/* tag::target-keyspace[] */ +target-keyspace ::= keyspace-ref ( 'AS'? alias )? +/* end::target-keyspace[] */ + +/* tag::returning-clause[] */ +returning-clause ::= 'RETURNING' (result-expr (',' result-expr)* | + ('RAW' | 'ELEMENT' | 'VALUE') expr) +/* end::returning-clause[] */ + +/* tag::set-clause[] */ +set-clause ::= 'SET' ( meta '=' expiration | path '=' expr update-for? ) + ( ',' ( meta '=' expiration | path '=' expr update-for? ) )* +/* end::set-clause[] */ + +/* tag::unset-clause[] */ +unset-clause ::= 'UNSET' path update-for? (',' path update-for?)* +/* end::unset-clause[] */ + +/* tag::update-for[] */ +update-for ::= ('FOR' (name-var ':')? var ('IN' | 'WITHIN') path + (',' (name-var ':')? var ('IN' | 'WITHIN') path)* )+ + ('WHEN' cond)? 'END' +/* end::update-for[] */ + +key ::= expr +value ::= expr +options ::= object \ No newline at end of file diff --git a/modules/n1ql/partials/grammar/dql.ebnf b/modules/n1ql/partials/grammar/dql.ebnf new file mode 100644 index 000000000..08b80d85d --- /dev/null +++ b/modules/n1ql/partials/grammar/dql.ebnf @@ -0,0 +1,492 @@ +/* Data Query Language */ + +dql-statement ::= select | + infer | + update-statistics + +/*************** + * N1QL SELECT * + ***************/ + +/* tag::select[] */ +select ::= select-term ( set-op select-term )* order-by-clause? limit-clause? offset-clause? +/* end::select[] */ + +/* tag::select-term[] */ +select-term ::= subselect | '(' select ')' +/* end::select-term[] */ + +/* tag::subselect[] */ +subselect ::= select-from | from-select +/* end::subselect[] */ + +/* tag::select-from[] */ +select-from ::= with-clause? select-clause from-clause? let-clause? where-clause? group-by-clause? window-clause? +/* end::select-from[] */ + +/* tag::from-select[] */ +from-select ::= with-clause? from-clause let-clause? where-clause? group-by-clause? window-clause? select-clause +/* end::from-select[] */ + +/* tag::set-op[] */ +set-op ::= ( 'UNION' | 'INTERSECT' | 'EXCEPT' ) 'ALL'? +/* end::set-op[] */ + + +/* WITH Clause */ + +/* tag::with-clause[] */ +with-clause ::= 'WITH' alias 'AS' '(' ( select | expr ) ')' + ( ',' alias 'AS' '(' ( select | expr ) ')' )* +/* end::with-clause[] */ + +/* tag::alias[] */ +alias ::= identifier +/* end::alias[] */ + + +/* WITH RECURSIVE Clause */ + +/* tag::with-recursive-clause[] */ +with-recursive-clause ::= 'WITH' 'RECURSIVE' alias 'AS' '(' ( recursive-select | select | expr ) ')' cycle-clause? options-clause? + ( ',' alias 'AS' '(' ( recursive-select | select | expr ) ')' cycle-clause? options-clause? )* +/* end::with-recursive-clause[] */ + +/* tag::recursive-select[] */ +recursive-select ::= anchor-select ('UNION' | 'UNION ALL') recursive-select-term +/* end::recursive-select[] */ + +/* tag::cycle-clause[] */ +cycle-clause ::= 'CYCLE' expr ( ',' expr )* 'RESTRICT' +/* end::cycle-clause[] */ + +/* tag::options-clause[] */ +options-clause ::= 'OPTIONS' expr +/* end::options-clause[] */ + +/* tag::anchor-select[] */ +anchor-select ::= select +/* end::anchor-select[] */ + +/* tag::recursive-select-term[] */ +recursive-select-term ::= select-term +/* end::recursive-select-term[] */ +/* SELECT Clause */ + +/* tag::select-clause[] */ +select-clause ::= 'SELECT' hint-comment? projection +/* end::select-clause[] */ + +hint-comment ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/hints.ebnf] + +/* tag::projection[] */ +projection ::= ( 'ALL' | 'DISTINCT' )? ( result-expr ( ',' result-expr )* | + ( 'RAW' | 'ELEMENT' | 'VALUE' ) expr ( 'AS'? alias )? ) +/* end::projection[] */ + +/* tag::result-expr[] */ +result-expr ::= ( path '.' )? '*' | expr ( 'AS'? alias )? +/* end::result-expr[] */ + +/* tag::path[] */ +path ::= identifier ( '[' expr ']' )* ( '.' identifier ( '[' expr ']' )* )* +/* end::path[] */ + + +/* FROM Clause */ + +/* tag::from-clause[] */ +from-clause ::= 'FROM' from-terms +/* end::from-clause[] */ + +/* tag::from-terms[] */ +from-terms ::= ( from-keyspace | from-subquery | from-generic ) + ( join-clause | nest-clause | unnest-clause )* comma-separated-join* +/* end::from-terms[] */ + +/* tag::from-keyspace[] */ +from-keyspace ::= keyspace-ref ( 'AS'? alias )? use-clause? +/* end::from-keyspace[] */ + +/* tag::keyspace-ref[] */ +keyspace-ref ::= keyspace-path | keyspace-partial +/* end::keyspace-ref[] */ + +/* tag::keyspace-path[] */ +keyspace-path ::= ( namespace ':' )? bucket ( '.' scope '.' collection )? +/* end::keyspace-path[] */ + +/* tag::keyspace-partial[] */ +keyspace-partial ::= collection +/* end::keyspace-partial[] */ + +/* tag::namespace[] */ +namespace ::= identifier +/* end::namespace[] */ + +/* tag::bucket[] */ +bucket ::= identifier +/* end::bucket[] */ + +/* tag::scope[] */ +scope ::= identifier +/* end::scope[] */ + +/* tag::collection[] */ +collection ::= identifier +/* end::collection[] */ + +/* tag::from-subquery[] */ +from-subquery ::= subquery-expr 'AS'? alias +/* end::from-subquery[] */ + +/* tag::subquery-expr[] */ +subquery-expr ::= '(' select ')' +/* end::subquery-expr[] */ + +/* tag::from-generic[] */ +from-generic ::= expr ( 'AS' alias )? +/* end::from-generic[] */ + + +/* JOIN Clause */ + +/* tag::join-clause[] */ +join-clause ::= ansi-join-clause | lookup-join-clause | index-join-clause +/* end::join-clause[] */ + + +/* ANSI JOIN */ + +/* tag::ansi-join-clause[] */ +ansi-join-clause ::= ansi-join-type? 'JOIN' 'LATERAL'? ansi-join-rhs ansi-join-predicate +/* end::ansi-join-clause[] */ + +/* tag::ansi-join-type[] */ +ansi-join-type ::= 'INNER' | ( 'LEFT' | 'RIGHT' ) 'OUTER'? +/* end::ansi-join-type[] */ + +/* tag::ansi-join-rhs[] */ +ansi-join-rhs ::= rhs-keyspace | rhs-subquery | rhs-generic +/* end::ansi-join-rhs[] */ + +/* tag::rhs-keyspace[] */ +rhs-keyspace ::= keyspace-ref ( 'AS'? alias )? ansi-join-hints? +/* end::rhs-keyspace[] */ + +/* tag::rhs-subquery[] */ +rhs-subquery ::= subquery-expr 'AS'? alias +/* end::rhs-subquery[] */ + +/* tag::rhs-generic[] */ +rhs-generic ::= expr ( 'AS'? alias )? +/* end::rhs-generic[] */ + +/* tag::ansi-join-hints[] */ +ansi-join-hints ::= use-hash-hint | use-nl-hint | multiple-hints +/* end::ansi-join-hints[] */ + +/* tag::use-hash-hint[] */ +use-hash-hint ::= 'USE' use-hash-term +/* end::use-hash-hint[] */ + +/* tag::use-hash-term[] */ +use-hash-term ::= 'HASH' '(' ( 'BUILD' | 'PROBE' ) ')' +/* end::use-hash-term[] */ + +/* tag::use-nl-hint[] */ +use-nl-hint ::= 'USE' use-nl-term +/* end::use-nl-hint[] */ + +/* tag::use-nl-term[] */ +use-nl-term ::= 'NL' +/* end::use-nl-term[] */ + +/* tag::multiple-hints[] */ +multiple-hints ::= 'USE' ( ansi-hint-terms other-hint-terms | + other-hint-terms ansi-hint-terms ) +/* end::multiple-hints[] */ + +/* tag::ansi-hint-terms[] */ +ansi-hint-terms ::= use-hash-term | use-nl-term +/* end::ansi-hint-terms[] */ + +/* tag::other-hint-terms[] */ +other-hint-terms ::= use-index-term | use-keys-term +/* end::other-hint-terms[] */ + +/* tag::ansi-join-predicate[] */ +ansi-join-predicate ::= 'ON' expr +/* end::ansi-join-predicate[] */ + + +/* Lookup JOIN */ + +/* tag::lookup-join-clause[] */ +lookup-join-clause ::= lookup-join-type? 'JOIN' lookup-join-rhs lookup-join-predicate +/* end::lookup-join-clause[] */ + +/* tag::lookup-join-type[] */ +lookup-join-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +/* end::lookup-join-type[] */ + +/* tag::lookup-join-rhs[] */ +lookup-join-rhs ::= keyspace-ref ( 'AS'? alias )? +/* end::lookup-join-rhs[] */ + +/* tag::lookup-join-predicate[] */ +lookup-join-predicate ::= 'ON' 'PRIMARY'? 'KEYS' expr +/* end::lookup-join-predicate[] */ + + +/* Index JOIN */ + +/* tag::index-join-clause[] */ +index-join-clause ::= index-join-type? 'JOIN' index-join-rhs index-join-predicate +/* end::index-join-clause[] */ + +/* tag::index-join-type[] */ +index-join-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +/* end::index-join-type[] */ + +/* tag::index-join-rhs[] */ +index-join-rhs ::= keyspace-ref ( 'AS'? alias )? +/* end::index-join-rhs[] */ + +/* tag::index-join-predicate[] */ +index-join-predicate ::= 'ON' 'PRIMARY'? 'KEY' expr 'FOR' alias +/* end::index-join-predicate[] */ + + +/* Comma-Separated Cartesian Join */ + +/* tag::comma-separated-join[] */ +comma-separated-join ::= ',' 'LATERAL'? ( rhs-keyspace | rhs-subquery | rhs-generic ) +/* end::comma-separated-join[] */ + + +/* NEST Clause */ + +/* tag::nest-clause[] */ +nest-clause ::= ansi-nest-clause | lookup-nest-clause | index-nest-clause +/* end::nest-clause[] */ + + +/* ANSI NEST */ + +/* tag::ansi-nest-clause[] */ +ansi-nest-clause ::= ansi-nest-type? 'NEST' 'LATERAL'? ansi-nest-rhs ansi-nest-predicate +/* end::ansi-nest-clause[] */ + +/* tag::ansi-nest-type[] */ +ansi-nest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +/* end::ansi-nest-type[] */ + +/* tag::ansi-nest-rhs[] */ +ansi-nest-rhs ::= keyspace-ref ( 'AS'? alias )? +/* end::ansi-nest-rhs[] */ + +/* tag::ansi-nest-predicate[] */ +ansi-nest-predicate ::= 'ON' expr +/* end::ansi-nest-predicate[] */ + + +/* Lookup NEST */ + +/* tag::lookup-nest-clause[] */ +lookup-nest-clause ::= lookup-nest-type? 'NEST' lookup-nest-rhs lookup-nest-predicate +/* end::lookup-nest-clause[] */ + +/* tag::lookup-nest-type[] */ +lookup-nest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +/* end::lookup-nest-type[] */ + +/* tag::lookup-nest-rhs[] */ +lookup-nest-rhs ::= keyspace-ref ( 'AS'? alias )? +/* end::lookup-nest-rhs[] */ + +/* tag::lookup-nest-predicate[] */ +lookup-nest-predicate ::= 'ON' 'KEYS' expr +/* end::lookup-nest-predicate[] */ + + +/* Index NEST */ + +/* tag::index-nest-clause[] */ +index-nest-clause ::= index-nest-type? 'NEST' index-nest-rhs index-nest-predicate +/* end::index-nest-clause[] */ + +/* tag::index-nest-type[] */ +index-nest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +/* end::index-nest-type[] */ + +/* tag::index-nest-rhs[] */ +index-nest-rhs ::= keyspace-ref ( 'AS'? alias )? +/* end::index-nest-rhs[] */ + +/* tag::index-nest-predicate[] */ +index-nest-predicate ::= 'ON' 'KEY' expr 'FOR' alias +/* end::index-nest-predicate[] */ + + +/* UNNEST Clause */ + +/* tag::unnest-clause[] */ +unnest-clause ::= unnest-type? ( 'UNNEST' | 'FLATTEN' ) expr ( 'AS'? alias )? +/* end::unnest-clause[] */ + +/* tag::unnest-type[] */ +unnest-type ::= 'INNER' | ( 'LEFT' 'OUTER'? ) +/* end::unnest-type[] */ + + +/* USE Clause */ + +/* tag::use-clause[] */ +use-clause ::= use-keys-clause | use-index-clause +/* end::use-clause[] */ + +/* tag::use-keys-clause[] */ +use-keys-clause ::= 'USE' use-keys-term +/* end::use-keys-clause[] */ + +/* tag::use-keys-term[] */ +use-keys-term ::= 'PRIMARY'? 'KEYS' expr +/* end::use-keys-term[] */ + +/* tag::use-index-clause[] */ +use-index-clause ::= 'USE' use-index-term +/* end::use-index-clause[] */ + +/* tag::use-index-term[] */ +use-index-term ::= 'INDEX' '(' index-ref ( ',' index-ref )* ')' +/* end::use-index-term[] */ + +/* tag::index-ref[] */ +index-ref ::= index-name? index-type? +/* end::index-ref[] */ + +/* tag::index-name[] */ +index-name ::= identifier +/* end::index-name[] */ + +/* tag::index-type[] */ +index-type ::= 'USING' ( 'GSI' | 'FTS' ) +/* end::index-type[] */ + + +/* LET Clause */ + +/* tag::let-clause[] */ +let-clause ::= 'LET' alias '=' expr ( ',' alias '=' expr )* +/* end::let-clause[] */ + + +/* WHERE Clause */ + +/* tag::where-clause[] */ +where-clause ::= 'WHERE' cond +/* end::where-clause[] */ + +/* tag::cond[] */ +cond ::= expr +/* end::cond[] */ + + +/* GROUP BY Clause */ + +/* tag::group-by-clause[] */ +group-by-clause ::= 'GROUP' 'BY' group-term ( ',' group-term )* + group-as-clause? letting-clause? having-clause? + | letting-clause +/* end::group-by-clause[] */ + +/* tag::group-term[] */ +group-term ::= expr ( ('AS')? alias )? +/* end::group-term[] */ + +/* tag::group-as-clause[] */ +group-as-clause ::= 'GROUP AS' alias +/* end::group-as-clause[] */ + +/* tag::letting-clause[] */ +letting-clause ::= 'LETTING' alias '=' expr ( ',' alias '=' expr )* +/* end::letting-clause[] */ + +/* tag::having-clause[] */ +having-clause ::= 'HAVING' cond +/* end::having-clause[] */ + + +/* WINDOW Clause */ + +/* tag::window-clause[] */ +window-clause ::= 'WINDOW' window-declaration ( ',' window-declaration )* +/* end::window-clause[] */ + +/* tag::window-declaration[] */ +window-declaration ::= window-name 'AS' '(' window-definition ')' +/* end::window-declaration[] */ + +/* tag::window-name[] */ +window-name ::= identifier +/* end::window-name[] */ + +/* tag::window-definition[] */ +window-definition ::= window-ref? window-partition-clause? window-order-clause? + window-frame-clause? +/* end::window-definition[] */ + +/* tag::window-ref[] */ +window-ref ::= identifier +/* end::window-ref[] */ + +/* tag::window-partition-clause[] */ +window-partition-clause ::= 'PARTITION' 'BY' expr ( ',' expr )* +/* end::window-partition-clause[] */ + +/* tag::window-order-clause[] */ +window-order-clause ::= 'ORDER' 'BY' ordering-term ( ',' ordering-term )* +/* end::window-order-clause[] */ + +/* tag::window-frame-clause[] */ +window-frame-clause ::= ( 'ROWS' | 'RANGE' | 'GROUPS' ) window-frame-extent + window-frame-exclusion? +/* end::window-frame-clause[] */ + +/* tag::window-frame-extent[] */ +window-frame-extent ::= 'UNBOUNDED' 'PRECEDING' | valexpr 'PRECEDING' | 'CURRENT' 'ROW' | + 'BETWEEN' ( 'UNBOUNDED' 'PRECEDING' | 'CURRENT' 'ROW' | + valexpr ( 'PRECEDING' | 'FOLLOWING' ) ) + 'AND' ( 'UNBOUNDED' 'FOLLOWING' | 'CURRENT' 'ROW' | + valexpr ( 'PRECEDING' | 'FOLLOWING' ) ) +/* end::window-frame-extent[] */ + +/* tag::window-frame-exclusion[] */ +window-frame-exclusion ::= 'EXCLUDE' ( 'CURRENT' 'ROW' | 'GROUP' | 'TIES' | 'NO' 'OTHERS' ) +/* end::window-frame-exclusion[] */ + + +/* ORDER BY Clause */ + +/* tag::order-by-clause[] */ +order-by-clause ::= 'ORDER' 'BY' ordering-term ( ',' ordering-term )* +/* end::order-by-clause[] */ + +/* tag::ordering-term[] */ +ordering-term ::= expr ( 'ASC' | 'DESC' )? ( 'NULLS' ( 'FIRST' | 'LAST' ) )? +/* end::ordering-term[] */ + + +/* LIMIT Clause */ + +/* tag::limit-clause[] */ +limit-clause ::= 'LIMIT' expr +/* end::limit-clause[] */ + + +/* OFFSET Clause */ + +/* tag::offset-clause[] */ +offset-clause ::= 'OFFSET' expr +/* end::offset-clause[] */ diff --git a/modules/n1ql/partials/grammar/hints.ebnf b/modules/n1ql/partials/grammar/hints.ebnf new file mode 100644 index 000000000..5d12583bf --- /dev/null +++ b/modules/n1ql/partials/grammar/hints.ebnf @@ -0,0 +1,119 @@ +/* Hints */ + +/* tag::hint-comment[] */ +hint-comment ::= block-hint-comment | line-hint-comment +/* end::hint-comment[] */ + +/* tag::block-hint-comment[] */ +block-hint-comment ::= '/*+' hints '*/' +/* end::block-hint-comment[] */ + +/* tag::line-hint-comment[] */ +line-hint-comment ::= '--+' hints +/* end::line-hint-comment[] */ + +/* tag::hints[] */ +hints ::= simple-hint-sequence | json-hint-object +/* end::hints[] */ + +/* tag::simple-hint-sequence[] */ +simple-hint-sequence ::= simple-hint+ +/* end::simple-hint-sequence[] */ + +/* tag::simple-hint[] */ +simple-hint ::= ordered-hint-simple + | gsi-hint-simple + | fts-hint-simple + | hash-hint-simple + | nl-hint-simple +/* end::simple-hint[] */ + +/* tag::ordered-hint-simple[] */ +ordered-hint-simple ::= 'ORDERED' +/* end::ordered-hint-simple[] */ + +/* tag::gsi-hint-simple[] */ +gsi-hint-simple ::= 'INDEX' '(' keyspace index* ')' +/* end::gsi-hint-simple[] */ + +/* tag::fts-hint-simple[] */ +fts-hint-simple ::= 'INDEX_FTS' '(' keyspace index* ')' +/* end::fts-hint-simple[] */ + +/* tag::nl-hint-simple[] */ +nl-hint-simple ::= 'USE_NL' '(' ( keyspace )+ ')' +/* end::nl-hint-simple[] */ + +/* tag::hash-hint-simple[] */ +hash-hint-simple ::= 'USE_HASH' '(' ( keyspace ( '/' ( 'BUILD' | 'PROBE' ) )? )+ ')' +/* end::hash-hint-simple[] */ + +/* tag::json-hint-object[] */ +json-hint-object ::= '{' json-hint (',' json-hint )* '}' +/* end::json-hint-object[] */ + +/* tag::json-hint[] */ +json-hint ::= ordered-hint-json + | gsi-hint-json + | fts-hint-json + | hash-hint-json + | nl-hint-json +/* end::json-hint[] */ + +/* tag::ordered-hint-json[] */ +ordered-hint-json ::= '"ordered"' ':' 'true' +/* end::ordered-hint-json[] */ + +/* tag::gsi-hint-json[] */ +gsi-hint-json ::= '"index"' ':' ( index-array | index-object ) +/* end::gsi-hint-json[] */ + +/* tag::fts-hint-json[] */ +fts-hint-json ::= '"index_fts"' ':' ( index-array | index-object ) +/* end::fts-hint-json[] */ + +/* tag::nl-hint-json[] */ +nl-hint-json ::= '"use_nl"' ':' ( keyspace-array | keyspace-object ) +/* end::nl-hint-json[] */ + +/* tag::hash-hint-json[] */ +hash-hint-json ::= '"use_hash"' ':' ( hash-array | hash-object ) +/* end::hash-hint-json[] */ + +/* tag::index-array[] */ +index-array ::= '[' index-object ( ',' index-object )* ']' +/* end::index-array[] */ + +/* tag::index-object[] */ +index-object ::= '{' keyspace-property ',' indexes-property '}' +/* end::index-object[] */ + +/* tag::indexes-property[] */ +indexes-property ::= '"indexes"' ':' ( 'null' + | '"' index '"' + | '[' '"' index '"' ( ',' '"' index '"' )* ']' ) +/* end::indexes-property[] */ + +/* tag::keyspace-array[] */ +keyspace-array ::= '[' keyspace-object ( ',' keyspace-object )* ']' +/* end::keyspace-array[] */ + +/* tag::keyspace-object[] */ +keyspace-object ::= '{' keyspace-property '}' +/* end::keyspace-object[] */ + +/* tag::keyspace-property[] */ +keyspace-property ::= ( '"keyspace"' | '"alias"' ) ':' '"' keyspace '"' +/* end::keyspace-property[] */ + +/* tag::hash-array[] */ +hash-array ::= '[' hash-object ( ',' hash-object )* ']' +/* end::hash-array[] */ + +/* tag::hash-object[] */ +hash-object ::= '{' keyspace-property ( "," option-property )? '}' +/* end::hash-object[] */ + +/* tag::option-property[] */ +option-property ::= '"option"' ':' ( '"build"' | '"probe"' | 'null' ) +/* end::option-property[] */ diff --git a/modules/n1ql/partials/grammar/n1ql.ebnf b/modules/n1ql/partials/grammar/n1ql.ebnf new file mode 100644 index 000000000..b0ce85a97 --- /dev/null +++ b/modules/n1ql/partials/grammar/n1ql.ebnf @@ -0,0 +1,437 @@ +/* SQL++ for Query (N1QL) */ + +/************** + * Statements * + **************/ + +request ::= statement ( ';' statement )* ';'? + +statement ::= dcl-statement | + ddl-statement | + dml-statement | + dql-statement | + tcl-statement | + utility-statement + +dcl-statement ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/dcl.ebnf] +ddl-statement ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/ddl.ebnf] +dml-statement ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/dml.ebnf] +dql-statement ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/dql.ebnf] +tcl-statement ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/tcl.ebnf] + +utility-statement ::= [https://github.com/couchbaselabs/docs-devex/blob/capella/modules/n1ql/partials/grammar/utility.ebnf] + + +/*************** + * Expressions * + ***************/ + +expr ::= literal | + identifier | + arithmetic-term | + comparison-term | + concatenation-term | + logical-term | + case-expr | + collection-expr | + construction-expr | + nested-expr | + sequence-expr | + function-call | + subquery-expr | + '(' expr ')' + + +/* Literal */ + +literal ::= string | number | boolean | null | missing + +/* tag::string[] */ +string ::= '"' char* '"' | "'" char* "'" +/* end::string[] */ + +/* NOTE: double-quoted string must not contain unescaped double-quote */ +/* NOTE: single-quoted string must not contain unescaped single-quote */ + +/* tag::char[] */ +char ::= unicode-character | + '\' ( '\' | '"' | "'" | 'b' | 'f' | 'n' | 'r' | 't' | 'u' hex hex hex hex ) +/* end::char[] */ + +/* NOTE: unicode-character may be TAB, LF, or CR, but must not be backslash */ + +/* tag::hex[] */ +hex ::= [0-9a-fA-F] +/* end::hex[] */ + +/* tag::number[] */ +number ::= '-'? integer fraction? exponent? +/* end::number[] */ + +/* tag::integer[] */ +integer ::= [0-9] | [1-9] [0-9]+ +/* end::integer[] */ + +/* tag::fraction[] */ +fraction ::= '.' [0-9]+ +/* end::fraction[] */ + +/* tag::exponent[] */ +exponent ::= ('e' | 'E') ('-' | '+')? [0-9]+ +/* end::exponent[] */ + +/* tag::boolean[] */ +boolean ::= 'TRUE' | 'FALSE' +/* end::boolean[] */ + +/* tag::null[] */ +null ::= 'NULL' +/* end::null[] */ + +/* tag::missing[] */ +missing ::= 'MISSING' +/* end::missing[] */ + + +/* Identifier */ + +/* tag::identifier[] */ +identifier ::= unescaped-identifier | escaped-identifier +/* end::identifier[] */ + +/* tag::unescaped-identifier[] */ +unescaped-identifier ::= [a-zA-Z_] ( [0-9a-zA-Z_$] )* +/* end::unescaped-identifier[] */ + +/* tag::escaped-identifier[] */ +escaped-identifier ::= '`' char+ '`' +/* end::escaped-identifier[] */ + + +/* Arithmetic Terms */ + +/* tag::arithmetic-term[] */ +arithmetic-term ::= expr '+' expr | + expr '-' expr | + expr '*' expr | + expr '/' expr | + expr '%' expr | + '-' expr +/* end::arithmetic-term[] */ + + +/* Comparison Terms */ + +comparison-term ::= relational-expr | + between-expr | + like-expr | + is-expr + +/* tag::relational-expr[] */ +relational-expr ::= expr '=' expr | + expr '==' expr | + expr '!=' expr | + expr '<>' expr | + expr '>' expr | + expr '>=' expr | + expr '<' expr | + expr '<=' expr +/* end::relational-expr[] */ + +/* tag::between-expr[] */ +between-expr ::= expr 'NOT'? 'BETWEEN' start-expr 'AND' end-expr +/* end::between-expr[] */ + +/* tag::like-expr[] */ +like-expr ::= expr 'NOT'? 'LIKE' expr +/* end::like-expr[] */ + +/* tag::is-expr[] */ +is-expr ::= expr 'IS' 'NOT'? 'NULL' | + expr 'IS' 'NOT'? 'MISSING' | + expr 'IS' 'NOT'? 'VALUED' +/* end::is-expr[] */ + + +/* Concatenation Terms */ + +/* tag::concatenation-term[] */ +concatenation-term ::= expr '||' expr +/* end::concatenation-term[] */ + + +/* Logical Terms */ + +logical-term ::= and | or | not + +/* tag::and[] */ +and ::= cond 'AND' cond +/* end::and[] */ + +/* tag::or[] */ +or ::= cond 'OR' cond +/* end::or[] */ + +/* tag::not[] */ +not ::= 'NOT' cond +/* end::not[] */ + + +/* Case Expressions */ + +/* tag::case-expr[] */ +case-expr ::= simple-case-expr | searched-case-expr +/* end::case-expr[] */ + +/* tag::simple-case-expr[] */ +simple-case-expr ::= 'CASE' expr ('WHEN' expr 'THEN' expr)+ ('ELSE' expr)? 'END' +/* end::simple-case-expr[] */ + +/* tag::searched-case-expr[] */ +searched-case-expr ::= 'CASE' ('WHEN' cond 'THEN' expr)+ ('ELSE' expr)? 'END' +/* end::searched-case-expr[] */ + + +/* Collection Expressions */ + +collection-expr ::= exists-expr | in-expr | within-expr | range-cond | range-xform + +/* tag::exists-expr[] */ +exists-expr ::= 'EXISTS' expr +/* end::exists-expr[] */ + +/* tag::in-expr[] */ +in-expr ::= search-expr 'NOT'? 'IN' target-expr +/* end::in-expr[] */ + +/* tag::within-expr[] */ +within-expr ::= search-expr 'NOT'? 'WITHIN' target-expr +/* end::within-expr[] */ + +/* tag::range-cond[] */ +range-cond ::= ( ( 'ANY' | 'SOME' ) ( 'AND' 'EVERY' )? | 'EVERY' ) + range 'SATISFIES' cond 'END' +/* end::range-cond[] */ + +/* tag::range-xform[] */ +range-xform ::= ( ( 'ARRAY' | 'FIRST' ) | 'OBJECT' name-expr ':' ) var-expr + 'FOR' range ( 'WHEN' cond )? 'END' +/* end::range-xform[] */ + +/* tag::range[] */ +range ::= ( name-var ':' )? var ( 'IN' | 'WITHIN' ) expr + ( ',' ( name-var ':' )? var ( 'IN' | 'WITHIN' ) expr )* +/* end::range[] */ + +search-expr ::= expr +target-expr ::= expr +var-expr ::= expr +name-expr ::= expr +var ::= identifier +name-var ::= identifier + + +/* Construction Expressions */ + +construction-expr ::= object | array + +/* tag::object[] */ +object ::= '{' ( ( name-expr ':' )? expr (',' ( name-expr ':' )? expr)* )? '}' +/* end::object[] */ + +/* tag::array[] */ +array ::= '[' ( expr ( ',' expr )* )? ']' +/* end::array[] */ + + +/* Nested Expressions */ + +/* tag::nested-expr[] */ +nested-expr ::= field-expr | element-expr | slice-expr +/* end::nested-expr[] */ + +/* tag::field-expr[] */ +field-expr ::= expr '.' ( identifier | ( ( escaped-identifier | '[' name-expr ']' ) 'i'? ) ) +/* end::field-expr[] */ + +/* tag::element-expr[] */ +element-expr ::= expr '[' position ']' +/* end::element-expr[] */ + +/* tag::slice-expr[] */ +slice-expr ::= expr '[' start-expr ':' end-expr? ']' +/* end::slice-expr[] */ + +start-expr ::= expr +end-expr ::= expr +position ::= expr + + +/* Sequence Expressions */ + +/* tag::sequence-expr[] */ +sequence-expr ::= next-val-expr | prev-val-expr +/* end::sequence-expr[] */ + +/* tag::next-val-expr[] */ +next-val-expr ::= 'NEXT' 'VALUE' 'FOR' sequence | + 'NEXTVAL' 'FOR' sequence +/* end::next-val-expr[] */ + +/* tag::prev-val-expr[] */ +prev-val-expr ::= 'PREVIOUS' 'VALUE' 'FOR' sequence | + 'PREV' 'VALUE' 'FOR' sequence | + 'PREVVAL' 'FOR' sequence +/* end::prev-val-expr[] */ + + +/* Function Calls */ + +function-call ::= ordinary-function | + aggregate-function | + window-function + +function-name ::= identifier +aggregate-function-name ::= identifier +window-function-name ::= identifier + +ordinary-function ::= function-name '(' ( expr ( ',' expr )* )? ')' + +/* tag::aggregate-function[] */ +aggregate-function ::= aggregate-function-name '(' ( aggregate-quantifier? expr | + ( path '.' )? '*' ) ')' filter-clause? over-clause? +/* end::aggregate-function[] */ + +/* tag::aggregate-quantifier[] */ +aggregate-quantifier ::= 'ALL' | 'DISTINCT' +/* end::aggregate-quantifier[] */ + +/* tag::filter-clause[] */ +filter-clause ::= 'FILTER' '(' 'WHERE' cond ')' +/* end::filter-clause[] */ + +/* tag::window-function[] */ +window-function ::= window-function-name '(' window-function-arguments ')' + window-function-options? over-clause +/* end::window-function[] */ + +/* tag::window-function-arguments[] */ +window-function-arguments ::= ( expr ( ',' expr ( ',' expr )? )? )? +/* end::window-function-arguments[] */ + +/* tag::window-function-options[] */ +window-function-options ::= nthval-from? nulls-treatment? +/* end::window-function-options[] */ + +/* tag::nthval-from[] */ +nthval-from ::= 'FROM' ( 'FIRST' | 'LAST' ) +/* end::nthval-from[] */ + +/* tag::nulls-treatment[] */ +nulls-treatment ::= ( 'RESPECT' | 'IGNORE' ) 'NULLS' +/* end::nulls-treatment[] */ + +/* tag::over-clause[] */ +over-clause ::= 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::over-clause[] */ + + +/* Subquery Expressions */ + +/* tag::subquery-expr[] */ +subquery-expr ::= '(' select ')' +/* end::subquery-expr[] */ + + +/************ + * Comments * + ************/ + +comment ::= block-comment | line-comment + +/* tag::block-comment[] */ +block-comment ::= '/*' ( text | newline )* '*/' +/* end::block-comment[] */ + +/* tag::line-comment[] */ +line-comment ::= '--' text? +/* end::line-comment[] */ + +/* NOTE: block-comment text must not contain asterisk-slash or asterisk-backslash-slash */ + + +/************** + * Additional * + **************/ + +/* Date-Time Functions */ + +/* tag::format-specifier[] */ +format-specifier ::= '%' ( '%' | ( '-' | '_' | '0' | '^' )? width? element) +/* end::format-specifier[] */ + +width ::= integer +element ::= [a-zA-Z] + + +/* Window Functions */ + +/* tag::cume-dist-function[] */ +cume-dist-function ::= 'CUME_DIST' '()' 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::cume-dist-function[] */ + +/* tag::dense-rank-function[] */ +dense-rank-function ::= 'DENSE_RANK' '()' 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::dense-rank-function[] */ + +/* tag::first-value-function[] */ +first-value-function ::= 'FIRST_VALUE' '(' expr ')' nulls-treatment? + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::first-value-function[] */ + +/* tag::lag-function[] */ +lag-function ::= 'LAG' '(' expr ( ',' offset ( ',' default )? )? ')' nulls-treatment? + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::lag-function[] */ + +/* tag::last-value-function[] */ +last-value-function ::= 'LAST_VALUE' '(' expr ')' nulls-treatment? + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::last-value-function[] */ + +/* tag::lead-function[] */ +lead-function ::= 'LEAD' '(' expr ( ',' offset ( ',' default )? )? ')' nulls-treatment? + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::lead-function[] */ + +/* tag::nth-value-function[] */ +nth-value-function ::= 'NTH_VALUE' '(' expr ',' offset ')' nthval-from? nulls-treatment? + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::nth-value-function[] */ + +/* tag::ntile-function[] */ +ntile-function ::= 'NTILE' '(' num_tiles ')' + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::ntile-function[] */ + +/* tag::percent-rank-function[] */ +percent-rank-function ::= 'PERCENT_RANK' '()' + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::percent-rank-function[] */ + +/* tag::rank-function[] */ +rank-function ::= 'RANK' '()' 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::rank-function[] */ + +/* tag::ratio-to-report-function[] */ +ratio-to-report-function ::= 'RATIO_TO_REPORT' '(' expr ')' + 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::ratio-to-report-function[] */ + +/* tag::row-number-function[] */ +row-number-function ::= 'ROW_NUMBER' '()' 'OVER' ( '(' window-definition ')' | window-ref ) +/* end::row-number-function[] */ + +offset ::= expr +default ::= expr +num_tiles ::= expr diff --git a/modules/n1ql/partials/grammar/tcl.ebnf b/modules/n1ql/partials/grammar/tcl.ebnf new file mode 100644 index 000000000..b7dccae83 --- /dev/null +++ b/modules/n1ql/partials/grammar/tcl.ebnf @@ -0,0 +1,31 @@ +/* Transaction Control Language */ + +tcl-statement ::= begin-transaction + | set-transaction + | savepoint + | rollback-transaction + | commit-transaction + +/* tag::begin-transaction[] */ +begin-transaction ::= ( 'BEGIN' | 'START' ) ( 'WORK' | 'TRAN' | 'TRANSACTION' ) + ( 'ISOLATION' 'LEVEL' 'READ' 'COMMITTED' )? +/* end::begin-transaction[] */ + +/* tag::set-transaction[] */ +set-transaction ::= 'SET' 'TRANSACTION' 'ISOLATION' 'LEVEL' 'READ' 'COMMITTED' +/* end::set-transaction[] */ + +/* tag::savepoint[] */ +savepoint ::= 'SAVEPOINT' savepointname +/* end::savepoint[] */ + +/* tag::rollback-transaction[] */ +rollback-transaction ::= 'ROLLBACK' ( 'WORK' | 'TRAN' | 'TRANSACTION' )? + ( 'TO' 'SAVEPOINT' savepointname )? +/* end::rollback-transaction[] */ + +/* tag::commit-transaction[] */ +commit-transaction ::= 'COMMIT' ( 'WORK' | 'TRAN' | 'TRANSACTION' )? +/* end::commit-transaction[] */ + +savepointname ::= identifier \ No newline at end of file diff --git a/modules/n1ql/partials/grammar/utility.ebnf b/modules/n1ql/partials/grammar/utility.ebnf new file mode 100644 index 000000000..db16e0dcd --- /dev/null +++ b/modules/n1ql/partials/grammar/utility.ebnf @@ -0,0 +1,93 @@ +/* Utility Statements */ + +utility-statement ::= advise + | explain + | explain-function + | prepare + | execute + +/* tag::advise[] */ +advise ::= 'ADVISE' 'INDEX'? ( select | update | delete | merge ) +/* end::advise[] */ + +/* tag::explain[] */ +explain ::= 'EXPLAIN' statement +/* end::explain[] */ + +/* tag::explain-function[] */ +explain-function ::= 'EXPLAIN' 'FUNCTION' function +/* end::explain-function[] */ + +/* tag::infer[] */ +infer ::= 'INFER' ( 'COLLECTION' | 'KEYSPACE' )? keyspace-ref ( 'WITH' options )? +/* end::infer[] */ + +options ::= object + +/*********************** + * Prepared Statements * + ***********************/ + +/* tag::prepare[] */ +prepare ::= 'PREPARE' 'FORCE'? ( name ( 'FROM' | 'AS' ) )? statement +/* end::prepare[] */ + +/* tag::execute[] */ +execute ::= 'EXECUTE' name ( 'USING' parameters )? +/* end::execute[] */ + +name ::= identifier +parameters ::= array | object + +/************** + * Statistics * + **************/ + +/* tag::update-statistics[] */ +update-statistics ::= update-statistics-expr | update-statistics-index | + updated-statistics-indexes | update-statistics-delete +/* end::update-statistics[] */ + +/* tag::update-statistics-expr[] */ +update-statistics-expr ::= ( 'UPDATE' 'STATISTICS' 'FOR'? | + 'ANALYZE' ( 'KEYSPACE' | 'COLLECTION')? ) + keyspace-ref '(' index-key ( ',' index-key )* ')' index-with? +/* end::update-statistics-expr[] */ + +/* tag::update-statistics-index[] */ +update-statistics-index ::= ( 'UPDATE' 'STATISTICS' 'FOR' | 'ANALYZE' ) + index-clause index-using? index-with? +/* end::update-statistics-index[] */ + +/* tag::index-clause[] */ +index-clause ::= 'INDEX' ( index-path '.' index-name | index-name 'ON' keyspace-ref ) +/* end::index-clause[] */ + +/* tag::update-statistics-indexes[] */ +update-statistics-indexes ::= ( 'UPDATE' 'STATISTICS' 'FOR'? | + 'ANALYZE' ( 'KEYSPACE' | 'COLLECTION')? ) + keyspace-ref indexes-clause index-using? index-with? +/* end::update-statistics-indexes[] */ + +/* tag::indexes-clause[] */ +indexes-clause ::= 'INDEX' ( '(' ( index-name ( ',' index-name )* | subquery-expr ) ')' | + 'ALL' ) +/* end::indexes-clause[] */ + +/* tag::update-statistics-delete[] */ +update-statistics-delete ::= ( 'UPDATE' 'STATISTICS' 'FOR'? | + 'ANALYZE' ( 'KEYSPACE' | 'COLLECTION')? ) + keyspace-ref delete-clause +/* end::update-statistics-delete[] */ + +/* tag::delete-clause[] */ +delete-clause ::= 'DELETE' ( delete-expr | delete-all ) +/* end::delete-clause[] */ + +/* tag::delete-expr[] */ +delete-expr ::= 'STATISTICS'? '(' index-key ( ',' index-key )* ')' +/* end::delete-expr[] */ + +/* tag::delete-all[] */ +delete-all ::= 'ALL' | 'STATISTICS' +/* end::delete-all[] */ \ No newline at end of file diff --git a/modules/n1ql/partials/n1ql-language-reference/advice-workbench.adoc b/modules/n1ql/partials/n1ql-language-reference/advice-workbench.adoc new file mode 100644 index 000000000..5cb15d032 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/advice-workbench.adoc @@ -0,0 +1,2 @@ +When you run an ADVISE statement in the Query tab, you can use the *Table*, *JSON*, or *Tree* link to see the result, just like any other query. +You can also use the *Advice* link in the Query tab to see the result of the ADVISE statement in graphical format. \ No newline at end of file diff --git a/modules/n1ql/partials/n1ql-language-reference/ansi-join-nest.adoc b/modules/n1ql/partials/n1ql-language-reference/ansi-join-nest.adoc new file mode 100644 index 000000000..c094781af --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/ansi-join-nest.adoc @@ -0,0 +1,2 @@ +NOTE: xref:n1ql-language-reference/join.adoc#section_ek1_jnx_1db[ANSI JOIN] and xref:n1ql-language-reference/nest.adoc#section_tc1_nnx_1db[ANSI NEST] clauses have much more flexible functionality than their earlier INDEX and LOOKUP equivalents. +Since these are standard compliant and more flexible, we recommend you to use ANSI JOIN and ANSI NEST exclusively, where possible. diff --git a/modules/n1ql/partials/n1ql-language-reference/collapsible-style.adoc b/modules/n1ql/partials/n1ql-language-reference/collapsible-style.adoc new file mode 100644 index 000000000..5a29fc2ff --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/collapsible-style.adoc @@ -0,0 +1,26 @@ +// FIXME: Temporary pass-through CSS for detail summaries + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] diff --git a/modules/n1ql/partials/n1ql-language-reference/column-style.adoc b/modules/n1ql/partials/n1ql-language-reference/column-style.adoc new file mode 100644 index 000000000..65bd19d59 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/column-style.adoc @@ -0,0 +1,12 @@ +// FIXME: Temporary pass-through CSS for columns + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] diff --git a/modules/n1ql/partials/n1ql-language-reference/file-based-index-rebalance-note.adoc b/modules/n1ql/partials/n1ql-language-reference/file-based-index-rebalance-note.adoc new file mode 100644 index 000000000..fb8e391fe --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/file-based-index-rebalance-note.adoc @@ -0,0 +1,4 @@ +// Remove after the 7.6 versions. +NOTE: In clusters running Couchbase Server versions 7.6.0 and 7.6.1, you cannot use this option to choose which Index Service nodes contain the index. +Clusters running Couchbase Server 7.6.2 and later do not have this restriction. +See xref:server:learn:clusters-and-availability/rebalance.adoc#index-rebalance-methods[Index Rebalance Methods]. \ No newline at end of file diff --git a/modules/n1ql/partials/n1ql-language-reference/from-term.adoc b/modules/n1ql/partials/n1ql-language-reference/from-term.adoc new file mode 100644 index 000000000..f27241aa4 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/from-term.adoc @@ -0,0 +1,73 @@ +=== Left-Hand Side + +The {from-term} cannot be the first term within the `FROM` clause; it must be preceded by another FROM term. +The term immediately preceding the {from-term} represents the _left-hand side_ of the {from-term}. + +You can chain the {from-term} with any of the other permitted FROM terms, including another {from-term}. +For more information, see the page on the xref:n1ql-language-reference/from.adoc[FROM] clause. + +There are restrictions on what types of FROM terms may be chained and in what order -- see the descriptions on this page for more details. + +The types of FROM term that may be used as the left-hand side of the {from-term} are summarized in the following table. + +include::ROOT:partial$query-context.adoc[tag=section] + +[#table_vrv_nxx_1db,cols="1,3"] +|=== +| Type | Example + +.^| xref:n1ql-language-reference/from.adoc#sec_from-keyspace[keyspace identifier] +a| +[source,N1QL] +---- +hotel +---- +.^| xref:n1ql-language-reference/from.adoc#generic-expr[generic expression] +a| +[source,N1QL] +---- +20+10 AS Total +---- +.^| xref:n1ql-language-reference/from.adoc#select-expr[subquery] +a| +[source,N1QL] +---- +SELECT ARRAY_AGG(t1.city) AS cities, + SUM(t1.city_cnt) AS apnum +FROM ( + SELECT city, city_cnt, country, + ARRAY_AGG(airportname) AS apnames + FROM airport + GROUP BY city, country + LETTING city_cnt = COUNT(city) +) AS t1 +WHERE t1.city_cnt > 5; +---- +.^| previous xref:n1ql-language-reference/join.adoc[join], xref:n1ql-language-reference/nest.adoc[nest], or xref:n1ql-language-reference/unnest.adoc[unnest] +a| +[source,N1QL] +---- +SELECT * +FROM route AS rte +JOIN airport AS apt + ON rte.destinationairport = apt.faa +NEST landmark AS lmk + ON apt.city = lmk.city +LIMIT 5; +---- + +ifeval::["{from-term}" == "comma-separated join"] +.^| previous comma-separated join +a| +[source,N1QL] +---- +SELECT a.airportname, h.name AS hotel, l.name AS landmark +FROM airport AS a, + hotel AS h, + landmark AS l +WHERE a.city = h.city + AND h.city = l.city +LIMIT 5; +---- +endif::[] +|=== diff --git a/modules/n1ql/partials/n1ql-language-reference/fun-token.adoc b/modules/n1ql/partials/n1ql-language-reference/fun-token.adoc new file mode 100644 index 000000000..26104eae4 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/fun-token.adoc @@ -0,0 +1,203 @@ +== TOKENS(in_str, opt) + +=== Description +This function tokenizes (i.e. +breaks up into meaningful segments) the given input string based on specified delimiters, and other options. +It recursively enumerates all tokens in a JSON value and returns an array of values (JSON atomic values) as the result. + +=== Arguments +in_str:: +A valid JSON object, this can be anything: constant literal, simple JSON value, JSON key name or the whole document itself. ++ +The following table lists the rules for each JSON type: ++ +|=== +| JSON Type | Return Value + +| MISSING +| [] + +| NULL +| [NULL] + +| false +| [false] + +| true +| [true] + +| number +| [number] + +| string +| SPLIT(string) + +| array +| FLATTEN(TOKENS(element) for each element in array + +(Concatenation of element tokens) + +| object +| For each name-value pair, name+TOKENS(value) +|=== + +opt:: +A JSON object indicating the options passed to the `TOKENS()` function. +Options can take the following options, and each invocation of `TOKENS()` can choose one or more of the options: +{"name": true};; *Optional*. +Valid values are `true` or `false`. +By default, this is set to true and `TOKENS()` will include field names. +You can choose to not include field names by setting this option to `false`. +{"case":"lower"};; *Optional*. +Valid values are [.in]`lower` or [.in]`upper`. +Default is neither, as in it returns the case of the original data. +Use this option to specify the case sensitivity. +{"specials": true};; *Optional*. +Use this option to preserve strings with specials characters, such as email addresses, URLs, and hyphenated phone numbers. +The default value is `false`. ++ +NOTE: The `specials` options preserves special characters except at the end of a word. + +=== Return Value +An array of strings containing all of the tokens obtained from the input string. + +=== Examples +NOTE: By default, for speed, the results are randomly ordered. +To make the difference more clear between the first two example queries, the `ARRAY_SORT()` function is used. + +.List the tokens of an array where `specials` is FALSE +==== +[source,sqlpp] +---- +SELECT ARRAY_SORT( + TOKENS( ['jim@example.com, kim@example.com, http://example.com/, 408-555-1212'], + {'specials': false} )); +---- + +[source,json] +---- +[ + { + "$1": [ + "1212", + "408", + "555", + "abc", + "com", + "http", + "jim", + "kim" + ] + } +] +---- +==== + +.List the tokens of an array where `specials` is TRUE +==== +[source,sqlpp] +---- +SELECT ARRAY_SORT( + TOKENS( ['jim@example.com, kim@example.com, http://example.com/, 408-555-1212'], + {'specials': true} )); +---- + +[source,json] +---- +[ + { + "$1": [ + "1212", + "408", + "408-555-1212", + "555", + "abc", + "com", + "http", + "http://example.com", + "jim", + "jim@example.com", + "kim", + "kim@example.com" + ] + } +] +---- +==== + +.Convert all of the URL data into UPPER case and adds the full URL to the delimited words +==== +include::ROOT:partial$query-context.adoc[tag=example] + +[source,sqlpp] +---- +SELECT ARRAY_SORT( TOKENS(url) ) AS defaulttoken, + ARRAY_SORT( TOKENS(url, {"specials":true, "case":"UPPER"}) ) AS specialtoken +FROM hotel +LIMIT 1; +---- + +[source,json] +---- +[ + { + "defaulttoken": [ + "http", + "org", + "uk", + "www", + "yha" + ], + "specialtoken": [ + "HTTP", + "HTTP://WWW.YHA.ORG.UK", + "ORG", + "UK", + "WWW", + "YHA" + ] + } +] +---- +==== + +You can also use `{"case":"lower"}` or `{"case":"upper"}` to have case sensitive search. +Index creation and querying can use this and other parameters in combination. +These parameters should be passed within the query predicates as well. +The parameters and values must match exactly for {sqlpp} to pick up and use the index correctly. + +.Create an index with `case` and use it your application +==== +include::ROOT:partial$query-context.adoc[tag=example] + +[source,sqlpp] +---- +CREATE INDEX idx_url_upper_special ON hotel( + DISTINCT ARRAY v FOR v IN + TOKENS(url, {"specials":true, "case":"UPPER"}) + END ); +---- + +[source,sqlpp] +---- +SELECT name, address, url +FROM hotel +WHERE ANY v IN TOKENS(url, {"specials":true, "case":"UPPER"}) + SATISFIES v = "HTTP://WWW.YHA.ORG.UK" + END; +---- + +[source,json] +---- +{ + "results": [ + { + "address": "Capstone Road, ME7 3JE", + "name": "Medway Youth Hostel", + "url": "http://www.yha.org.uk" + } + ] +} +---- +==== + diff --git a/modules/n1ql/partials/n1ql-language-reference/horizontal-style.adoc b/modules/n1ql/partials/n1ql-language-reference/horizontal-style.adoc new file mode 100644 index 000000000..77048e75b --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/horizontal-style.adoc @@ -0,0 +1,39 @@ +// FIXME: Temporary pass-through CSS for horizontal description lists + +ifdef::basebackend-html[] +++++ + +++++ +endif::[] diff --git a/modules/n1ql/partials/n1ql-language-reference/over-clause.adoc b/modules/n1ql/partials/n1ql-language-reference/over-clause.adoc new file mode 100644 index 000000000..ad0fd58b8 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/over-clause.adoc @@ -0,0 +1,27 @@ +:imagesdir: ../../assets/images + +:identifier: xref:n1ql-language-reference/identifiers.adoc +:window: xref:n1ql-language-reference/window.adoc +:window-definition: {window}#window-definition + +=== OVER Clause + +// tag::body[] +[source,ebnf] +---- +include::partial$grammar/n1ql.ebnf[tag=over-clause] +---- + +image::n1ql-language-reference/over-clause.png["Syntax diagram", align=left] + +The OVER clause introduces the window specification for the function. +There are two ways of specifying the window. + +* An _inline window definition_ specifies the window directly within the function call. +It is delimited by parentheses `()` and has exactly the same syntax as the window definition in a WINDOW clause. +For further details, refer to {window-definition}[Window Definition]. + +* A _window reference_ is an {identifier}[identifier] which refers to a named window. +The named window must be defined by a WINDOW clause in the same query block as the function call. +For further details, refer to {window}[WINDOW Clause]. +// end::body[] diff --git a/modules/n1ql/partials/n1ql-language-reference/select-privilege.adoc b/modules/n1ql/partials/n1ql-language-reference/select-privilege.adoc new file mode 100644 index 000000000..6b03fb75f --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/select-privilege.adoc @@ -0,0 +1,6 @@ +== Prerequisites + +For you to select data from keyspace or expression, you must have the [.param]`query_select` privilege on that keyspace. +For more details about user roles, see +xref:server:learn:security/authorization-overview.adoc[Authorization]. + diff --git a/modules/n1ql/partials/n1ql-language-reference/statistics-options.adoc b/modules/n1ql/partials/n1ql-language-reference/statistics-options.adoc new file mode 100644 index 000000000..3eb5523a8 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/statistics-options.adoc @@ -0,0 +1,41 @@ +=== WITH Clause + +:distribution-stats: xref:n1ql-language-reference/cost-based-optimizer.adoc#distribution-stats + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=index-with] +---- + +image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] + +Use the `WITH` clause to specify additional options. + +[horizontal] +expr:: +An object with the following properties: + +sample_size;; +[Optional] An integer specifying the sample size to use for distribution statistics. +A minimum sample size is also calculated. +If the specified sample size is smaller than the minimum sample size, the minimum sample size is used instead. + +resolution;; +[Optional] A float representing the percentage of documents to store in each distribution bin. +If omitted, the default value is `1.0`, meaning each distribution bin contains 1% of the documents, and therefore 100 bins are required. +The minimum resolution is `0.02` (5000 distribution bins) and the maximum is `5.0` (20 distribution bins). + +update_statistics_timeout;; +[Optional] A number representing a duration in seconds. +The command times out when this timeout period is reached. +If omitted, a default timeout value is calculated based on the number of samples used. + +batch_size;; +[Optional] Only applies when processing multiple index expressions at once. +If there is a large number of index expressions to process, the cost-based optimizer deals with them in batches. +This option is an integer specifying the maximum number of index expressions in each batch. +If omitted, the default value is `10`. +You can specify a different value based on the memory availability of the system. +Note that when index expressions are processed in batches, the `update_statistics_timeout` value (above) applies to each batch. + +Refer to {distribution-stats}[Distribution Statistics] for more information on sample size and resolution. diff --git a/modules/n1ql/partials/n1ql-language-reference/transaction-id.adoc b/modules/n1ql/partials/n1ql-language-reference/transaction-id.adoc new file mode 100644 index 000000000..9925f02ab --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/transaction-id.adoc @@ -0,0 +1,10 @@ +:txid: xref:n1ql:n1ql-manage/query-settings.adoc#txid + +If you are using the Query REST API, you must set the {txid}[txid] query parameter to specify the transaction ID. + +If you are using the Query tab, you don't need to specify the transaction ID, as long as the statement is part of a multi-statement request. +When you start a transaction within a multi-statement request, all statements within the request are assumed to be part of the same transaction until you rollback or commit the transaction. + +Similarly, if you are using the cbq shell, you don't need to specify the transaction ID. +Once you have started a transaction, all statements within the cbq shell session are assumed to be part of the same transaction until you rollback or commit the transaction. +footnote:[You must be using cbq shell version 2.0 or above to use the automatic transaction ID functionality.] \ No newline at end of file diff --git a/modules/n1ql/partials/n1ql-language-reference/transaction-restrictions.adoc b/modules/n1ql/partials/n1ql-language-reference/transaction-restrictions.adoc new file mode 100644 index 000000000..b473fb10e --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/transaction-restrictions.adoc @@ -0,0 +1,8 @@ +* Only DML statements are permitted within a transaction: {insert}[INSERT], {upsert}[UPSERT], {delete}[DELETE], {update}[UPDATE], {merge}[MERGE], {select}[SELECT], {execfunction}[EXECUTE FUNCTION], {prepare}[PREPARE], or {execute}[EXECUTE]. + +* The `EXECUTE FUNCTION` statement is only permitted in a transaction if the user-defined function does not contain any subqueries other than `SELECT` subqueries. + +* The `PREPARE` and `EXECUTE` statements are only permitted in a transaction for the DML statements listed above. + +All statements within a transaction are sent to the same Query node. +If your cluster uses private endpoints, the load balancer ensures that the same query node carries out all the steps in the transaction. \ No newline at end of file diff --git a/modules/n1ql/partials/n1ql-language-reference/udf-output.adoc b/modules/n1ql/partials/n1ql-language-reference/udf-output.adoc new file mode 100644 index 000000000..1ba09ceb4 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/udf-output.adoc @@ -0,0 +1,20 @@ +== Return Value + +// tag::body[] +The function returns one value, of any valid {sqlpp} type. +The result (and the data type of the result) depend on the expression or code that were used to define the function. + +If you supply the wrong number of arguments, or arguments with the wrong data type, the possible results differ, depending on whether the function is variadic, or requires a definite number of arguments. + +If the function requires a definite number of arguments: + +* If you do not supply enough arguments, the function generates error `10104: Incorrect number of arguments`. +* If you supply too many arguments, the function generates error `10104: Incorrect number of arguments`. +* If any of the arguments have the wrong data type, the function may return unexpected results, depending on the function expression or code. + +If the function is variadic: + +* If you do not supply enough arguments, the function may return unexpected results, depending on the function expression or code. +* If you supply too many arguments, the extra parameters are ignored. +* If any of the arguments have the wrong data type, the function may return unexpected results, depending on the function expression or code. +// end::body[] diff --git a/modules/n1ql/partials/n1ql-language-reference/window-intro.adoc b/modules/n1ql/partials/n1ql-language-reference/window-intro.adoc new file mode 100644 index 000000000..33ae9f5d1 --- /dev/null +++ b/modules/n1ql/partials/n1ql-language-reference/window-intro.adoc @@ -0,0 +1,24 @@ +:aggregatefun: xref:n1ql-language-reference/aggregatefun.adoc + +// tag::windows[] +Window functions are used to compute an aggregate or cumulative value, based on a group of objects. +The objects are not grouped into a single output object — each object remains separate in the query output. + +All window functions must have a window definition. +This divides the query result set into one or more partitions, and determines the order of objects in those partitions. +Within each partition, a movable window frame is defined for every input object. +The window frame determines the objects to be used by the window function. +// end::windows[] + +// tag::functions[] +{sqlpp} has a dedicated set of window functions. +Each window function call includes an OVER clause, which introduces the window specification. +Some window functions take additional window options, which are specified by further clauses before the OVER clause. + +In Couchbase Server Enterprise Edition, {aggregatefun}[aggregate functions] can also be used as window functions when they are used with an OVER clause. +// end::functions[] + +// tag::syntax[] +In Couchbase Server 7.0 and later, window functions (and aggregate functions used as window functions) may specify their own inline window definitions, or they may refer to a named window defined by the WINDOW clause elsewhere in the query. +By defining a named window with the WINDOW clause, you can reuse the window definition across several functions in the query, potentially making the query easier to write and maintain. +// end::syntax[] \ No newline at end of file diff --git a/modules/n1ql/partials/nav.adoc b/modules/n1ql/partials/nav.adoc new file mode 100644 index 000000000..2c0ac4549 --- /dev/null +++ b/modules/n1ql/partials/nav.adoc @@ -0,0 +1,167 @@ +// Combined nav for Query +* xref:n1ql:query.adoc[] + ** xref:n1ql:n1ql-intro/index.adoc[] + *** xref:n1ql:n1ql-intro/queriesandresults.adoc[] + *** xref:clusters:query-service/query-workbench.adoc[] + *** xref:n1ql:n1ql-intro/cbq.adoc[] + ** xref:guides:query.adoc[] + *** xref:guides:select.adoc[] + *** xref:guides:join.adoc[] + *** xref:guides:nest-unnest.adoc[] + *** xref:guides:group-agg.adoc[] + *** xref:guides:prep-statements.adoc[] + ** xref:guides:indexes.adoc[] + *** xref:guides:create-index.adoc[] + *** xref:guides:place-index.adoc[] + *** xref:guides:defer-index.adoc[] + *** xref:guides:select-index.adoc[] + *** xref:guides:drop-index.adoc[] + *** xref:guides:index-advisor.adoc[] + ** xref:guides:manipulate.adoc[] + *** xref:guides:insert.adoc[] + *** xref:guides:update.adoc[] + *** xref:guides:delete.adoc[] +ifdef::flag-devex-javascript-udfs[] + ** xref:guides:javascript-udfs.adoc[] + *** xref:guides:create-javascript-library.adoc[] + *** xref:guides:create-user-defined-function.adoc[] + *** xref:guides:call-user-defined-function.adoc[] +endif::flag-devex-javascript-udfs[] + ** xref:n1ql:advanced.adoc[] + *** xref:n1ql:n1ql-language-reference/cost-based-optimizer.adoc[] + *** xref:guides:cbo.adoc[] + *** xref:n1ql:n1ql-language-reference/transactions.adoc[] + *** xref:guides:transactions.adoc[] + *** xref:n1ql:n1ql-language-reference/flex-indexes.adoc[] + *** xref:n1ql:n1ql-language-reference/time-series.adoc[] + ** xref:n1ql:n1ql-manage/index.adoc[] + *** xref:n1ql:n1ql-intro/sysinfo.adoc[] + *** xref:n1ql:n1ql-manage/monitoring-n1ql-query.adoc[] + *** xref:clusters:index-service/manage-indexes.adoc[] + *** xref:n1ql:n1ql-manage/query-settings.adoc[] + ** xref:n1ql:n1ql-language-reference/index.adoc[] + *** xref:n1ql:n1ql-language-reference/conventions.adoc[] + *** xref:n1ql:n1ql-language-reference/reservedwords.adoc[] + *** xref:n1ql:n1ql-language-reference/datatypes.adoc[] + *** xref:n1ql:n1ql-language-reference/literals.adoc[] + *** xref:n1ql:n1ql-language-reference/identifiers.adoc[] + *** xref:n1ql:n1ql-language-reference/operators.adoc[Operators] + **** xref:n1ql:n1ql-language-reference/arithmetic.adoc[] + **** xref:n1ql:n1ql-language-reference/collectionops.adoc[] + **** xref:n1ql:n1ql-language-reference/comparisonops.adoc[] + **** xref:n1ql:n1ql-language-reference/conditionalops.adoc[] + **** xref:n1ql:n1ql-language-reference/constructionops.adoc[] + **** xref:n1ql:n1ql-language-reference/logicalops.adoc[] + **** xref:n1ql:n1ql-language-reference/nestedops.adoc[] + **** xref:n1ql:n1ql-language-reference/sequenceops.adoc[] + **** xref:n1ql:n1ql-language-reference/stringops.adoc[] + *** xref:n1ql:n1ql-language-reference/functions.adoc[Functions] + **** xref:n1ql:n1ql-language-reference/aggregatefun.adoc[] + **** xref:n1ql:n1ql-language-reference/arrayfun.adoc[] + **** xref:n1ql:n1ql-language-reference/bitwisefun.adoc[] + **** xref:n1ql:n1ql-language-reference/comparisonfun.adoc[] + **** xref:n1ql:n1ql-language-reference/condfununknown.adoc[] + **** xref:n1ql:n1ql-language-reference/condfunnum.adoc[] + **** xref:n1ql:n1ql-language-reference/datefun.adoc[] + **** xref:n1ql:n1ql-language-reference/jsonfun.adoc[] + **** xref:n1ql:n1ql-language-reference/metafun.adoc[] + ***** xref:n1ql:n1ql-language-reference/advisor.adoc[] + ***** xref:n1ql:n1ql-language-reference/timeseries.adoc[] + **** xref:n1ql:n1ql-language-reference/numericfun.adoc[] + **** xref:n1ql:n1ql-language-reference/objectfun.adoc[] + **** xref:n1ql:n1ql-language-reference/patternmatchingfun.adoc[] + **** xref:n1ql:n1ql-language-reference/searchfun.adoc[] + **** xref:n1ql:n1ql-language-reference/stringfun.adoc[] + **** xref:n1ql:n1ql-language-reference/tokenfun.adoc[] + **** xref:n1ql:n1ql-language-reference/typefun.adoc[] + **** xref:n1ql:n1ql-language-reference/userfun.adoc[] + **** xref:n1ql:n1ql-language-reference/windowfun.adoc[] + *** xref:n1ql:n1ql-language-reference/subqueries.adoc[] + **** xref:n1ql:n1ql-language-reference/correlated-subqueries.adoc[] + **** xref:n1ql:n1ql-language-reference/subquery-examples.adoc[] + *** xref:n1ql:n1ql-language-reference/optimizer-hints.adoc[Hints] + **** xref:n1ql:n1ql-language-reference/query-hints.adoc[] + **** xref:n1ql:n1ql-language-reference/keyspace-hints.adoc[] + *** xref:n1ql:n1ql-language-reference/booleanlogic.adoc[] + *** Statements + **** xref:n1ql:n1ql-language-reference/advise.adoc[] + **** xref:n1ql:n1ql-language-reference/alterindex.adoc[] + **** xref:n1ql:n1ql-language-reference/altersequence.adoc[] + **** xref:n1ql:n1ql-language-reference/begin-transaction.adoc[] + **** xref:n1ql:n1ql-language-reference/build-index.adoc[] + **** xref:n1ql:n1ql-language-reference/commit-transaction.adoc[] + **** xref:n1ql:n1ql-language-reference/createcollection.adoc[] + **** xref:n1ql:n1ql-language-reference/createfunction.adoc[] + **** xref:n1ql:n1ql-language-reference/createindex.adoc[] + ***** xref:n1ql:n1ql-language-reference/indexing-arrays.adoc[] + ***** xref:n1ql:n1ql-language-reference/adaptive-indexing.adoc[] + ***** xref:n1ql:n1ql-language-reference/indexing-meta-info.adoc[] + ***** xref:n1ql:n1ql-language-reference/index-partitioning.adoc[] + **** xref:n1ql:n1ql-language-reference/createprimaryindex.adoc[] + **** xref:n1ql:n1ql-language-reference/createsequence.adoc[] + **** xref:n1ql:n1ql-language-reference/createscope.adoc[] + **** xref:n1ql:n1ql-language-reference/delete.adoc[] + **** xref:n1ql:n1ql-language-reference/dropcollection.adoc[] + **** xref:n1ql:n1ql-language-reference/dropfunction.adoc[] + **** xref:n1ql:n1ql-language-reference/dropindex.adoc[] + **** xref:n1ql:n1ql-language-reference/dropprimaryindex.adoc[] + **** xref:n1ql:n1ql-language-reference/dropsequence.adoc[] + **** xref:n1ql:n1ql-language-reference/dropscope.adoc[] + **** xref:n1ql:n1ql-language-reference/execute.adoc[] + **** xref:n1ql:n1ql-language-reference/execfunction.adoc[] + **** xref:n1ql:n1ql-language-reference/explain.adoc[] + **** xref:n1ql:n1ql-language-reference/explainfunction.adoc[] + **** xref:n1ql:n1ql-language-reference/grant.adoc[] + **** xref:n1ql:n1ql-language-reference/infer.adoc[] + **** xref:n1ql:n1ql-language-reference/insert.adoc[] + **** xref:n1ql:n1ql-language-reference/merge.adoc[] + **** xref:n1ql:n1ql-language-reference/prepare.adoc[] + **** xref:n1ql:n1ql-language-reference/revoke.adoc[] + **** xref:n1ql:n1ql-language-reference/rollback-transaction.adoc[] + **** xref:n1ql:n1ql-language-reference/savepoint.adoc[] + **** xref:n1ql:n1ql-language-reference/selectintro.adoc[SELECT] + ***** xref:n1ql:n1ql-language-reference/select-syntax.adoc[] + ***** xref:n1ql:n1ql-language-reference/selectclause.adoc[] + ***** xref:n1ql:n1ql-language-reference/with.adoc[] + ***** xref:n1ql:n1ql-language-reference/with-recursive.adoc[] + ***** xref:n1ql:n1ql-language-reference/from.adoc[] + ***** xref:n1ql:n1ql-language-reference/hints.adoc[] + ***** xref:n1ql:n1ql-language-reference/join.adoc[] + ***** xref:n1ql:n1ql-language-reference/nest.adoc[] + ***** xref:n1ql:n1ql-language-reference/unnest.adoc[] + ***** xref:n1ql:n1ql-language-reference/comma.adoc[] + ***** xref:n1ql:n1ql-language-reference/let.adoc[] + ***** xref:n1ql:n1ql-language-reference/where.adoc[] + ***** xref:n1ql:n1ql-language-reference/groupby.adoc[] + ***** xref:n1ql:n1ql-language-reference/window.adoc[] + ***** xref:n1ql:n1ql-language-reference/union.adoc[] + ***** xref:n1ql:n1ql-language-reference/orderby.adoc[] + ***** xref:n1ql:n1ql-language-reference/limit.adoc[] + ***** xref:n1ql:n1ql-language-reference/offset.adoc[] + **** xref:n1ql:n1ql-language-reference/set-transaction.adoc[] + **** xref:n1ql:n1ql-language-reference/update.adoc[] + **** xref:n1ql:n1ql-language-reference/updatestatistics.adoc[] + ***** xref:n1ql:n1ql-language-reference/statistics-expressions.adoc[] + ***** xref:n1ql:n1ql-language-reference/statistics-index.adoc[] + ***** xref:n1ql:n1ql-language-reference/statistics-indexes.adoc[] + ***** xref:n1ql:n1ql-language-reference/statistics-delete.adoc[] + **** xref:n1ql:n1ql-language-reference/upsert.adoc[] + *** xref:n1ql:n1ql-language-reference/n1ql-auditing.adoc[] + *** xref:n1ql:n1ql-language-reference/n1ql-error-codes.adoc[] + ** xref:learn:services-and-indexes/indexes/global-secondary-indexes.adoc[] + *** xref:learn:services-and-indexes/indexes/query-without-index.adoc[] + *** xref:learn:services-and-indexes/indexes/indexing-and-query-perf.adoc[] + *** xref:learn:services-and-indexes/indexes/index-lifecycle.adoc[] + *** xref:n1ql:n1ql-language-reference/covering-indexes.adoc[] + *** xref:learn:services-and-indexes/indexes/index-scans.adoc[] + *** xref:learn:services-and-indexes/indexes/index_pushdowns.adoc[] + *** xref:n1ql:n1ql-language-reference/groupby-aggregate-performance.adoc[] + *** xref:learn:services-and-indexes/indexes/early-filters-and-pagination.adoc[] + *** xref:learn:services-and-indexes/indexes/index-replication.adoc[] + *** xref:learn:services-and-indexes/indexes/storage-modes.adoc[] +ifdef::flag-devex-javascript-udfs[] + ** xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] + *** xref:javascript-udfs:calling-javascript-from-n1ql.adoc[] + *** xref:javascript-udfs:calling-n1ql-from-javascript.adoc[] + *** xref:javascript-udfs:handling-errors-javascript-udf.adoc[] +endif::flag-devex-javascript-udfs[] diff --git a/modules/search/examples/autocomplete-sample.cs b/modules/search/examples/autocomplete-sample.cs new file mode 100644 index 000000000..72817df05 --- /dev/null +++ b/modules/search/examples/autocomplete-sample.cs @@ -0,0 +1,38 @@ +using Couchbase; +using Couchbase.Search.Queries.Simple; + +await using var cluster = await Cluster.ConnectAsync(new ClusterOptions +{ + ConnectionString = "CB_HOSTNAME", + UserName = "CB_USERNAME", + Password = "CB_PASSWORD", + Buckets = new List{"travel-sample"} +}.ApplyProfile("wan-development")); + +var searchString = "Beaufort Hotel"; +for (var i = 2; i <= 8; i++) +{ + var lettersEntered = searchString.Substring(0, i); + Console.WriteLine($"Input <{lettersEntered}>, len: {lettersEntered.Length}"); + await FtsMatchPrefix(lettersEntered); +} + +async Task FtsMatchPrefix(string letters) +{ + try + { + var results = await cluster.SearchQueryAsync("e-ngram-2-8", + new QueryStringQuery(letters), + options => + { + options.Limit(8); + options.Fields("name"); + }); + results.Hits.ToList().ForEach(row => { Console.WriteLine($"{row.Id}, {row.Fields}"); }); + Console.WriteLine(results); + } + catch (Exception e) + { + Console.WriteLine(e); + } +} \ No newline at end of file diff --git a/modules/search/examples/autocomplete-sample.go b/modules/search/examples/autocomplete-sample.go new file mode 100644 index 000000000..58ed07155 --- /dev/null +++ b/modules/search/examples/autocomplete-sample.go @@ -0,0 +1,55 @@ +package main + +import ( + "os" + "fmt" + "math" + "log" + "github.com/couchbase/gocb/v2" + "github.com/couchbase/gocb/v2/search" +) + +func main() { + cluster, err := gocb.Connect( + os.Getenv("CB_HOSTNAME"), + gocb.ClusterOptions{ + Authenticator: gocb.PasswordAuthenticator{ + Username: os.Getenv("CB_USERNAME"), + Password: os.Getenv("CB_PASSWORD"), + }, + }) + if err != nil { + log.Fatal(err) + } + + iterStr := "Beaufort Hotel" + maxsz := int(math.Min(float64(len(iterStr)), float64(8))) + for i := 2; i <= maxsz; i++ { + testStr := iterStr[0:i] + fmt.Printf("Input <%s>, len: %d\n", testStr, len(testStr)); + results, err := cluster.SearchQuery( + "e-ngram-2-8", + search.NewQueryStringQuery(testStr), + &gocb.SearchOptions { Fields: []string{"name"}, Limit: 8, }, + ) + if err != nil { + log.Fatal(err) + } + + for results.Next() { + row := results.Row() + docID := row.ID + var fields interface {} + err := row.Fields( & fields) + if err != nil { + panic(err) + } + fmt.Printf("Document ID: %s, fields: %v\n", docID, fields) + } + + err = results.Err() + if err != nil { + log.Fatal(err) + } + } +} diff --git a/modules/search/examples/autocomplete-sample.java b/modules/search/examples/autocomplete-sample.java new file mode 100644 index 000000000..9c834669c --- /dev/null +++ b/modules/search/examples/autocomplete-sample.java @@ -0,0 +1,29 @@ +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.search.SearchOptions; +import com.couchbase.client.java.search.SearchQuery; +import com.couchbase.client.java.search.result.SearchResult; +import com.couchbase.client.java.search.result.SearchRow; + +public class MockTypeAheadEnGram { + static String connstrn = System.getenv("CB_HOSTNAME"); + static String username = System.getenv("CB_USERNAME"); + static String password = System.getenv("CB_PASSWORD"); + + public static void main(String... args) { + Cluster cluster = Cluster.connect(connstrn, username, password); + + String iterStr = "Beaufort Hotel"; + for (int i=2; i<=Math.min(8, iterStr.length());i++) { + String testStr = iterStr.substring(0, i); + System.out.println("Input <" + testStr + ">, len: " + testStr.length()); + + SearchQuery query = SearchQuery.queryString(testStr); + SearchOptions options = SearchOptions.searchOptions().limit(8).skip(0).explain(false).fields("name"); + SearchResult result = cluster.searchQuery("e-ngram-2-8" , query, options); + for (SearchRow row : result.rows()) { + System.out.println(row.id() + "," + row.fieldsAs(JsonObject.class) ); + } + } + } +} diff --git a/modules/search/examples/autocomplete-sample.js b/modules/search/examples/autocomplete-sample.js new file mode 100644 index 000000000..9eb9f7459 --- /dev/null +++ b/modules/search/examples/autocomplete-sample.js @@ -0,0 +1,32 @@ +const couchbase = require('couchbase') + +const main = async () => { + const hostname = process.env.CB_HOSTNAME + const username = process.env.CB_USERNAME + const password = process.env.CB_PASSWORD + const bucketName = 'travel-sample' + + const cluster = await couchbase.connect(hostname, {username: username, password: password }) + + const ftsMatchPrefix = async (term) => { + try { + const result = await cluster.searchQuery( + "e-ngram-2-8", + couchbase.SearchQuery.queryString(term), { limit: 8, fields: ["name"] } + ) + result.rows.forEach((row) => { console.log(row.id,row.fields)}) + } catch (error) { + console.error(error) + } + } + + const inputStr = "Beaufort Hotel" + for (let i = 2; i <= 8; i++) { + var testStr = inputStr.substring(0, i); + console.log("Input <" + testStr + ">, len: " + testStr.length) + const res = await ftsMatchPrefix(testStr) + } +} + +main() + diff --git a/modules/search/examples/autocomplete-sample.py b/modules/search/examples/autocomplete-sample.py new file mode 100644 index 000000000..b915225bf --- /dev/null +++ b/modules/search/examples/autocomplete-sample.py @@ -0,0 +1,32 @@ +from couchbase.cluster import Cluster, ClusterOptions +from couchbase.auth import PasswordAuthenticator +from couchbase.exceptions import CouchbaseException +import couchbase.search as search +import os + +username = os.getenv("CB_USERNAME", default=None) +password = os.getenv("CB_PASSWORD", default=None) +hostname = os.getenv("CB_HOSTNAME", default=None) + +cluster = Cluster.connect( + "couchbase://" + hostname, + ClusterOptions(PasswordAuthenticator(username,password))) + +try: + inputStr = "Beaufort Hotel" + for i in range(2, min(8,len(inputStr))): + testStr = inputStr[0:i] + print("Input <" + testStr + ">, len: " + str(len(testStr))); + + result = cluster.search_query( + "e-ngram-2-8", + search.QueryStringQuery(testStr), + search.SearchOptions(limit=8, fields=["name"])) + + for row in result.rows(): + print(row.id,row.fields) + +except CouchbaseException as ex: + import traceback + traceback.print_exc() + diff --git a/modules/search/examples/autocomplete-search-index.jsonc b/modules/search/examples/autocomplete-search-index.jsonc new file mode 100644 index 000000000..5733dcffc --- /dev/null +++ b/modules/search/examples/autocomplete-search-index.jsonc @@ -0,0 +1,86 @@ +{ + "type": "fulltext-index", + "name": "$INDEX_NAME", + "sourceType": "gocbcore", + "sourceName": "$BUCKET_NAME", + "planParams": { + "maxPartitionsPerPIndex": 1024, + "indexPartitions": 1 + }, + "params": { + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "scope.collection.type_field", + "type_field": "type" + }, + "mapping": { + "analysis": { + "analyzers": { + "edge_ngram": { + "token_filters": [ + "to_lower", + "edge_ngram_2_8" + ], + "tokenizer": "unicode", + "type": "custom" + }, + "keyword_to_lower": { + "token_filters": [ + "to_lower" + ], + "tokenizer": "single", + "type": "custom" + } + }, + "token_filters": { + "edge_ngram_2_8": { + "back": false, + "max": 8, + "min": 2, + "type": "edge_ngram" + } + } + }, + "default_analyzer": "keyword_to_lower", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "default_mapping": { + "dynamic": true, + "enabled": false + }, + "default_type": "_default", + "docvalues_dynamic": false, + "index_dynamic": true, + "store_dynamic": false, + "type_field": "_type", + "types": { + "$SCOPE_NAME.$COLLECTION_NAME": { + "dynamic": false, + "enabled": true, + "properties": { + "$FIELD_NAME": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "analyzer": "edge_ngram", + "include_in_all": true, + "index": true, + "name": "$FIELD_NAME", + "store": true, + "type": "text" + } + ] + } + } + } + } + }, + "store": { + "indexType": "scorch", + "segmentVersion": 15 + } + }, + "sourceParams": {} + } diff --git a/modules/search/examples/complex-search-index-payload.jsonc b/modules/search/examples/complex-search-index-payload.jsonc index 6e6acb2c7..7e3826fbf 100644 --- a/modules/search/examples/complex-search-index-payload.jsonc +++ b/modules/search/examples/complex-search-index-payload.jsonc @@ -1,173 +1,210 @@ { - // tag::initial[] - "name": "travel-sample._default.gfx", - "type": "fulltext-index", - "uuid": "28b999e9e17dd4a7", - "sourceType": "gocbcore", - "sourceName": "travel-sample", - "sourceUUID": "d3604c0ec4792b4c6c5f7f2cc8207b80", - "sourceParams": {}, - // tag::planparams[] - "planParams": { - "maxPartitionsPerPIndex": 1024, - "indexPartitions": 1, - "numReplicas": 0 - }, - // end::planparams[] - "params": { - // end::initial[] - // tag::doc_config[] - "doc_config": { - "docid_prefix_delim": "", - "docid_regexp": "", - "mode": "scope.collection.type_field", - "type_field": "type" + "name": "travel-sample._default.gfx", + "type": "fulltext-index", + "uuid": "28b999e9e17dd4a7", + "sourceType": "gocbcore", + "sourceName": "travel-sample", + "sourceUUID": "d3604c0ec4792b4c6c5f7f2cc8207b80", + "sourceParams": {}, + "planParams": { + "maxPartitionsPerPIndex": 1024, + "indexPartitions": 1, + "numReplicas": 0 + }, + "params": { + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "scope.collection.type_field", + "type_field": "type" + }, + "mapping": { + "analysis": { + "analyzers": { + "My_Analyzer": { + "token_filters": [ + "apostrophe", + "My_Token_Filter" + ], + "char_filters": [ + "asciifolding", + "html", + "My_Char_Filter" + ], + "type": "custom", + "tokenizer": "My_Tokenizer" + } }, - // end::doc_config[] - "mapping": { - "analysis": { - // tag::analyzers[] - "analyzers": { - "My_Analyzer": { - "token_filters": [ - "apostrophe", - "My_Token_Filter" - ], - "char_filters": [ - "asciifolding", - "html", - "My_Char_Filter" - ], - "type": "custom", - "tokenizer": "My_Tokenizer" - } - }, - // end::analyzers[] - // tag::char_filter[] - "char_filters": { - "My_Char_Filter": { - "regexp": "[']", - "replace": " ", - "type": "regexp" - } - }, - // end::char_filter[] - // tag::tokenizers[] - "tokenizers": { - "My_Tokenizer_Excep": { - "exceptions": [ - "[*]" - ], - "tokenizer": "unicode", - "type": "exception" - }, - "My_Tokenizer_RegExp": { - "regexp": "[*]", - "type": "regexp" - } - }, - // end::tokenizers[] - // tag::token_filters[] - "token_filters": { - "My_Token_Filter": { - "min": 3, - "max": 255, - "type": "length" - } - }, - // end::token_filters[] - // tag::token_maps[] - "token_maps": { - "My_Wordlist": { - "type": "custom", - "tokens": [ - "the", - "is", - "and" - ] - } - }, - // end::token_maps[] - // tag::date_time[] - "date_time_parsers": { - "My_Date_Time_Parser": { - "type": "flexiblego", - "layouts": [ - "RFC850" - ] - } - } - // end::date_time[] + "char_filters": { + "My_Char_Filter": { + "regexp": "[']", + "replace": " ", + "type": "regexp" + } + }, + "tokenizers": { + "My_Tokenizer_Excep": { + "exceptions": [ + "[*]" + ], + "tokenizer": "unicode", + "type": "exception" }, - "default_analyzer": "standard", - "default_datetime_parser": "dateTimeOptional", - "default_field": "_all", - // tag::default_mapping[] - "default_mapping": { - "dynamic": false, - "enabled": false + "My_Tokenizer_RegExp": { + "regexp": "[*]", + "type": "regexp" + } + }, + "token_filters": { + // tag::dict_compound[] + "My_Dict_Compound_Filter": { + "dict_token_map": "articles_ca", + "type": "dict_compound" + }, + // end::dict_compound[] + // tag::edge_ngram[] + "My_Edge_ngram_Filter": { + "back": false, + "min": 4, + "max": 5, + "type": "edge_ngram" + }, + // end::edge_ngram[] + // tag::elision[] + "My_Elision_Filter": { + "articles_token_map": "stop_fr", + "type": "elision" + }, + // end::elision[] + // tag::keyword_marker[] + "My_Keyword_Marker_Filter": { + "keywords_token_map": "articles_ca", + "type": "keyword_marker" + }, + // end::keyword_marker[] + // tag::length[] + "My_Length_Filter": { + "min": 2, + "max": 4, + "type": "length" + }, + // end::length[] + // tag::ngram[] + "My_Ngram_Filter": { + "min": 4, + "max": 5, + "type": "ngram" }, - // end::default_mapping[] - "default_type": "_default", - "docvalues_dynamic": true, - "index_dynamic": true, - "store_dynamic": true, - "type_field": "_type", - // tag::types[] - "types": { - "inventory.hotel": { + // end::ngram[] + // tag::normalize_unicode[] + "My_Normalize_Unicode_Filter": { + "form": "nfkd", + "type": "normalize_unicode" + }, + // end::normalize_unicode[] + // tag::shingle[] + "My_Shingle_Filter":{ + "min": 2, + "max": 3, + "output_original": true, + "separator": " ", + "filler": "x", + "type": "shingle" + }, + // end::shingle[] + // tag::stop_tokens[] + "My_Stop_Tokens_Filter":{ + "stop_token_map": "articles_ca", + "type": "stop_tokens" + }, + // end::stop_tokens[] + // tag::truncate_token[] + "My_Truncate_Token_Filter":{ + "length": 4, + "type": "truncate_token" + } + // end::truncate_token[] + }, + "token_maps": { + "My_Wordlist": { + "type": "custom", + "tokens": [ + "the", + "is", + "and" + ] + } + }, + "date_time_parsers": { + "My_Date_Time_Parser": { + "type": "flexiblego", + "layouts": [ + "RFC850" + ] + } + } + }, + "default_analyzer": "standard", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "default_mapping": { + "dynamic": false, + "enabled": false + }, + "default_type": "_default", + "docvalues_dynamic": true, + "index_dynamic": true, + "store_dynamic": true, + "type_field": "_type", + "types": { + "inventory.hotel": { + "dynamic": false, + "enabled": true, + "properties": { + "reviews": { "dynamic": false, "enabled": true, "properties": { - "reviews": { - "dynamic": false, - "enabled": true, - "properties": { - "content": { - "enabled": true, - "dynamic": false, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "content", - "store": true, - "type": "text" - } - ] - } - } - }, - // tag::child_field[] - "city": { + "content": { "enabled": true, "dynamic": false, - // tag::fields[] "fields": [ { "docvalues": true, "include_in_all": true, "include_term_vectors": true, "index": true, - "name": "city", + "name": "content", "store": true, - "type": "text", - "analyzer": "en" + "type": "text" } ] - // end::fields[] } - // end::child_field[] } + }, + "city": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "city", + "store": true, + "type": "text", + "analyzer": "en" + } + ] } } - // end::types[] - }, - "store": { - "indexType": "scorch", - "segmentVersion": 15 + } } - } + }, + "store": { + "indexType": "scorch", + "segmentVersion": 15 + } + } } \ No newline at end of file diff --git a/modules/search/examples/create-search-index-header.sh b/modules/search/examples/create-search-index-header.sh deleted file mode 100644 index 0dc7ef1cc..000000000 --- a/modules/search/examples/create-search-index-header.sh +++ /dev/null @@ -1,3 +0,0 @@ -curl -s -XPUT -H "Content-Type: application/json" \ --u ${CB_USERNAME}:${CB_PASSWORD} http://${CB_HOSTNAME}:8094/api/index/landmark-content-index --d \ \ No newline at end of file diff --git a/modules/search/examples/create-search-index-payload.sh b/modules/search/examples/geospatial-search-index.jsonc similarity index 69% rename from modules/search/examples/create-search-index-payload.sh rename to modules/search/examples/geospatial-search-index.jsonc index 88f2435b2..242fe86ac 100644 --- a/modules/search/examples/create-search-index-payload.sh +++ b/modules/search/examples/geospatial-search-index.jsonc @@ -1,11 +1,8 @@ -curl -s -XPUT -H "Content-Type: application/json" \ --u ${CB_USERNAME}:${CB_PASSWORD} http://${CB_HOSTNAME}:8094/api/index/landmark-content-index --d \ -'{ +{ "type": "fulltext-index", - "name": "landmark-content-index", + "name": "$INDEX_NAME", "sourceType": "gocbcore", - "sourceName": "travel-sample", + "sourceName": "$BUCKET_NAME", "planParams": { "maxPartitionsPerPIndex": 1024, "indexPartitions": 1 @@ -32,22 +29,19 @@ curl -s -XPUT -H "Content-Type: application/json" \ "store_dynamic": false, "type_field": "_type", "types": { - "inventory.landmark": { - "dynamic": false, + "$SCOPE_NAME.$COLLECTION_NAME": { + "dynamic": true, "enabled": true, "properties": { - "content": { + "$FIELD_NAME": { "dynamic": false, "enabled": true, "fields": [ { - "docvalues": true, "include_in_all": true, - "include_term_vectors": true, "index": true, - "name": "content", - "store": true, - "type": "text" + "name": "$FIELD_NAME", + "type": "geopoint" } ] } @@ -57,8 +51,9 @@ curl -s -XPUT -H "Content-Type: application/json" \ }, "store": { "indexType": "scorch", - "segmentVersion": 15 + "segmentVersion": 15, + "spatialPlugin": "s2" } }, "sourceParams": {} - }' \ No newline at end of file + } \ No newline at end of file diff --git a/modules/search/examples/geospatial-search-query.jsonc b/modules/search/examples/geospatial-search-query.jsonc new file mode 100644 index 000000000..0448d6288 --- /dev/null +++ b/modules/search/examples/geospatial-search-query.jsonc @@ -0,0 +1,23 @@ +{ + "from": 0, + "size": 10, + "query": { + "location": { + "lon": -2.235143, + "lat": 53.482358 + }, + "distance": "100mi", + "field": "geo" + }, + "sort": [ + { + "by": "geo_distance", + "field": "geo", + "unit": "mi", + "location": { + "lon": -2.235143, + "lat": 53.482358 + } + } + ] + } \ No newline at end of file diff --git a/modules/search/examples/nested-json-object-example.jsonc b/modules/search/examples/nested-json-object-example.jsonc new file mode 100644 index 000000000..79ff8dc6b --- /dev/null +++ b/modules/search/examples/nested-json-object-example.jsonc @@ -0,0 +1,38 @@ +{ + "inventory.hotel": { + "dynamic": false, + "enabled": true, + "properties": { + "_$xattrs": { + "dynamic": true, + "enabled": true + }, + "reviews": { + "dynamic": false, + "enabled": true, + "properties": { + "ratings": { + "dynamic": false, + "enabled": true, + "properties": { + "Cleanliness": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "index": true, + "name": "Cleanliness", + "store": true, + "type": "number" + } + ] + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/modules/search/examples/query-analytic.jsonc b/modules/search/examples/query-analytic.jsonc new file mode 100644 index 000000000..4e060487b --- /dev/null +++ b/modules/search/examples/query-analytic.jsonc @@ -0,0 +1,53 @@ +// tag::match[] +{ + "query": { + "match": "best great", + "field": "reviews.content", + "analyzer": "standard", + "operator": "or" + } +} +// end::match[] +// tag::match_analyzer[] +{ + "query":{ + "match": "location hostel", + "field": "reviews.content", + "analyzer": "en" + } +} +// end::match_analyzer[] +// tag::match_operator[] +{ + "query": { + "match": "best worst", + "field": "reviews.content", + "operator": "or" + } +} +// end::match_operator[] +// tag::match_prefix_length[] +{ + "query": { + "match": "location hostel", + "field": "reviews.content", + "prefix_length": 4 + } +} +// end::match_prefix_length[] +// tag::match_phrase[] +{ + "query": { + "match_phrase": "very nice", + "field": "reviews.content" + } +} +// end::match_phrase[] + +// tag::short_match_phrase[] +{ + "query": { + "query": "continental breakfast" + } +} +// end::short_match_phrase[] \ No newline at end of file diff --git a/modules/search/examples/query-boolean.jsonc b/modules/search/examples/query-boolean.jsonc new file mode 100644 index 000000000..d214f77ec --- /dev/null +++ b/modules/search/examples/query-boolean.jsonc @@ -0,0 +1,109 @@ +// tag::short[] +{ + "query": { + "query": "+description:pool -continental breakfast" + } +} +// end::short[] + +// tag::long[] +{ + "query":{ + "must":{ + "conjuncts":[ + { + "field": "reviews.content", + "match": "location" + }, + { + "field":"reviews.content", + "match_phrase": "nice view" + } + ] + }, + "must_not":{ + "disjuncts":[ + { + "field": "free_breakfast", + "bool": false + }, + { + "field": "ratings.Cleanliness", + "min": 1, + "max": 3 + } + ] + }, + "should":{ + "disjuncts":[ + { + "field": "free_parking", + "bool": true + }, + { + "field": "free_internet", + "bool": true + } + ], + "min": 1 + } + } +} +// end::long[] + +// tag::must[] +{ + "query":{ + "must":{ + "conjuncts":[ + { + "field": "reviews.content", + "match": "location" + }, + { + "field":"reviews.content", + "match_phrase": "nice view" + } + ] + } + } +} +// end::must[] +// tag::must_not[] +{ + "query":{ + "must_not":{ + "disjuncts":[ + { + "field": "free_breakfast", + "bool": false + }, + { + "field": "ratings.Cleanliness", + "min": 1, + "max": 3 + } + ] + } + } +} +// end::must_not[] +// tag::should[] +{ + "query":{ + "should":{ + "disjuncts":[ + { + "field": "free_parking", + "bool": true + }, + { + "field": "free_internet", + "bool": true + } + ], + "min": 1 + } + } +} +// end::should[] \ No newline at end of file diff --git a/modules/search/examples/query-boost.jsonc b/modules/search/examples/query-boost.jsonc new file mode 100644 index 000000000..1d9d15cef --- /dev/null +++ b/modules/search/examples/query-boost.jsonc @@ -0,0 +1,25 @@ +// tag::short[] +{ + "query": { + "query": "description:pool name:pool^5" + } +} +// end::short[] + +// tag::long[] +{ + "query": { + "disjuncts": [ + { + "match": "glossop", + "field": "city", + "boost": 10 + }, + { + "match": "glossop", + "field": "title" + } + ] + } +} +// end::long[] \ No newline at end of file diff --git a/modules/search/examples/query-compound.jsonc b/modules/search/examples/query-compound.jsonc new file mode 100644 index 000000000..fa77e76f5 --- /dev/null +++ b/modules/search/examples/query-compound.jsonc @@ -0,0 +1,37 @@ +// tag::conjuncts[] +{ + "query":{ + "conjuncts":[ + { + "field": "reviews.date", + "start": "2001-10-09", + "end": "2016-10-31", + "inclusive_start": false, + "inclusive_end": false + }, + { + "field": "description", + "match": "pool" + } + ] + } +} +// end::conjuncts[] + +// tag::disjuncts[] +{ + "query":{ + "disjuncts":[ + { + "field": "free_parking", + "bool": true + }, + { + "field": "checkin", + "match": "1PM" + } + ], + "min": 1 + } +} +// end::disjuncts[] \ No newline at end of file diff --git a/modules/search/examples/query-date-range.jsonc b/modules/search/examples/query-date-range.jsonc new file mode 100644 index 000000000..44eda9e9e --- /dev/null +++ b/modules/search/examples/query-date-range.jsonc @@ -0,0 +1,19 @@ +// tag::short[] +{ + "query": { + "query": "reviews.date:>\"2012-09-21\"" + } +} +// end::short[] + +// tag::long[] +{ + "query": { + "start": "2001-10-09T10:20:30-08:00", + "end": "2016-10-31", + "inclusive_start": false, + "inclusive_end": false, + "field": "reviews.date" + } +} +// end::long[] \ No newline at end of file diff --git a/modules/search/examples/query-escape-characters.jsonc b/modules/search/examples/query-escape-characters.jsonc new file mode 100644 index 000000000..a49e516b9 --- /dev/null +++ b/modules/search/examples/query-escape-characters.jsonc @@ -0,0 +1,15 @@ +// tag::exclamation[] +{ + "query": { + "query": "\!" + } +} +// end::exclamation[] + +// tag::quotes[] +{ + "query": { + "query": "\" a phrase in quotes \"" + } +} +// end::quotes[] \ No newline at end of file diff --git a/modules/search/examples/query-field-name.jsonc b/modules/search/examples/query-field-name.jsonc new file mode 100644 index 000000000..06b3c15d3 --- /dev/null +++ b/modules/search/examples/query-field-name.jsonc @@ -0,0 +1,15 @@ +// tag::short[] +{ + "query": { + "query": "description:pool" + } +} +// end::short[] + +// tag::xattrs[] +{ + "query": { + "query": "_$xattrs.description:sample" + } +} +// end::xattrs[] \ No newline at end of file diff --git a/modules/search/examples/query-geojson.jsonc b/modules/search/examples/query-geojson.jsonc new file mode 100644 index 000000000..fbc32802c --- /dev/null +++ b/modules/search/examples/query-geojson.jsonc @@ -0,0 +1,210 @@ +// tag::point[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "Point", + "coordinates": [0.47482593026924746, 51.31232878073189] + }, + "relation": "intersects" + } + } +} +// end::point[] +// tag::linestring[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "LineString", + "coordinates": [ + [-2.753735609842721, 53.94860827535115], + [-2.599898256093695,53.65007434185782] + ] + }, + "relation": "intersects" + } + } +} +// end::linestring[] +// tag::polygon[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "Polygon", + "coordinates": [ + [ + [ + 0.47482593026924746, + 51.31232878073189 + ], + [ + 0.6143265647863245, + 51.31232878073189 + ], + [ + 0.6143265647863245, + 51.384000374770466 + ], + [ + 0.47482593026924746, + 51.384000374770466 + ], + [ + 0.47482593026924746, + 51.31232878073189 + ] + ] + ] + }, + "relation": "within" + } + } +} +// end::polygon[] +// tag::multipoint[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "MultiPoint", + "coordinates": [ + [1.954764, 50.962097], + [3.029578, 49.868547] + ] + }, + "relation": "intersects" + } + } +} +// end::multipoint[] +// tag::multilinestring[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "MultiLineString", + "coordinates": [ + [ [1.954764, 50.962097], [3.029578, 49.868547] ], + [ [3.029578, 49.868547], [-0.387444, 48.545836] ] + ] + }, + "relation": "intersects" + } + } +} +// end::multilinestring[] +// tag::multipolygon[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "MultiPolygon", + "coordinates": [ + [ + [[-1.8167959002718135, 53.8626654046235], + [-1.8728039536828476, 53.6335890387158], + [-1.4029586167332582, 53.57727933778668], + [-1.0031233465474827, 53.664942195474936], + [-1.1742590653039997, 53.84522968338081], + [-1.5523134258297944, 53.89384804206853], + [-1.8167959002718135, 53.8626654046235]] + ], + [ + [[-2.4935598789906805, 53.64373525825596], + [-2.664695597747226, 53.33735696804186], + [-2.0143798664721544, 53.28065279675474], + [-1.8572461610683888, 53.550482816448266], + [-2.309977926141812, 53.604982015453714], + [-2.4935598789906805, 53.64373525825596]] + ] + ] + }, + "relation": "within" + } + } +} +// end::multipolygon[] +// tag::geometrycollection[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "GeometryCollection", + "geometries": [ + { + "type": "LineString", + "coordinates": [ + [-2.753735609842721, 53.94860827535115], + [-2.599898256093695, 53.65007434185782] + ] + }, + { + "type": "MultiPolygon", + "coordinates": [ + [[ + [-1.8167959002718135, 53.8626654046235], + [-1.8728039536828476, 53.6335890387158], + [-1.4029586167332582, 53.57727933778668], + [-1.0031233465474827, 53.664942195474936], + [-1.1742590653039997, 53.84522968338081], + [-1.5523134258297944, 53.89384804206853], + [-1.8167959002718135, 53.8626654046235] + ]], + [[ + [-2.4935598789906805, 53.64373525825596], + [-2.664695597747226, 53.33735696804186], + [-2.0143798664721544, 53.28065279675474], + [-1.8572461610683888, 53.550482816448266], + [-2.309977926141812, 53.604982015453714], + [-2.4935598789906805, 53.64373525825596] + ]] + ] + } + ] + }, + "relation": "contains" + } + } +} +// end::geometrycollection[] +// tag::circle[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "coordinates": [-2.2450285424707204, 53.48503270828377], + "type": "Circle", + "radius": "100mi" + }, + "relation": "within" + } + } +} +// end::circle[] +// tag::envelope[] +{ + "query": { + "field": "geojson", + "geometry": { + "shape": { + "type": "Envelope", + "coordinates": [ + [-3.1720240079703785, 53.58545703217979], + [-1.8566251855731082, 53.282076725710596] + ] + }, + "relation": "intersects" + } + } +} +// end::envelope[] \ No newline at end of file diff --git a/modules/search/examples/query-geopoint.jsonc b/modules/search/examples/query-geopoint.jsonc new file mode 100644 index 000000000..425d2fbdb --- /dev/null +++ b/modules/search/examples/query-geopoint.jsonc @@ -0,0 +1,39 @@ +// tag::distance[] +{ + "query": { + "location": { + "lon": -2.235143, + "lat": 53.482358 + }, + "distance": "100mi", + "field": "geo" + } +} +// end::distance[] +// tag::rectangle[] +{ + "query": { + "top_left": [-2.235143, 53.482358], + "bottom_right": { + "lon": 28.955043, + "lat": 40.991862 + }, + "field": "geo" + } +} +// end::rectangle[] +// tag::polygon[] +{ + "query": { + "field": "geo", + "polygon_points": [ + "37.79393211306212,-122.44234633404847", + "37.77995881733997,-122.43977141339417", + "37.788031092020155,-122.42925715405579", + "37.79026946582319,-122.41149020154114", + "37.79571192027403,-122.40735054016113", + "37.79393211306212,-122.44234633404847" + ] + } +} +// end::polygon[] \ No newline at end of file diff --git a/modules/search/examples/query-ip-range.jsonc b/modules/search/examples/query-ip-range.jsonc new file mode 100644 index 000000000..f8bf914f0 --- /dev/null +++ b/modules/search/examples/query-ip-range.jsonc @@ -0,0 +1,14 @@ +{ + "query": { + "conjuncts": [ + { + "cidr": "2.7.13.0/24", + "field": "ipv4" + }, + { + "cidr": "2001:db8:1234:5678::/119", + "field": "ipv6" + } + ] + } +} diff --git a/modules/search/examples/query-non-analytic.jsonc b/modules/search/examples/query-non-analytic.jsonc new file mode 100644 index 000000000..d7817344f --- /dev/null +++ b/modules/search/examples/query-non-analytic.jsonc @@ -0,0 +1,54 @@ +// tag::bool[] +{ + "query": { + "field": "pets_ok", + "bool": true + } +} +// end::bool[] + +// tag::prefix[] +{ + "query": { + "prefix": "inter", + "field": "reviews.content" + } +} +// end::prefix[] + +// tag::regexp[] +{ + "query": { + "regexp": "plan.+", + "field": "reviews.content" + } +} +// end::regexp[] + +// tag::term[] +{ + "query": { + "term": "interest", + "field": "reviews.content", + "fuzziness": 2 + } +} +// end::term[] + +// tag::phrase[] +{ + "query": { + "terms": ["nice", "view"], + "field": "reviews.content" + } +} +// end::phrase[] + +// tag::wildcard[] +{ + "query": { + "wildcard": "inter*", + "field": "reviews.content" + } +} +// end::wildcard[] \ No newline at end of file diff --git a/modules/search/examples/query-numeric-range.jsonc b/modules/search/examples/query-numeric-range.jsonc new file mode 100644 index 000000000..180a19766 --- /dev/null +++ b/modules/search/examples/query-numeric-range.jsonc @@ -0,0 +1,19 @@ +// tag::short[] +{ + "query": { + "query": "reviews.ratings.Cleanliness:>4" + } +} +// end::short[] + +// tag::long[] +{ + "query": { + "min": 3, + "max": 5, + "inclusive_min": false, + "inclusive_max": true, + "field": "reviews.ratings.Cleanliness" + } +} +// end::long[] \ No newline at end of file diff --git a/modules/search/examples/query-special.jsonc b/modules/search/examples/query-special.jsonc new file mode 100644 index 000000000..3c968adc6 --- /dev/null +++ b/modules/search/examples/query-special.jsonc @@ -0,0 +1,15 @@ +// tag::match_all[] +{ + "query": { + "match_all": {} + } +} +// end::match_all[] + +// tag::match_none[] +{ + "query": { + "match_none": {} + } +} +// end::match_none[] \ No newline at end of file diff --git a/modules/search/examples/query-term-range.jsonc b/modules/search/examples/query-term-range.jsonc new file mode 100644 index 000000000..2677c84db --- /dev/null +++ b/modules/search/examples/query-term-range.jsonc @@ -0,0 +1,9 @@ +{ + "query": { + "min": "be", + "max": "beautiful", + "inclusive_min": true, + "inclusive_max": true, + "field": "reviews.content" + } +} \ No newline at end of file diff --git a/modules/search/examples/run-search-full-request.jsonc b/modules/search/examples/run-search-full-request.jsonc new file mode 100644 index 000000000..c2389966e --- /dev/null +++ b/modules/search/examples/run-search-full-request.jsonc @@ -0,0 +1,172 @@ +// tag::full[] +// tag::query[] +{ + "query": { + "must": { + "conjuncts":[ + { + "field": "free_breakfast", + "bool": false + }, + { + "field": "reviews.ratings.Cleanliness", + "min": 1, + "max": 3, + "inclusive_min": true, + "inclusive_max": false + } + ] + }, + "must_not": { + "disjuncts": [ + { + "field": "geojson", + "geometry": { + "shape": { + "coordinates": [-2.2450285424707204, 53.48503270828377], + "type": "circle", + "radius": "100mi" + }, + "relation": "within" + } + } + ], + "min": 1 + }, + "should": { + "disjuncts": [ + { + "match_phrase": "very nice", + "field": "reviews.content" + } + ] + } + }, + // end::query[] + // tag::knn[] + "knn": [ + { + "k": 10, + "params": { + "ivf_nprobe_pct": 1, + "ivf_max_codes_pct": 0.2 + }, + "field": "vector_field", + "vector": [ 0.707106781186548, 0, 0.707106781186548 ], + "filter": { + "min": 10000, + "field": "id" + } + } + ], + // end::knn[] + // tag::ctl[] + "ctl": { + "timeout": 10000, + // tag::consistency[] + "consistency": { + // tag::vectors[] + "vectors": { + "searchIndexName": { + "607/205096593892159": 2, + "640/298739127912798": 4 + } + }, + // end::vectors[] + "level": "at_plus", + "results": "complete" + }, + // end::consistency[] + "validate": true + }, + // end::ctl[] + "size": 10, + "from": 0, + // tag::highlight[] + "highlight": { + + "style": "html", + "fields": ["textField"] + + }, + // end::highlight[] + "fields": ["textField"], + // tag::facets[] + "facets": { + + "field1": { + "size": 5, + "field": "field1" + }, + + "field2": { + "size": 5, + "field": "field2", + // tag::numeric_ranges[] + "numeric_ranges": [ + { + + "name": "high", + "min": 7, + "max": 10 + + }, + { + + "name": "low", + "min": 0, + "max": 7 + + } + ] + // end::numeric_ranges[] + }, + + "field3": { + "size": 10, + "field": "dateField", + // tag::date_ranges[] + "date_ranges": [ + { + "name": "old", + "start": "2020-12-31", + "end": "2023-12-31" + }, + { + "name": "new", + "start": "2023-12-31", + "end": "2024-12-31" + } + ] + // end::date_ranges[] + } + + }, + // end::facets[] + "explain": true, + // tag::sort[] + "sort": [ + + "field1", + { + "by": "field", + "field": "field2", + "desc": false, + "mode": "default", + "missing": "last", + "type": "string" + }, + "-_score", + "-_id" + + ], + // end::sort[] + "includeLocations": false, + "score": "none", + "search_after": ["field1String", "field2String", "10.033205341869529", "hotel_1234"], + "search_before": ["field1String", "field2String", "10.033205341869529", "hotel_1234"], + "limit": 10, + "offset": 0, + "collections": ["collection1", "collection2"] +} +// end::full[] \ No newline at end of file diff --git a/modules/search/examples/run-search-header.sh b/modules/search/examples/run-search-header.sh deleted file mode 100644 index 031380c0d..000000000 --- a/modules/search/examples/run-search-header.sh +++ /dev/null @@ -1,2 +0,0 @@ -curl -s -XPUT -H "Content-Type: application/json" \ --u ${CB_USERNAME}:${CB_PASSWORD} http://${CB_HOSTNAME}:8094/api/index/${INDEX-NAME}/query -d \ \ No newline at end of file diff --git a/modules/search/examples/run-search-payload-ui.jsonc b/modules/search/examples/run-search-payload-ui.jsonc index 0f8beb34b..8fb657a40 100644 --- a/modules/search/examples/run-search-payload-ui.jsonc +++ b/modules/search/examples/run-search-payload-ui.jsonc @@ -1,4 +1,3 @@ -// tag::server[] { "explain": true, "fields": [ @@ -11,4 +10,4 @@ "size": 10, "from": 0 } -// end::server[] + diff --git a/modules/search/examples/run-search-payload.sh b/modules/search/examples/run-search-payload.sh deleted file mode 100644 index 98e841baf..000000000 --- a/modules/search/examples/run-search-payload.sh +++ /dev/null @@ -1,14 +0,0 @@ -curl -XPOST -H "Content-Type: application/json" \ --u ${CB_USERNAME}:${CB_PASSWORD} http://${CB_HOSTNAME}:8094/api/index/travel-sample.inventory.landmark-content-index/query \ --d '{ - "explain": true, - "fields": [ - "*" - ], - "highlight": {}, - "query": { - "query": "+view +food +beach" - }, - "size": 10, - "from": 0 -}' \ No newline at end of file diff --git a/modules/search/examples/run-search-validate-ui.jsonc b/modules/search/examples/run-search-validate-ui.jsonc new file mode 100644 index 000000000..127ce382f --- /dev/null +++ b/modules/search/examples/run-search-validate-ui.jsonc @@ -0,0 +1,20 @@ +{ + "explain": true, + "fields": [ + "content" + ], + "highlight": {}, + "query": { + "location": { + "lon": -2.235143, + "lat": 53.482358 + }, + "distance": "100mi", + "field": "geo" + }, + "ctl": { + "validate": true + }, + "size": 10, + "from": 0 +} \ No newline at end of file diff --git a/modules/search/examples/search-index-alias.jsonc b/modules/search/examples/search-index-alias.jsonc new file mode 100644 index 000000000..f7a032b93 --- /dev/null +++ b/modules/search/examples/search-index-alias.jsonc @@ -0,0 +1,17 @@ +{ + "name": "travel-color-index", + "type": "fulltext-alias", + "params": { + "targets": { + "travel-sample.inventory.travel-index": {}, + "color-vector-sample.color.color-test": {} + } + }, + "sourceType": "nil", + "sourceName": "", + "sourceUUID": "", + "sourceParams": null, + "planParams": {}, + "uuid": "", + "id": "" + } diff --git a/modules/search/examples/short-search-index.jsonc b/modules/search/examples/short-search-index.jsonc new file mode 100644 index 000000000..2c70b082f --- /dev/null +++ b/modules/search/examples/short-search-index.jsonc @@ -0,0 +1,47 @@ +{ + "type": "fulltext-index", + "name": "travel-sample.inventory.travel-index", + "uuid": "2c4b22c60b59c524", + "sourceType": "gocbcore", + "sourceName": "travel-sample", + "sourceUUID": "76a82f1f3471d9fae3b483f9ee75459d", + "planParams": { + "maxPartitionsPerPIndex": 1024, + "indexPartitions": 1 + }, + "params": { + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "scope.collection.type_field", + "type_field": "type" + }, + "mapping": { + "analysis": {}, + "default_analyzer": "standard", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "default_mapping": { + "dynamic": false, + "enabled": false + }, + "default_type": "_default", + "docvalues_dynamic": false, + "index_dynamic": false, + "store_dynamic": false, + "type_field": "_type", + "types": { + "inventory.airline": { + "dynamic": false, + "enabled": true, + "properties": {} + } + } + }, + "store": { + "indexType": "scorch", + "segmentVersion": 15 + } + }, + "sourceParams": {} + } \ No newline at end of file diff --git a/modules/search/examples/simple-search-index-payload.jsonc b/modules/search/examples/simple-search-index-payload.jsonc new file mode 100644 index 000000000..d52642edd --- /dev/null +++ b/modules/search/examples/simple-search-index-payload.jsonc @@ -0,0 +1,193 @@ +// tag::json-snippet[] +{ + "name": "gfx", + "type": "fulltext-index", + "uuid": "28b999e9e17dd4a7", + "sourceType": "gocbcore", + "sourceName": "travel-sample", + "sourceUUID": "d3604c0ec4792b4c6c5f7f2cc8207b80", + "sourceParams": {}, + // tag::plan-params[] + "planParams": { + "maxPartitionsPerPIndex": 1024, + "indexPartitions": 1, + "numReplicas": 0 + }, + // end::plan-params[] + "params": { + // end::json-snippet[] + // tag::doc_config[] + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "scope.collection.type_field", + "type_field": "type" + }, + // end::doc_config[] + // tag::mapping[] + "mapping": { + "analysis": { + // tag::analyzers[] + "analyzers": { + // tag::analyzer_name[] + "My_Analyzer": { + "token_filters": [ + "apostrophe", + "My_Token_Filter" + ], + "char_filters": [ + "asciifolding", + "html", + "My_Char_Filter" + ], + "type": "custom", + "tokenizer": "My_Tokenizer_Excep" + } + // end::analyzer_name[] + }, + // end::analyzers[] + // tag::char_filters[] + "char_filters": { + // tag::char_filter_name[] + "My_Char_Filter": { + "regexp": "[']", + "replace": " ", + "type": "regexp" + } + // end::char_filter_name[] + }, + // end::char_filters[] + // tag::tokenizers[] + "tokenizers": { + // tag::tokenizer_name[] + "My_Tokenizer_Excep": { + "exceptions": [ + "[*]" + ], + "tokenizer": "unicode", + "type": "exception" + }, + // end::tokenizer_name[] + "My_Tokenizer_RegExp": { + "regexp": "[*]", + "type": "regexp" + } + }, + // end::tokenizers[] + // tag::token_filters[] + "token_filters": { + // end::mapping[] + // tag::token_filter_name[] + "My_Token_Filter": { + "min": 3, + "max": 255, + "type": "length" + } + // end::token_filter_name[] + }, + // end::token_filters[] + // tag::token_maps[] + "token_maps": { + // tag::wordlist_name[] + "My_Wordlist": { + "type": "custom", + "tokens": [ + "the", + "is", + "and" + ] + } + // end::wordlist_name[] + }, + // end::token_maps[] + // tag::date_time_parsers[] + "date_time_parsers": { + // tag::date_time_parser_name[] + "My_Date_Time_Parser": { + "type": "flexiblego", + "layouts": [ + "RFC850" + ] + } + // end::date_time_parser_name[] + } + // end::date_time_parsers[] + }, + "default_analyzer": "standard", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + // tag::default_mapping[] + "default_mapping": { + "dynamic": false, + "enabled": false + }, + // end::default_mapping[] + "default_type": "_default", + "docvalues_dynamic": true, + "index_dynamic": true, + "store_dynamic": true, + "type_field": "_type", + // tag::types[] + "types": { + // tag::scope_collection[] + "inventory.hotel": { + "dynamic": false, + "enabled": true, + "properties": { + "_$xattrs": { + "dynamic": true, + "enabled": true + }, + // tag::field_name[] + "reviews": { + "dynamic": false, + "enabled": true, + "properties": { + "content": { + "enabled": true, + "dynamic": false, + // tag::fields[] + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "content", + "store": true, + "type": "text", + "analyzer": "My_Analyzer" + } + ] + // end::fields[] + } + } + }, + // end::field_name[] + "city": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "city", + "store": true, + "type": "text" + } + ] + } + } + } + // end::scope_collection[] + } + // end::types[] + }, + "store": { + "indexType": "scorch", + "segmentVersion": 15 + } + } +} diff --git a/modules/search/pages/create-child-field.adoc b/modules/search/pages/create-child-field.adoc deleted file mode 100644 index 3098404cd..000000000 --- a/modules/search/pages/create-child-field.adoc +++ /dev/null @@ -1,47 +0,0 @@ -= Create a Child Field With The UI -:page-topic-type: guide -:tabs: - -== Prerequisites - -* You've created an index. -For more information, see xref:search/create-search-index-ui.adoc[]. - -* You've created a type mapping. -For more information about how to create a type mapping on an index, see xref:search/create-type-mapping.adoc[]. - -* You've logged in to the Couchbase Server Web Console or Capella UI. - - -== Procedure - -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Click the index where you want to create a child field. -. Click btn:[Edit]. -. Expand *Customize Index*. -. Expand *Mappings*. -. Point to an existing mapping and click btn:[+]. -. Click *insert child field*. -include::partial$create-child-field-steps.adoc[] -. Click btn:[OK]. --- - -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a child field. -. Go to menu:Data Tools[Search]. -. Click the name of the index where you want to create a child field. -. Expand *Advanced Configuration*. -. Expand *Type Mappings*. -. Click the *More Options* (⋮) menu. -. Click *Insert Child Field*. -include::partial$create-child-field-steps.adoc[] -. Click btn:[Submit]. --- -==== \ No newline at end of file diff --git a/modules/search/pages/create-child-mapping.adoc b/modules/search/pages/create-child-mapping.adoc deleted file mode 100644 index b1b7a3db8..000000000 --- a/modules/search/pages/create-child-mapping.adoc +++ /dev/null @@ -1,54 +0,0 @@ -= Create a Child Mapping With The UI -:page-topic-type: guide -:tabs: - -== Prerequisites - -* You've created an index. -For more information, see xref:search/create-search-index-ui.adoc[]. - -* You've created a type mapping. -For more information about how to create a type mapping on an index, see xref:search/create-type-mapping.adoc[]. - -* You've logged in to the Couchbase Server Web Console or Capella UI. - -== Procedure - -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Click the index where you want to create a child mapping. -. Click btn:[Edit]. -. Expand *Customize Index*. -. Expand *Mappings*. -. Point to an existing mapping and click btn:[+]. -. Click *insert child mapping*. -. In the *{}* field, enter the name of a JSON object field in your database's documents. -. (Optional) To only index the fields you add to the child mapping, select *only index specified fields*. -. (Optional) To set a different analyzer for the child mapping, in the *Analyzer* list, select an analyzer. -+ -For more information about the available default analyzers, see xref:search/default-analyzers-reference.adoc[]. -. Click btn:[OK]. --- - -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a child mapping. -. Go to menu:Data Tools[Search]. -. Click the name of the index where you want to create a child mapping. -. Expand *Advanced Configuration*. -. Expand *Type Mappings*. -. Click the *More Options* (⋮) menu. -. Click *Insert Child Mapping*. -. In the *Name* field, enter the name of a JSON object field in your database's documents. -. (Optional) To set a different analyzer for the child mapping, in the *Default Analyzer* list, select an analyzer. -+ -For more information about the available default analyzers, see xref:search/default-analyzers-reference.adoc[]. -. (Optional) To only index the fields you add to the child mapping, clear *Index all contained fields*. -. Click btn:[Submit]. --- -==== \ No newline at end of file diff --git a/modules/search/pages/create-custom-analyzer.adoc b/modules/search/pages/create-custom-analyzer.adoc index b708514c2..7a722da84 100644 --- a/modules/search/pages/create-custom-analyzer.adoc +++ b/modules/search/pages/create-custom-analyzer.adoc @@ -1,43 +1,100 @@ -= Create a Custom Analyzer -:tabs: += Create a Custom Analyzer :page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Create a custom analyzer with the Couchbase {page-ui-name}'s Advanced Mode to modify the input text from a Search query or Search index and improve search results. + +[abstract] +{description} +For more information, see xref:customize-index.adoc#analyzers[Search Index Features]. + +NOTE: You must use Advanced Mode to add a custom analyzer to your Search index. +For more information, see xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing]. == Prerequisites -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. == Procedure -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a custom analyzer on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a custom analyzer on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -include::partial$custom-analyzer-first-steps.adoc[] -. To add the selected character filter to the analyzer, click btn:[Add]. -include::partial$custom-analyzer-tokenizer-steps.adoc[] -. To add the selected token filter to the analyzer, click btn:[Add]. -. Click btn:[Save]. --- - -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a custom analyzer. +To create a custom analyzer with the {page-ui-name} in Advanced Mode: + +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. . Go to menu:Data Tools[Search]. -. Do one of the following: -.. To create a custom analyzer on an existing Search Index, click the index name. -.. To create a custom analyzer on a new Search Index, click btn:[Add Search Index]. -. Expand *Advanced Configuration*. -include::partial$custom-analyzer-first-steps.adoc[] -include::partial$custom-analyzer-tokenizer-steps.adoc[] -. Click btn:[Submit]. --- +. Do one of the following: +.. To work with an existing Search index, click the name of the index where you want to create a custom analyzer. +.. To create a new Search index, click btn:[Create Search Index]. +. Make sure to select *Enable Advanced Options*. +. Expand *Global Index Settings*. +. Click btn:[Add Custom Analyzer]. +. In the *Analyzer Name* field, enter a name for the new custom analyzer. +. <>. +. Click btn:[Add Custom Analyzer]. + +=== Configure Analyzer Components + +For more information about analyzers and their components, see xref:customize-index.adoc#analyzers[Analyzers]. + +Add the following components to a custom analyzer to take input text from a document or Search query and convert it into tokens: + +. <> +. <> +. <> + +[#tokenizers] +==== Configure Tokenizers + +For more information about tokenizers, see xref:customize-index.adoc#tokenizers[Tokenizers]. + +To configure the tokenizer for a custom analyzer: + +. (Optional) Create a custom tokenizer. +For more information, see xref:create-custom-tokenizer.adoc[]. +. In the *Tokenizer* list, select a tokenizer to use in your custom analyzer. +You can choose your custom tokenizer or xref:default-tokenizers-reference.adoc[use a default tokenizer]. + +[#character-filters] +==== Configure Character Filters + +For more information about character filters, see xref:customize-index.adoc#character-filters[Character Filters]. + +To add a character filter or character filters to a custom analyzer: + +. (Optional) Create 1 or more custom character filters. +For more information, see xref:create-custom-character-filter.adoc[]. +. In the *Character Filters* list, select 1 or more character filters to use in your custom analyzer. +You can choose your custom character filter or xref:default-character-filters-reference.adoc[use the default character filters]. + +Remove a character filter from your custom analyzer by clicking the *x* next to a listed filter. + +[#token-filters] +==== Configure Token Filters + +For more information about token filters, see xref:customize-index.adoc#token-filters[Token Filters]. + +To add a token filter or token filters to a custom analyzer: + +. (Optional) Create 1 or more custom token filters. +For more information, see xref:create-custom-token-filter.adoc[]. +. In the *Token Filters* list, select 1 or more token filters to use in your custom analyzer. +You can choose your custom token filter or xref:default-token-filters-reference.adoc[use the default token filters]. + +Remove a token filter from your custom analyzer by clicking the *x* next to a listed filter. + +== Next Steps + +After you create a custom analyzer, you can xref:create-search-index-ui.adoc#default-analyzer[set it as the default analyzer] for your Search index. + +You can also use the custom analyzer when you create a type mapping or mapping while you xref:create-search-index-ui.adoc[]. + +To continue customizing your Search index, you can also: -==== +* xref:set-type-identifier.adoc[] +* xref:create-custom-character-filter.adoc[] +* xref:create-custom-tokenizer.adoc[] +* xref:create-custom-token-filter.adoc[] +To run a search and test the contents of your Search index, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-custom-character-filter.adoc b/modules/search/pages/create-custom-character-filter.adoc index 1600b634f..99b3378e8 100644 --- a/modules/search/pages/create-custom-character-filter.adoc +++ b/modules/search/pages/create-custom-character-filter.adoc @@ -1,35 +1,57 @@ = Create a Custom Character Filter :page-topic-type: guide -:tabs: +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Create a custom character filter with the Couchbase {page-ui-name} to remove unwanted characters from a Search query or the contents of a Search index. + +[abstract] +{description} == Prerequisites -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. + +* You have started to create or already created an index in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing]. + +* You have already created or started to create a xref:create-custom-analyzer.adoc[custom analyzer] in your Search index. == Procedure -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a custom character filter on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a custom character filter on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -include::partial$custom-character-filter-first-steps.adoc[] --- +To create a custom character filter with the {page-ui-name} in Advanced Mode: -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a custom character filter. +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. . Go to menu:Data Tools[Search]. +. Do one of the following: +.. To work with an existing Search index, click the name of the index where you want to create a custom character filter. +.. To create a new Search index, click btn:[Create Search Index]. +. Make sure to select *Enable Advanced Options*. +. Expand *Global Index Settings*. . Do one of the following: -.. To create a custom character filter on an existing Search Index, click the index name. -.. To create a custom character filter on a new Search Index, click btn:[Add Search Index]. -* Expand *Advanced Configuration*. -include::partial$custom-character-filter-first-steps.adoc[] --- -==== \ No newline at end of file +.. To create a new custom analyzer with a new character filter, click btn:[Add Custom Analyzer]. +.. To add a new custom character filter to use with an existing analyzer, expand the *Default Analyzer* list, and next to your custom analyzer, click btn:[Edit]. +. Click btn:[Add Custom Character Filter]. +. In the *Character Filter Name* field, enter a name for the character filter. ++ +NOTE: The Search Service supports only the *regexp* Type for character filters. +. In the *Regular Expression* field, enter the regular expression for the character filter. ++ +Any analyzer that uses your character filter will remove any characters that match the regular expression from token results. ++ +For example, if you wanted to remove numeric characters from your tokens, you could use `[0-9]` as your regular expression. +. (Optional) In the *Replacement* field, enter a string that replaces any matches for the regular expression. +. Click btn:[Add Custom Character Filter]. + +== Next Steps + +After you create a custom character filter, you can use it with xref:create-custom-analyzer.adoc[a custom analyzer]. + +To continue customizing your Search index, you can also: + +* xref:set-type-identifier.adoc[] +* xref:create-custom-tokenizer.adoc[] +* xref:create-custom-token-filter.adoc[] + +To run a search and test the contents of your Search index, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-custom-date-time-parser.adoc b/modules/search/pages/create-custom-date-time-parser.adoc index baa8e83b2..bae4ead58 100644 --- a/modules/search/pages/create-custom-date-time-parser.adoc +++ b/modules/search/pages/create-custom-date-time-parser.adoc @@ -1,53 +1,52 @@ -= Create a Custom Date/Time Parser parser -:tabs: += Create a Custom Date/Time Parser :page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Create a custom date/time parser with the Couchbase {page-ui-name} to tell the Search Service how to process a new date/time format. + +[abstract] +{description} If you store date data in a format other than RFC-3339 (ISO-8601), then you need to create a date/time parser. == Prerequisites -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. + +* You have started to create or already created an index in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing]. == Procedure -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a custom date/time parser on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a custom date/time parser on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -. Expand *Date/Time Parsers*. -. Click btn:[Add Date/Time Parser] -. In the *Name* field, enter a name for the date/time parser. -. In the *Layout to be added* field, enter a date/time layout with Go syntax. -+ -For more information, see the documentation about the https://pkg.go.dev/time#pkg-constants[Go Programming Language Time Package's Layout Constant^]. -. Click btn:[Add]. -. (Optional) To add an additional layout, repeat Steps 7-8. -. Click btn:[Save]. --- +To create a custom date/time parser with the {page-ui-name} in Advanced Mode: -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a custom date/time parser. +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. . Go to menu:Data Tools[Search]. -. Do one of the following: -.. To create a custom date/time parser on an existing Search Index, click the index name. -.. To create a custom date/time parser on a new Search Index, click btn:[Add Search Index]. -. Expand *Advanced Configuration*. -. Expand *Date/Time Parsers*. -. Click btn:[Add Date/Time Parser] -. In the *Name* field, enter a name for the date/time parser. -. In the *New Word* field, enter a date/time layout with Go syntax. +. Do one of the following: +.. To work with an existing Search index, click the name of the index where you want to create a custom date/time parser. +.. To create a new Search index, click btn:[Create Search Index]. +. Make sure to select *Enable Advanced Options*. +. Expand *Global Index Settings*. +. Click btn:[Add Custom Date/Time Parser] +. In the *Date/Time Parser Name* field, enter a name for the date/time parser. +. In the *New Date and Time* field, enter a date/time layout with Go syntax. + -For more information, see the documentation about the https://pkg.go.dev/time#pkg-constants[Go Programming Language Time Package's Layout Constant^]. -. Click btn:[Add]. -. (Optional) To add an additional layout, repeat Steps 8-9. -. Click btn:[Save]. --- -==== \ No newline at end of file +For more information, see the documentation about the https://pkg.go.dev/time#pkg-constants[Go Programming Language Time Package's Layout Constant^]. +. (Optional) To add an additional layout, click btn:[Add] and enter a new layout. +. Click btn:[Add Custom Date/Time Parser]. + +== Next Steps + +After you create a custom date/time parser, you can xref:create-search-index-ui.adoc#date-time[set it as the default date/time parser] for your Search index. + +To continue customizing your Search index, you can also: + +* xref:set-type-identifier.adoc[] +* xref:create-custom-analyzer.adoc[] +* xref:create-custom-character-filter.adoc[] +* xref:create-custom-tokenizer.adoc[] +* xref:create-custom-token-filter.adoc[] + +To run a search and test the contents of your Search index, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-custom-token-filter.adoc b/modules/search/pages/create-custom-token-filter.adoc index bbd164a7d..9ac387a68 100644 --- a/modules/search/pages/create-custom-token-filter.adoc +++ b/modules/search/pages/create-custom-token-filter.adoc @@ -1,144 +1,239 @@ -= Create a Custom Token Filter -:tabs: += Create a Custom Token Filter :page-topic-type: guide -:page-toc-levels: 3 +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: create-custom-wordlist.adoc +:description: Create a custom token filter with the Couchbase {page-ui-name} to change how the Search Service creates tokens from Search index content and Search queries. +:page-toclevels: 3 + +[abstract] +{description} + +xref:customize-index.adoc#token-filters[Token filters] can improve your search results by removing characters from your Search index or Search queries that prevent matches. == Prerequisites -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. -== Procedure +* You have started to create or already created an index in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing]. -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a custom token filter on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a custom token filter on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -. Expand *Custom Filters*. -. Click btn:[Add Token Filter]. -. In the *Name* field, enter a name for the token filter. +* You have already created or started to create a xref:create-custom-analyzer.adoc[custom analyzer] in your Search index. -include::partial$custom-token-filter-tf-list.adoc[] +== Procedure --- +To create a custom token filter with the {page-ui-name} in Advanced Mode: -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a custom token filter. +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. . Go to menu:Data Tools[Search]. +. Click the name of the index where you want to create a custom analyzer. +. Make sure to select *Enable Advanced Options*. +. Expand *Global Index Settings*. . Do one of the following: -.. To create a custom token filter on an existing Search Index, click the index name. -.. To create a custom token filter on a new Search Index, click btn:[Add Search Index]. -. Expand *Advanced Configuration*. -. Expand *Custom Filters*. -. Click btn:[Add Token Filter]. -. In the *Name* field, enter a name for the token filter. +.. To create a new custom analyzer with a new token filter, click btn:[Add Custom Analyzer]. +.. To add a new custom token filter to use with an existing analyzer, expand the *Default Analyzer* list, and next to your custom analyzer, click btn:[Edit]. +. Click btn:[Add Custom Token Filter]. +. In the *Token Filter Name* field, enter a name for the token filter. +. In the *Type* list, select a token filter type. + +You can create any of the following custom token filters: + +|==== +| Token Filter Type | Description + +| <> +| Use a xref:customize-index.adoc#wordlists[word list] to find and create tokens from compound words in existing tokens. -include::partial$custom-token-filter-tf-list.adoc[] +| <> +| Use a set character length to create tokens from the start or end of existing tokens. --- +| <> +| Use a xref:customize-index.adoc#wordlists[word list] to remove elisions from input tokens. -==== +| <> +| Use a xref:customize-index.adoc#wordlists[word list] of keywords to find and create new tokens. +| <> +| Use a set character length to filter out tokens that are too long or too short. +| <> +| Use a set character length to create new tokens. + +| <> +| Use Unicode Normalization to convert tokens. + +| <> +| Use a set character length and separator to concatenate and create new tokens. + +| <> +| Use a xref:customize-index.adoc#wordlists[word list] to find and remove words from tokens. + +| <> +| Use a set character length to truncate existing tokens. + +|==== [#dict-compound] === Create a Custom `dict_compound` Token Filter + +include::partial$custom-token-filters-descriptions.adoc[tags=dict;!dict_example] + +To create a new `dict_compound` token filter with the {page-ui-name} in Advanced Mode: -. In the *Type* field, select *dict_compound*. -. In the *Sub Words* list, select an available wordlist to . -+ -You can choose your own xref:search/create-custom-wordlist.adoc[custom wordlist] or a xref:search/default-wordlists-reference.adoc[default wordlist]. -. Click btn:[Save]. +. In the *Type* list, select *dict_compound*. +. In the *Sub Words* list, do one of the following to configure how the token filter finds subwords to create new tokens: +.. Choose an available xref:default-wordlists-reference.adoc[default word list]. +.. Click btn:[Create Custom Word List]. +... In the *Word List Name* field, enter a name for the new custom word list. +... In the *Add Words* field, enter each word you want to add to your custom word list, separated by commas (`,`). +... Click btn:[Create Custom Word List]. +. Click btn:[Add Custom Token Filter]. [#edge-ngram] === Create a Custom `edge_ngram` Token Filter +include::partial$custom-token-filters-descriptions.adoc[tags=edge;!edge_example] + +To create a new `edge_ngram` token filter with the {page-ui-name} in Advanced Mode: -. In the *type* field, select *edge_ngram*. +. In the *Type* list, select *edge_ngram*. . Do one of the following: -.. To ?, select *Back*. -.. To ?, clear *Back*. -. In the *Min* field, enter . -. In the *Max* field, enter . -. Click btn:[Save]. +.. To create new tokens starting from the end of input tokens, select *Back*. +.. To create new tokens starting from the beginning of input tokens, clear *Back*. +. In the *Min* box, enter the minimum character length for a new token. +. In the *Max* box, enter the maximum character length for a new token. +. Click btn:[Add Custom Token Filter]. [#elision] === Create a Custom `elision` Token Filter -. In the *Type* field, select *elision*. -. In the *Articles* list, select an available wordlist to . -+ -You can choose your own xref:search/create-custom-wordlist.adoc[custom wordlist] or a xref:search/default-wordlists-reference.adoc[default wordlist]. -. Click btn:[Save]. +include::partial$custom-token-filters-descriptions.adoc[tags=elision;!elision_example] + +To create a new `elision` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *elision*. +. In the *Articles* list, do one of the following to choose how to find elisions in input tokens: +.. Choose an available xref:default-wordlists-reference.adoc[default word list]. +.. Click btn:[Create Custom Word List]. +... In the *Word List Name* field, enter a name for the new custom word list. +... In the *Add Words* field, enter each word you want to add to your custom word list, separated by commas (`,`). +... Click btn:[Create Custom Word List]. +. Click btn:[Add Custom Token Filter]. [#keyword-marker] === Create a Custom `keyword_marker` Token Filter -. In the *Type* field, select *keyword_marker*. -. In the *Keywords* list, select an available wordlist to . -+ -You can choose your own xref:search/create-custom-wordlist.adoc[custom wordlist] or a xref:search/default-wordlists-reference.adoc[default wordlist]. -. Click btn:[Save]. +include::partial$custom-token-filters-descriptions.adoc[tags=keyword;!keyword_example] + +To create a new `keyword_marker` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *keyword_marker*. +. In the *Articles* list, do one of the following to choose how to find keywords to create tokens: +.. Choose an available xref:default-wordlists-reference.adoc[default word list]. +.. Click btn:[Create Custom Word List]. +... In the *Word List Name* field, enter a name for the new custom word list. +... In the *Add Words* field, enter each word you want to add to your custom word list, separated by commas (`,`). +... Click btn:[Create Custom Word List]. +. Click btn:[Add Custom Token Filter]. [#length] === Create a Custom `length` Token Filter -. In the *Type* field, select *length*. -. In the *Min* field, enter . -. In the *Max* field, enter . -. Click btn:[Save]. +include::partial$custom-token-filters-descriptions.adoc[tags=length;!length_example] + +To create a new `length` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *length*. +. In the *Min* box, enter the minimum character length for a new token. +. In the *Max* box, enter the maximum character length for a new token. +. Click btn:[Add Custom Token Filter]. [#ngram] === Create a Custom `ngram` Token Filter -. In the *Type* field, select *ngram*. -. In the *Min* field, enter . -. In the *Max* field, enter . -. Click btn:[Save]. +include::partial$custom-token-filters-descriptions.adoc[tags=ngram;!ngram_example] + +To create a new `ngram` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *ngram*. +. In the *Min* box, enter the minimum character length for a new token. +. In the *Max* box, enter the maximum character length for a new token. +. Click btn:[Add Custom Token Filter]. [#normalize-unicode] === Create a Custom `normalize_unicode` Token Filter -. In the *Type* field, select *normalize_unicode*. +include::partial$custom-token-filters-descriptions.adoc[tags=normalize;!normalize_example] + +To create a new `normalize_unicode` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *normalize_unicode*. . In the *Form* list, select the type of Unicode normalization to apply: + -* *nfc*: -* *nfd*: -* *nfkc*: -* *nfkd*: -. Click btn:[Save]. +* *nfc*: Use canonical decomposition and canonical composition to normalize characters. +The token filter separates combined unicode characters, then merges them into a single character. +* *nfd*: Use canonical decomposition to normalize characters. +The token filter separates combined unicode characters. +* *nfkc*: Use compatibility decomposition to normalize characters. +The token filter converts unicode characters to remove variants. +* *nfkd*: Use compatibility decomposition and canonical composition to normalize characters. +The token filter removes variants, then separates combined unicode characters to merge them into a single character. +. Click btn:[Add Custom Token Filter]. [#shingle] === Create a Custom `shingle` Token Filter -. In the *Type* field, select *shingle*. -. In the *Min* field, enter . -. In the *Max* field, enter . +include::partial$custom-token-filters-descriptions.adoc[tags=shingle;!shingle_example] + +To create a new `shingle` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *shingle*. +. In the *Min* box, enter the minimum character length for a new token before concatenation. +. In the *Max* box, enter the maximum character length for a new token before concatenation. . Do one of the following: -.. To , select *Include original token*. -.. To , clear *Include original token*. -. In the *Separator* field, enter . -. In the *Filler* field, enter . -. Click btn:[Save]. +.. To include the original token as an output token, select *Include original token*. +.. To remove the original token from output, clear *Include original token*. +. (Optional) In the *Separator* field, enter a character or characters to add in between concatenated tokens. +. (Optional) In the *Filler* field, enter a character or characters to replace tokens that are removed by another token filter. +. Click btn:[Add Custom Token Filter]. [#stop-tokens] === Create a Custom `stop_tokens` Token Filter -. In the *Type* field, select *stop_tokens*. -. In the *Stop Words* list, select an available wordlist to . -+ -You can choose your own xref:search/create-custom-wordlist.adoc[custom wordlist] or a xref:search/default-wordlists-reference.adoc[default wordlist]. -. Click btn:[Save]. +include::partial$custom-token-filters-descriptions.adoc[tags=stop;!stop_example] + +To create a new `stop_tokens` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *stop_tokens*. +. In the *Stop Words* list, do one of the following to choose what word list the token filter should use to remove tokens: +.. Choose an available xref:default-wordlists-reference.adoc[default word list]. +.. Click btn:[Create Custom Word List]. +... In the *Word List Name* field, enter a name for the new custom word list. +... In the *Add Words* field, enter each word you want to add to your custom word list, separated by commas (`,`). +... Click btn:[Create Custom Word List]. +. Click btn:[Add Custom Token Filter]. [#truncate-token] === Create a Custom `truncate_token` Token Filter -. In the *Type* field, select *truncate_token*. -. In the *Length* field, enter . -. Click btn:[Save]. \ No newline at end of file +include::partial$custom-token-filters-descriptions.adoc[tags=truncate;!truncate_example] + +To create a new `truncate_token` token filter with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *truncate_token*. +. In the *Length* box, enter the maximum character length for an output token. +. Click btn:[Add Custom Token Filter]. + +== Next Steps + +After you create a custom token filter, you can use it with xref:create-custom-analyzer.adoc[a custom analyzer]. + +To continue customizing your Search index, you can also: + +* xref:set-type-identifier.adoc[] +* xref:create-custom-analyzer.adoc[] +* xref:create-custom-character-filter.adoc[] +* xref:create-custom-tokenizer.adoc[] + +To run a search and test the contents of your Search index, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-custom-tokenizer.adoc b/modules/search/pages/create-custom-tokenizer.adoc index 616928088..0c56b11ff 100644 --- a/modules/search/pages/create-custom-tokenizer.adoc +++ b/modules/search/pages/create-custom-tokenizer.adoc @@ -1,85 +1,88 @@ = Create a Custom Tokenizer -:tabs: :page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Create a custom tokenizer with the Couchbase {page-ui-name} to change how the Search Service creates tokens for matching Search index content to a Search query. +:page-toclevels: 3 + +[abstract] +{description} == Prerequisites -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. -== Procedure + +* You have logged in to the Couchbase {page-ui-name}. -=== Create a Custom Tokenizer With a Regular Expression +* You have started to create or already created an index in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing]. -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a custom tokenizer on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a custom tokenizer on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -include::partial$custom-tokenizer-regexp-steps.adoc[] --- +* You have already created or started to create a xref:create-custom-analyzer.adoc[custom analyzer] in your Search index. -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a tokenizer. +== Procedure + +To create a new custom tokenizer with the {page-ui-name} in Advanced Mode: + +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. . Go to menu:Data Tools[Search]. +. Do one of the following: +.. To work with an existing Search index, click the name of the index where you want to create a custom analyzer. +.. To create a new Search index, click btn:[Create Search Index]. +. Make sure to select *Enable Advanced Options*. +. Expand *Global Index Settings*. . Do one of the following: -.. To create a custom tokenizer on an existing Search Index, click the index name. -.. To create a custom tokenizer on a new Search Index, click btn:[Add Search Index]. -. Expand *Advanced Configuration*. -include::partial$custom-tokenizer-regexp-steps.adoc[] --- -==== - -=== Create a Custom Tokenizer With an Exception - -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a custom tokenizer on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a custom tokenizer on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -. Expand *Custom Filters*. -. Click btn:[Add Tokenizer]. -. In the *Name* field, enter a name for the custom tokenizer. -. In the *Type* field, select *exception*. -. In the *Exception Patterns* field, enter ? -. To add the ? to the list of exception patterns, click btn:[Add]. -. (Optional) To add additional ? to the list of exception patterns, repeat Steps 5-6. -. In the *Tokenizer for Remaining Input* field, select a tokenizer to ?: -+ -For more information about the available tokenizers, see xref:search/customize-index.adoc#tokenizers[Tokenizers]. -. Click btn:[Save]. --- +.. To create a new custom analyzer with a new tokenizer, click btn:[Add Custom Analyzer]. +.. To add a new custom tokenizer to use with an existing analyzer, expand the *Default Analyzer* list, and next to your custom analyzer, click btn:[Edit]. +. Click btn:[Add Custom Tokenizer]. +. In the *Tokenizer Name* field, enter a name for the tokenizer. +. In the *Type* list, select a tokenizer type. +. Configure your tokenizer based on your chosen tokenizer type. + +You can create 2 types of custom tokenizers: + +|==== +|Tokenizer Type |Description + +|<> |The tokenizer uses any input that matches the regular expression to create new tokens. -Couchbase Capella:: +|<> |The tokenizer removes any input that matches the regular expression, and creates tokens from the remaining input. +You can choose another tokenizer to apply to the remaining input. + +|==== + +[#regexp] +=== Create a Regular Expression Tokenizer + +To create a regular expression tokenizer with the {page-ui-name}: + +. In the *Type* list, select *regexp*. +. In the *Regular Expression* field, enter the regular expression to use to split input into tokens. + --- -. From your organization page, select the database where you want to create a tokenizer. -. Go to menu:Data Tools[Search]. -. Do one of the following: -.. To create a custom tokenizer on an existing Search Index, click the index name. -.. To create a custom tokenizer on a new Search Index, click btn:[Add Search Index]. -. Expand *Advanced Configuration*. -. Expand *Custom Filters*. -. Click btn:[Add Tokenizer]. -. In the *Name* field, enter a name for the custom tokenizer. -. In the *Type* field, select *exception*. -. In the *New Word* field, enter ? -. To add the ? to the list of exception patterns, click btn:[Add]. -. (Optional) To add additional ? to the list of exception patterns, repeat Steps 6-7. -. In the *Tokenizer for Remaining Input* field, select a tokenizer to ?: +For example, the regular expression `\b\w+\b` would create tokens based on the word boundaries and word characters found in the input. +. Click btn:[Add Custom Tokenizer]. + +[#excep] +=== Create an Exception Custom Tokenizer + +To create an exception custom tokenizer with the {page-ui-name} in Advanced Mode: + +. In the *Type* list, select *exception*. +. In the *Regular Expressions* field, enter 1 or more regular expression to use to remove content from your input. +Separate multiple regular expression patterns by entering a comma (`,`). +. In the *Tokenizer for Remaining Input* list, select a tokenizer to apply to your input after removing any content that matches your provided *Regular Expressions*. + -For more information about the available tokenizers, see xref:search/customize-index.adoc#tokenizers[Tokenizers]. -. Click btn:[Save]. --- -==== \ No newline at end of file +For more information about the available tokenizers, see xref:default-tokenizers-reference.adoc[]. +. Click btn:[Add Custom Tokenizer]. + +== Next Steps + +After you create a custom tokenizer, you can use it with xref:create-custom-analyzer.adoc[a custom analyzer]. + +To continue customizing your Search index, you can also: + +* xref:set-type-identifier.adoc[] +* xref:create-custom-character-filter.adoc[] +* xref:create-custom-token-filter.adoc[] + +To run a search and test the contents of your Search index, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-custom-wordlist.adoc b/modules/search/pages/create-custom-wordlist.adoc deleted file mode 100644 index 87e2b365e..000000000 --- a/modules/search/pages/create-custom-wordlist.adoc +++ /dev/null @@ -1,52 +0,0 @@ -= Create a Wordlist -:tabs: -:page-topic-type: guide - -== Prerequisites - -* You've logged in to the Couchbase Server Web Console or Capella UI. - -== Procedure - -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Do one of the following: -.. To create a wordlist on an existing Search Index, click an index. Then, click btn:[Edit]. -.. To create a wordlist on a new Search Index, click btn:[Add Index]. -. Expand *Customize Index*. -. Expand *Custom Filters*. -. Click btn:[Add Wordlist]. -. In the *Name* field, enter a name for the wordlist. -. In the *Word to be added* field, enter a word you want to add to the wordlist. -. To add the word to the list, do one of the following: -.. Click btn:[Add]. -.. Press kbd:[Enter]. -. (Optional) To add more words to the wordlist, repeat Steps 4-5. -. Click btn:[Save]. --- - -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a wordlist. -. Go to menu:Data Tools[Search]. -. Do one of the following: -.. To create a wordlist on an existing Search Index, click the index name. -.. To create a wordlist on a new Search Index, click btn:[Add Search Index]. -. Expand *Advanced Configuration*. -. Expand *Custom Filters*. -. Click btn:[Add Wordlist]. -. In the *Name* field, enter a name for the wordlist. -. In the *New Word* field, enter a word you want to add to the wordlist. -. To add the word to the list, do one of the following: -.. Click btn:[Add]. -.. Press kbd:[Enter]. -. (Optional) To add more words to the wordlist, repeat Steps 5-6. -. Click btn:[Submit]. --- - -==== \ No newline at end of file diff --git a/modules/search/pages/create-quick-index.adoc b/modules/search/pages/create-quick-index.adoc deleted file mode 100644 index 507d57570..000000000 --- a/modules/search/pages/create-quick-index.adoc +++ /dev/null @@ -1,35 +0,0 @@ -= Create a Quick Index -:description: You can use the Quick Index editor in Couchbase Server's Web Console to create a Search index. -:page-topic-type: guide - -[abstract] -{description} - -== Prerequisites - -* You have the Search Service enabled on a node in your database. - -* You have a bucket with scopes and collections in your database. - -* Your user account has the *Search Admin* role for the bucket where you want to create the index. - -* You've logged in to the Couchbase Server Web Console. - -== Procedure - -. Go to *Search*. -. Click btn:[Quick Index]. -. In the *Index Name* field, enter a name for the index. -. In the first *Keyspace* list, select the bucket where you want to create the index. -. In the second *Keyspace* list, select the scope where you want to create the index. -. In the third *Keyspace* list, select the collection where you want to create the index. -. In the *Select Fields* box, click a field in the document that you want to add to the index. -. In the *Type* list, select the field's data type. -+ -For more information about the available data types, see xref:search/field-data-types-reference.adoc[]. -. Set the field's options. -+ -For more information about the available field options, see xref:search/quick-index-field-options.adoc[]. -. Click btn:[Add]. -. (Optional) Repeat Steps 7-10 for each field you want to add to the index. -. Click btn:[Create Index]. \ No newline at end of file diff --git a/modules/search/pages/create-search-index-alias.adoc b/modules/search/pages/create-search-index-alias.adoc new file mode 100644 index 000000000..c5cfb1cb2 --- /dev/null +++ b/modules/search/pages/create-search-index-alias.adoc @@ -0,0 +1,33 @@ += Create a Search Index Alias with the {page-ui-name} +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use a Search index alias to run a Search query across multiple buckets, scopes, or Search indexes. + +[abstract] +{description} + +For more information about Search index aliases, see xref:index-aliases.adoc[]. + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have created at least one Search index. +For more information, see xref:create-search-index-ui.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. + +== Procedure + +To create a Search index alias with the {page-ui-name}: + +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. +. Click btn:[Create Search Alias]. + +== Next Steps + +To customize a Search index, see xref:customize-index.adoc[]. + +To run a search and test the contents of your Search index or Search index alias, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-search-index-rest-api.adoc b/modules/search/pages/create-search-index-rest-api.adoc deleted file mode 100644 index c5de04377..000000000 --- a/modules/search/pages/create-search-index-rest-api.adoc +++ /dev/null @@ -1,43 +0,0 @@ -= Create a Search Index with the REST API -:description: You can create a Search index with the Search Service API. -:page-topic-type: guide - -[abstract] -{description} - -== Prerequisites - -* You have the Search Service enabled on a node in your database. - -* You have a bucket with scopes and collections in your database. - -* Your user account has the *Search Admin* role for the bucket where you want to create the index. - -* You have installed the Couchbase command-line tool (CLI). - -* You have the hostname or IP address for your database. - -== Procedure - -. In the command-line tool, start a `curl` command with the `XPUT` verb. -. Set your header content to include `Content-Type: application/json`. -. Enter your username, password, and the Search Service endpoint on port `8094` with the name of the index you want to create: -+ -[source,console] ----- -include::example$create-search-index-header.sh[] ----- -. Enter the JSON payload for the settings you want in your index. -+ -TIP: You can copy the Index Definition from the Couchbase Server or Couchbase Capella UI to use in your REST API call. -For more information about how to create an index with the UI, see xref:search/create-search-index-ui.adoc[]. - -+ -In the following example, the JSON payload creates a simple index named `landmark-content-index` on the `travel-sample` bucket. It creates a type mapping for the `inventory.landmark` collection, with a child field, `content`: -+ -[source,console] ----- -include::example$create-search-index-payload.sh[] ----- -+ -For more information on the available JSON properties for a Search index, see xref:search/search-index-params.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/create-search-index-ui.adoc b/modules/search/pages/create-search-index-ui.adoc index 6cf8147e7..86cdc641c 100644 --- a/modules/search/pages/create-search-index-ui.adoc +++ b/modules/search/pages/create-search-index-ui.adoc @@ -1,64 +1,77 @@ -= Create a Basic Search Index with the UI -:description: You can create a Search index with the Couchbase Server, Couchbase Capella, and Couchbase ? UI. += Create a Search Index with the Capella UI :page-topic-type: guide -:tabs: +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: create-quick-index.adoc, set-advanced-settings.adoc +:description: You can create a Search index using the Couchbase {page-ui-name} to generate a properly formatted Search index definition. +:page-toclevels: 3 [abstract] {description} -== Prerequisites +Use Advanced Mode to create a Search index in the Couchbase {page-ui-name} with full customization and advanced features, such as xref:create-custom-analyzer.adoc[creating custom analyzers] or xref:set-type-identifier.adoc[setting a document filter]. + +You must create a Search index before you can xref:simple-search-ui.adoc[run a search] with the Search Service. -* You've deployed the Search Service on a node in your database. +== Prerequisites -* You have a bucket with scopes and collections in your database. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. -* Your user account has the *Search Admin* role for the bucket where you want to create the index. +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have logged in to the Couchbase {page-ui-name}. == Procedure -To create a Search index with the Couchbase Server Web Console or Couchbase Capella UI: +To use the {page-ui-name} to create a Search index: -[{tabs}] +. On the *Operational Clusters* page, select the operational cluster where you want to create a Search index. +. Go to menu:Data Tools[Search]. +. Click btn:[Create Search Index]. +. (Optional) To add additional customization options to your Search index, click btn:[Enable Advanced Mode]. +. In the *Index Name* field, enter a name for the Search index. ++ +[NOTE] +==== +Your index name must start with an alphabetic character (a-z or A-Z). It can only contain alphanumeric characters (a-z, A-Z, or 0-9), hyphens (-), or underscores (_). + +For Couchbase Server version 7.6 and later, your index name must be unique inside your selected bucket and scope. +You cannot have 2 indexes with the same name inside the same bucket and scope. ==== -Couchbase Server:: + +. In the *Bucket* and *Scope* lists, choose the bucket and scope where you want to create your Search index. +. In the *Collections* list, select the collections you want to include in your Search index, or accept the default of *All*. + --- -. Go to *Search*. -. Click btn:[Add Index]. -. In the *Index Name* field, enter a name for the index. +If you select specific collections, you can only use documents from these collections in your Search index. +. In the *Choose a Collection or Document Field* panel, click a collection name. +. Click *Index everything from: $COLLECTION_NAME*. +. Click btn:[Index All Fields]. +. Click btn:[Add to Index]. +. (Optional) <>. +. (Optional) Expand *Replicas & Partitions* and configure your *Number of Replicas* and *Number of Partitions*. + -NOTE: Your index name must start with an alphabetic character (a-z or A-Z). It can only contain alphanumeric characters (a-z, A-Z, or 0-9), hyphens (-), or underscores (_). - -. In the *Bucket* list, select the bucket where you want to create the index. -. Expand *Customize Index*. -. (Optional) To create the index on a scope other than `_default`, select *Use non-default scope/collection(s)*. -.. In the *Scope* list, select the scope where you want to create the index. +For more information, see xref:customize-index.adoc#replica[Replica and Partition Settings]. . Click btn:[Create Index]. --- -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a search index. -. Go to menu:Data Tools[Search]. -. Click btn:[Create Search Index]. -. In the *Name* field, enter a name for the index. +[#configure-settings] +=== Configure Global Search Index Settings + +To configure global settings for your Search index: + +. Expand *Global Index Settings*: +.. [[default-analyzer]]In the *Default Analyzer* list, select the xref:customize-index.adoc#analyzers[default analyzer] to assign to new xref:customize-index.adoc#type-mappings[type mappings] in your index. +.. [[date-time]]In the *Default Date/Time Parser* list, select the xref:customize-index.adoc#date-time[default date/time parser] to use for date data in your index. + -NOTE: Your index name must start with an alphabetic character (a-z or A-Z). It can only contain alphanumeric characters (a-z, A-Z, or 0-9), hyphens (-), or underscores (_). -. In the *Bucket* list, select the bucket where you want to create the index. -. (Optional) To create the index on a scope other than `_default`, select *Use non-default scope/collection(s)*. -.. In the *Scope* list, select the scope where you want to create the index. -. Click btn:[Create Index]. --- -==== +TIP: If you're editing your index in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing], you can also choose to xref:create-custom-analyzer.adoc[] or xref:create-custom-date-time-parser.adoc[]. +. (Advanced Mode Only) In the *Configured Type Mappings* pane, under *Choose Document Filter*, xref:set-type-identifier.adoc[configure a document filter] for your Search index. == Next Steps -This basic index includes all documents from the bucket and scope you selected. -You can run a search against this index, but it's recommended that you customize your index to improve performance and reduce the index size. +Your Search index will contain documents that match the collection type mapping you specified. +You can run a search against your index, but it's recommended that you create more xref:create-type-mapping.adoc[specific type mappings] to improve performance and reduce the index size. -For more information about how to customize an index, see xref:search/customize-index.adoc[]. +For more information about the different features you can add to your Search index to improve performance and search results, see xref:customize-index.adoc[]. -For more information about how to run a search, see xref:search/simple-search-ui.adoc[]. \ No newline at end of file +For more information about how to run a search, see xref:simple-search-ui.adoc[]. diff --git a/modules/search/pages/create-search-indexes.adoc b/modules/search/pages/create-search-indexes.adoc index 148fb5526..d596e9b36 100644 --- a/modules/search/pages/create-search-indexes.adoc +++ b/modules/search/pages/create-search-indexes.adoc @@ -1,25 +1,91 @@ = Create a Search Index :page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: clusters:search-service/create-full-text-indexes.adoc, clusters:search-service/manage-full-text-indexes.adoc +:description: Create a Search index to get started with the Search Service in your operational cluster. + +[abstract] +{description} You can create a Search index with: -* The Couchbase Server Web Console or Couchbase Capella UI. -* The Search Service REST API. +* The <>. +// * The <>. +* A JSON payload that you xref:import-search-index.adoc[import through the UI]. + +All Search indexes are built from a JSON payload. +For more information about the available properties for a Search index JSON payload, see xref:search-index-params.adoc[]. + +TIP: If you're new to developing with the Search Service, <>. +You can export the Search index definition JSON payload from the UI to xref:import-search-index.adoc[]. + +[#ui] +== Creating a Search Index with the {page-ui-name} + +Couchbase {page-product-name} supports creating a Search index with a streamlined experience, or Advanced Options. + +When you xref:create-search-index-ui.adoc[create a new Search index], you can: + +* xref:create-search-index-ui.adoc#configure-settings[Configure global index settings], which include: +** xref:customize-index.adoc#analyzers[Setting a default analyzer] +** xref:customize-index.adoc#date-time[Setting a default date/time parser] +* Create xref:customize-index.adoc#type-mappings[Type mappings and mappings] +* Configure xref:customize-index.adoc#replica[Replica and partition settings] + +If you select *Enable Advanced Options* to enable Advanced Mode in the Search index editor, the following additional options become available: + +* Creating custom xref:customize-index.adoc#analyzers[analyzers], which can include: +** Custom xref:customize-index.adoc#character-filters[character filters] +** Custom xref:customize-index.adoc#tokenizers[tokenizers] +** Custom xref:customize-index.adoc#token-filters[token filters], which can use custom xref:customize-index.adoc#wordlists[word lists] +* Creating custom xref:customize-index.adoc#date-time[date/time parsers] +* Creating xref:customize-index.adoc#type-mappings[mappings] for Extended Attributes (XATTRs) data in documents +* Creating xref:customize-index.adoc#type-mappings[mappings] for objects and fields that do not yet exist in your document schema +* Configuring a xref:customize-index.adoc#type-identifiers[document filter] + +All initial editing options remain available in Advanced Mode editing. + +[NOTE] +==== +For indexes created with Couchbase Server version 7.6 and later, index names must be unique inside a bucket and scope. +You cannot have 2 indexes with the same name inside the same bucket and scope on a {page-product-name} operational cluster running version 7.6 or later. + +The {page-ui-name} marks indexes as scoped or not scoped to a specific bucket and scope. + +Indexes created with a previous version of Couchbase Server are not scoped. +==== + +After you create a Search index, the Search Service streams data from your chosen collection or collections, and any document mutations, into the index builder. +Before your index finishes building, you can run a search and return partial results. + +//[#sdks] +//== Creating a Search Index with Couchbase SDKs + +//You can create a Search index with Couchbase SDKs. + +//For an example of directly using the Java SDK to create a Search index, see *NEED_NEW_EXAMPLE_PAGE* -TIP: If you're new to developing with the Search Service, xref:search/create-search-index-ui.adoc[create a Search Index with the UI]. -You can copy the JSON payload from the UI to create your index with the REST API. +//For more information about Search in the various Couchbase SDKs, see *SDK_INTRO_PAGE*. -== Creating a Search Index With The UI +// [#api] +// == Creating a Search Index with the REST API -To xref:search/create-search-index-ui.adoc[create a basic Search index], you only need to provide the following information: +// You can create a Search index with the REST API through a JSON payload. -* The name of the index. -* The bucket where you want to create the index. +// Most properties in the JSON payload correspond to settings in the {page-ui-name}. +// You can also copy the Search index definition JSON payload from a Search index in the {page-ui-name} to use in a REST API call. -If you want to restrict the documents you add to an index, you can also: +// [NOTE] +// ==== +// Use the scoped name for an index with the xref:server:rest-api:rest-fts.adoc[Search Service REST API] for any endpoints that do not include the bucket and scope in their path. +// For example, you must use `bucket.scope.index_name` as the format for your index name with the `analyzeDoc` endpoint, but not with the new 7.6 `query` endpoint. +// ==== -* Specify a scope or collection. -* xref:search/create-child-field.adoc[Add child fields] to add or remove fields from the index. +// For more information about how to use the REST API to create a Search index, see. -For more information about how you can customize a Search index, see xref:search/customize-index.adoc[]. +== See Also +* xref:customize-index.adoc[] +* xref:index-aliases.adoc[] +* xref:run-searches.adoc[] diff --git a/modules/search/pages/create-type-mapping.adoc b/modules/search/pages/create-type-mapping.adoc index 7504e6d19..20a04a46b 100644 --- a/modules/search/pages/create-type-mapping.adoc +++ b/modules/search/pages/create-type-mapping.adoc @@ -1,58 +1,138 @@ -= Create a Type Mapping With The UI += Create a New Mapping or Type Mapping :page-topic-type: guide -:tabs: - -== Prerequisites - -* You've created an index. -For more information, see xref:search/create-search-index-ui.adoc[]. - -* You've logged in to the Couchbase Server Web Console or Capella UI. - -== Procedure - -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Click the index where you want to create a type mapping. -. Click btn:[Edit]. -. Expand *Customize Index*. -. Expand *Mappings*. -. Click btn:[Add Type Mapping]. -. Do one of the following: -.. If you selected *Use non-default scope/collection(s)*, in the *Collection* list, select the collection where you want to create the type mapping. -.. If you cleared *Use non-default scope/collection(s)*, in the *#* field, enter the name of a type field where you want to create a type mapping. -. (Optional) To only include documents of a specific type from a collection, in the *#* field, add the document type to the end of the collection. -+ -For example, `scope.collection.document_type`. -. (Optional) To use a specific analyzer for documents in the type mapping, in the *Analyzer* list, select an analyzer. -+ -You can xref:search/default-analyzers-reference.adoc[use a default analyzer] or xref:search/create-custom-analyzer.adoc[create your own]. -. (Optional) To switch from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping to a static type mapping], select *Only index specified fields*. -.. To choose which fields to add or remove from the static type mapping, see xref:search/create-child-field.adoc[]. -. (Optional) To add a child type mapping for a document field that contains a JSON object, see xref:search/create-child-mapping.adoc[]. -. Click btn:[OK]. --- - -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a type mapping. +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: create-xattrs-mapping.adoc, create-child-field.adoc, create-child-mapping.adoc +:description: Create a type mapping with the Couchbase {page-ui-name} to control what documents are included or excluded from a Search index. +:page-toclevels: 3 + +[abstract] +{description} + +You can create xref:customize-index.adoc#static[static type mappings], which include only specific fields from your documents, or xref:customize-index.adoc#dynamic[dynamic type mappings], which include all available fields. +For more information about type mappings and mappings in the Search Service, see xref:customize-index.adoc#type-mappings[Type Mappings and Mappings]. + +Some mappings are only available in Advanced Mode. + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have created a basic Search index with the {page-ui-name}. +For more information, see xref:create-search-index-ui.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. + +== Procedure + +To use the {page-ui-name} to create a new type mapping or mapping on a Search index: + +. On the *Operational Clusters* page, select the operational cluster where you created your Search index. . Go to menu:Data Tools[Search]. -. Click the index where you want to create a type mapping. -. Expand *Advanced Configuration*. -. Expand *Type Mappings*. -. Click btn:[Add Type Mapping]. -. In the *Collection* list, select the collection where you want to create the type mapping. -. (Optional) To use a specific analyzer for documents in the type mapping, in the *Default Analyzer* list, select an analyzer. -+ -You can xref:search/default-analyzers-reference.adoc[use a default analyzer] or xref:search/create-custom-analyzer.adoc[create your own]. -. (Optional) To switch from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping to a static type mapping], clear *Index all contained fields*. -.. To choose which fields to add or remove from the static type mapping, see xref:search/create-child-field.adoc[]. -. (Optional) To add a child type mapping for a document field that contains a JSON object, see xref:search/create-child-mapping.adoc[]. -. Click btn:[Submit]. --- -==== \ No newline at end of file +. Click the name of the index where you want to create a new type mapping. +. If you have not already, create at least 1 <>. +. Do one of the following: +.. To index all documents from an additional collection, create a <>. +.. (Advanced Mode Only) To index Extended Attributes (XATTRs) data from your documents, create an <>. +.. To index an entire JSON object from your document schema, create a <>. +.. To index a single document field from your document schema, create a <>. +.. (Advanced Mode Only) Index <>. +. (Optional) To remove all documents that match a type mapping or mapping from your Search index, <>. +. Click btn:[Update Index]. + +[#collection] +=== Add a Collection Type Mapping + +Add a collection type mapping to index all documents from a specific collection in your chosen bucket and scope. + +To add an entire collection as a new type mapping: + +. In the *Choose a Collection or Document Field* panel, click a collection name. +. xref:type-mapping-options.adoc#collection[Configure your type mapping options]. +. Click btn:[Add To Index]. + +[#xattrs] +=== Add an XATTRs Mapping + +NOTE: XATTRs mappings can only be created with *Advanced Mode*. + +Add an XATTRs mapping to index document metadata from a specific collection. + +To add Extended Attributes (XATTRs) document metadata as a new mapping: + +. If you have not already, <> for the collection that has documents with XATTRs data. +. Under your *Configured Type Mappings*, next to your collection type mapping, click btn:[Add XATTRs]. +. xref:type-mapping-options.adoc#xattrs[Configure your mapping options]. +. Click btn:[Add To Index]. + +[#object] +=== Add a JSON Object Mapping + +Add a JSON object mapping to index a JSON object from your document schema. +You can choose to index the fields inside the JSON object as <>, or keep your JSON object mapping as a xref:customize-index.adoc#dynamic[dynamic mapping]. + +To add an entire JSON object from your documents as a new mapping: + +. In the *Choose a Collection or Document Field* panel, expand a collection. +. Inside your displayed document schema, click the name of a JSON object in your documents. +. xref:type-mapping-options.adoc#object[Configure your mapping options]. +. Click btn:[Add To Index]. + +[#field] +=== Add a Single Document Field Mapping + +Add a single document field mapping to index a single document field from your document schema. +Adding document field mappings turns any parent mappings into xref:customize-index.adoc#static[static type mappings]. + +To add only a single field from your documents as a new mapping: + +. In the *Choose a Collection or Document Field* panel, expand a collection. +. Inside your displayed document schema, click the name of a document field. +. xref:type-mapping-options.adoc#field[configure your type mapping options]. +. Click btn:[Add To Index]. + +[#future] +=== Add a Mapping or Type Mapping for a Future Object or Field + +NOTE: Mappings for objects that do not yet exist in your documents can only be created in *Advanced Mode*. + +You can choose to add a mapping or type mapping for a JSON object or field that does not yet exist in your document schema. +If you know the name of the object or field, the Search Service can search these fields after they have been added to the documents in your Search index. + +To add a mapping or type mapping for a future object or field: + +. Select *Enable Advanced Options*. +. <> for the collection that will hold the documents with your future field. +. Under your *Configured Type Mappings*, next to your collection type mapping, do one of the following: +.. To create a new JSON Object, click btn:[Add Object]. +.. To create a new field, click btn:[Add Field]. +. In the *Property Name* field, enter the name of the JSON object or field. +. Configure your xref:type-mapping-options.adoc#object[object mapping] or xref:type-mapping-options.adoc#field[field type mapping] options. +. Click btn:[Add To Index]. + +[#disable-mapping] +=== Turn a Mapping On or Off + +You can turn off a type mapping or mapping to remove any documents that match that type mapping from your Search index. +These documents will not appear in search results when you run a query on the index. +Turning off mappings is useful for troubleshooting Search index configurations, without losing configuration settings. + +To turn off a mapping or type mapping in your Search index: + +. Under *Configured Type Mappings*, find the type mapping or mapping you want to turn off. +. Clear the checkbox for the type mapping or mapping. + +You can select a type mapping or mapping again at any time to add it back to your Search index and search results. + +== Next Steps + +Your Search index will contain any documents, objects, or fields that you specify in your type mappings and mappings. + +You can keep adding additional features to your Search index to improve performance and search results. +For more information, see xref:customize-index.adoc[]. + +For more information about how to run a search, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/customize-index.adoc b/modules/search/pages/customize-index.adoc index ce55a159f..659733056 100644 --- a/modules/search/pages/customize-index.adoc +++ b/modules/search/pages/customize-index.adoc @@ -1,81 +1,126 @@ -= Customize a Search Index += Search Index Features :page-topic-type: concept -:description: Customize a Search Index +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Search indexes in Couchbase {page-product-name} have multiple features that you can configure to improve performance and fine tune your search results. -You can customize your Search indexes to improve performance and the quality of your search results. +[abstract] +{description} + +Some features are only available in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode editing]. You can add the following components and configure the following options for a Search index: -[cols="1,2"] -|==== -|Option |Description +* <> +* <> +* <> +* <> +* <> +* <> -|[[type-identifiers]]Type Identifier a| -Set a type identifier to change how the index sets a document's type. +[#analyzers] +== Analyzers -For more information about how to set a type identifier, see xref:search/set-type-identifier.adoc[]. +Use analyzers to improve and customize the search results in your index. -|[[type-mappings]]Mappings a| +Analyzers transform input text into tokens, which give you greater control over your index's text matching. +The *Default Analyzer* sets the analyzer that's used by default for new <> across your Search index. -Use a type mapping to include or exclude specific documents in a scope or collection from an index. +You can use one of Couchbase's built-in analyzers as the *Default Analyzer* or the analyzer for a specific <>. +If you use Advanced Mode, you can create your own analyzer. -You can create two types of type mappings: +Analyzers have different components that control how text is transformed for search. +When you create a custom analyzer, you can choose these components. +For more information about Search analyzer components, see <>. -* *Dynamic type mappings*: Add all available fields from their document type to an index. -* *Static type mappings*: Add only specific fields from their document type to an index. +For more information about how to create a custom analyzer, see xref:create-custom-analyzer.adoc[]. + +[#date-time] +== Default Date/Time Parser -By default, all indexes have a dynamic type mapping that includes all documents from the *_default* scope and *_default* collection in a bucket. +Set the default format that the Search index should use to interpret date and time data in your Search index. -Add xref:search/create-child-field.adoc[child fields] to a type mapping to create a static type mapping. -Child fields set the specific fields from a document that you want to include or exclude from an index. +If the documents in your index contain date and time data in a format other than the xref:default-date-time-parsers-reference.adoc[default date/time parsers], you need to create a custom date/time parser. +You can only create a custom date/time parser if you switch to Advanced Mode. +For more information about how to add a custom date/time parser, see xref:create-custom-date-time-parser.adoc[]. -For more information about how to add a type mapping to an index, see xref:search/create-search-index-ui.adoc[]. +[#type-identifiers] +== Document Filters -|[[analyzers]]Analyzers a| +In Advanced Mode, you can also choose and configure an additional document filter to add or remove documents in your Search index that meet certain conditions: -Use analyzers to improve and customize the search results in your index. +* *JSON Type Field*: Selects only documents that contain a specific field with a specified string value. +* *Doc ID up to Separator*: Selects only documents with an ID or key up to a specific substring. +* *Doc ID with Regex*: Selects only documents with an ID or key that matches a regular expression. -Analyzers transform input text into tokens, which give you greater control over your index's text matching. +For more information about how to configure a document filter, see xref:set-type-identifier.adoc[]. -You can use one of Couchbase's built-in analyzers or create your own. -For more information about how to create a custom analyzer, see xref:search/create-custom-analyzer.adoc[]. +[#type-mappings] +== Type Mappings and Mappings -Analyzers have different components that control how text is transformed for search. -When you create a custom analyzer, you can choose these components. +Use a type mapping to include or exclude specific documents in a collection from an index. + +Type mappings can also set a field's data type and other settings. + +Type mappings start at the collection level. +Create additional mappings for document fields or JSON objects under a collection's type mapping to restrict the documents added to your index. +This can improve Search index performance over indexing entire collections. + +If your operational cluster is running Couchbase Server version 7.6.2 and later, you can also choose to include document metadata inside your Search index by creating an XATTRs mapping. +For more information about how to configure settings for the different types of mappings and type mappings, see xref:type-mapping-options.adoc[]. + +For more information about how to configure a type mapping in the Search index editor, see xref:create-type-mapping.adoc[]. + +You can create two types of type mappings with the Search Service: -Both custom and default analyzers can contain custom filters. +* <> +* <> -|[[custom-filters-table]]Custom Filters a| +[#dynamic] +=== Dynamic Type Mappings -Use custom filters to add more customization to a custom analyzer. +When you do not know the structure of your data fields ahead of time, use a dynamic type mapping to add all available fields from a matching document type to an index. +For example, you could create a dynamic type mapping to include all documents from the `hotel` collection in your Search index, or include all fields under a JSON object from your document schema. -For more information about these filters, see the <> section. +Configure this type of mapping by selecting a collection or JSON object in the Search index editor when you xref:create-type-mapping.adoc[]. -|[[date-time]]Date/Time Parsers a| +[#static] +=== Static Type Mappings -If the documents in your index contain date and time data in a format other than RFC-3339 (ISO-8601), then you need to create a date/time parser. +When your data fields are stable and unlikely to change, use a static type mapping to add and define only specific fields from a matching document type to an index. +For example, you could create a static type mapping to only include the contents of the `city` field from the `hotel` collection in your Search index, as a text field with an `en` analyzer. -A custom date/time parser tells the Search index how to interpret date data from your documents. +Configure this type of mapping by selecting a field in your document schema in the Search index editor when you xref:create-type-mapping.adoc[]. -For more information about how to add a custom date/time parser, see xref:search/create-custom-date-time-parser.adoc[]. +[#replica] +== Replica and Partition Settings -|Advanced a| +Use replicas and partitions to add high availability, fault tolerance, and scalability to your Search index. -Set advanced settings to change your index's default analyzer, replication, and more. +=== Number of Replicas -NOTE: In Couchbase Capella, Advanced settings appear under the *General Settings* section. +Add Search index replicas to create copies of your Search index on other nodes. +If 1 of the nodes running the Search Service in your cluster goes offline, you can still use your indexes if they exist on another node. -For more information about how to change advanced settings, see xref:search/set-advanced-settings.adoc[]. +Adding more replicas increases the storage used by the Search Service for your indexes. +You cannot add more replicas if your cluster configuration does not have the nodes to support those replicas. -|==== +=== Number of Partitions + +Add Search index partitions to distribute the contents of a Search index over multiple Search Service nodes in your cluster. + +Partitions improve Search index performance, but increase the complexity of a Search index and its resource usage. + +It's recommended to set your Search index partitions to the number of nodes running the Search Service in your operational cluster, to get the most efficient resource usage. [#custom-filters] -== Custom Filters +== Custom Analyzers and Other Filters -Custom filters are components of a Search index <>. +Custom filters are components of a Search index <>. -Create and add these components to a custom analyzer to improve search results and performance for an index. +Create and add custom filters to a custom analyzer to improve search results and performance for an index in Advanced Mode. +You cannot create custom analyzers or custom filters if *Advanced Options* are not enabled. You can create the following custom filters: @@ -88,39 +133,14 @@ You can create the following custom filters: === Character Filters Character filters remove unwanted characters from the input for a search. - For example, the default *html* character filter removes HTML tags from your search content. You can use a default character filter in an analyzer or create your own. +When you create a custom character filter, you can choose whether your analyzer replaces any removed characters with your own configured string. -The following default character filters are available: - -|==== -|Character Filter |Description - -|asciifolding a| - -The analyzer converts any characters that aren't in the Basic Latin Unicode block to their ASCII equivalent. - -This means the filter converts any alphabetic, numeric, or symbol characters that aren't in the first 127 ASCII characters. - -For example, the character filter converts `á` to `a`. - -|html a| +For more information about the available default character filters, see xref:default-character-filters-reference.adoc[]. -The analyzer removes all HTML tags from search input. - -For example, the character filter removes the

      tags from indexed content, but keeps the text inside the

      tag. - -|zero_width_spaces a| - -The analyzer replaces zero-width non-joiner spaces with regular space characters. - -Zero-width non-joiner spaces are unicode characters that interrupt https://en.wikipedia.org/wiki/Ligature_(writing)[ligatures^] (joins between characters) in text formatting. - -|==== - -For more information about how to create your own custom character filter, see xref:search/create-custom-character-filter.adoc[]. +For more information about how to create your own custom character filter, see xref:create-custom-character-filter.adoc[]. [#tokenizers] === Tokenizers @@ -131,26 +151,9 @@ The Search Service takes token streams from search queries to determine matches You can use a default tokenizer in an analyzer or create your own. -The following default tokenizers are available: - -|==== -|Tokenizer |Description - -|hebrew |Separates an input string into tokens that contain only Hebrew alphabet characters. Punctuation marks and numbers are excluded. - -|letter |Separates an input string into tokens that contain only Latin alphabet characters. Punctuation marks and numbers are excluded. - -|single |Creates a single token from the input string. Special characters and whitespace are preserved. +For more information about the available default tokenizers, see xref:default-tokenizers-reference.adoc[]. -|[[unicode]]unicode |Separates input strings into tokens based on http://www.unicode.org/reports/tr29/#Word_Boundaries[Unicode Word Boundaries^]. - -|web |Creates tokens from an input string that match email address, URL, Twitter username, and hashtag patterns. - -|whitespace |Separates an input string into tokens based on the location of whitespace characters. - -|==== - -For more information about how to create your own tokenizer, see xref:search/create-custom-tokenizer.adoc[]. +For more information about how to create your own tokenizer, see xref:create-custom-tokenizer.adoc[]. [#token-filters] === Token Filters @@ -158,22 +161,41 @@ For more information about how to create your own tokenizer, see xref:search/cre Token filters take the token stream from a tokenizer and modify the tokens. A token filter can create stems from tokens to increase the matches for a search term. - For example, if a token filter creates the stem `play`, a search can return matches for `player`, `playing`, and `playable`. -The Search Service has default tokenizers available. -For a list of all available tokenizers, see xref:search/default-token-filters-reference.adoc[]. +The Search Service has default token filters available. +For a list of all available token filters, see xref:default-token-filters-reference.adoc[]. You can also create your own token filters. Custom token filters can use <> to modify their tokens. -For more information about how to create your own token filter, see xref:search/create-custom-token-filter.adoc[]. +For more information about how to create your own token filter, see xref:create-custom-token-filter.adoc[]. [#wordlists] -=== Wordlists +=== Word Lists + +Word lists define a list of words that you can use with a <> to create tokens. + +You can use a word list to find words and create tokens, or remove words from a tokenizer's token stream. + +When you create a custom token filter, the Search Service you can use a default word list, or create your own word list. +Only specific custom token filter types use word lists in their configuration: + +* xref:create-custom-token-filter.adoc#dict-compound[dict_compound] +* xref:create-custom-token-filter.adoc#elision[elision] +* xref:create-custom-token-filter.adoc#keyword-marker[keyword_marker] +* xref:create-custom-token-filter.adoc#stop-tokens[stop_tokens] -Wordlists define a list of words to ... +For more information about the available default word lists, see xref:default-wordlists-reference.adoc[]. +For more information about how to create your own word list, see xref:create-custom-token-filter.adoc[]. -When you create a custom <>, the Search Service has a set of default wordlists. -For more information about the available default wordlists, see xref:search/default-wordlists-reference.adoc[]. +== See Also -For more information about how to create a wordlist, see xref:search/create-custom-wordlist.adoc[]. \ No newline at end of file +* xref:create-search-index-ui.adoc[] +* xref:create-type-mapping.adoc[] +* xref:set-type-identifier.adoc[] +* xref:create-custom-analyzer.adoc[] +* xref:create-custom-character-filter.adoc[] +* xref:create-custom-tokenizer.adoc[] +* xref:create-custom-token-filter.adoc[] +* xref:run-searches.adoc[] +* xref:index-aliases.adoc[] \ No newline at end of file diff --git a/modules/search/pages/default-analyzers-reference.adoc b/modules/search/pages/default-analyzers-reference.adoc index b4e60ab8d..881e27ebe 100644 --- a/modules/search/pages/default-analyzers-reference.adoc +++ b/modules/search/pages/default-analyzers-reference.adoc @@ -1,83 +1,116 @@ = Default Analyzers :page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: quick-index-supported-languages.adoc +:description: Use an analyzer to filter and modify search strings to improve matches for search results. + -When you xref:search/create-type-mapping.adoc[create a type mapping], you can choose a default analyzer for your type mappings, or xref:search/create-custom-analyzer.adoc[create your own]. +[abstract] +{description} -Analyzers use character filters, tokenizers, and token filters to filter and modify search strings and improve matches for a search. -For more information about analyzers and their components, see xref:search/customize-index.adoc[]. +Analyzers contain: + +* xref:customize-index.adoc#character-filters[Character filters], which remove unwanted characters from search input. +* xref:customize-index.adoc#tokenizers[Tokenizers], which separate input strings into individual tokens. +* xref:customize-index.adoc#token-filters[Token filters], which modify tokens. + +When you xref:create-type-mapping.adoc[create a type mapping], you can choose a default analyzer for your type mappings, or xref:create-custom-analyzer.adoc[create your own]. The following default analyzer options are available: +[cols="1,2"] |==== |Analyzer |Description -|inherit | Set the analyzer for a type mapping to `inherit` to inherit the default analyzer set for an index. - -|ar |The `ar` analyzer uses character filters, tokenizers, and token filters designed for Arabic language searches. +| inherit +| If you set an analyzer to `inherit`, the Search index component inherits the xref:create-search-index-ui.adoc#default-analyzer[default analyzer set for an index]. -|cjk |The `cjk` analyzer uses character filters, tokenizers, and token filters designed for Chinese, Japanese and Korean language searches. +| Arabic - ar +| An Arabic language analyzer. -|ckb |The `ckb` analyzer uses character filters, tokenizers, and token filters designed for Kurdish language searches. +| Chinese, Japanese, and Korean - cjk +| An analyzer designed for the Chinese, Japanese, and Korean languages. -|da |The `da` analyzer uses character filters, tokenizers, and token filters designed for Danish language searches. +| Kurdish - ckb +| A Kurdish language analyzer. -|de |The `de` analyzer uses character filters, tokenizers, and token filters designed for German language searches. +| Danish - da +| A Danish language analyzer. -|en |The `en` analyzer uses character filters, tokenizers, and token filters designed for English language searches. +| German - de +| A German language analyzer. -|es |The `es` analyzer uses character filters, tokenizers, and token filters designed for Castilian Spanish language searches. +| English - en +| An English language analyzer. -|fa |The `fa` analyzer uses character filters, tokenizers, and token filters designed for Persian language searches. +| Castilian Spanish - es +| A Castilian Spanish language analyzer. -|fi |The `fi` analyzer uses character filters, tokenizers, and token filters designed for Finnish language searches. +| Persian - fa +| A Persian language analyzer. -|fr |The `fr` analyzer uses character filters, tokenizers, and token filters designed for French language searches. +| Finnish - fi +| A Finnish language analyzer. -|he |The `he` analyzer uses character filters, tokenizers, and token filters designed for Hebrew language searches. +| French - fr +| A French language analyzer. -|hi |The `hi` analyzer uses character filters, tokenizers, and token filters designed for Hindi language searches. +| Hebrew - he +| A Hebrew language analyzer. -|hr |The `hr` analyzer uses character filters, tokenizers, and token filters designed for Croatian language searches. +| Hindi - hi +| A Hindi language analyzer. -|hu |The `hu` analyzer uses character filters, tokenizers, and token filters designed for Hungarian language searches. +| Croatian - hr +| A Croatian language analyzer. -|it |The `it` analyzer uses character filters, tokenizers, and token filters designed for Italian language searches. +| Hungarian - hu +| A Hungarian language analyzer. -|keyword a| +| Italian - it +| An Italian language analyzer. -The `keyword` analyzer turns input into a single token. It forces exact matches and preserves whitespace characters like spaces. +|[[keyword]]keyword +a| The `keyword` analyzer turns input into a single token. +It forces exact matches and preserves whitespace characters like spaces. For example, the `keyword` analyzer turns an input of `Couchbase Server` into a single token: `Couchbase Server`. -|nl |The `nl` analyzer uses character filters, tokenizers, and token filters designed for Dutch language searches. +| Dutch - nl +| A Dutch language analyzer. -|no |The `no` analyzer uses character filters, tokenizers, and token filters designed for Norwegian language searches. +| Norwegian - no +| A Norwegian language analyzer. -|pt |The `pt` analyzer uses character filters, tokenizers, and token filters designed for Portuguese language searches. +| Portuguese - pt +| A Portuguese language analyzer. -|ro |The `ro` analyzer uses character filters, tokenizers, and token filters designed for Romanian language searches. +| Romanian - ro +| A Romanian language analyzer. -|ru |The `ru` analyzer uses character filters, tokenizers, and token filters designed for Russian language searches. +| Russian - ru +| A Russian language analyzer. -|simple a| - -The `simple` analyzer turns input into tokens based on letter characters. It removes characters like punctuation and numbers, and uses these characters as the boundaries for tokens. +| simple +a| The `simple` analyzer turns input into tokens based on letter characters. +It removes characters like punctuation and numbers, and uses these characters as the boundaries for tokens. For example, the `simple` analyzer turns an input of `Couchbase Server` into two tokens: `Couchbase` and `Server`. -|standard a| - -The `standard` analyzer uses the xref:search/customize-index.adoc#unicode[`unicode` tokenizer] with the xref:search/default-token-filters-reference.adoc#to-lower[`to_lower`] and xref:search/default-token-filters-reference.adoc#stop-en[`stop_en`] token filters. +| standard +a| The `standard` analyzer uses the xref:default-tokenizers-reference.adoc#unicode[`unicode` tokenizer] with the xref:default-token-filters-reference.adoc#to-lower[`to_lower`] and xref:default-token-filters-reference.adoc#stop-en[`stop_en`] token filters. For example, the `standard` analyzer turns an input of `The name is Couchbase Server` into three tokens: `name`, `couchbase`, and `server`. -|sv |The `sv` analyzer uses character filters, tokenizers, and token filters designed for Swedish language searches. - -|tr |The `tr` analyzer uses character filters, tokenizers, and token filters designed for Turkish language searches. +| Swedish - sv +|A Swedish language analyzer. -|web a| +| Turkish - tr +| A Turkish language analyzer. -The `web` analyzer finds email addresses, URLs, Twitter usernames, and hashtags in its input and turns them into tokens. +| web +a| The `web` analyzer finds email addresses, URLs, Twitter usernames, and hashtags in its input and turns them into tokens. For example, the `web` analyzer turns an input of `Send #Couchbase to example@gmail.com` into four tokens: `send`, `#Couchbase`, `to`, and `example@gmail.com`. diff --git a/modules/search/pages/default-character-filters-reference.adoc b/modules/search/pages/default-character-filters-reference.adoc new file mode 100644 index 000000000..6874c8b71 --- /dev/null +++ b/modules/search/pages/default-character-filters-reference.adoc @@ -0,0 +1,38 @@ += Default Character Filters +:page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Character filters remove unwanted characters from your search input. + +[abstract] +{description} + +You can use a xref:customize-index.adoc#character-filters[character filter] when you xref:create-custom-analyzer.adoc[create a custom analyzer]. +Choose a default character filter or xref:create-custom-character-filter.adoc[create your own]. + +The following default character filters are available: + +|==== +|Character Filter |Description + +|asciifolding a| + +The analyzer converts any characters that are not in the Basic Latin Unicode block to their ASCII equivalent. + +This means the filter converts any alphabetic, numeric, or symbol characters that are not in the first 127 ASCII characters. + +For example, the character filter converts `á` to `a`. + +|html a| + +The analyzer removes all HTML tags from search input. + +For example, the character filter removes the

      tags from indexed content, but keeps the text inside the

      tag. + +|zero_width_spaces a| + +The analyzer replaces zero-width non-joiner spaces with regular space characters. + +Zero-width non-joiner spaces are unicode characters that interrupt https://en.wikipedia.org/wiki/Ligature_(writing)[ligatures^](joins between characters) in text formatting. + +|==== \ No newline at end of file diff --git a/modules/search/pages/default-date-time-parsers-reference.adoc b/modules/search/pages/default-date-time-parsers-reference.adoc new file mode 100644 index 000000000..2d72fd327 --- /dev/null +++ b/modules/search/pages/default-date-time-parsers-reference.adoc @@ -0,0 +1,48 @@ += Default Date/Time Parsers +:page-topic-type: reference +:description: Use a date/time parser to tell the Search Service how to interpret date and time data in your documents. + +[abstract] +{description} + +You can set a xref:customize-index.adoc#date-time[default date/time parser] for your Search index, or set a date/time parser when you xref:create-type-mapping.adoc#field[create a single document field mapping] with a `datetime` type. + +The following default date/time parsers are available: + +|==== +| Date/Time Parser | Description + +| datetime optional +a| The default date/time parser. + +The default date/time parser can parse dates in the following formats: + +* `%Y-%m-%dT%H:%M:%S.%N%z:M`: For example, a date/time string like `2023-09-15T14:24:50.1567+05:30` +* `%Y-%m-%dT%H:%M:%S%z:M: For example, a date/time string like `2023-09-15T14:24:50+05:30` +* `%Y-%m-%dT%H:%M:%S`: For example, a date/time string like `2023-09-15T14:24:50` +* `%Y-%m-%d %H:%M:%S`: For example, a date/time string like `2023-09-15 14:24:50` +* `%Y-%m-%d %H:%M:%S %z`: For example, a date/time string like `2023-09-15 14:24:50 +0530` +* `%Y-%m-%d`: For example, a date/time string like `2023-09-15` + +| disabled +| The default date/time parser is disabled. + +| unix_micro +| For date/time data formatted as the number of microseconds since the Unix epoch `1970-01-01T00:00:00Z`. + +| unix_milli +| For date/time data formatted as the number of milliseconds since the Unix epoch `1970-01-01T00:00:00Z`. + +| unix_nano +| For date/time data formatted as the number of nanoseconds since the Unix epoch `1970-01-01T00:00:00Z`. + +| unix_sec +| For date/time data formatted as the number of seconds since the Unix epoch `1970-01-01T00:00:00Z`. + +|==== + +== See Also + +* xref:create-custom-date-time-parser.adoc[] +* xref:create-custom-analyzer.adoc[] +* xref:create-search-indexes.adoc[] \ No newline at end of file diff --git a/modules/search/pages/default-token-filters-reference.adoc b/modules/search/pages/default-token-filters-reference.adoc index 97eb9f7a0..914bcefab 100644 --- a/modules/search/pages/default-token-filters-reference.adoc +++ b/modules/search/pages/default-token-filters-reference.adoc @@ -1,46 +1,53 @@ = Default Token Filters :page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use a token filter to filter a tokenizer's results and get better search result matches. -The Search Service's token filters work with xref:search/customize-index.adoc#tokenizers[tokenizers] to filter search input tokens. +[abstract] +{description} -Use a token filter to filter a tokenizer's results and get better search result matches in your index. +The Search Service's xref:customize-index.adoc#token-filters[token filters] work with xref:customize-index.adoc#tokenizers[tokenizers] to filter search input tokens. +Tokens can come from the content of your Search index or a Search query. -For more information about token filters, see xref:search/customize-index.adoc#token-filters[Token Filters]. +For more information about token filters, see xref:customize-index.adoc#token-filters[Token Filters]. The following token filters are available: +[cols="1,2"] |==== |Token Filter Type |Description -|apostrophe | Removes all characters after an apostrophe (') in a token. Also removes the apostrophe. +|apostrophe | Removes all characters after an apostrophe (') from tokenizer results. Also removes the apostrophe. +For example, the token `Couchbase's` becomes `Couchbase`. -|camelCase a| Splits text in camelCase inside a token into separate tokens. +|camelCase a| Splits text in camelCase inside tokenizer results into separate tokens. For example, the token filter splits the token `camelCaseText` into `camel`, `Case`, and `Text`. -|cjk_bigram | +|cjk_bigram | Converts Chinese, Japanese, and Korean tokenizer results into bigrams, or groups of two consecutive words. -|cjk_width | +|cjk_width | Converts Chinese, Japanese, and Korean tokenizer results from full width ASCII variants into Latin characters, and half-width katakana characters into their equivalent kana characters. -|elision_ca | Removes characters that prefix a term with an apostrophe for the Catalan language. +|elision_ca | Removes all characters before an apostrophe from Catalan language tokenizer results. Also removes the apostrophe. |elision_fr a| -Removes characters that prefix a term with an apostrophe for the French language. +Removes all characters before an apostrophe from French language tokenizer results. Also removes the apostrophe. For example, the token filter converts the token `l'avion` to `avion`. -|elision_ga | Removes characters that prefix a term with an apostrophe for the Gaelic language. +|elision_ga | Removes all characters before an apostrophe from Gaelic language tokenizer results. Also removes the apostrophe. -|elision_it | Removes characters that prefix a term with an apostrophe for the Italian language. +|elision_it | Removes all characters before an apostrophe from Italian language tokenizer results. Also removes the apostrophe. -|hr_suffix_transformation_filter | +|hr_suffix_transformation_filter | Replaces suffixes in Croatian tokenizer results with normalized suffixes. -|lemmatizer_he | Lemmatizes similar forms of Hebrew words. Corrects spelling mistakes +|lemmatizer_he | Lemmatizes similar forms of Hebrew words. Corrects spelling mistakes. |mark_he | Marks the Hebrew, non-Hebrew, and numeric tokens from tokenizer results. -|niqqud_he | +|niqqud_he | Forces niqqud-less spelling for Hebrew text in tokenizer results. |normalize_ar | Uses http://unicode.org/reports/tr15/[Unicode Normalization^] to normalize Arabic characters in tokens. @@ -54,119 +61,153 @@ For example, the token filter converts the token `l'avion` to `avion`. |normalize_in | Uses http://unicode.org/reports/tr15/[Unicode Normalization^] to normalize Indonesian characters in tokens. -|possessive_en | +|possessive_en | Checks the second-last character in English-language tokenizer results for an apostrophe. If it finds an apostrophe, the token filter removes the last two characters from the token. -|reverse | Reverses the tokens from the tokenizer results. For example, the token filter converts the token `acrobat` to `taborca`. +|reverse | Reverses the tokens in tokenizer results. For example, the token filter converts the token `acrobat` to `taborca`. -|stemmer_ar | +|stemmer_ar | Checks Arabic tokenizer results for suffixes and prefixes. If it finds a suffix or any prefixes, the token filter removes them to leave the root word. -|stemmer_ckb | +|stemmer_ckb | Checks Kurdish tokenizer results for prefixes. If it finds a prefix, the token filter removes it to leave the root word. -|stemmer_da_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Danish language tokens into word stems. +|stemmer_da_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Danish language tokenizer results into word stems. -|stemmer_de_light | +|stemmer_de_light a| -|stemmer_de_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert German language tokens into word stems. +Uses light stemming to convert German language tokenizer results into word stems. -|stemmer_en_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert English language tokens into word stems. +Regular stemming can affect the semantic meaning of words, as several words with different meanings might have the same root stem. -|stemmer_es_light | +Light stemming only removes frequently used prefixes and suffixes, and doesn't produce the root of a word to preserve semantics. -|stemmer_es_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Castilian Spanish language tokens into word stems. +|stemmer_de_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert German language tokenizer results into word stems. -|stemmer_fi_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Finnish language tokens into word stems. +|stemmer_en_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert English language tokenizer results into word stems. -|stemmer_fr_light | +|stemmer_es_light a| -|stemmer_fr_min | +Uses light stemming to convert Spanish language tokenizer results into word stems. -|stemmer_fr_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert French language tokens into word stems. +Regular stemming can affect the semantic meaning of words, as several words with different meanings might have the same root stem. -|stemmer_hi | +Light stemming only removes frequently used prefixes and suffixes, and doesn't produce the root of a word to preserve semantics. -|stemmer_hr | +|stemmer_es_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Castilian Spanish language tokenizer results into word stems. -|stemmer_hu_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Hungarian language tokens into word stems. +|stemmer_fi_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Finnish language tokenizer results into word stems. -|stemmer_it_light | +|stemmer_fr_light a| -|stemmer_it_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Italian language tokens into word stems. +Uses light stemming to convert French language tokenizer results into word stems. -|stemmer_nl_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Dutch language tokens into word stems. +Regular stemming can affect the semantic meaning of words, as several words with different meanings might have the same root stem. -|stemmer_no_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Norwegian language tokens into word stems. +Light stemming only removes frequently used prefixes and suffixes, and doesn't produce the root of a word to preserve semantics. -|stemmer_porter | Transforms the tokens from the tokenizer results with the porter stemming algorithm. For more information, see the https://tartarus.org/martin/PorterStemmer/[official Porter Stemming Algorithm documentation^]. +|stemmer_fr_min a| -|stemmer_pt_light | +Uses minimal stemming to convert French language tokenizer results. -|stemmer_ro_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Romanian language tokens into word stems. +Minimal stemming only removes the last character of a word or replaces some suffixes. For example, the `stemmer_fr_min` removes `x`, `s`, `r`, `e`, and `é` characters from the end of words and replaces the `aux` suffix with `al`. -|stemmer_ru_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Russian language tokens into word stems. +|stemmer_fr_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert French language tokenizer results into word stems. -|stemmer_sv_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Swedish language tokens into word stems. +|stemmer_hi | Uses a https://www.semanticscholar.org/paper/A-Lightweight-Stemmer-for-Hindi-Ramanathan-Rao/041a475a2b30b3f4397405e45098b40177e39de1[lightweight stemmer for Hindi^] to remove suffixes from tokenizer results. -|stemmer_tr_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Turkish language tokens into word stems. +|stemmer_hr | Uses an open source stemming rule set to find the root word in Croatian language tokenizer results. -|stop_ar | Removes tokens from the tokenizer results that are unnecessary for a search, based on an Arabic dictionary. +|stemmer_hu_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Hungarian language tokenizer results into word stems. -|stop_bg | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Bulgarian dictionary. +|stemmer_it_light a| -|stop_ca | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Catalan dictionary. +Uses light stemming to convert Italian language tokenizer results into word stems. -|stop_ckb | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Kurdish dictionary. +Regular stemming can affect the semantic meaning of words, as several words with different meanings might have the same root stem. -|stop_cs | Removes tokens from the tokenizer results that are unnecessary for a search, based on a ? dictionary. +Light stemming only removes frequently used prefixes and suffixes, and doesn't produce the root of a word to preserve semantics. -|stop_da | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Danish dictionary. +|stemmer_it_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Italian language tokenizer results into word stems. -|stop_de | Removes tokens from the tokenizer results that are unnecessary for a search, based on a German dictionary. +|stemmer_nl_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Dutch language tokenizer results into word stems. -|stop_el | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Greek dictionary. +|stemmer_no_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Norwegian language tokenizer results into word stems. -|[[stop-en]]stop_en | Removes tokens from the tokenizer results that are unnecessary for a search, based on an English dictionary. For example, the token filter removes `and`, `is`, and `the` from tokenizer results. +|stemmer_porter | Transforms tokenizer results with the porter stemming algorithm. For more information, see the https://tartarus.org/martin/PorterStemmer/[official Porter Stemming Algorithm documentation^]. -|stop_es | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Castilian Spanish dictionary. +|stemmer_pt_light a| -|stop_eu | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Basque dictionary. +Uses light stemming to convert Portuguese language tokenizer results into word stems. -|stop_fa | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Persian dictionary. +Regular stemming can affect the semantic meaning of words, as several words with different meanings might have the same root stem. -|stop_fi | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Finnish dictionary. +Light stemming only removes frequently used prefixes and suffixes, and doesn't produce the root of a word to preserve semantics. -|stop_fr | Removes tokens from the tokenizer results that are unnecessary for a search, based on a French dictionary. +|stemmer_ro_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Romanian language tokenizer results into word stems. -|stop_ga | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Gaelic dictionary. +|stemmer_ru_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Russian language tokenizer results into word stems. -|stop_gl | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Galician Spanish dictionary. +|stemmer_sv_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Swedish language tokenizer results into word stems. -|stop_he | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Hebrew dictionary. +|stemmer_tr_snowball | Uses the https://snowballstem.org/[Snowball string processing language^] to convert Turkish language tokenizer results into word stems. -|stop_hi | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Hindi dictionary. +|stop_ar | Removes tokens from tokenizer results that are unnecessary for a search, based on an Arabic dictionary. -|stop_hr | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Croatian dictionary. +|stop_bg | Removes tokens from tokenizer results that are unnecessary for a search, based on a Bulgarian dictionary. -|stop_hu | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Hungarian dictionary. +|stop_ca | Removes tokens from tokenizer results that are unnecessary for a search, based on a Catalan dictionary. -|stop_hy | Removes tokens from the tokenizer results that are unnecessary for a search, based on an Armenian dictionary. +|stop_ckb | Removes tokens from tokenizer results that are unnecessary for a search, based on a Kurdish dictionary. -|stop_id | Removes tokens from the tokenizer results that are unnecessary for a search, based on an Indonesian dictionary. +|stop_cs | Removes tokens from tokenizer results that are unnecessary for a search, based on a Czech dictionary. -|stop_it | Removes tokens from the tokenizer results that are unnecessary for a search, based on an Italian dictionary. +|stop_da | Removes tokens from tokenizer results that are unnecessary for a search, based on a Danish dictionary. -|stop_nl | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Dutch dictionary. +|stop_de | Removes tokens from tokenizer results that are unnecessary for a search, based on a German dictionary. -|stop_no | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Norwegian dictionary. +|stop_el | Removes tokens from tokenizer results that are unnecessary for a search, based on a Greek dictionary. -|stop_pt | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Portuguese dictionary. +|[[stop-en]]stop_en | Removes tokens from tokenizer results that are unnecessary for a search, based on an English dictionary. For example, the token filter removes `and`, `is`, and `the` from tokenizer results. -|stop_ro | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Romanian dictionary. +|stop_es | Removes tokens from tokenizer results that are unnecessary for a search, based on a Castilian Spanish dictionary. -|stop_ru | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Russian dictionary. +|stop_eu | Removes tokens from tokenizer results that are unnecessary for a search, based on a Basque dictionary. -|stop_sv | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Swedish dictionary. +|stop_fa | Removes tokens from tokenizer results that are unnecessary for a search, based on a Persian dictionary. -|stop_tr | Removes tokens from the tokenizer results that are unnecessary for a search, based on a Turkish dictionary. +|stop_fi | Removes tokens from tokenizer results that are unnecessary for a search, based on a Finnish dictionary. + +|stop_fr | Removes tokens from tokenizer results that are unnecessary for a search, based on a French dictionary. + +|stop_ga | Removes tokens from tokenizer results that are unnecessary for a search, based on a Gaelic dictionary. + +|stop_gl | Removes tokens from tokenizer results that are unnecessary for a search, based on a Galician Spanish dictionary. + +|stop_he | Removes tokens from tokenizer results that are unnecessary for a search, based on a Hebrew dictionary. + +|stop_hi | Removes tokens from tokenizer results that are unnecessary for a search, based on a Hindi dictionary. + +|stop_hr | Removes tokens from tokenizer results that are unnecessary for a search, based on a Croatian dictionary. + +|stop_hu | Removes tokens from tokenizer results that are unnecessary for a search, based on a Hungarian dictionary. + +|stop_hy | Removes tokens from tokenizer results that are unnecessary for a search, based on an Armenian dictionary. + +|stop_id | Removes tokens from tokenizer results that are unnecessary for a search, based on an Indonesian dictionary. + +|stop_it | Removes tokens from tokenizer results that are unnecessary for a search, based on an Italian dictionary. + +|stop_nl | Removes tokens from tokenizer results that are unnecessary for a search, based on a Dutch dictionary. + +|stop_no | Removes tokens from tokenizer results that are unnecessary for a search, based on a Norwegian dictionary. + +|stop_pt | Removes tokens from tokenizer results that are unnecessary for a search, based on a Portuguese dictionary. + +|stop_ro | Removes tokens from tokenizer results that are unnecessary for a search, based on a Romanian dictionary. + +|stop_ru | Removes tokens from tokenizer results that are unnecessary for a search, based on a Russian dictionary. + +|stop_sv | Removes tokens from tokenizer results that are unnecessary for a search, based on a Swedish dictionary. + +|stop_tr | Removes tokens from tokenizer results that are unnecessary for a search, based on a Turkish dictionary. |[[to-lower]]to_lower | Converts all characters in tokens to lowercase. diff --git a/modules/search/pages/default-tokenizers-reference.adoc b/modules/search/pages/default-tokenizers-reference.adoc new file mode 100644 index 000000000..16a2657ad --- /dev/null +++ b/modules/search/pages/default-tokenizers-reference.adoc @@ -0,0 +1,30 @@ += Default Tokenizers +:page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Tokenizers control how the Search Service splits input strings into individual tokens. + +[abstract] +{description} + +You can use a xref:customize-index.adoc#tokenizers[tokenizer] when you xref:create-custom-analyzer.adoc[create a custom analyzer]. +Choose a default tokenizer or xref:create-custom-tokenizer.adoc[create your own]. + +The following default tokenizers are available: + +|==== +|Tokenizer |Description + +|hebrew |Separates an input string into tokens that contain only Hebrew alphabet characters. Punctuation marks and numbers are excluded. + +|letter |Separates an input string into tokens that contain only Latin alphabet characters. Punctuation marks and numbers are excluded. + +|single |Creates a single token from the input string. Special characters and whitespace are preserved. + +|[[unicode]]unicode |Separates input strings into tokens based on http://www.unicode.org/reports/tr29/#Word_Boundaries[Unicode Word Boundaries^]. + +|web |Creates tokens from an input string that match email address, URL, Twitter username, and hashtag patterns. + +|[[whitespace]]whitespace |Separates an input string into tokens based on the location of whitespace characters. + +|==== \ No newline at end of file diff --git a/modules/search/pages/default-wordlists-reference.adoc b/modules/search/pages/default-wordlists-reference.adoc index c2af1535a..0a7f38149 100644 --- a/modules/search/pages/default-wordlists-reference.adoc +++ b/modules/search/pages/default-wordlists-reference.adoc @@ -1,76 +1,86 @@ = Default Wordlists +:page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: A wordlist can contain articles, conjunctions, prepositions, or other terms that limit matches in a search. -The following default wordlists are available when you create a xref:search:create-custom-token-filter.adoc[custom token filter]: +[abstract] +{description} +Use wordlists with xref:customize-index.adoc#token-filters[token filters] to choose what input from a xref:customize-index.adoc#tokenizers[tokenizer] becomes a token. + +The following default wordlists are available when you create a xref:create-custom-token-filter.adoc[custom token filter]: + +[cols="1,2"] |==== |Wordlist |Description -|articles_ca | Contains a list of ? in Catalan. +|articles_ca | Contains a list of articles in Catalan. -|articles_fr | Contains a list of ? in French. +|articles_fr | Contains a list of articles in French. -|articles_ga | Contains a list of ? in Gaelic. +|articles_ga | Contains a list of articles in Gaelic. -|articles_it | Contains a list of ? in Italian. +|articles_it | Contains a list of articles in Italian. -|stop_ar | Contains a list of ? in Arabic. +|stop_ar | Contains a list of Arabic words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_bg | Contains a list of ? in Bulgarian. +|stop_bg | Contains a list of Bulgarian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_ca | Contains a list of ? in Catalan. +|stop_ca | Contains a list of Catalan words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_ckb | Contains a list of ? in Kurdish. +|stop_ckb | Contains a list of Kurdish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_cs | Contains a list of ? in ?. +|stop_cs | Contains a list of Czech words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_da | Contains a list of ? in Danish. +|stop_da | Contains a list of Danish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_de | Contains a list of ? in German. +|stop_de | Contains a list of German words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_el | Contains a list of ? in Greek. +|stop_el | Contains a list of Greek words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_en | Contains a list of ? in English. +|stop_en | Contains a list of English words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_es | Contains a list of ? in Castilian Spanish. +|stop_es | Contains a list of Castilian Spanish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_eu | Contains a list of ? in Basque. +|stop_eu | Contains a list of Basque words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_fa | Contains a list of ? in Persian. +|stop_fa | Contains a list of Persian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_fi | Contains a list of ? in Finnish. +|stop_fi | Contains a list of Finnish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_fr | Contains a list of ? in French. +|stop_fr | Contains a list of French words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_ga | Contains a list of ? in Gaelic. +|stop_ga | Contains a list of Gaelic words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_gl | Contains a list of ? in Galician Spanish. +|stop_gl | Contains a list of Galician Spanish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_he | Contains a list of ? in Hebrew. +|stop_he | Contains a list of Hebrew words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_hi | Contains a list of ? in Hindi. +|stop_hi | Contains a list of Hindi words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_hr | Contains a list of ? in Croatian. +|stop_hr | Contains a list of Croatian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_hu | Contains a list of ? in Hungarian. +|stop_hu | Contains a list of Hungarian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_hy | Contains a list of ? in Armenian. +|stop_hy | Contains a list of Armenian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_id | Contains a list of ? in Indonesian. +|stop_id | Contains a list of Indonesian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_it | Contains a list of ? in Italian. +|stop_it | Contains a list of Italian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_nl | Contains a list of ? in Dutch. +|stop_nl | Contains a list of Dutch words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_no | Contains a list of ? in Norwegian. +|stop_no | Contains a list of Norwegian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_pt | Contains a list of ? in Portuguese. +|stop_pt | Contains a list of Portuguese words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_ro | Contains a list of ? in Romanian. +|stop_ro | Contains a list of Romanian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_ru | Contains a list of ? in Russian. +|stop_ru | Contains a list of Russian words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_sv | Contains a list of ? in Swedish. +|stop_sv | Contains a list of Swedish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. -|stop_tr | Contains a list of ? in Turkish. +|stop_tr | Contains a list of Turkish words that are unnecessary for a search, such as articles, conjunctions, and prepositions. |==== \ No newline at end of file diff --git a/modules/search/pages/field-data-types-reference.adoc b/modules/search/pages/field-data-types-reference.adoc index 14812266d..f56d2864b 100644 --- a/modules/search/pages/field-data-types-reference.adoc +++ b/modules/search/pages/field-data-types-reference.adoc @@ -1,33 +1,96 @@ = Field Data Types :page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: You can assign a data type to a field to tell the Search Service how to analyze its data. -When you xref:search/create-child-field.adoc[create a child field] on a type mapping, you need to set the field's data type. +[abstract] +{description} -You also need to choose a field data type when you xref:search/create-quick-index.adoc[create a quick index]. +When you xref:create-type-mapping.adoc[], you need to set the field's data type. + +If you create a Search index and do not set a data type for a field, the Search Service automatically assigns a field data type. +For example, if you created a xref:customize-index.adoc#type-mappings[dynamic type mapping], the Search Service automatically assigns data types to all fields in the type mapping. The following field data types are available: +[cols="1,2"] |==== -|Data Type |Description +|Field Data Type |Description -|text |The field contains a string. The string can contain numbers and special characters. +|text |The field contains a string. +The string can contain numbers and special characters. -|number |The field contains a number. It doesn't contain any alphabetic characters. +|number |The field contains a number. +It does not contain any alphabetic characters. -|datetime |The field contains a date/time value that matches the format of a xref:[Date/Time Parser] in the index. +|datetime |The field contains a date/time value that matches the format of a xref:customize-index.adoc#date-time[Date/Time Parser] in the index. |boolean |The field contains a true or false value. -|disabled | +|disabled | This field data type is deprecated. +It's included for compatibility only. -|geopoint a| +|[[geopoint]]geopoint a| The field contains geopoint (latitude and longitude) data, represented as either: * A string, as two numeric values separated by a comma. * A string, as a geohash point. * An array, as two floating point integers. -* A JSON object, as the properties `"lon"`/`"lng"` and `"lat"`. +* A JSON object, with the properties `lon`/`lng` and `lat`. + +|[[geoshape]]geoshape a| + +The field contains a GeoJSON object. + +A GeoJSON object describes a shape made of floating point coordinates with the following JSON properties: + +* A `type` string, for the type of GeoJSON object. +For example, a `point` or `MultiLineString`. + +* A `coordinates` array of floating point numbers, for each latitude and longitude coordinate point in the GeoJSON shape. + +For example: +---- +{ + "type": "LineString", + "coordinates": [ + + [-2.753735609842721, 53.94860827535115], + [-2.599898256093695,53.65007434185782] + ] +} +---- +This JSON object describes a `LineString` GeoJSON object with 2 latitude and longitude coordinates. + +For more information about GeoJSON queries, see xref:search-request-params.adoc#query-object[the Query object]. + +|ip a| + +The field contains an IP address, formatted in IPv4 or IPv6 CIDR syntax. + +For example: +---- +{ + "ipv4": "4.7.44.162", + "ipv6": "2001:4800:0000:0000:0000:0000:0000:0000" +} +---- + +|[[vector]]vector a| + +The field contains an array of floating point numbers or an array of arrays that represent a vector embedding. + +Use the `vector` type to perform vector similarity searches with Vector Search. + +For more information about Vector Search, see xref:vector-search:vector-search.adoc[]. + +|(Server version 7.6.2 and later) vector_base64 a| + +The field contains an array of floating point numbers formatted as a base64 encoded string that represent a vector embedding. + +Use the `vector_base64` type to perform vector similarity searches with Vector Search. -|geoshape |The field contains a GeoJSON object. For more information on GeoJSON objects, see xref:[]. +For more information about Vector Search, see xref:vector-search:vector-search.adoc[]. |==== \ No newline at end of file diff --git a/modules/search/pages/geo-search-ui.adoc b/modules/search/pages/geo-search-ui.adoc new file mode 100644 index 000000000..fd3832c2a --- /dev/null +++ b/modules/search/pages/geo-search-ui.adoc @@ -0,0 +1,77 @@ += Run a Geospatial Search Query with the {page-ui-name} +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Search for geospatial data in your Couchbase {page-product-name} operational cluster with a compatible Search index and the {page-ui-name}. + +[abstract] +{description} + +For more information about how the Search Service scores documents in search results, see xref:run-searches.adoc#scoring[Scoring for Search Queries]. + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have documents in your operational cluster that contain geospatial data. + +* You have logged in to the Couchbase {page-ui-name}. + +== Procedure + +To run a geospatial Search query, <>. + +Then, <>. + +[#geospatial-index] +=== Create a Search Index with a Geospatial Type Mapping + +To create the Search index in the {page-ui-name} with Advanced Mode: + +. On the *Operational Clusters* page, select the operational cluster where you want to create a Search index. +. Go to menu:Data Tools[Search]. +. Click btn:[Create Search Index]. +. In the *Index Name* field, enter a name for the Search index. ++ +[NOTE] +==== +Your index name must start with an alphabetic character (a-z or A-Z). It can only contain alphanumeric characters (a-z, A-Z, or 0-9), hyphens (-), or underscores (_). + +For Couchbase Server version 7.6 and later, your index name must be unique inside your selected bucket and scope. +You cannot have 2 indexes with the same name inside the same bucket and scope. +==== + +. In the *Bucket* and *Scope* lists, choose the bucket and scope where you want to create your Search index. +This bucket and scope should contain the collection and documents that have your geospatial data. +. In your document schema, expand the collection that holds the documents with your geospatial data. +. Click the name of the field that holds your geospatial data. +. In the *Type* list, select *Geopoint*. +. Select *Include in search results*. +. Select *Support field agnostic search*. +. Click btn:[Add To Index]. +. Click btn:[Create Index]. + +[#geospatial-query] +=== Run a Geospatial Search Query + +To run a Search query against the Search index from the {page-ui-name}: + +. Next to your <>, click btn:[Search]. +. In the *Search* field, enter a search query for geospatial data. ++ +For example, the following query searches a geospatial field, `geo`, for any locations within a 100 mile radius of the coordinates `-2.235143, 53.482358`: ++ +[source,json] +---- +include::example$geospatial-search-query.jsonc[] +---- + +== Next Steps + +For more information about the different features you can add to your Search index to improve performance and search results, see xref:customize-index.adoc[]. + +If you want to add autocomplete to your operational cluster's search, see xref:search-query-auto-complete.adoc[]. diff --git a/modules/search/pages/import-search-index.adoc b/modules/search/pages/import-search-index.adoc new file mode 100644 index 000000000..1935ffb02 --- /dev/null +++ b/modules/search/pages/import-search-index.adoc @@ -0,0 +1,74 @@ += Import a Search Index Definition with the {page-ui-name} +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use the Couchbase {page-ui-name} to import a JSON Search index definition. + +[abstract] +{description} + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have a Search index definition saved as a JSON file. +For more information about the properties you can include in a Search index definition, see xref:search-index-params.adoc[]. ++ +NOTE: Your JSON file must be smaller than 40 MB. + +* You have logged in to the Couchbase {page-ui-name}. + + +== Import a Search Index Definition + +To import a full xref:search-index-params.adoc[Search index definition] with the {page-ui-name}: + +. On the *Operational Clusters* page, select the operational cluster where you want to import a JSON Search index definition. +. Go to menu:Data Tools[Search]. +. Click btn:[Import Search Index]. +. Upload a JSON file that contains your Search index definition. ++ +For example: ++ +[source,json] +---- +include::example$short-search-index.jsonc[] +---- +. Close the *Index Definition* panel. +. (Optional) Make changes to your Search index settings. ++ +For more information, see xref:create-search-index-ui.adoc[]. +. Click btn:[Create Index]. + + +== Import a Search Index Alias Definition + +To import a xref:index-aliases.adoc[Search alias] with the {page-ui-name}: + +. On the *Operational Clusters* page, select the operational cluster where you want to import a JSON Search index alias. +. Go to menu:Data Tools[Search]. +. Click btn:[Create Search Alias]. +. Click btn:[Alias Definition]. +. Click btn:[Import from File]. +. Upload a JSON file that contains your Search alias definition. ++ +For example: ++ +[source,json] +---- +include::example$search-index-alias.jsonc[] +---- +. (Optional) Make changes to your Search index alias settings. ++ +For more information, see xref:create-search-index-alias.adoc[]. +. Click btn:[Create Alias]. + +== Next Steps + +To add additional features to your imported Search index, see xref:customize-index.adoc[]. + +To run a search with your Search index, see xref:simple-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/index-aliases.adoc b/modules/search/pages/index-aliases.adoc new file mode 100644 index 000000000..7924e3fff --- /dev/null +++ b/modules/search/pages/index-aliases.adoc @@ -0,0 +1,28 @@ += Create Search Index Aliases +:page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: A Search index alias lets you run a Search query against a Search index without using the original Search index name. + +[abstract] +{description} + +You can also use a Search index alias to run a Search query across multiple buckets, scopes, or Search indexes. +The Search Service runs the Search query on each Search index in the alias, and returns a merged set of results. + +Search index aliases are useful when you need to update an existing Search index. + +For example, say you had a Search index, `old-index`, and an alias, `my-alias`. + +If you wanted to make updates to `old-index`, you could add it to the alias `my-alias`. +If you created a clone of `old-index`, then made your updates, you could replace `old-index` in the alias `my-alias`. + +Using a Search index alias lets you edit `old-index` without any downtime. + +For more information about how to create a Search index alias, see xref:create-search-index-alias.adoc[]. + +== See Also + +* xref:create-search-index-alias.adoc[] +* xref:import-search-index.adoc[] + diff --git a/modules/search/pages/quick-index-field-options.adoc b/modules/search/pages/quick-index-field-options.adoc deleted file mode 100644 index 1528ffca9..000000000 --- a/modules/search/pages/quick-index-field-options.adoc +++ /dev/null @@ -1,65 +0,0 @@ -= Quick Index Field Options -:page-topic-type: reference - -When you xref:search/create-quick-index.adoc[create a Search index with the Quick Editor], you must set options for each field you add to the index. - -The following options are available for fields in the Quick Editor: - -|==== -|Option |Description - -|Index this field as an identifier (Text Only) a| - -To use the field to set the document's type in the index, select *Index this field as an identifier*. - -To not use the field as the document's type, clear *Index this field as an identifier*. - -|Language (Text Only) a| - -Select the language for the content inside a text field. - -The Search Service automatically applies an xref:search/customize-index.adoc#analyzers[analyzer] to the field's contents based on the selected language. - -For more information about the available language options, see xref:search/supported-languages.adoc[]. - -|Include in search results a| - -To include content from the field in search results, select *Include in search results*. - -To exclude the field's content from search results, clear *Include in search results*. - -|Support highlighting a| - -The Search Service can highlight matching search terms in search results from an index. - -To enable highlighting in search results, select *Support highlighting*. - -To turn off highlighting in search results, clear *Support highlighting*. - -NOTE: To enable *Support highlighting*, you must also enable *Include in search results*. - -|Support phrase matching a| - -To support searches for whole phrases, select *Support phrase matching*. - -To turn off phrase matching, clear *Support phrase matching*. - -|Support field agnostic search a| - -To search the field's contents without specifying the field name in a search query, select *Support field agnostic search*. - -To turn off field agnostic search, clear *Support field agnostic search*. - -|Support sorting and faceting a| - -To sort search results and use xref:[facets] with the field's contents, select *Support sorting and faceting*. - -To turn off sorting and facets, clear *Support sorting and faceting*. - -|Searchable As a| - -Set a different name that you can use to search the field's contents in a query. - -The default value is the field's name. - -|==== \ No newline at end of file diff --git a/modules/search/pages/run-searches.adoc b/modules/search/pages/run-searches.adoc index dffc31a52..117a14886 100644 --- a/modules/search/pages/run-searches.adoc +++ b/modules/search/pages/run-searches.adoc @@ -1,8 +1,143 @@ = Run a Search With a Search Index :page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: clusters:search-service/perform-full-text-searches.adoc +:description: Run a Search query to search and return the contents of a Search index. + +[abstract] +{description} + +If you use the default search result xref:search-request-params.adoc#sort[sorting] of `_score`, a document's <> determines where it appears in your search results. + +NOTE: You must xref:create-search-indexes.adoc[create a Search index] before you can run a search with the Search Service. You can run a search against a Search index with: -* The Couchbase Server Web Console or Couchbase Capella UI. -* The Search Service REST API with cURL and HTTP. -* The Couchbase SDKs. +* The <>. +//* The <>. +* A <>. +* The Couchbase SDKs: ++ +include::partial$sdks-fts-links.adoc[] + +To run a Search query against multiple Search indexes at once, xref:create-search-index-alias.adoc[]. + +[#scoring] +== Scoring for Search Queries + +To determine a document's score in search results, the Search Service uses the https://en.wikipedia.org/wiki/Tf%E2%80%93idf[tf-idf^] algorithm. +`tf-idf` increases the score of a document based on term frequency, or the number of times a term appears in a document divided by the total number of terms in the document. +It penalizes document frequency, or how often a term appears across all documents. + +The `tf-idf` score is calculated at a partition level in a Search index. + +The Search Service uses `tf-idf` to calculate the hit score for a document, multiplied by any xref:search-request-params.adoc#boost[boost] parameters applied to each query inside the xref:search-request-params.adoc#query-object[query object]: + +---- +hit_score = (query_1_boost * query_1_hit_score) + (query_2_boost * query_2_hit_score) +---- + +If one of your Search queries is a xref:vector-search:vector-search.adoc[Vector Search query], the calculation changes to: + +---- +hit_score = (query_1_boost * query_1_hit_score) + (knn_boost * knn_distance) +---- + +When running a hybrid search with the <> or <>, the Search Service displays results as a disjunct (`OR`) between your regular Search and Vector Search queries. + +TIP: When running a hybrid Search query, you should add a `boost` value to your regular Search query to level the `tf-idf` score with the `knn` distance. +Otherwise, you might see unexpected search results. +This is because of the differences in the scoring algorithms between the 2 query types. + +[#ui] +== Run a Search with the {page-ui-name} + +You can use the {page-ui-name} to test your Search index before you integrate search into your application. + +You can enter a basic search query in the {page-ui-name}, or use a xref:search-request-params.adoc#query[query object] and other JSON properties for a more complex search. + +For more information about how to run a search with the {page-ui-name}, see xref:simple-search-ui.adoc[]. + +For more information about how to configure a Search index and search for geospatial data, see xref:geo-search-ui.adoc[]. + +// [#api] +// == Run a Search with the REST API + +// You can also use the REST API, curl, and HTTP to run a search. + +// Use a xref:search-request-params.adoc[Search request JSON payload] to control how the Search Service returns results. + +// For more information about how to run a search with the REST API, see. + +// For more information about how to configure a Search index and search for geospatial data, see. + +[#sql] +== Run a Search with a {sqlpp} Query + +Use the xref:clusters:query-service/query-workbench.adoc[Query tab] to search using natural-language search and {sqlpp} features in the same query. + +When using {sqlpp} with a hybrid xref:vector-search:vector-search.adoc[Vector Search] query, you have more flexibility in how you choose to display your search results. +When running a hybrid search with the <> or <>, the Search Service displays results as a disjunct (`OR`) between your 2 search queries. +For example: + +---- + +{ + "query": + { + "match_phrase": "my regular query" + } +} + +OR + +{ + "knn": [ + "k": 5, + "field": "vector_field", + "vector": [0, 0, 128] + ] +} +---- + +{sqlpp} allows you to choose whether to return search results as a conjunct (`AND`) or a disjunct (`OR`) for hybrid search queries. + +As a conjunct, the Search Service: + +* Returns matches that score highly for both the regular Search query and the Vector Search query. +* Excludes matches that only match the Vector Search query. +For example: + +[source,sqlpp] +---- + +SELECT meta().id FROM +WHERE text = "content" +AND SEARCH(, {"query": {"match": "content", "field": "text"}, "knn": {"vector": ", "field": "vector_field", "k": 5}}); + +---- + +As a disjunct, the Search Service: + +* Returns matches for the regular Search query, followed by matches for the Vector Search query. + +As a result, you could see matches for the Vector Search query that do not contain matches for the regular Search query. + +For example: + +[source,sqlpp] +---- + +SELECT meta().id FROM +WHERE SEARCH (, {"query": {"match": "content", "field": "text"}, "knn": {"vector": ", "field": "vector_field", "k": 5}}); + +---- + +For more information about how to use the Search Service from a {sqlpp} query, see xref:n1ql:n1ql-language-reference/searchfun.adoc[]. + +== See Also + +* xref:create-search-indexes.adoc[] +* xref:customize-index.adoc[] +* xref:index-aliases.adoc[] diff --git a/modules/search/pages/search-index-params.adoc b/modules/search/pages/search-index-params.adoc index c74db22d3..3c3e40021 100644 --- a/modules/search/pages/search-index-params.adoc +++ b/modules/search/pages/search-index-params.adoc @@ -1,9 +1,20 @@ = Search Index JSON Properties +:page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use a JSON payload to control the settings for a Search index. +:page-toclevels: 2 -When you xref:search/create-search-index-rest-api.adoc[create a Search index with the REST API], you need to add a JSON payload with the settings for your index. +[abstract] +{description} + +You can choose to create a Search index with a JSON payload, and xref:import-search-index.adoc[import it through the Capella UI]. +This JSON payload sets all the settings for your new Search index. Your JSON payload must contain the properties described in <>, including the <>. +xref:index-aliases.adoc[Search index aliases] only need to include the properties described in <>. + [#initial] == Initial Settings @@ -11,108 +22,159 @@ The start of the JSON payload for a Search index contains important settings for [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=initial] +include::example$simple-search-index-payload.jsonc[tag=json-snippet] ---- -It contains the following properties: +// include::example$simple-search-index-payload.jsonc[lines=1..14] + +TIP: To view the entire JSON payload, click btn:[View]. + +All Search index payloads have the following properties: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|name |String |Yes |The name of the index. +|name |String |Yes |The name of the Search index. A Search index name must be unique for each cluster. |type |String |Yes a| The type of index you want to create: -* `fulltext-index`: Create a search index. -* `fulltext-alias`: Create an alias for a search index. -For more information about search index alias, see xref:[] +* `fulltext-index`: Create a Search index. +* `fulltext-alias`: Create an alias for a Search index. +For more information about Search index aliases, see xref:index-aliases.adoc[]. + +|[[uuid]]uuid |String |No a| + +The UUID for the Search index. + +The Search Service automatically generates a UUID for a Search index. -|uuid |String |No a| +If you use an existing UUID, the Search Service updates the existing Search index. +Do not include the `uuid` property when you want to copy an index to a different cluster or create a new index. -The UUID for the index. +View the UUID for an existing index from the {page-ui-name} by selecting an existing index and clicking btn:[Index Definition]. +The UUID displays in the Index Definition on the Update Index page. -The Search Service automatically generates a UUID for an index. +|sourceType |String |Yes |The `sourceType` is always `"gocbcore"` for a Search index. +For a xref:index-aliases.adoc[Search index alias], it's `"nil"`. -|sourceType |String |Yes |The `sourceType` is always `"gocbcore"`. +|sourceName |String |Yes |The name of the bucket where you want to create the Search index. +Do not include a `sourceName` for a Search index alias. -|sourceName |String |Yes a| -The name of the bucket where you want to create the index. +|[[sourceuuid]]sourceUUID |String |No a| + +The UUID of the bucket where you want to create the Search index. The Search Service automatically finds the UUID for the bucket. -|sourceUUID |String |No |The UUID of the bucket where you want to create the index. +Do not include the `sourceUUID` property when you want to copy an index to a different cluster, or create a new index. + +|sourceParams |Object |No a| -|sourceParams |Object |? | +This object contains advanced settings for index behavior. -|planParams |Object |Yes |An object that sets the index's partitions and replications. +Do not add content into this object unless instructed by Couchbase Support. + +|planParams |Object |Yes a|An object that sets the Search index's partitions and replications. For more information, see <>. -|params |Object |Yes |An object that sets the index's type identifier, type mappings, and analyzers. +Do not include any of the properties in a `planParams` object for a xref:index-aliases.adoc[Search index alias]. + +|params |Object |Yes a| + +An object that sets the Search index's type identifier, type mappings, and analyzers. For more information, see <>. +For a xref:index-aliases.adoc[Search index alias], this object contains the <>. + |==== [#planparams] - == planParams Object -The `planParams` object sets an index's partition and replication settings: +NOTE: Do not include any of the properties in a `planParams` object for a xref:index-aliases.adoc[Search index alias]. + +The `planParams` object sets a Search index's partition and replication settings: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=planparams] +include::example$simple-search-index-payload.jsonc[tag=plan-params] ---- -It contains the following properties: +TIP: To view the entire JSON payload, click btn:[View]. + +The `planParams` object contains the following properties: [cols="2,1,1,4"] |==== |Property |Type |Required? |Description |maxPartitionsPerPIndex |n/a |No |This setting is deprecated. Use `indexPartitions`, instead. -|indexPartitions |Number |Yes |The number of partitions to split the index into, across the nodes you have available with the Search Service enabled. -|numReplicas |Number |Yes a| +|indexPartitions |Number |Yes a|The number of partitions to split the Search index into, across the nodes you have available in your cluster with the Search Service enabled. +Use index partitions to increase index and query performance on large datasets. -For high-availability, set the number of replicas the Search Service creates for the index. +NOTE: The scoring calculation for regular Search queries can be affected by the number of partitions in your Search index, and how the Search Service distributes documents across partitions. +This is a limitation of the https://en.wikipedia.org/wiki/Tf%E2%80%93idf[tf-idf^] weighting scheme. -You can create up to three replicas for an index. -To turn off replication for the index, set `numReplicas` to `0`. +|numReplicas |Number |Yes a| + +For high-availability, set the number of replicas the Search Service creates for the Search index. -The number of replicas you can create depends on the number of nodes you have available with the Search Service enabled. +You can create up to three replicas for a Search index. +Each replica creates a full copy of the Search index to increase high-availability. +To turn off replication for the Search index, set `numReplicas` to `0`. +The number of replicas you can create depends on the number of nodes you have available with the Search Service enabled. |==== [#params] == Params Object -The `params` object sets an index's type identifier, type mappings, and analyzers. +The `params` object sets a Search index's xref:customize-index.adoc#type-identifiers[type identifier], xref:customize-index.adoc#type-mappings[type mappings], and xref:customize-index.adoc#analyzers[analyzers]. + +For a xref:index-aliases.adoc[Search index alias], it includes a JSON object for each Search index to include in the alias. + It contains the following properties: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|doc_config |Object |Yes |An object that sets how the index sets a document's type. +|doc_config |Object |Yes |An object that sets how the Search index sets a document's type. For more information, see <>. -|mapping |Object |Yes |An object that sets the analyzers and type mappings for an index. +|mapping |Object |Yes |An object that sets the analyzers and type mappings for a Search index. For more information, see <>. +|[[targets]]targets |Object |Index Alias Only a| An object that contains JSON objects for each Search index to add to the alias definition. + +The key for each JSON object must be the fully qualified name of each Search index. + +For example: + +---- +"targets": { + + "vector-sample.color.color-index": {} +} +---- + |==== [#doc-config] -== Doc_config Object +=== Doc_config Object -The `doc_config` object sets how the index sets a document's type: +The `doc_config` object sets how the Search index sets a document's type: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=doc_config] +include::example$simple-search-index-payload.jsonc[tag=doc_config] ---- -It contains the following properties: +TIP: To view the entire JSON payload, click btn:[View]. + +The `doc_config` object is a child object of the <>. It contains the following properties: [cols="1,1,1,2"] |==== @@ -120,109 +182,177 @@ It contains the following properties: |mode |String |Yes a| -Set how the index identifies a document's type: +Set a xref:customize-index.adoc#type-identifiers[type identifier] for the Search index to filter documents from search results: * `type_field`: Use the value from a specific field in the documents. -* `docid_prefix_delim`: Use the characters in the documents' ID values, up to but not including a specified separator. +* `docid_prefix_delim`: Use the leading characters in the documents' ID values, up to but not including a specified separator. * `docid_regexp`: Use a regular expression on the documents' ID values. -NOTE: If your index uses a specific collection, the `mode` value must be `"scope.collection.{mode}"`. +NOTE: If you want your Search index to only include documents from a specific collection, the `mode` value must be `"scope.collection.\{mode\}"`. + +|docid_prefix_delim |String |Yes a| + +If `mode` is `docid_prefix_delim`, set the separator character to use on a document's ID value. + +For example, to filter documents based on the characters before a `\_` in their ID values, set `docid_prefix_delim` to `_`. + +|docid_regexp |String |Yes a| + +If `mode` is `docid_regexp`, set the regular expression to use on a document's ID value to determine its type. + +For example, to filter documents that contain the characters `\_40` in their ID value, set `docid_regexp` to `_[3-5]0`. -|docid_prefix_delim |String |Yes |If `mode` is `docid_prefix_delim`, set the separator character to use on a document's ID value to determine its type. +|type_field |String |Yes a| -|docid_regexp |String |Yes |If `mode` is `docid_regexp`, set the regular expression to use on a document's ID value to determine its type. +If `mode` is `type_field`, set the name of the field to use to filter documents. -|type_field |String |Yes |If `mode` is `type_field`, set the name of the field to use to determine a document's type. +For example, to filter documents based on the value of their `type` field, set `type_field` to `type`. |==== [#mapping] -== Mapping Object +=== Mapping Object + +The `mapping` object contains a Search index's xref:customize-index.adoc#analyzers[analyzers] and other global index settings. +Some of these settings map to xref:create-search-index-ui.adoc#configure-settings[Global Index Settings in the UI]: + +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=mapping] +---- + +TIP: To view the entire JSON payload, click btn:[View]. + +The `mapping` object is a child object of the <>. It contains the following properties: [cols="2,1,1,4"] |==== |Property |Type |Required? |Description -|analysis |Object |Yes |An object that contains the <>, <>, tokenizers, token_filters, <>, and <> objects. +|[[analysis]]analysis |Object |Yes a| + +An object that contains the following child objects: + +* <> +* <> +* <> +* <> +* <> +* <> |default_analyzer |String |Yes a| -The name of the default analyzer to use for the type mapping. +The name of the default analyzer to use for the Search index. -For more information about analyzers, see xref:search/customize-index.adoc#analyzers[Analyzers]. +For more information about analyzers, see xref:customize-index.adoc#analyzers[Analyzers]. |default_datetime_parser |String |Yes a| -The name of the default date/time parser to use for the type mapping. +The name of the default date/time parser to use for the Search index. -For more information about date/time parsers, see xref:search/customize-index.adoc#date-time[Date/Time Parsers]. +For more information about date/time parsers, see xref:customize-index.adoc#date-time[Date/Time Parsers]. -|default_field |String |Yes a| -Set a name for the type mapping's `all` field. +|[[all-field]]default_field |String |Yes a| +Set a name for the `all` field in the Search index. -If you enable `include_in_all` for a child field, the contents of that child field can be searched by specifying this field's name in your search. +If you enable the <> for a document field, the contents of that document field can be searched without specifying a field name or by specifying the default field's name in your Search query. |default_mapping |Object |No a| -An object that contains settings for the default type mapping on the index. +An object that contains settings for the default type mapping on the Search index. The default type mapping contains all documents under the `_default` scope and `_default` collection in the bucket. This type mapping is included for compatibility only. -For more information on the properties inside the `default_mapping` object, see <>. +For more information about the properties inside the `default_mapping` object, see <>. -|default_type |String |Yes a|Set the default type for any documents in ...? +|default_type |String |No |This setting is included for compatibility with earlier indexes only. |docvalues_dynamic |Boolean |Yes a| -To include the values for an indexed field in the index, set `docvalues_dynamic` to `true`. +To include the value for each instance of an indexed field in the Search index to support xref:search-request-params.adoc#facet-name[facets] and sorting search results, set `docvalues_dynamic` to `true`. To exclude the values for an indexed field in the index, set `docvalues_dynamic` to `false`. |index_dynamic |Boolean |Yes a| -To index any fields in the index where `dynamic` is `true`, set `index_dynamic` to `true`. +To index any fields in the Search index where `dynamic` is `true`, set `index_dynamic` to `true`. To exclude dynamic fields from the index, set `index_dynamic` to `false`. |store_dynamic |Boolean |Yes a| -To return the content from an indexed field in the index, set `store_dynamic` to `true`. +To return the content from an indexed field in the Search index, set `store_dynamic` to `true`. To exclude field content from the index, set `store_dynamic` to `false`. |type_field |String |No |Use the same value assigned to the `type_field` in `doc_config`, if applicable. -|types |Object |No a| An object that contains any additional user-defined type mappings for the index, as `{scope}.{collection}` objects. For more information, see <>. +|types |Object |No a| + +An object that contains any user-defined type mappings for the Search index, as `\{scope\}.\{collection\}` objects inside a `types` object. + +For more information, see <>. |==== [#analyzers] == Analyzers Object -The `analyzers` object contains any custom analyzers defined for an index. +The `analyzers` object contains any custom analyzers defined for a Search index. + +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=analyzers] +---- + +TIP: To view the entire JSON payload, click btn:[View]. + +The `analyzers` object is a child object of the <>. It contains any number of <>: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|\{analyzer_name\} |Object |Yes a| + +Set the name of this object to the name you want for your custom analyzer. + +You can reference the `\{analyzer_name\}` object elsewhere in your Search index definition to use the analyzer. + +For more information about the properties in an `\{analyzer_name\}` object, see <>. +|==== + +[#analyzer-name] +=== \{Analyzer_name\} Object -It contains any number of `{analyzer_name}` objects: +The `\{analyzer_name\}` object defines a custom analyzer for a Search index: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=analyzers] +include::example$simple-search-index-payload.jsonc[tag=analyzer_name] ---- -The following table describes the available properties for the `analyzers` object: +An `\{analyzer_name\}` object is a child object of the <>. It contains the following properties: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|{analyzer_name} |Object |Yes a| +|token_filters |Array |Yes a| + +An array of strings that contains the token filters for the custom analyzer. + +For more information about the token filters you can define in a Search index JSON payload, see <>. -The name of this object matches the name of the custom analyzer. +You can also use one of the xref:default-token-filters-reference.adoc[default token filters]. -NOTE: The {analyzer_name} object contains the `token_filters`, `char_filters`, `type`, and `tokenizer` properties described in the following rows. +|char_filters |Array |Yes a| -|token_filters |Array |Yes |An array of strings that contains the token filters for the custom analyzer. +An array of strings that contains the character filters for the custom analyzer. -|char_filters |Array |Yes |An array of strings that contains the character filters for the custom analyzer. +For more information about the character filters you can define in a Search index JSON payload, see <>. + +You can also use one of the xref:default-character-filters-reference.adoc[default character filters] available. |type |String |Yes |The `type` is always `"custom"`. @@ -233,26 +363,46 @@ NOTE: The {analyzer_name} object contains the `token_filters`, `char_filters`, ` [#char_filters] == Char_filters Object -The `char_filters` object contains any custom character filters defined for an index. - -It contains any number of `{char_filter_name}` objects: +The `char_filters` object contains any custom character filters defined for a Search index: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=char_filter] +include::example$simple-search-index-payload.jsonc[tag=char_filters] ---- -The following table describes the available properties for the `char_filters` object: +TIP: To view the entire JSON payload, click btn:[View]. + +The `char_filters` object is a child object of the <>. It contains any number of <>: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|{char_filter_name} |Object |Yes a| +|\{char_filter_name\} |Object |Yes a| + +Set the name of this object to the name you want for your custom character filter. + +You can reference the `\{char_filter_name\}` object elsewhere in your Search index definition to use the character filter. + +For more information about the properties in an `\{char_filter_name\}` object, see <>. +|==== + +[#char-name] +=== \{Char_filter_name\} Object + +The `\{char_filter_name\}` object defines a specific custom character filter for a Search index: -The name of this object matches the name of the custom character filter. +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=char_filter_name] +---- -NOTE: The {char_filter_name} object contains the `regexp`, `replace`, and `type` properties described in the following rows. +A `\{char_filter_name\}` object is a child object of the <>. +It contains the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description |regexp |String |Yes |The regular expression to use to filter characters from search queries and documents. @@ -265,94 +415,148 @@ NOTE: The {char_filter_name} object contains the `regexp`, `replace`, and `type` [#tokenizers] == Tokenizers Object -The `tokenizers` object contains any custom tokenizers defined for an index. - -It contains any number of `{tokenizer_name}` objects: +The `tokenizers` object contains any custom xref:customize-index.adoc#tokenizers[tokenizers] defined for a Search index: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=tokenizers] +include::example$simple-search-index-payload.jsonc[tag=tokenizers] ---- -The following table describes the available properties for the `tokenizers` object: +TIP: To view the entire JSON payload, click btn:[View]. + +The `tokenizers` object is a child object of the <>. +It contains any number of <>: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|{tokenizer_name} |Object |Yes a| +|\{tokenizer_name\} |Object |Yes a| -The name of this object matches the name of the custom tokenizer. +Set the name of this object to the name you want for your custom tokenizer. + +You can reference the `\{tokenizer_name\}` object elsewhere in your Search index definition to use the tokenizer. + +For more information about the properties in an `\{tokenizer_name\}` object, see <>. + +|==== -NOTE: The {tokenizer_name} object contains the `type`, `regexp`, `exceptions`, and `tokenizer` properties described in the following rows. +[#tokenizer-name] +=== \{Tokenizer_name\} Object + +The `\{tokenizer_name\}` object defines a specific custom tokenizer for a Search index. +For example, the following `My_Tokenizer_Excep` object defines an `exception` tokenizer: + +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=tokenizer_name] +---- + +A `\{tokenizer_name\}` object is a child object of the <>. +It contains the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description |exceptions |Array |Yes a| -? +If the tokenizer's <> is `exception`, define an array of regular expressions to remove from text input to create tokens. -If the tokenizer's `type` value is `exception`, +For example, if you add the characters `sh` as a string to the `exceptions` array, an input string of `shTimeshToshGo` has the tokens `Time`, `To`, and `Go`. |regexp |String |Yes a| -The regular expression that the tokenizer uses to divide input into tokens. +If the tokenizer's <> is `regexp`, set the regular expression that the tokenizer uses to divide input into tokens. + +The tokenizer takes any matches for the regular expression from the input text stream and uses them as tokens. + +For example, if you use the regular expression `\w*\w`, an input string of `Full Text Search` has the tokens `Full`, `Text`, and `Search`. |tokenizer |String |Yes a| -? +If the tokenizer's `type` value is `exception`, give a default tokenizer to apply to the tokens created with the `exceptions` array. -If the tokenizer's `type` value is `exception`, +You can choose a xref:default-tokenizers-reference.adoc[default tokenizer] or use a tokenizer defined in the `tokenizers` object. -|type |String |Yes a| +|[[tokenizer_type]]type |String |Yes a| The tokenizer's type. Can be one of: -* `regexp`: The tokenizer uses a regular expression to create tokens. -* `exception`: The tokenizer uses ...? +* `regexp`: The tokenizer uses a regular expression to create tokens. +The tokenizer uses any matches to the regular expression as individual tokens. +* `exception`: The tokenizer uses an array of regular expressions to remove content and create tokens. +The tokenizer uses any matches to the regular expressions and creates tokens from the surrounding text. |==== [#token_filters] == Token_filters Object -The `token_filters` object contains any custom token filters defined for an index. - -It contains any number of `{token_filter__name}` objects: +The `token_filters` object contains any custom token filters defined for a Search index. [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=token_filters] +include::example$simple-search-index-payload.jsonc[tag=token_filters] ---- -The following table describes the available properties for the `token_filters` object: +TIP: To view the entire JSON payload, click btn:[View]. + +The `token_filters` object is a child object of the <>. +It contains any number of <>: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|{token_filter_name} |Object |Yes a| +|\{token_filter_name\} |Object |Yes a| -The name of this object matches the name of the custom token filter. +Set the name of this object to the name you want for your custom token filter. -NOTE: The {token_filter_name} object contains the `type` property described in the following row. The other properties depend on the value assigned to `type`. +You can reference the `\{token_filter_name\}` object elsewhere in your Search index definition to use the token filter. + +For more information about the properties in an `\{token_filter_name\}` object, see <>. +|==== + +[#token-filter-name] +=== \{Token_filter_name\} Object + +The `\{token_filter_name\}` object defines a custom token filter for a Search index. +For example, the following `My_Token_Filter` object defines a custom `length` token filter: + +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=token_filter_name] +---- + +A `\{token_filter_name\}` object is a child object of the <>. +It contains the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description |type |String |Yes a| The token filter's type. Can be one of: -* `dict_compound`: ...? See <>. -* `edge_ngram`: ...? See <>. -* `elision`: ...? See <>. -* `keyword_marker`: ..? See <>. -* `ngram`: ...? See <>. -* `normalize_unicode`: ...? See <>. -* `shingle`: ...? See <>. -* `stop_tokens`: ...? See <>. -* `truncate_token`: ...? See <>. +* `dict_compound`: Use a wordlist to find and create tokens from compound words in existing tokens. See <>. +* `edge_ngram`: Use a set character length to create tokens from the start or end of existing tokens. See <>. +* `elision`: Use a wordlist to remove elisions from input tokens. See <>. +* `keyword_marker`: Use a wordlist of keywords to find and create new tokens. See <>. +* `length`: Use a set character length to filter tokens that are too long or too short. See <>. +* `ngram`: Use a set character length to create new tokens. See <>. +* `normalize_unicode`: Use Unicode Normalization to convert tokens. See <>. +* `shingle`: Use a set character length and separator to concatenate and create new tokens. See <>. +* `stop_tokens`: Use a wordlist to find and remove words from tokens. See <>. +* `truncate_token`: Use a set character length to truncate existing tokens. See <>. |==== [#dict_compound] -=== Dict_compound Token Filters +==== Dict_compound Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=dict] [cols="1,1,1,2"] |==== @@ -360,12 +564,16 @@ The token filter's type. Can be one of: |dict_token_map |String |Yes a| -...? +The wordlist to use to find subwords in existing tokens. + +You can use a xref:default-wordlists-reference.adoc[default wordlist] or one defined in the <>. |==== [#edge_ngram] -=== Edge_ngram Token Filters +==== Edge_ngram Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=edge] [cols="1,1,1,2"] |==== @@ -373,20 +581,24 @@ The token filter's type. Can be one of: |back |Boolean |Yes a| -...? +To create new tokens starting from the end and moving backward in an input token, set `back` to `true`. + +To create new tokens starting from the beginning and moving forward in an input token, set `back` to `false`. |min |Integer |Yes a| -...? +Set the minimum character length for a new token. |max |Integer |Yes a| -...? +Set the maximum character length for a new token. |==== [#elision] -=== Elision Token Filters +==== Elision Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=elision] [cols="1,1,1,2"] |==== @@ -394,12 +606,16 @@ The token filter's type. Can be one of: |articles_token_map |String |Yes a| -...? +The wordlist to use to find and remove elisions in existing tokens. + +You can use a xref:default-wordlists-reference.adoc[default wordlist] or one defined in the <>. |==== [#keyword_marker] -=== Keyword_marker Token Filters +==== Keyword_marker Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=keyword] [cols="1,1,1,2"] |==== @@ -407,29 +623,46 @@ The token filter's type. Can be one of: |keywords_token_map |String |Yes a| -...? +The wordlist to use to find keywords in existing tokens. + +You can use a xref:default-wordlists-reference.adoc[default wordlist] or one defined in the <>. |==== -[#ngram] -=== Ngram Token Filters +[#length] +==== Length Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=length] [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|min |Integer |Yes a| +|min |Integer |Yes |The minimum character length for a new token from the token filter. -...? +|max |Integer |Yes |The maximum character length for a new token from the token filter. -|max |Integer |Yes a| +|==== + +[#ngram] +==== Ngram Token Filters -...? +include::partial$custom-token-filters-descriptions.adoc[tag=ngram] + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|min |Integer |Yes |The minimum character length for a new token from the token filter. + +|max |Integer |Yes |The maximum character length for a new token from the token filter. |==== [#normalize] -=== Normalize_unicode Token Filters +==== Normalize_unicode Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=normalize] [cols="1,1,1,2"] |==== @@ -437,41 +670,46 @@ The token filter's type. Can be one of: |form |String |Yes a| -...? +Select the form of Unicode Normalization to use on input tokens: + +* `nfc`: Use canonical decomposition and canonical composition to normalize characters. The token filter separates combined unicode characters, then merges them into a single character. +* `nfd`: Use canonical decomposition to normalize characters. The token filter separates combined unicode characters. +* `nfkc`: Use compatibility decomposition to normalize characters. The token filter converts unicode characters to remove variants. +* `nfkd`: Use compatibility decomposition and canonical composition to normalize characters. The token filter removes variants, then separates combined unicode characters to merge them into a single character. + +For more information about Unicode Normalization, see the Unicode Consortium's https://unicode.org/reports/tr15/#Introduction[Unicode Normalization Forms^] report. |==== [#shingle] -=== Shingle Token Filters +==== Shingle Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=shingle] [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|min |Integer |Yes a| +|min |Integer |Yes |The minimum character length for a new token before concatenation. -...? - -|max |Integer |Yes a| - -...? +|max |Integer |Yes |The maximum character length for a new token before concatenation. |output_original |Boolean |Yes a| -...? - -|separator |String |Yes a| +To add the original token to the token filter's output, set `output_original` to `true`. -...? +To exclude the original token from the token filter's output, set `output_original` to `false`. -|filler |String |Yes a| +|separator |String |No |Set a `separator` to include a character or characters in between concatenated tokens. -...? +|filler |String |No |If another token filter removes a token from the input for this token filter, set a `filler` to replace the removed token. |==== [#stop_token] -=== Stop_tokens Token Filters +==== Stop_tokens Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=stop] [cols="1,1,1,2"] |==== @@ -479,46 +717,71 @@ The token filter's type. Can be one of: |stop_token_map |String |Yes a| -...? +The wordlist to use to filter tokens. + +The token filter removes any tokens from input that match an entry in the wordlist. + +You can use a xref:default-wordlists-reference.adoc[default wordlist] or one defined in the <>. |==== [#truncate_token] -=== Truncate_token Token Filters +==== Truncate_token Token Filters + +include::partial$custom-token-filters-descriptions.adoc[tag=truncate] [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|length |Integer |Yes a| - -...? +|length |Integer |Yes |The maximum character length for an output token. |==== [#token_maps] == Token_maps Object -The `token_maps` object contains any custom wordlists defined for an index. - -It contains any number of `{wordlist_name}` objects: +The `token_maps` object contains any custom wordlists defined for a Search index: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=token_maps] +include::example$simple-search-index-payload.jsonc[tag=token_maps] ---- -The following table describes the available properties for the `token_maps` object: +TIP: To view the entire JSON payload, click btn:[View]. + +The `token_maps` object is a child object of the <>. +It contains any number of <>: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|{wordlist_name} |Object |Yes a| +|\{wordlist_name\} |Object |Yes a| + +Set the name of this object to the name you want for your custom wordlist. -The name of this object matches the name of the custom wordlist. +You can reference the `\{wordlist_name\}` object elsewhere in your Search index definition to use the wordlist. -NOTE: The {wordlist_name} object contains the `type` and `tokens` properties described in the following rows. +For more information about the properties in an `\{wordlist_name\}` object, see <>. +|==== + +[#wordlist-name] +=== \{Wordlist_name\} Object + +The `\{wordlist_name\}` object defines a custom wordlist for a Search index: + +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=wordlist_name] +---- + +A `\{wordlist_name\}` object is a child object of the <>. +It contains the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description |type |String |Yes |The `type` is always `"custom"`. @@ -529,26 +792,48 @@ NOTE: The {wordlist_name} object contains the `type` and `tokens` properties des [#date_time_parsers] == Date_time_parsers Object -The `date_time_parsers` object contains any custom date/time parsers defined for an index. - -It contains any number of `{date_time_parser_name}` objects: +The `date_time_parsers` object contains any custom date/time parsers defined for a Search index: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=date_time] +include::example$simple-search-index-payload.jsonc[tag=date_time_parsers] ---- -The following table describes the available properties for the `date_time_parsers` object: +TIP: To view the entire JSON payload, click btn:[View]. -[cols="1,1,1,2"] +The `date_time_parsers` object is a child object of the <>. +It contains any number of <>: + +[cols="2,1,1,2"] |==== |Property |Type |Required? |Description -|{date_time_parser_name} |Object |Yes a| +|\{date_time_parser_name\} |Object |Yes a| + +Set the name of this object to the name you want for your custom date/time parser. + +You can reference the `\{date_time_parser_name\}` object elsewhere in your Search index definition to use the date/time parser. + +For more information about the properties in an `\{date_time_parser_name\}` object, see <>. + +|==== + +[#dt-parser-name] +=== \{date_time_parser_name\} Object + +The `\{date_time_parser_name\}` object defines a custom date/time parser for a Search index: -The name of the custom date/time parser. +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=date_time_parser_name] +---- -NOTE: The `{date_time_parser_name}` object contains the `type` and `layouts` properties described in the following rows. +A `\{date_time_parser_name\}` object is a child object of the <>. +It contains the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description |type |String |Yes |The `type` is always `"flexiblego"`. @@ -563,15 +848,18 @@ Use a layout from the https://pkg.go.dev/time#pkg-constants[Go Programming Langu [#default-mapping] == Default_mapping Object -The `default_mapping` object contains settings for the default type mapping on the index. +The `default_mapping` object contains settings for the default type mapping on the Search index. The default type mapping is a legacy feature and only included for compatibility. [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=default_mapping] +include::example$simple-search-index-payload.jsonc[tag=default_mapping] ---- -The following table describes the available properties for the `default_mapping` object: +TIP: To view the entire JSON payload, click btn:[View]. + +The `default_mapping` object is a child object of the <>. +It contains the following properties: [cols="1,1,1,2"] |==== @@ -585,7 +873,7 @@ To only index the fields you specify in the type mapping, set `dynamic` to `fals |enabled |Boolean |Yes a| To enable the Search Service's default type mapping, set `enabled` to `true`. -The default type mapping includes all documents in the bucket in the index, even if they don't match another configured type mapping. +The default type mapping includes all documents in the bucket in the Search index, even if they do not match another configured type mapping. This can increase index size and indexing time. To disable the default type mapping, set `enabled` to `false`. @@ -595,84 +883,134 @@ To disable the default type mapping, set `enabled` to `false`. [#types] == Types Object -The `types` object contains any additional user-defined type mappings for an index. - -It contains any number of `{scope}.{collection}` objects: +The `types` object contains any additional user-defined type mappings for a Search index. [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=types] +include::example$simple-search-index-payload.jsonc[tag=types] ---- +TIP: To view the entire JSON payload, click btn:[View]. + +The `types` object is a child object of the <>. +It contains any number of <>: + [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|`{scope}.{collection}` |Object |Yes a| +|\{scope\}.\{collection\} |Object |Yes a| + +The name of the type mapping. +Corresponds to the selected scope and collection where the type mapping applies. +For example, `inventory.airline`. + +For more information about the properties in an `\{scope\}.\{collection\}` object, see <>. + +TIP: To add a type identifier as an additional filter to your type mapping, add the filter to the end of your `\{scope\}.\{collection\}` object. For example, to use a `type_field` filter that uses the `type` field, and add only documents with a `type` value of `hotel`, the object name would be `\{scope\}.\{collection\}.hotel` +|==== + +[#scope-collection] +=== \{Scope\}.\{collection\} Objects, JSON Object Field Objects, and XATTRs Objects + +The `\{scope\}.\{collection\}` object defines a custom type mapping for a Search index, on a specific scope and collection in the cluster: + +[source,json] +---- +include::example$simple-search-index-payload.jsonc[tag=scope_collection] +---- + +A `\{scope\}.\{collection\}` object is a child object of the <>. + +A JSON object field object is a child object of the `\{scope\}.\{collection\}` object. +It defines a mapping for a field that contains a JSON object in your document schema. +It can contain additional mappings as <> under its <> object. + +A JSON object field object must: + +* Be a child object of a `\{scope\}.\{collection\}` object. +* Have a name that matches a JSON object field in your documents. +* Use the same property structure as a `\{scope\}.\{collection\}` object. + +If your cluster is running Couchbase Server version 7.6.2 and later and you're adding Extended Attributes (XATTRs) from your document metadata to your Search index, your XATTRs mapping definition must: -The name of the type mapping. Corresponds to the selected scope and collection where the type mapping applies. For example, `inventory.airline`. +* Be a child object of a `\{scope\}.\{collection\}` object. +* Have the name `_$xattrs`. +* Use the same property structure as a `\{scope\}.\{collection\}` object. -NOTE: The `{scope}.{collection}` object contains the `enabled`, `dynamic`, and `properties` properties described in the following rows. +For example, the following JSON index definition snippet defines a `\{scope\}.\{collection\}` object for the `inventory.hotel` scope and collection. +It adds a dynamic mapping for any XATTRs metadata present on documents in the collection. +It adds two nested JSON Object Field objects, `reviews` and `ratings`, that contain a single <> for the `Cleanliness` field: + +[source,json] +---- +include::example$nested-json-object-example.jsonc[] +---- + +You can view the JSON document schema for this example by looking at any document in the `hotel` collection from the `travel-sample` dataset. +For more information, see xref:clusters:data-service/manage-documents.adoc[]. + +`\{scope\}.\{collection\}` objects, JSON Object Field objects, and XATTRs objects can contain the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description |dynamic |Boolean |Yes a| -To index all fields under the specified scope and collection, set `dynamic` to `true`. +To index all fields under the specified scope and collection, JSON object, or all fields inside XATTRs, set `dynamic` to `true`. To only index the fields you specify and enable the `properties` block, set `dynamic` to `false`. |enabled |Boolean |Yes a| -To enable the type mapping and include any documents that match it in the index, set `enabled` to `true`. +To enable the mapping and include any documents that match it in the Search index, set `enabled` to `true`. -To remove any documents that match this type mapping from the index, set `enabled` to `false`. +To remove any documents that match this mapping from the Search index, set `enabled` to `false`. -|properties |Object |No a| +|[[properties]]properties |Object |No a| The `properties` object is only enabled if `dynamic` is set to `false`. -Specifies properties for the fields to index in the type mapping. Contains any number of `{field_name}` objects. +Specifies properties for the fields to index in the mapping. +Contains any number of `\{field_name\}` objects. -For more information, see <> +For more information, see <>. |==== [#child-fields] -=== {field_name} Object +=== \{field_name\} Object -The `{field_name}` object contains settings and an array for a child field in a type mapping. You can have multiple `{field_name}` objects in a `properties` object. +The `\{field_name\}` object contains properties and an array for a document field in a type mapping. +You can have multiple `\{field_name\}` objects in a <>. [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=child_field] +include::example$simple-search-index-payload.jsonc[tag=field_name] ---- -A `{field_name}` object contains the following properties: +TIP: To view the entire JSON payload, click btn:[View]. + +The name of the object corresponds to the name of the field you want to include or exclude from your Search index. + +A `\{field_name\}` object contains the following properties: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|{field_name} |Object |Yes a| - -The name of the child field you want to index in the type mapping. For example, `city`. - -NOTE: The {field_name} object contains the `enabled`, `dynamic`, and `fields` properties described in the following rows. - |enabled |Boolean |Yes a| -To add this child field to the index, set `enabled` to `true`. +To add this document field to the Search index, set `enabled` to `true`. -To remove this child field from the index, set `enabled` to `false`. +To remove this document field from the index, set `enabled` to `false`. -|dynamic |Boolean |Yes a| - -To , set `dynamic` to `true`. - -To , set `dynamic` to `false`. +|dynamic |Boolean |No a|This field is included for legacy compatibility only. |fields |Array |Yes a| -An array that contains objects with settings for each child field to index in the type mapping. +An array that contains objects with settings for each document field to index in the type mapping. For more information, see <>. @@ -681,26 +1019,39 @@ For more information, see <>. [#fields] === Fields Array -The `fields` array contains objects with settings for each child field to index in the type mapping: +The `fields` array contains objects with settings for each document field to index in the type mapping: [source,json] ---- -include::example$complex-search-index-payload.jsonc[tag=fields] +include::example$simple-search-index-payload.jsonc[tag=fields] ---- +TIP: To view the entire JSON payload, click btn:[View]. + +The `fields` array is located inside a <>. It contains the following properties: [cols="1,1,1,2"] |==== |Property |Type |Required? |Description +|analyzer |String |Text Only a| + +If the document field's `type` is `text`, set the analyzer to use for the document field. + +NOTE: If you want to use the default analyzer for the content of this document field, you do not need to include an `analyzer` property. + +|[[dims]]dims |Number |Vector Only a| + +include::partial$vector-search-field-descriptions.adoc[tag=dimension] + |docvalues |Boolean |Yes a| -To include the value for each instance of the field in the index to support xref:[Facets] and sorting search results, set `docvalues` to `true`. +To include the value for each instance of the field in the Search index to support xref:search-request-params.adoc#facet-name[facets] and sorting search results, set `docvalues` to `true`. To exclude the values for each instance of this field from the index, set `docvalues` to `false`. -|include_in_all |Boolean |Yes a| +|[[include-in-all]]include_in_all |Boolean |Yes a| To allow this field to be searched without specifying the specific field's name in the search, set `include_in_all` to `true`. @@ -708,31 +1059,37 @@ When enabled, you can search this field through the specified `default_field` se To only search this field by specifying the field name, set `include_in_all` to `false`. -|include_term_vectors |Boolean |Yes a| +|[[term-vectors]]include_term_vectors |Boolean |Yes a| NOTE: To use term vectors, `store` must be set to `true`. To allow the Search Service to highlight matching search terms in search results for this field, set `include_term_vectors` to `true`. +You must also enable term vectors to use `includeLocations` in a Search query. For more information, see xref:search-request-params.adoc#includelocations[includeLocations]. + To disable term highlighting and reduce index size, set `include_term_vectors` to `false`. |index |Boolean |Yes a| -To include the child field in the index, set `index` to `true`. +To include the document field in the Search index, set `index` to `true`. + +To exclude the document field from the index, set `index` to `false`. -To exclude the child field from the index, set `index` to `false`. +|name |String |Yes |The document field's name. -|name |String |Yes |The child field's name. +|[[similarity]]similarity |String |Vector Only a| + +include::partial$vector-search-field-descriptions.adoc[tag=similarity_metric] |store |Boolean |Yes a| -To include the content of the child field in the index and allow its content to be viewed in search results, set `store` to `true`. +To include the content of the document field in the Search index and allow its content to be viewed in search results, set `store` to `true`. -To exclude the content of the child field from the index, set `store` to `false`. +To exclude the content of the document field from the index, set `store` to `false`. |type |String |Yes a| -The child field's type. Can be one of: +The document field's type. Can be one of: * `text` * `number` @@ -741,13 +1098,14 @@ The child field's type. Can be one of: * `geopoint` * `geoshape` * `disabled` +* `ip` +* `vector` +* (Server version 7.6.2 and later) `vector_base64` -For more information on the available field data types, see xref:search/field-data-types-reference.adoc[]. - -|analyzer |String |No a| +For more information about the available field data types, see xref:field-data-types-reference.adoc[]. -If the child field's `type` is `text`, set the analyzer to use for the child field. +|[#vector-index-optimized-param]#vector_index_optimized_for# |String |Vector Only a| -NOTE: If you want to use the default analyzer for the content of this child field, you don't need to include an `analyzer` property. +include::partial$vector-search-field-descriptions.adoc[tag=optimized_for] -|==== \ No newline at end of file +|==== diff --git a/modules/search/pages/search-query-auto-complete-code.adoc b/modules/search/pages/search-query-auto-complete-code.adoc new file mode 100644 index 000000000..7138adffb --- /dev/null +++ b/modules/search/pages/search-query-auto-complete-code.adoc @@ -0,0 +1,85 @@ += Add Autocomplete to Your Application +:description: Use autocomplete to add suggestions for a user's Search query as they type in your application. +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-topic-type: guide +:tabs: + +[abstract] +{description} + +After you xref:search-query-auto-complete-ui.adoc[create and configure a Search index that supports autocomplete], configure your application to return results from the Search Service. + +== Prerequisites + +* You have the Search Service enabled on a node in your cluster. +For more information about how to change Services on your cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have the hostname for the node in your cluster that's running the Search Service. ++ +Go to your cluster settings and click btn:[Nodes] to view node hostnames. + +* You have created a compatible Search index. +For more information, see xref:search-query-auto-complete-ui.adoc[]. + +* You have created cluster access credentials that have Read/Write permissions on the bucket and scope where you created your Search index. +For more information, see xref:clusters:manage-database-users.adoc[]. + +== Procedure + +To add autocomplete with the Search Service to your application: + +. Test that your Search index was configured correctly by xref:simple-search-ui.adoc[running a Search query from the {page-ui-name}] with 2-8 characters in the *Search* field. ++ +For example, with the `travel-sample` bucket, you could enter the strings `Be`, `Bea`, `Beau`, and `Beauf` to find a document with the text `Beaufort Hotel`. + +. Configure your application to return results from the Search Service. ++ +The following examples simulate a user typing an input string and return search results for each partial string: ++ +[{tabs}] +==== +C#:: ++ +[source,csharp] +---- +include::example$autocomplete-sample.cs[] +---- +Go:: ++ +[source,go] +---- +include::example$autocomplete-sample.go[] +---- + +Java:: ++ +[source,java] +---- +include::example$autocomplete-sample.java[] +---- + +JavaScript:: ++ +[source,javascript] +---- +include::example$autocomplete-sample.js[] +---- + +Python:: ++ +[source,python] +---- +include::example$autocomplete-sample.py[] +---- +==== + +== Next Steps + +After you add autocomplete to your application, to improve your search results, you can: + +* xref:customize-index.adoc[Add additional features to your Search index from the UI]. +* Change the xref:search-index-params.adoc[JSON payload] for your Search index. diff --git a/modules/search/pages/search-query-auto-complete-ui.adoc b/modules/search/pages/search-query-auto-complete-ui.adoc new file mode 100644 index 000000000..938d8bfd8 --- /dev/null +++ b/modules/search/pages/search-query-auto-complete-ui.adoc @@ -0,0 +1,78 @@ += Configure an Autocomplete Search Index +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Create a Search index with the {page-ui-name} or import a JSON Search index payload to start using autocomplete with the Search Service. + +[abstract] +{description} + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. + + +== Procedure + +You can create a compatible Search index with the <> or <>. + +[#ui] +=== Create an Autocomplete Search Index Manually with the {page-ui-name} + +To create the Search index in the {page-ui-name} with Advanced Mode: + +. On the *Operational Clusters* page, select the operational cluster where you want to create a Search index. +. Go to menu:Data Tools[Search]. +. Click btn:[Create Search Index]. +. Click btn:[Enable Advanced Options]. +. In the *Index Name* field, enter a name for the Search index. ++ +[NOTE] +==== +Your index name must start with an alphabetic character (a-z or A-Z). It can only contain alphanumeric characters (a-z, A-Z, or 0-9), hyphens (-), or underscores (_). + +For Couchbase Server version 7.6 and later, your index name must be unique inside your selected bucket and scope. +You cannot have 2 indexes with the same name inside the same bucket and scope. +==== + +. In the *Bucket*, *Scope*, and *Collection* lists, choose the bucket and scope where you want to create your Search index, and the collections you want to include. +. xref:create-custom-analyzer.adoc[] with the following settings: +.. In the *Name* field, enter `keyword_to_lower`. +.. In the *Tokenizer* list, select *single*. +.. In the *Token Filters* list, select and add the *to_lower* token filter. +. xref:create-custom-analyzer.adoc[Create another custom analyzer] with the following settings: +.. In the *Name* field, enter `edge_ngram`. +.. In the *Tokenizer* list, select *unicode*. +.. xref:create-custom-token-filter.adoc#edge-ngram[Create a custom token filter] with the following settings: +... In the *Name* field, enter `edge_ngram_2_8`. +... In the *Type* list, select *edge_ngram*. +... In the *Min* box, enter `2`, or the minimum number of characters you want the Search index to use for autocomplete. +... In the *Max* box, enter `8`, or the maximum number of characters you want the Search index to use for autocomplete. +.. In the *Token Filters* list for your custom analyzer, click both the *to_lower* and your custom *edge_ngram_2_8* token filter. +. xref:create-search-index-ui.adoc#configure-settings[Set your default analyzer] to your custom *keyword_to_lower* analyzer. +. Under *Type Mappings*, in your document schema, click the name of a field that contains the data you want to search. +. Configure the field: +.. In the *Analyzer/Language* list, select your *edge_ngram* analyzer. +.. Select *Include in search results*. +.. Select *Support field agnostic search*. +. Click btn:[Create Index]. + +[#import] +=== Import a Search Index Payload + +. xref:import-search-index.adoc[] with the following JSON payload, replacing all placeholder values that start with a `$`: ++ +[source,json] +---- +include::example$autocomplete-search-index.jsonc[] +---- + +== Next Steps + +To add an autocomplete feature to your application, see xref:search-query-auto-complete-code.adoc[] for example code. diff --git a/modules/search/pages/search-query-auto-complete.adoc b/modules/search/pages/search-query-auto-complete.adoc new file mode 100644 index 000000000..93c2f0744 --- /dev/null +++ b/modules/search/pages/search-query-auto-complete.adoc @@ -0,0 +1,23 @@ += Use Autocomplete with the Search Service +:page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Add autocomplete to your application to provide a search engine-like experience for your operational cluster. + +[abstract] +{description} + +Also known as auto suggest or type-ahead, autocomplete guesses potential matches for a user's search input as they type. + +Autocomplete can provide a better user experience with search in your application. + +== Set Up Autocomplete + +To use autocomplete with the Search Service and your Couchbase {page-product-name} operational cluster: + +. Create a compatible Search index. +You can create the index xref:search-query-auto-complete-ui.adoc#ui[with the UI] or xref:search-query-auto-complete-ui.adoc#import[import a JSON payload]. +. Configure your application to return autocomplete search results from the Search Service. +For example code that you can use with your application, see xref:search-query-auto-complete-code.adoc[]. + +You can use the `travel-sample` dataset to test and configure autocomplete, or use your own data. \ No newline at end of file diff --git a/modules/search/pages/search-request-params.adoc b/modules/search/pages/search-request-params.adoc index d4a702e4c..d83b2a995 100644 --- a/modules/search/pages/search-request-params.adoc +++ b/modules/search/pages/search-request-params.adoc @@ -1,54 +1,2201 @@ -= Search Request Properties += Search Request JSON Properties +:page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: You can add additional properties to a Search request to control how the Search Service returns results. +:page-toclevels: 3 + +[abstract] +{description} + +The following is an example Search request: + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=full] +---- + +A Search request can contain the following properties: + +[cols="1,1,1,4"] +|==== +|Property |Type |Required? |Description + +|[[query]]query |Object |Regular or Hybrid Search Only a| + +An object that contains the properties for one of the supported query types. + +The `query` object is required if you want to run a regular search, or a hybrid search that includes a xref:vector-search:vector-search.adoc[Vector Search] query. +If your cluster is running Couchbase Server version 7.6.2 and later, you do not need to include the `query` object for a pure Vector Search query. + +For more information about how to configure the `query` object, see <>. + +|[[knn]]knn |Array of Objects |Vector Only a| + +An array that contains objects that describe a xref:vector-search:vector-search.adoc[Vector Search] query. + +For more information about how to configure the objects inside a `knn` array, see <>. + +|ctl |Object |No a| + +An object that contains properties for query consistency. + +For more information about how to configure Search query consistency inside the `ctl` object, see <>. + +|[[size-limit]]size/limit |Integer |No a| + +Set the total number of results to return for a single page of search results. + +If you provide both the `size` and `limit` properties, the Search Service uses the `size` value. + +The Search Service returns the `size` number of results: + +* Starting at the offset in the `from` or `offset` property. +* Starting from the key specified in the <>. +* Starting backward from the key specified in the <>. + +The `size` property is added by default to all Search requests, if not otherwise specified, with a value of `10`. + +|from/offset |Integer |No a| + +Set an offset value to change where pagination starts for search results, based on the Search query's <>. + +For example, if you set a `size` value of `5` and a `from` value of `10`, the Search query returns results 11 through 15 on a page. + +If you provide both the `from` and `offset` properties, the Search Service uses the `from` value. + +The `from` property is added by default to all Search requests, if not otherwise specified, with a value of `0`. + +|highlight |Object |No a| + +Contains properties to control search result highlighting. + +For more information about how to configure highlighting in Search results, see <>. + +|[[fields]]fields |Array |No a| + +An array of strings to specify each indexed field you want to return in search results. + +You must add a field and its contents to a Search index to view it in search results or add it to the `fields` array. + +|[[facets]]facets |Object |No a| + +Contains `\{facet-name\}` objects to define each facet you want to return with search results. + +The Search Service supports the following facet types: + +* *Term Facet*: Counts the documents that have the same value for a specified field. +* *Numeric Range Facet*: Counts the documents with numeric field values that are greater than or less than a specified range or ranges. +* *Date Range Facet*: Counts the documents with date field values that are earlier or later than a specified range or ranges. + +For more information, about how to configure the different facet types inside the `facets` object, see <>. + +|explain |Boolean |No a| + +To create an explanation for a search result's score in search results, set `explain` to `true`. + +To turn off explanations for search result scoring, set `explain` to `false`. + +|[[sort_arr]]sort |Array |No a| + +Contains an array of strings or JSON objects to set how to sort search results. +By default, the Search Service sorts results based on score values, from highest to lowest. + +The strings can be: + +* `\{field_name\}`: Specify the name of a field to use to sort the search results. +* `_id`: Use the document's identifier to sort the search results. +* `_score`: Use the document's score from the Search query to sort the search results. + +For more information about the properties for a `sort` JSON object, see <>. + +|[[includelocations]]includeLocations |Boolean |No a| + +To return the position of each occurrence of a search term inside a document, set `includeLocations` to `true`. + +NOTE: You must have *Include Term Vectors* enabled or the `include_term_vectors` property set to `true` on a field to use `includeLocations`. +For more information about how to enable term vectors, see xref:type-mapping-options.adoc#term-vectors[Field Type Mapping Options] or xref:search-index-params.adoc#term-vectors[Search Index JSON Properties]. + +// Need to revisit what's up with term vectors + +To turn off term locations, set `includeLocations` to `false`. + +|score |String |No a| + +To turn off document relevancy scoring in search results, set `score` to `none`. + +To turn on document relevancy scoring in search results, remove the `score` property. + +|[[search_after]]search_after |Array |No a| + +NOTE: If you use `search_after` in a search request, you can't use `search_before`. +Both properties are included in the example code to show the correct syntax. + +Use `search_after` with `from/offset` and `sort` to control pagination in search results. + +Give a value for each string or JSON object in the <> to the `search_after` array. +You must provide the values in the same order that they appear in the <>. +Values in the `search_after` array must be strings. +You cannot use `search_after` with numbers or other field data types - if your `sort` array includes fields with a `date` or `number` type, you cannot use `search_after`. +Only result relevancy score values can be entered as strings in the array. + +The Search Service starts search result pagination after the document with the values you provide in the array. + +For example, if you had a set of 10 documents to sort based on `_id` values of 1-10, with `from` set to `2` and `search_after` set to `8`, documents 9-10 appear on the same page. + +To reduce the resource costs of deeper pagination on your Search queries, try to always include your document ID values as the final sort criteria in your <>. +Set the `search_after` property to include the values from the last result on your previous page of search results to effectively paginate. + +|[[search_before]]search_before |Array |No a| + +NOTE: If you use `search_before` in a search request, you can't use `search_after`. +Both properties are included in the example code to show the correct syntax. + +Use `search_before` with `from/offset` and `sort` to control pagination in search results. + +Give a value for each string or JSON object in the `sort` array to the `search_before` array. +You must provide the values in the same order that they appear in the `sort` array. +Values in the `search_before` array must be strings. +You cannot use `search_before` with numbers or other field data types - if your `sort` array includes fields with a `date` or `number` type, you cannot use `search_before`. +Only result relevancy score values can be entered as strings in the array. + +The Search Service starts search result pagination before the document with the values you provide in the array. + +For example, if you had a set of 10 documents to sort based on `_id` values of 1-10, with `from` set to `2` and `search_before` set to `8`, documents 2-6 appear on the same page. + +To reduce the resource costs of deeper pagination on your Search queries, try to always include your document ID values as the final sort criteria in your <>. +Set the `search_before` property to include the values from the last result on your previous page of search results to effectively paginate. + +|[[collections]]collections |Array |No |Contains an array of strings that specify the collections where you want to run the query. + +|==== + +[#knn-object] +== Knn Objects + +Each object inside the `knn` array in a Search query describes a xref:vector-search:vector-search.adoc[Vector Search] query. + +Add the `knn` array with at least one object to run a Vector Search query: + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=knn] +---- + +NOTE: If your cluster is running Couchbase Server version 7.6.2 and later, to return only results from your Vector Search query, do not include a `query` object with your Search request. +To run a hybrid query that uses regular Search Service parameters together with Vector Search to return results, see the <> section. + +An object in the `knn` array can contain the following properties: + +[cols="1,1,1,4"] +|==== +|Property |Type |Required? |Description + +|k |Integer |Yes a| + +Enter the total number of results that you want to return from your Vector Search query. + +The Search Service returns the `k` closest vectors to the vector given in `vector` or, if your cluster is running Couchbase Server version 7.6.2 or later, `vector_base64`. + +NOTE: The <> overrides any value set in `k`. + +|params |Object |No a| + +Enter additional parameters to control how the Search Service compares vectors when running a Vector Search request. + +For more information about the `params` object, see <>. + +|field |String |Yes a| + +The name of the field that contains the vector data you want to search. + +|vector |Array of Floats |Must have `vector` or `vector_base64` a| + +Enter the vector that you want to compare to the vector data in `field`. + +The Search Service uses the similarity metric defined in the xref:search-index-params.adoc#similarity[Search index definition] to return the `k` closest vectors from the Search index. + +NOTE: The vector in your Search query must match the dimension of the vectors stored in your Search index. +If the dimensions do not match, your Search query does not return any results. +For more information about the dimension value, see the xref:search-index-params.adoc#dims[dims property] or the xref:type-mapping-options.adoc#dimension[Dimension option] in the UI. + +|vector_base64 |Base64 Encoded String |Must have `vector` or `vector_base64` a| + +If your cluster is running Couchbase Server version 7.6.2 or later, enter a vector, encoded as a base64 string, that you want to compare to the vector data in `field`. + +The Search Service uses the similarity metric defined in the xref:search-index-params.adoc#similarity[Search index definition] to return the `k` closest vectors from the Search index. + +NOTE: The vector in your Search query must match the dimension of the vectors stored in your Search index. +If the dimensions do not match, your Search query does not return any results. +For more information about the dimension value, see the xref:search-index-params.adoc#dims[dims property] or the xref:type-mapping-options.adoc#dimension[Dimension option] in the UI. + +|[[filter]]filter |Object |No a| + +Add a filter object to xref:vector-search:pre-filtering-vector-search.adoc[add pre-filtering], based on an additional query, to a Vector Search query. + +The `filter` object can take properties from any of the query types supported by the <>. +|==== + +[#knn-params] +=== Knn params Object + +Use the `params` object inside a `knn` object to fine tune the probes and centroids the Search Services uses and searches while running a Vector Search request. + +The `params` object can contain the following properties: + +[cols="1,1,1,4"] +|==== +|Property |Type |Required? |Description + +|ivf_nprobe_pct |Number (percentage) |No a| + +Set the `ivf_nprobe_pct` value to control the percentage of probes, or the percentage of clusters, that the Search Service searches during a single Vector Search query. + +The Search Service automatically calculates a default `nprobe` percentage based on the vectors in a given partition of your Vector Search index. +For more information about this calculation, see xref:vector-search:fine-tune-vector-search.adoc[]. + +If you set the value of `ivf_nprobe_pct` higher than this default calculated value, the Search Service will search a higher percentage of clusters in your processed vectors. +This can increase your accuracy and recall for Vector Search, but requires more compute time for each query. + +In the example, the Search Service searches only `1%` of the total available clusters. + +|ivf_max_codes_pct |Number (percentage out of 100) |No a| + +Set the `ivf_max_codes_pct` value to control the maximum number of centroids that the Search Service accesses during a single Vector Search query. + +By default, this value is always 100%. + +If you reduce your `ivf_max_codes_pct` value, the Search Service accesses fewer centroids, which reduces your Vector Search accuracy and recall, but gives faster compute times for your search. + +In the example, the Search Service searches only `0.2%` of the available centroids in your vector data. +|==== + +[#query-object] +== Query Object + +Use the `query` object to set the specific details of your Search query. + +Use the properties in the `query` object to control search result rankings, add multiple subqueries, and more. + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=query] +---- + +[#boolean-queries] +=== Boolean Queries + +Use any of the following properties to run a boolean query. +A boolean query searches for a combination of queries that a document must match to be included in search results. + +Boolean queries use a <> inside the <>, <> and <> objects to set the queries a document must match. + +[cols="1,1,4,4"] +|==== +|Property |Type |Description |Examples + +| [[must]]must +| Object +a| Use a `must` object to create a boolean query. + +A `must` object must contain a <>. +The array lists all the queries that must have a match in a document to include the document in search results. + +For example, a query could have a `must` object with 2 queries in a `conjuncts` array. +The Search Service must find a match for both those queries in a document to include it in search results. + +a| +.reviews.content field must contain "location" and the phrase "nice view" +[source,json] +---- +include::example$query-boolean.jsonc[tag=must] +---- + +| [[must_not]]must_not +| Object +a| Use a `must_not` object to create a boolean query. + +A `must_not` object must contain a <>. +The array lists all the queries that must have a match in a document to include the document in search results. + +For example, a query could have a `must_not` object with 3 queries in a `disjuncts` array. +The Search Service must not find a match for any of the 3 queries in a document to include it in search results. + +a| +.free_breakfast field must not be false and reviews.Cleanliness field must not be between 1 and 3 +[source,json] +---- +include::example$query-boolean.jsonc[tag=must_not] +---- + +| [[should]]should +| Object +a| Use a `should` object to create a boolean query. + +A `should` object must contain a <>. +The array lists all the queries that must have a match in a document to score the document higher in search results. + +A document can be included in search results if it does not match the query or queries in a `should` object. +The document scores higher in search results if it does match the query. + +a| +.free_parking and free_internet fields should be true +[source,json] +---- +include::example$query-boolean.jsonc[tag=should] +---- + +|==== + +[#compound-queries] +=== Compound Queries (AND and OR) + +Use a compound query array to specify multiple child queries that must have a match in a document for that document to be included in search results. + +You must use compound query arrays to run a <>, but you can use a compound query array outside of a boolean query. + +You can use 2 different types of compound queries: + +[cols="1,1,4,4"] +|==== +|Property |Type |Description |Examples + +| [[conjuncts]]conjuncts +| Array +a| Use the `conjuncts` array to specify multiple child queries in a single `query` object. + +You can use the `conjuncts` array inside a <> or directly inside a `query` object. + +If you use the `conjuncts` array, every query object in the array must have a match in a document to include the document in search results. + +You can create objects in a `conjuncts` array to describe any of the available query types: + +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> + +a| +.reviews.date field must be between 2001-10-09 and 2016-10-31 and description field must contain "pool" +[source,json] +---- +include::example$query-compound.jsonc[tag=conjuncts] +---- + +| [[disjuncts]]disjuncts +| Array +a| Use the `disjuncts` array to specify multiple child queries in a single `query` object. + +You can use the `disjuncts` array inside a <>, <>, or directly inside a `query` object. + +Use a `min` property to set the number of query objects from the `disjuncts` array that must have a match in a document. +If a document does not match the `min` number of query objects, the Search Service does not include the document in search results. + +You can create objects in a `disjuncts` array to describe any of the available query types: + +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> + +a| +.free_parking field must be true or checkin field must be "1PM" +[source,json] +---- +include::example$query-compound.jsonc[tag=disjuncts] +---- + +|==== + +=== Query String Query Syntax + +Use the following properties and syntax to run a Query String query. + +Query String queries let you express more complex queries with a special syntax. +You can reduce the properties you need to specify for a Search query with Query String syntax. + +If you do not add any additional Query String syntax to a query, the Search Service interprets the query as a match query. +It searches for an exact match to the provided term in any fields that have been added to the `default` field. +For more information about how to configure the default field for your Search index, see the xref:search-index-params.adoc#all-field[default_field property]. + +CAUTION: Query String syntax is not recommended for use in production environments. + +[cols="1,1,4,4"] +|==== +| Operator | Property | Description | Examples + +| `^` +| See <>. +a| If you use multiple clauses in a query, you can use the `^` operator to assign the relative importance to a clause. + +Clauses with a larger number after the `^` operator score higher and appear earlier in search results. +a| +.Query String query with a boost on the name field containing pool +[source,json] +---- +include::example$query-boost.jsonc[tag=short] +---- + +| [[range-query-string]]`>`, `>=`, `<`, and `<=` +| See <> or <>. +a| You can run two types of range queries with the the later than (`>`), later than or equal to (`>=`), earlier than (`<`), and earlier than or equal to (`<=`) operators: + +* Use the operators with a date value to run a *date range query*. +The Search Service searches for a date value in the specified field that matches the specified operator. +* Use operators with a numeric value to run a *numeric range query*. +The Search Service searches for a numeric value in the specified field that matches the specified operator. +a| +.Query String query for a date in the created field after September 21, 2016 +[source,json] +---- +include::example$query-date-range.jsonc[tag=short] +---- + +.Query String query for a rating in the reviews.ratings.Cleanliness field greater than 4 +[source,json] +---- +include::example$query-numeric-range.jsonc[tag=short] +---- + +| `\` +| N/A +a| Use a backslash character (`\`) to escape characters in a Query String query. + +You must escape the following characters to search for them literally in a Query String query: + +* Quotes (`"`) +* Plus sign (`+`) +* Dash (`-`) +* Equals sign (`=`) +* Ampersand (`&`) +* Caret (`^`) +* Asterix (`*`) +* Pipe (`\|`) +* Greater than and less than symbol (`>` and `<`) +* Exclamation mark (`!`) +* Question mark (`?`) +* Parentheses (`( )`) +* Curly braces (`{ }`) +* Square brackets (`[ ]`) +* Single or double backslash (`\`) +* Forward slash (`/`) +* Tilde (`~`) +* Colon (`:`) +a| +.Query String match query with escaped exclamation mark (!) +[source,json] +---- +include::example$query-escape-characters.jsonc[tag=exclamation] +---- + +.Query String match phrase query with escaped quotation mark (") +[source,json] +---- +include::example$query-escape-characters.jsonc[tag=quotes] +---- + +| [[field-name]]`{field-name}:` +| See <>. +a| Set the field in a document where the Search Service should search for your query by adding a field name and a colon to the start of a search term. + +Use dot notation for the field name. +For example, `parentField.childField`. + +The Query String syntax does not support SQL++ field syntax. +For example, you cannot use `[*]` or `[3]` as array locations in a field name path. + +If your cluster is running Couchbase Server version 7.6.2 or later and you want to search your document metadata, you must prefix the metadata field's name with `_$xattrs`. +a| +.Query String query for "pool" in the description field +[source,json] +---- +include::example$query-field-name.jsonc[tag=short] +---- + +.(Version 7.6.2) Query String query for "sample" in an XATTRs description field +[source,json] +---- +include::example$query-field-name.jsonc[tag=xattrs] +---- + +| `+` and `-` +| See the <>, <>, and <>. +a| Use the `+` and `-` operators before a clause in a Query String query to run a <>: + +* The `+` operator adds the clause to the `MUST` list of a boolean query. +* The `-` operator adds the clause to the `MUST_NOT` list of a boolean query. +* The Search Service adds any additional query clauses not marked with a `+` or a `-` operator to the `SHOULD` list of a boolean query. + +Documents that match the `SHOULD` list of queries score higher than those that do not return a match. + +a| +.Query String query with boolean syntax +[source,json] +---- +include::example$query-boolean.jsonc[tag=short] +---- + +The Query String syntax specifies that: + +* The document must have `pool` in the `description` field. +* The document must not have `continental` in the `default` field. +* The document should have `breakfast` in the `default` field. + +| `""` +| See <>. +a| Surround a search term in quotation marks (`" "`) to run a match phrase query. + +To use a match phrase query: + +* You must specify a field to search with the <> or the <> syntax in your search query. +* You must have *Include Term Vectors* enabled or the `include_term_vectors` property set to `true` on the field you want to search. + +For more information about how to enable term vectors, see xref:type-mapping-options.adoc#term-vectors[Field Type Mapping Options] or xref:search-index-params.adoc#term-vectors[Search Index JSON Properties]. + +The Search Service searches for exact matches to the phrase you specify. + +a| +.Query String match phrase query for "continental breakfast" +[source,json] +---- +include::example$query-analytic.jsonc[tag=short_match_phrase] +---- +|==== + +=== Analytic Queries + +Analytic queries use an analyzer to analyze the contents of your Search query, and find a match in the documents inside your Search index. + +For more information about analyzers, see xref:customize-index.adoc#analyzers[Customize a Search Index with the {page-ui-name}]. + +NOTE: From Couchbase Server 7.6 and later, when you run a Search query with the xref:n1ql:n1ql-language-reference/searchfun.adoc[{sqlpp} Search Function], the analyzer used in your Analytic query does not need to match the analyzer used in the Search index. + +[cols="1,1,4,4"] +|==== +|Property |Type |Description |Examples + +| [[match]]match +| String +a| Use the `match` property to run a match query. +The Search Service searches for an exact match to the specified term inside the Search index's default field. + +You can set a specific field to search with the <>. + +You can change the matching behavior by using the <>. + +You cannot include spaces inside the string you provide to the `match` property without specifying the <>, which tells the Search Service how to interpret the string. + +For more information about the properties you can specify with a match query, see <>. +a| +.Match query for "best" or "great" in reviews.content with the "standard" analyzer +[source,json] +---- +include::example$query-analytic.jsonc[tag=match] +---- + +| [[match_phrase]]match_phrase +| String +a| Use the `match_phrase` property to run a match phrase query. +The Search Service searches for exact matches to the phrase you specify. + +Unlike a `match` query string, a match_phrase query string can contain spaces without using the <>. + +To use a match phrase query: + +* You must specify a field to search with the <> or the <> syntax in your search query. +* You must have *Include Term Vectors* enabled or the `include_term_vectors` property set to `true` on the field you want to search. + +For more information about how to enable term vectors, see xref:type-mapping-options.adoc#term-vectors[Field Type Mapping Options] or xref:search-index-params.adoc#term-vectors[Search Index JSON Properties]. + +For more information about the additional properties you can specify with a match phrase query, see <>. +a| +.Match phrase query for "very nice" in reviews.content +[source,json] +---- +include::example$query-analytic.jsonc[tag=match_phrase] +---- + +|==== + +=== Non-Analytic Queries + +Use Non-Analytic queries to run a search query without using an analyzer on the contents of your Search query. + +For more information about analyzers, see xref:customize-index.adoc#analyzers[Customize a Search Index with the {page-ui-name}]. + +NOTE: From Couchbase Server 7.6 and later, when you run a Search query with the xref:n1ql:n1ql-language-reference/searchfun.adoc[{sqlpp} Search Function], you do not need to use the xref:default-analyzers-reference.adoc#keyword[keyword analyzer] in your Search index to run a non-analytic query. + +[cols="1,1,4,4"] +|==== +|Property |Type |Description |Examples + +|[[bool]]bool +| Boolean +a| Use the `bool` property to query a field that contains a boolean value. + +Use the <> and set the `bool` property to `true` or `false` to run a search. + +The Search Service does not use any analyzers on the contents of your query. + +For more information about the additional properties you can specify with a bool query, see <>. +a| +.Search for documents where the pets_ok field is true +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=bool] +---- + +| [[prefix]]prefix +| String +a| Use the `prefix` property to run a prefix query. + +Set the property to a string to return matches for any term that starts with that string in search results. + +For example, you could set the `prefix` property to `inter` to return matches for `interview`, `internal`, `interesting`, and so on. + +If you use the `prefix` property, the Search Service does not use any analyzers on the contents of your query text. + +For more information about the additional properties you can specify with a prefix query, see <>. +a| +.Search for terms that start with "inter" inside the reviews.content field +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=prefix] +---- + +| [[regexp]]regexp +| String +a| Use the `regexp` property to run a regular expression query. + +Set the property to a regular expression to return matches for that regular expression in search results. + +If you use the `regexp` property, the Search Service does not use any analyzers on the contents of your query text. + +For more information about the additional properties you can specify with a regexp query, see <>. +a| +.Search for terms that match the regular expression "plan.+" inside the reviews.content field +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=regexp] +---- + +| [[term]]term +| String +a| Use the `term` property to run a term query. + +The Search Service searches for an exact match for the text you provide in the `term` property. + +You can change the matching behavior by using the <>. + +If you use the `term` property, the Search Service does not use any analyzers on the contents of your query text. + +For more information about the additional properties you can specify with a term query, see <>. + +a| +.Search for terms that match the term "interest" inside the reviews.content field with a fuzziness of 2 +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=term] +---- + +| [[terms]]terms +| Array +a| Use the `terms` array to run a phrase query. +The Search Service searches for the strings you provide in the `terms` array in the specified order. + +Unlike the <>, the `terms` array does not use any analyzers on the contents of your query text. + +For example, set the `terms` array to `["nice", "view"]`. +The Search Service looks for any occurrences of `nice` in a document that are followed by an occurrence of `view`. + +To use a phrase query: + +* You must set the <> in your search query. +* You must have *Include Term Vectors* enabled or the `include_term_vectors` property set to `true` on the field you want to search. + +For more information about how to enable term vectors, see xref:type-mapping-options.adoc#term-vectors[Field Type Mapping Options] or xref:search-index-params.adoc#term-vectors[Search Index JSON Properties]. +a| +.Search for the phrase "nice view" in the reviews.content field +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=phrase] +---- + +| [[wildcard]]wildcard +| String +a| Use the `wildcard` property to run a wildcard query. + +Set the property to a regular expression that includes a wildcard character in the middle or end of a search term: + +* Use `?` to allow a match to any single character. +* Use `*` to allow a match to zero or many characters. + +For example, you could set the `wildcard` property to `inter*` to return matches for `interview`, `interject`, `internal`, and so on. + +You cannot place the wildcard character at the start of the search term. + +If you use the `wildcard` property, the Search Service does not use any analyzers on the contents of your query text. +a| +.Search for any terms that start with "inter" followed by zero or more characters in the reviews.content field +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=wildcard] +---- + +|==== + +[#numeric-range-queries] +=== Numeric Range Queries + +Use a numeric range query to search for a range of numbers inside documents in your Search index: + +[source,json] +---- +include::example$query-numeric-range.jsonc[tag=long] +---- + +The `field` value is an optional property. For more information about the `field` property, see <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|min +|Integer +|No +a| Set the minimum value of the numeric range that you want to search for. + +You can specify only a `min` value or only a `max` value on your numeric range. + +By default, `min` is inclusive to the range. + +|max +|Integer +|No +a| Set the maximum value of the numeric range that you want to search for. + +You can specify only a `max` value or only a `min` value on your numeric range. + +By default, `max` is exclusive to the range. + +|inclusive_min +|Boolean +|No +a| Set whether the Search Service should return documents that contain the exact `min` value. + +If you set `inclusive_min` to `false`, only values greater than `min` count as a match to your Search query. + +If you do not set the `inclusive_min` value, by default, `min` is inclusive to the range. + +|inclusive_max +|Boolean +|No +a| Set whether the Search Service should return documents that contain the exact `max` value. + +If you set `inclusive_max` to `false`, only values less than `max` count as a match to your Search query. + +If you do not set the `inclusive_max` value, by default, `max` is exclusive to the range. + +|==== + +[#date-range-queries] +=== Date Range Queries + +Use a date range query to search for a range of date values inside documents in your Search index: + +[source,json] +---- +include::example$query-date-range.jsonc[tag=long] +---- + +The `field` value is an optional property. For more information about the `field` property, see <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|start +|Integer +|No +a| Set the start date of the date range that you want to search for. + +You can specify only a `start` value or only a `end` value on your date range. + +By default, `start` is inclusive to the range. + +|end +|Integer +|No +a| Set the end date of the date range that you want to search for. + +You can specify only a `end` value or only a `start` value on your date range. + +By default, `end` is exclusive to the range. + +|inclusive_start +|Boolean +|No +a| Set whether the Search Service should return documents that contain the exact `start` value. + +If you set `inclusive_start` to `false`, only dates later than `start` count as a match to your Search query. + +If you do not set the `inclusive_start` value, by default, `start` is inclusive to the range. + +|inclusive_end +|Boolean +|No +a| Set whether the Search Service should return documents that contain the exact `end` value. + +If you set `inclusive_end` to `false`, only dates earlier than `end` count as a match to your Search query. + +If you do not set the `inclusive_end` value, by default, `end` is exclusive to the range. + +|==== + +[#term-range-queries] +=== Term Range Queries + +Use a term range query to search for a range of terms inside documents in your Search index. + +For example, the following query searches for any terms that occur in alphabetical order between `be` and `beautiful` from the `reviews.content` field in a Search index: + +[source,json] +---- +include::example$query-term-range.jsonc[] +---- + +The query returns results such as `beach`, `beaches`, `beans`, and `beast`. + +The `field` value is an optional property. For more information about the `field` property, see <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|min +|Integer +|No +a| Set the minimum term of the term range that you want to search for. + +You can specify only a `min` value or only a `max` value on your term range. + +By default, `min` is inclusive to the range. + +|max +|Integer +|No +a| Set the minimum term of the term range that you want to search for. + +You can specify only a `max` value or only a `min` value on your term range. + +By default, `max` is exclusive to the range. + +|inclusive_min +|Boolean +|No +a| Set whether the Search Service should return documents that contain the exact `min` value. + +If you set `inclusive_min` to `false`, only terms that would occur after `min` in the dictionary count as a match to your Search query. + +If you do not set the `inclusive_min` value, by default, `min` is inclusive to the range. + +|inclusive_max +|Boolean +|No +a| Set whether the Search Service should return documents that contain the exact `max` value. + +If you set `inclusive_max` to `false`, only terms that would occur before `max` in the dictionary count as a match to your Search query. + +If you do not set the `inclusive_max` value, by default, `max` is exclusive to the range. + +|==== + +=== IP Address Range Queries + +Use an IP Address Range query to search for IP address data in your Search index. + +You can use IPv4 or IPv6 CIDR syntax in your query. + +For example, the following query searches for any IP addresses in the range `2.7.13.141/32` and `2001:4860:4860::8888/24`: + +[source,json] +---- +include::example$query-ip-range.jsonc[] +---- + +NOTE: If your IP range includes over 1024 IP addresses, you must update the `bleveMaxResultWindow` setting to accommodate your results. +For more information about how to change this setting, see xref:server:fts:fts-advanced-settings-bleveMaxResultWindow.adoc[]. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|cidr +|String Containing An IPv4 or IPv6 IP Address +|Yes +a| Enter an IP address range or single IP address, in IPv4 or IPv6 CIDR notation. + +The Search Service returns documents with IP addresses that fall inside the specified range or match the specified IP address. + +|==== + +[#geopoint-queries-distance] +=== Distance/Radius-Based Geopoint Queries + +Use a Geopoint distance/radius-based query to search for geo location values in a set radius around a specified latitude and longitude: + +[source,json] +---- +include::example$query-geopoint.jsonc[tag=distance] +---- + +To use a Geopoint query, you must have a document field in your Search index with the `geopoint` type. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|location +|Object or Array +|Yes +a| Set the geo location value to use as the center of the search radius for your query. + +If you use `location` as an object, you must set two values: + +* `lon`: The longitude of the geo location to use as the center of the search radius. +* `lat`: The latitude of the geo location to use as the center of the search radius. + +If you use `location` as an array, your array must contain a longitude value followed by a latitude value. +For example, `[-2.235143, 53.482358]`, where `-2.235143` is the longitude. + +|distance +|String +|Yes +a| The radius where the Search Service should search for matching geo location values. + +Enter the radius as a single string, with a numeric value and a unit value. +For example, `100.5mi`. + +You can use the following distance units: + +* `mm`: Millimeters +* `cm`: Centimeters +* `in`: Inches +* `yd`: Yards +* `ft`: Feet +* `m`: Meters +* `km`: Kilometers +* `mi`: Miles +* `nm`: Nautical miles + +|==== + +[#geopoint-queries-rectangle] +=== Rectangle-Based Geopoint Queries + +Use a Geopoint rectangle-based query to search for geo location values in a defined rectangle: + +[source,json] +---- +include::example$query-geopoint.jsonc[tag=rectangle] +---- + +The Search Service takes a value for the top-left and bottom-right corners of a rectangle, and draws a bounding box that connects those points. +The resulting rectangle is used as the search area for geo location values. + +To use a Geopoint query, you must have a document field in your Search index with the `geopoint` type. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|top_left +|Object or Array +|Yes +a| Set the geo location value to use as the top-left corner point of the rectangle search area. + +If you use `top_left` as an object, you must set two values: + +* `lon`: The longitude of the geo location to use as the top-left corner of the rectangle. +* `lat`: The latitude of the geo location to use as the top-left corner of the rectangle. + +If you use `top_left` as an array, your array must contain a longitude floating point value followed by a latitude floating point value. +For example, `[-2.235143, 53.482358]`, where `-2.235143` is the longitude. + +|bottom_right +|Object or Array +|Yes +a| Set the geo location value to use as the bottom-right corner point of the rectangle search area. + +If you use `bottom_right` as an object, you must set two values: + +* `lon`: The longitude of the geo location to use as the bottom-right corner of the rectangle. +* `lat`: The latitude of the geo location to use as the bottom-right corner of the rectangle. + +If you use `bottom_right` as an array, your array must contain a longitude floating point value followed by a latitude floating point value. +For example, `[-2.235143, 53.482358]`, where `-2.235143` is the longitude. + +|==== + +[#geopoint-queries-polygon] +=== Polygon-Based Geopoint Queries + +Use a Geopoint polygon-based query to search for geo location values in a defined polygon: + +[source,json] +---- +include::example$query-geopoint.jsonc[tag=polygon] +---- + +The Search Service takes an array of latitude and longitude values and connects them in the specified order to form a polygon. +The resulting polygon is used as the search area for geo location values. + +To use a Geopoint query, you must have a document field in your Search index with the `geopoint` type. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|polygon_points +|Array +|Yes +a| Set an array of latitude and longitude string values to use as the points in your polygon search area. + +For example, an array of `[ "37.79393211306212,-122.44234633404847", "37.77995881733997,-122.43977141339417", "37.788031092020155,-122.42925715405579"]` is interpreted as 3 separate polygon points and creates a 3-sided polygon. + +For `polygon_points`, the first value in the string is the latitude, and the second is the longitude. + +You can set the last value in the array to the same value as the first latitude and longitude to explicitly close your polygon. +Otherwise, the Search Service infers the polygon's closure. + +|==== + +[#geojson-queries-point] +=== Point GeoJSON Queries + +Use a GeoJSON Point query to search for a single latitude and longitude coordinate that intersects or is contained inside a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=point] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[point-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[point-type]]type +|String +|Yes +a| Set `type` to `Point`. + +|[[point-coordinates]]coordinates +|Array +|Yes +a| An array of coordinate floating point values that define the GeoJSON shape. + +For a `point` query, set the `coordinates` array to a single array with a longitude and latitude value. + +The Search Service uses the first value in the `coordinates` array as the longitude value. + +|[[point-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON Point search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: The defined query Point overlaps a defined Point or LineString, or exists within the defined area for a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, the query point must only overlap with one Point, LineString, or Polygon. + +* `contains`: The defined query Point overlaps a defined Point or LineString, or exists within the defined area for a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, the query point must only overlap with one Point, LineString, or Polygon. + +* `within`: Not supported for Point queries. + +|==== + + +[#geojson-queries-linestring] +=== LineString GeoJSON Queries + +Use a GeoJSON LineString query to search for a line of coordinates that intersects or is contained inside a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=linestring] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[linestring-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[linestring-type]]type +|String +|Yes +a| Set `type` to `LineString`. + +|[[linestring-coordinates]]coordinates +|Array of Arrays +|Yes +a| An array that contains arrays of 2 coordinate floating point values that define the GeoJSON LineString shape. + +For a `linestring` query, the `coordinates` array can contain multiple coordinate point arrays. + +The Search Service uses the first value in any nested `coordinates` array as the longitude value for the coordinate. + +|[[linestring-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON LineString search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: The defined query LineString overlaps a defined Point or LineString, or intersects with the defined edges of a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, the defined LineString must only overlap one Point, or intersect one LineString or Polygon. + +* `contains`: The start and end points of the LineString are within the defined area of a Polygon, Circle, or Envelope. ++ +Points and LineStrings are not supported. +For MultiPolygon or GeometryCollection shapes, only one Polygon must contain both the start and end points of the LineString. + +* `within`: Not supported for LineString queries. + +|==== + +[#geojson-queries-polygon] +=== Polygon GeoJSON Queries + +Use a GeoJSON Polygon query to search for a defined area that intersects, is contained inside, or surrounds a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=polygon] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[polygon-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[polygon-type]]type +|String +|Yes +a| Set `type` to `Polygon`. + +|[[polygon-coordinates]]coordinates +|Array of Arrays +|Yes +a| An array that contains an outer array, and arrays of 2 coordinate floating point values that define the GeoJSON Polygon shape. + +The Search Service uses the first value in any nested `coordinates` array as the longitude value for the coordinate. + +The Search Service also follows strict GeoJSON syntax, and expects exterior coordinates in a polygon to be in counterclockwise order. + +|[[polygon-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON Polygon search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: The defined query Polygon contains a Point, or one of its edges intersects a LineString, Polygon, Circle, or Envelope. ++ +For multi-shape geometries, only one Point must be contained, or only one LineString or Polygon must intersect. + +* `contains`: The entire defined area of the query Polygon exists inside a Polygon, Circle, or Envelope. ++ +Points and LineStrings are not supported. +For multi-shape geometries, one shape must contain the entirety of the defined query Polygon. + +* `within`: The query Polygon contains a Point, the endpoints of a LineString, or the entirety of a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, the query Polygon must contain the entirety of each defined Point, LineString, or Polygon. + +|==== + + +[#geojson-queries-multipoint] +=== MultiPoint GeoJSON Queries + +Use a GeoJSON MultiPoint query to search for multiple coordinate points that intersect or are contained inside a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=multipoint] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[multipoint-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[multipoint-type]]type +|String +|Yes +a| Set `type` to `MultiPoint`. + +|[[multipoint-coordinates]]coordinates +|Array of Arrays +|Yes +a| An array that contains arrays of 2 coordinate floating point values that define the GeoJSON MultiPoint shape. + +The Search Service uses the first value in any nested `coordinates` array as the longitude value for the coordinate. + +|[[multipoint-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON MultiPoint search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: One of the points in the MultiPoint overlaps a Point or a LineString endpoint, or exists inside the area of a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, only one Point must inside the shape or overlap a Point or endpoint. + +* `contains`: All points in the MultiPoint exist inside a Polygon, Circle, or Envelope. ++ +Points and LineStrings are not supported. +A MultiPoint shape can return a match if all points in the query overlap with the MultiPoint in the document. ++ +A MultiPolygon or GeometryCollection returns a match if all query points exist within any of the defined Polygons or MultiPoints. + +* `within`: Any of the points in the query MultiPoint overlap with a defined Point. ++ +A MultiPoint shape returns a match if all points in the query overlap with the MultiPoint in the document. + +|==== + +[#geojson-queries-multilinestring] +=== MultiLineString GeoJSON Queries + +Use a GeoJSON MultiLineString query to search for multiple <> that intersect or are contained inside a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=multilinestring] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[multilinestring-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[multilinestring-type]]type +|String +|Yes +a| Set `type` to `MultiLineString`. + +|[[multilinestring-coordinates]]coordinates +|Array of Arrays +|Yes +a| An array that contains nested arrays, each with their own nested arrays of 2 coordinate floating point values. + +For example, the following `coordinates` array defines 2 LineStrings with start and end points: +---- +"coordinates": [ + [ + [1.954764, 50.962097], [3.029578, 49.868547] + ], + + [ + [3.029578, 49.868547], [-0.387444, 48.545836] + ] +] +---- + +The innermost arrays define the individual points for a LineString in the MultiLineString shape. + +The Search Service uses the first value in the nested `coordinates` arrays as the longitude value for a coordinate. + +|[[multilinestring-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON MultiLineString search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: Any LineString inside the defined query MultiLineString overlaps a defined Point or LineString, or intersects with the defined edges of a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, any defined LineString must only overlap one Point, or intersect one LineString or Polygon. + +* `contains`: The start and end points of every LineString inside the defined query MultiLineString are within the defined area of a Polygon, Circle, or Envelope. ++ +Points and LineStrings are not supported. +For MultiPolygon or GeometryCollection shapes, only one Polygon must contain both the start and end points of every LineString. + +* `within`: Not supported for MultiLineString queries. + +|==== + +[#geojson-queries-multipolygon] +=== MultiPolygon GeoJSON Queries + +Use a GeoJSON MultiPolygon query to search for a group of defined <> that intersect, are contained inside, or surround a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=multipolygon] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[multipolygon-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[multipolygon-type]]type +|String +|Yes +a| Set `type` to `MultiPolygon`. + +|[[multipolygon-coordinates]]coordinates +|Array of Arrays +|Yes +a| An array that contains arrays that describe a GeoJSON Polygon shape. + +Each inner array that describes a Polygon can contain multiple arrays with 2 coordinate floating point values. +These innermost arrays describe the coordinates of the Polygon. + +The Search Service uses the first value in any nested `coordinates` array as the longitude value for the coordinate. + +The Search Service also follows strict GeoJSON syntax, and expects exterior coordinates in a polygon to be in counterclockwise order. + +|[[multipolygon-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON MultiPolygon search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: Any of the Polygons defined in the query MultiPolygon contain a Point, or one of their edges intersects a LineString, Polygon, Circle, or Envelope. ++ +For multi-shape geometries, only one Point must be contained in a query Polygon, or only one LineString or Polygon must intersect. + +* `contains`: Every Polygon defined in the query MultiPolygon exists inside a Polygon, Circle, or Envelope. ++ +Points and LineStrings are not supported. +For multi-shape geometries, one shape must contain the entirety of the defined query Polygons. + +* `within`: Any of the Polygons defined in the query MultiPolygon contain a Point, the endpoints of a LineString, or the entirety of a Polygon, Circle, or Envelope. ++ +For multi-shape geometries, any of the query Polygons must collectively contain the entirety of each defined Point, LineString, or Polygon. + +|==== + +[#geojson-queries-geometrycollection] +=== GeometryCollection GeoJSON Queries + +Use a GeoJSON GeometryCollection query to search for a group of defined <>, <>, or <> that intersect, are contained inside, or surround a GeoJSON shape in your documents: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=geometrycollection] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[geometrycollection-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +|[[geometrycollection-type]]type +|String +|Yes +a| Set `type` to `GeometryCollection`. + +|[[geometrycollection-geometries]]geometries +|Array of Objects +|Yes +a| Contains objects to define each GeoJSON shape in the GeometryCollection. + +Each object in the `geometries` array has a `type` property and a <>. + +Set the `type` property inside the object to the specific shape type you want to define: + +* <> +* <> +* <> +* <> +* <> +* <> + +|[[geometrycollection-coordinates]]coordinates +|Array or Array of Arrays +|Yes +a| An array or array of arrays that describes a GeoJSON shape. + +The exact structure of the arrays depends on the shape: + +* <> +* <> +* <> +* <> +* <> +* <> + +For any array that contains only floating point values, the Search Service uses the first value as the longitude. + +The Search Service also follows strict GeoJSON syntax, and expects exterior coordinates in a polygon to be in counterclockwise order. + +|[[geometrycollection-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON GeometryCollection search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: If any of the shapes in the query intersect with a shape in the document, the Search Service returns the document. + +* `contains`: Every shape in the query must be contained, cumulatively, inside the shape or shapes defined in a document. + +* `within`: Any of the shapes in a document must be contained within a shape in the query. + +|==== + +[#geojson-queries-circle] +=== Circle GeoJSON Queries + +Use a GeoJSON Circle query to search in a radius around a single latitude and longitude coordinate: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=circle] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. [cols="1,1,1,2"] |==== |Property |Type |Required? |Description -|explain |Boolean |Yes a| +|geometry +|Object +|Yes +a| Contains the <> and <> property. -To create an explanation for a search result's score in search results, set `explain` to `true`. +Defines the GeoJSON shape and how the Search Service should find a match in documents. -To turn off explanations for search result scoring, set `explain` to `false`. +|[[circle-shape]]shape +|Object +|Yes +a| Contains the <>, <>, and <>. -|fields |Array |Yes a| +Defines the specific GeoJSON shape to use in the query. -An array of strings for each indexed field to return in search results. +|[[circle-type]]type +|String +|Yes +a| Set `type` to `Circle`. -If you didn't add a field and its content to the index, you can't view it in search results. +|[[circle-coordinates]]coordinates +|Array +|Yes +a| An array of coordinate floating point values that define the center point of the Circle. -|highlight |Object |No | +Set the `coordinates` array to a single array with a longitude and latitude value. -|query |Object |Yes |Contains the search query. See <>. +The Search Service uses the first value in the `coordinates` array as the longitude value. -|sort |Array |Yes a| +|[[circle-radius]]radius +|String +|Yes +a| Set the radius of the Circle. -Contains an array of strings or JSON objects to set how to sort search results. +Enter the radius as a single string, with a numeric value and a unit value. For example, `100.5mi`. -The strings can be: +You can use the following distance units: -* `{field_name}`: Specify the name of a field to use to sort the search results. -* `_id`: Use the document's identifier to sort the search results. -* `_score`: Use the document's score from the search query to sort the search results. -* A JSON object. +* `mm`: Millimeters +* `cm`: Centimeters +* `in`: Inches +* `yd`: Yards +* `ft`: Feet +* `m`: Meters +* `km`: Kilometers +* `mi`: Miles +* `nm`: Nautical miles -For more information on the properties for a `sort` JSON object, see <>. +|[[circle-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON Circle search. -|search_after |Array |No a| +Your selected `relation` type determines which shapes return a match for your query. -NOTE: If you use `search_after` in a search request, you can't use `search_before`. +You can use the following string values in the `relation` property: +* `intersects`: A defined Point exists within the radius of the Circle, or a LineString, Polygon, Envelope or Circle intersects the Circle. ++ +For multi-shape geometries, the Circle must only contain with one Point, or intersect one LineString or Polygon. -|search_before |Array |No a| +* `contains`: A defined Polygon, Envelope, or Circle contains the entire defined query Circle. ++ +Points and LineStrings are not supported. +For MultiPolygons or GeometryCollections containing only Polygons, the query Circle must be contained by one Polygon. -NOTE: If you use `search_before` in a search request, you can't use `search_after`. +* `within`: All defined GeoJSON shapes in the document must exist inside the defined query Circle. + +|==== + +[#geojson-queries-envelope] +=== Envelope GeoJSON Queries + +Use a GeoJSON Envelope query to search in a bounded rectangle, based on a pair of coordinates that define the minimum and maxium longitude and latitude: + +[source,json] +---- +include::example$query-geojson.jsonc[tag=envelope] +---- + +To use a GeoJSON query, you must have a document field in your Search index with the `geoshape` type. +The `geoshape` field must contain a `type` property and a `coordinates` array. +For more information about how to create a document field, see xref:create-type-mapping.adoc#field[Add a Single Document Field Mapping] or <>. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|geometry +|Object +|Yes +a| Contains the <> and <> property. + +Defines the GeoJSON shape and how the Search Service should find a match in documents. + +|[[envelope-shape]]shape +|Object +|Yes +a| Contains the <> and <>. + +Defines the specific GeoJSON shape to use in the query. + +|[[envelope-type]]type +|String +|Yes +a| Set `type` to `Envelope`. + +|[[envelope-coordinates]]coordinates +|Array of 2 Arrays +|Yes +a| An array of 2 different arrays that contain coordinate floating point values. + +The first `coordinates` nested array contains the minimum longitude and maximum latitude, or the top-left corner of the rectangle. + +The second nested array contains the maximum longitude and minimum latitude, or the bottom-right corner. + +The Search Service uses the first value in the nested `coordinates` array as the longitude value. + +|[[envelope-relation]]relation +|String +|Yes +a| Set how the Search Service should return a match for a GeoJSON Envelope search. + +Your selected `relation` type determines which shapes return a match for your query. + +You can use the following string values in the `relation` property: + +* `intersects`: A defined Point exists within the Envelope, or a LineString, Polygon, Envelope or Circle intersects the Envelope. ++ +For multi-shape geometries, the Envelope must only contain with one Point, or intersect one LineString or Polygon. + +* `contains`: A defined Polygon, Envelope, or Circle contains the entire defined query Envelope. ++ +Points and LineStrings are not supported. +For MultiPolygons or GeometryCollections containing only Polygons, the query Envelope must be contained by one Polygon. + +* `within`: All defined GeoJSON shapes in the document must exist inside the defined query Envelope. + +|==== + +=== Special Queries + +You can use the following special queries as the only properties inside a `query` object to return all or no documents from your Search index in search results. + +[cols="1,1,4,4"] +|==== +|Property |Type |Description |Examples + +| match_all +| Object +| Use the `match_all` object as the only property in your `query` object to return all documents from the Search index in search results. +a| +.Return all documents in the Search index +[source,json] +---- +include::example$query-special.jsonc[tag=match_all] +---- + +| [[match_none]]match_none +| Object +a| Use the `match_none` object as the only property in your `query` object to return no documents from the Search index in search results. + +If you add a <> and a `query` object with the `match_none` object to your request, your search returns only matches to the Vector Search query inside the `knn` object. +If your cluster is running Couchbase Server version 7.6.2 and later, when running a xref:vector-search:vector-search.adoc[Vector Search] query without a `query` object, the Search Service automatically adds a `query` object with a `match_none` query object to your request. + +a| +.Return no documents from the Search index +[source,json] +---- +include::example$query-special.jsonc[tag=match_none] +---- + +|==== + +[#additional-query-properties] +=== Additional Query Object Properties + +You can use the following properties to modify the results returned by specific query types. + +[cols="1,1,4,4"] +|==== +|Property |Type |Description |Examples + +| [[analyzer]]analyzer +| String +a| Use the `analyzer` property to modify the behavior of a <> or a <>. + +Set the `analyzer` property to the name of the analyzer you want to use on the contents of the <> or <>. + +The specified analyzer only applies to the content of your Search request. +It does not apply to the contents of documents in the Search index. +However, the analyzer set on your Search request and in your Search index should match. +a| + +.Match query for "location" and "hostel" in reviews.content with the "en" analyzer +[source,json] +---- +include::example$query-analytic.jsonc[tag=match_analyzer] +---- + +|[[boost]]boost +| Integer +a| If you use multiple clauses in a query, you can use the `boost` property to assign the relative importance to a clause. + +Clauses with a higher value in the `boost` property score higher and appear earlier in search results. +a| +.Disjunction query with boost property on the city field containing glossop +[source,json] +---- +include::example$query-boost.jsonc[tag=long] +---- + +| [[field]]field +| String +a| Specify a specific field name, using dot notation, where the Search Service should search for a match to your search query. + +If your cluster is running Couchbase Server version 7.6.2 or later and you want to search for document metadata held in XATTRs, you must add `_$xattrs` to the start of your metadata field's name. +For example, `"_$xattrs.description"`. +a| +.Search for documents where the pets_ok field is true +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=bool] +---- + +| [[fuzziness]]fuzziness +| Integer +a| Use the `fuzziness` property to run a fuzzy query. + +The `fuzziness` property uses your specified edit distance to match terms based on their similarity, rather than exact matches. + +You can set `fuzziness` to a maximum value of `2`. + +Use the `fuzziness` property with the <> for a term query or the <> for a match query. +a| +.Search for a match the term "interest" inside the reviews.content field with a fuzziness of 2 +[source,json] +---- +include::example$query-non-analytic.jsonc[tag=term] +---- + +|[[operator]]operator +| String +a| Use the `operator` property to modify the behavior of a <>: + +* "and": Any spaces between terms in the <> are interpreted as the `AND` operator. Documents must match all of the terms in the query. +* "or": Any spaces between terms in the <> are interpreted as the `OR` operator. Documents must match at least one of the terms in the query. + +For example, if you set a `match` property to the value `"good great"` and the `operator` property to `"and"`, the Search Service only returns matches for documents that contain `good` and `great`. + +If you set the `operator` property to `"or"`, a document only needs to contain one of the terms from the `match` property: `good` or `great`. +a| + +.Match query for "best" or "worst" in reviews.content +[source,json] +---- +include::example$query-analytic.jsonc[tag=match_operator] +---- + +|[[prefix-length]]prefix_length +| Integer +a| Use the `prefix_length` property to modify the behavior of a <>. + +The `prefix_length` changes a <> to a prefix match query. +The Search Service matches terms based on the query and the result sharing a prefix of the specified length. +a| +.Match query for "location hostel" in reviews.content with a prefix_length of 4 +[source,json] +---- +include::example$query-analytic.jsonc[tag=match_prefix_length] +---- + +|==== + +[#ctl] +== Ctl Object + +Use the `ctl` object to make sure that the Search Service runs your Search query against the latest version of the documents in your database. + +The `ctl` object and its properties cause the Search Service to run your query against the latest version of a document written to a xref:server:learn:buckets-memory-and-storage/vbuckets.adoc[vBucket]. +The Search Service uses a consistency vector to synchronize the last document write to a vBucket from the Data Service with the Search index. + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=ctl] +---- + +In Couchbase Server 7.6.5 and later, you can also use the `ctl` object with the `validate` property to add an extra check to your queries and get help troubleshooting when a query does not return results. + +The `ctl` object can contain the following properties: + +[cols="1,1,1,4"] +|==== +|Property |Type |Required? |Description + +|timeout |Integer |No a| + +Set the maximum time, in milliseconds, that a Search query can execute on a Search index partition. + +If the query time exceeds the `timeout`, the Search Service cancels the query. +The query might return partial results if any index partitions responded before the timeout. + +|consistency |Object |Yes a| + +An object that contains a `vectors` object and the `level` and `results` properties. + +For more information, see <>. + +|[[validate]]validate |Boolean |No a| + +[.status]#Couchbase Server 7.6.5# + +Add the `validate` property with a value of `true` to add extra validation checks to your Search query. + +For example, the Search Service can tell you through the Web Console or the REST API that a field in your Search query is not in your Search index: + +---- +err: query_validate: field not indexed, field: ratings.Cleanliness, type: number +---- + +|==== + +[#consistency] +=== Consistency Object + +Use the `consistency` object to control the consistency behavior for a Search index: + +[source,json] +include::example$run-search-full-request.jsonc[tag=consistency] + +A `consistency` object has the following properties: + +[cols="1,1,1,4"] +|==== +|Property |Type |Required? |Description + +|vectors |Object |Yes a| + +An object that contains a `\{search-index-name\}` object for each Search index in the query. + +For more information about the `\{search-index-name\}` object, see <>. + +|level |String |Yes a| + +Set the consistency to bounded or unbounded consistency: + +* `at_plus`: The Search query executes but requires that the Search index matches the timestamp of the last document update. +You must provide a `vectors` object +* `not_bounded`: The Search query executes without a consistency requirement. +`not_bounded` is faster than `at_plus`, as it doesn't rely on a `vectors` object or wait for the Search index to match the Data Service index. + +|results |String |No a| -|score |String |No |To disable document relevancy scoring in search results, set `score` to `none`. +To display an error instead of partial results if any index partitions are unavailable on a node, set `results` to `complete`. -|size/limit |Integer |Yes |Set the total number of results to return for a single page of search results. +To return partial results from a query if a node is unreachable, remove the `results` property. -|from/offset |Integer |Yes |Set +|==== + +[#vectors] +==== \{search-index-name\} Object + +Use a `\{search-index-name\}` object to set the Search index and consistency vectors for a Search query. + +The `\{search-index-name\}` object contains a vBucket mapping and UUID property with the sequence number for each update to a vBucket's data that you want to include in your search results. +For example, the `SearchIndexName` object contains 2 vBucket mappings, UUIDs, and sequence numbers: + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=vectors] +---- + +If your Search query uses an xref:index-aliases.adoc[index alias] that references multiple Search indexes, you must include a `\{search-index-name\}` object for each Search index in the alias. + +To get the vBucket mapping, UUID, and the sequence number for a data write, use a `MutationToken` from a Data Service `MutationResult`. +The Data Service returns a `MutationResult` object or promise for CRUD operations. +For more information, see xref:server:guides:kv-operations.adoc[]. + +For examples on how to obtain and use a `MutationToken` with the Couchbase SDKs, see: + +* xref:dotnet-sdk:howtos:full-text-searching-with-sdk.adoc#consistency[.NET] + | xref:go-sdk:howtos:full-text-searching-with-sdk.adoc#consistency[Go] + | xref:java-sdk:howtos:full-text-searching-with-sdk.adoc#consistency[Java] + | xref:kotlin-sdk:howtos:full-text-search.adoc#scan-consistency[Kotlin] + | xref:nodejs-sdk:howtos:full-text-searching-with-sdk.adoc#scan-consistency-and-consistentwith[Node.js] + | xref:php-sdk:howtos:full-text-searching-with-sdk.adoc#consistency[PHP] + | xref:python-sdk:howtos:full-text-searching-with-sdk.adoc#scan-consistency-and-consistent-with[Python] + | xref:ruby-sdk:howtos:full-text-searching-with-sdk.adoc#consistency[Ruby] + | xref:scala-sdk:howtos:full-text-searching-with-sdk.adoc#consistency[Scala] + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|\{search-index-name\} |Object |Yes a| + +The name of the Search index that you want to search and use with consistency. + +The `\{search-index-name\}` object contains a `\{vBucketMapping\}/\{vBucketUUID\}` property for each document write operation that you want in your search results. + +Set the value of the property to the sequence number for the write operation. + +For example, if you had a property of `607/205096593892159": 2`, the Search Service looks for a write operation on vBucket `607`, with a UUID of `205096593892159`, with sequence number `2`. + +|==== + + +[#highlight] +== Highlight Object + +Use the `highlight` object to control how the Search Service highlights matches in search results. + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=highlight] +---- + +[cols="1,1,1,4"] +|==== +|Property |Type |Required? |Description + +|style |String |No a| + +Sets how the Search Service highlights a match from a search query: + +* `ansi`: The Search Service highlights matches with a yellow background (`\u001b[43m`). +* `html`: The Search Service surrounds matches with `` and `` HTML tags. + +|fields |Array |No a| + +Contains an array of strings for each field name where you want to highlight a search query match. + +If you include the `fields` array, the Search Service only highlights fields that are in the array. + +|==== + +[#facet-name] +== \{facet-name\} Object + +Use a `\{facet-name\}` object to create a search facet. + +You can have multiple `\{facet-name\}` objects inside the <> in your search query. + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=facets] +---- + +A `\{facet-name\}` object contains the following properties: + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|size |Integer |Yes a| + +Set the total number of categories to return with the search results for a Term facet. + +The Search Service orders facet categories from values with the most occurrences to the least occurrences. + +For Numeric Range and Date Range facets, the total number of categories returned depends on the number of ranges defined for the facet. + +|field |String |Yes |The name of the field to use to collect facet information. + +|numeric_ranges |Array |No a| + +If you want to collect a Numeric Range facet, add a `numeric_ranges` array. + +A `numeric_ranges` array contains objects that define each numeric range you want to collect with your search results. + +For more information, see <>. + +|date_ranges |Array |No a| + +If you want to collect a Date Range facet, add a `date_ranges` array. + +A `date_ranges` array contains objects that define each date range you want to collect with your search results. + +For more information, see <>. + +|==== + +[#numeric] +=== Numeric_ranges Array Objects + +The objects in a `numeric_ranges` array specify the range or ranges for a Numeric Range facet. + +For example, the following `numeric_ranges` array sets two ranges, `high` and `low`, to collect for a Numeric Range facet: + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=numeric_ranges] +---- + +The Search query increments the `count` property for `high` when the value of the `field` in the <> is greater than 7 but less than 10. -|collections |Array |No |Contains an array of strings that specify the collections where you want to run the query. +If the document's `field` value is less than 7 but greater than 0, the query increments the `count` value for `low`. + +You can set both a `min` and `max` for a range, or just a `min` or `max`. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|name |String |Yes |The name for the numeric range. + +|min |Integer |No a| + +The minimum value to compare against the value of the `field` in the <>. + +If a document's value for the field is greater than `min`, the Search Service increments the `count` value returned in the Search query results. + +You can also define a `max` property to set an upper limit for your numeric range. + +|max |Integer |No a| + +The maximum value to compare against the value of the `field` in the <>. + +If a document's value for the field is less than `max`, the Search Service increments the `count` value returned in the Search query results. + +You can also define a `min` property to set a lower limit for your numeric range. + +|==== + +[#date] +=== Date_ranges Array Objects + +The objects in a `date_ranges` array specify the range or ranges for a Date Range facet. + +For example, the following `date_ranges` array sets two ranges, `old` and `new`, to collect for a Date Range facet: + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=date_ranges] +---- + +The Search query increments the `count` property for `old` when the value of the `field` in the <> is later than `2020-12-31` but earlier than `2023-12-31`. + +If the document's `field` value is later than `2023-12-31` but earlier than `2024-12-31`, the query increments the `count` value for `new`. + +You can set both a `start` and `end` for a range, or just a `start` or `end`. + +[cols="1,1,1,2"] +|==== +|Property |Type |Required? |Description + +|name |String |Yes |The name for the date range. + +|start |RFC-3339 formatted Date String |No a| + +The starting date value to compare against the value of the `field` in the <>. + +If a document's value for the field is later than `start`, the Search Service increments the `count` value returned in the Search query results. + +You can also define a `end` property to set an upper limit for your date range. + +|end |RFC-3339 formatted Date String |No a| + +The ending date value to compare against the value of the `field` in the <>. + +If a document's value for the field is earlier than `end`, the Search Service increments the `count` value returned in the Search query results. + +You can also define a `start` property to set a lower limit for your date range. |==== @@ -57,7 +2204,47 @@ NOTE: If you use `search_before` in a search request, you can't use `search_afte Use the `sort` object to control how the Search Service sorts search results. -[cols="1,1,1,2"] +The following `sort` object orders search results by the values in `field1`, then by `field2`, the document's score, and then the document's ID value: + +[source,json] +---- +include::example$run-search-full-request.jsonc[tag=sort] +---- + +This means that if 2 documents have the same value in `field1`, then the Search Service will sort them again based on their `field2` values. +If they have the same value in `field2`, then sorting will happen again based on each document's score, and then finally the documents' ID values. + +The `sort` object can contain the following string values: + +[cols="1,2"] +|==== +|Value |Description + +|\{field_name\} a| + +The name of a field in the Search index. The Search Service sorts documents based on the value of the field, in ascending order. + +To sort in descending order based on a `{field-name}`, add a hyphen (-) to the start of the field name string. + +|_id a| + +The Search Service sorts documents based on their identifier value, in ascending order. + +To sort in descending order based on a document's ID value, add a hyphen (-) before the underscore (_) in the `_id` string. + +|_score a| + +The Search Service sorts documents based on their score value, in ascending order. + +To sort in descending order based on a document's score, add a hyphen (-) before the underscore (_) in the `_score` string. + +|==== + +To customize search result sorting beyond ascending and descending values, use a JSON object. + +JSON objects in a `sort` object can contain the following properties: + +[cols="1,1,1,4"] |==== |Property |Type |Required? |Description @@ -67,21 +2254,27 @@ Sets what value to use for the sort: * `id`: Uses the document's ID value. * `score`: Uses the document's score. -* `field`: Uses the value of a specific field to sort. See <>. +* `field`: Uses the value of a specific field to sort. See <>. + +|[[by-field]]field |String |No |When `by` is set to `field`, specify the name of the field to use to sort search results. + +|desc |Boolean |Yes a| -|[[field]]field |String |No |When `by` is set to `field`, specify the name of the field to use to sort search results. +To sort the values in the field in descending order, set `desc` to `true`. + +To sort the values in the field in ascending order, set `desc` to `false`. |mode |String |Yes a| -Set the order for search results when the `field` contains multiple values: +Set the order for search results when the `field` contains multiple values, such as an array: -* `default`: -* `min`: -* `max`: +* `default`: Use the first value in the field as the sort key. +* `min`: Use the smallest value in the field as the sort key. +* `max`: Use the largest value in the field as the sort key. |missing |String |Yes a| -Set how the Search Service sorts documents that don't have a value for the field specified in `field`: +Set how the Search Service sorts documents that do not have a value for the field specified in `field`: * `first`: Documents with a missing value appear first and before other results in search results. * `last`: Documents with a missing value appear last and after other results in search results. @@ -94,20 +2287,10 @@ Set the data type of the field specified in `field`: * `date`: The field contains date/time data. * `number`: The field contains a number or geographic data, like a latitude or longitude value. -| +|unit |String |No a| -|==== +When running a <>, you can set the unit of distance to use when sorting documents. -[#query] -== Query Object +The unit of distance does not have to match the unit specified in the <>. -[cols="1,1,1,2"] |==== -|Property |Type |Required? |Description - -|match |String | - -|field |String | - -|analyzer |String | -|==== \ No newline at end of file diff --git a/modules/search/pages/search.adoc b/modules/search/pages/search.adoc index 225f48450..e5c13008a 100644 --- a/modules/search/pages/search.adoc +++ b/modules/search/pages/search.adoc @@ -1,6 +1,78 @@ -= Search for Documents -:description: += Add Search to Your Application :page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: clusters:search-service/search-service.adoc +:description: Use the Search Service to create a customizable search experience for your operational cluster and your end-user applications. -Use the Search Service +[abstract] +{description} +The Search Service offers near real-time search capabilities for a diverse range of data types. +For example, you can use the Search Service with: + +* Structured or unstructured text +* Dates +* Numbers +* CIDR notation +* Geospatial data + +Use a <> to efficiently store your data, and retrieve it with a <>. + +[#indexes] +== Search Indexes + +A Search index tells the Search Service what content to use from the documents in your operational cluster for processing <>. +A Search index can use any field across multiple collections in a single scope. +If your operational cluster is running Couchbase Server version 7.6.2 and later, it can also include any document metadata stored in Extended Attributes (XATTRs). + +You can choose to exclude content to improve search performance and improve the relevance of search results. + +A Search index can also analyze and modify the content in your Search index or Search query to improve matching and search results. +The Search Service has default components that you can use to customize a Search index, or you can create your own. + +You need to create a Search index before you can use the Search Service to search the contents of your operational cluster from your application. + +For more information about how to create a Search index, see xref:create-search-indexes.adoc[]. + +You can create a Search index: + +* xref:create-search-index-ui.adoc[With the Couchbase {page-ui-name}] +* With a xref:search-index-params.adoc[JSON payload] that you xref:import-search-index.adoc[import through the UI]. +//* With the Couchbase SDKs +//* xref:create-search-index-rest-api.adoc[From the REST API] + +[#queries] +== Search Queries + +A Search query tells the Search Service what to search for in the contents of a Search index. + +Search queries use a simple string-based query syntax or JSON objects to control how the Search Service retrieves search results. + +For more information about how you can run a search against a Search index, see xref:run-searches.adoc[]. + +You can run a Search query: + +* xref:simple-search-ui.adoc[With the Couchbase {page-ui-name}] +* xref:n1ql:n1ql-language-reference/searchfun.adoc[With a SQL++ query]. +* With the Couchbase SDKs: ++ +include::partial$sdks-fts-links.adoc[] +//* xref:simple-search-rest-api.adoc[From the REST API] + +== Vector Search for AI Applications + +Vector Search builds on {page-product-name}'s Search Service to provide vector index support for Retrieval Augmented Generation (RAG) with an existing Large Language Model (LLM). + +Vector Search adds a new index type to the Search Service to support AI application development, known as a Vector Search index. +Using Vector Search and Couchbase {page-product-name}, you can develop applications with an existing LLM while giving context and up-to-date information from your own data. + +For more information about Vector Search, see xref:vector-search:vector-search.adoc[]. + +== See Also + +* xref:create-search-indexes.adoc[] +* xref:customize-index.adoc[] +* xref:index-aliases.adoc[] +* xref:run-searches.adoc[] +* xref:vector-search:vector-search.adoc[] diff --git a/modules/search/pages/set-advanced-settings.adoc b/modules/search/pages/set-advanced-settings.adoc deleted file mode 100644 index 2967ae636..000000000 --- a/modules/search/pages/set-advanced-settings.adoc +++ /dev/null @@ -1,115 +0,0 @@ -= Set Advanced Settings for a Search Index -:page-topic-type: guide -:tabs: - -== Prerequisites - -* You've created an index. -For more information, see xref:search/create-search-index-ui.adoc[]. - -* You've logged in to the Couchbase Server Web Console or Capella UI. - -== Procedure - -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Click the index that you want to edit. -. Click btn:[Edit]. -. Expand *Customize Index*. -. Expand *Advanced*. -. Configure any of the following advanced settings for your index: -|==== -|Option |Description - -|Default Type |Change the default type assigned to documents in the index. The default value is `_default`. - -|Default Analyzer a| - -Change the default analyzer assigned to type mappings in the index. - -For more information about the available default analyzers, see xref:search/default-analyzers-reference.adoc[]. - -|Default Date/Time Parser |Change the default date/time parser used for date data. - -|[[all-field]]Default Field a| - -When you xref:search/create-child-field.adoc[create a child field] in a type mapping, you can choose to include that field in an `_all` field. - -You can add fields to the `_all` field to search their contents without specifying their field name in your search query. - -Enter a value in the *Default Field* field to change the name of this default field. - -|Store Dynamic Fields |Select *Store Dynamic Fields* to include field values in search results from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping] in the index. - -|Index Dynamic Fields |Select *Index Dynamic Fields* to include fields from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping] in the index. - -|DocValues for Dynamic Fields |Select *DocValues for Dynamic Fields* to include the values of each field from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping] in the index. - -|Index Replicas a| - -Set the number of replicas that the Search Service creates for the index. - -For more information about replication and the Search Service, see xref:[]. - -|Index Type |This setting is included for compatibility only. For new indexes, this setting is always *Version 6.0 (Scorch)*. - -|Index Partitions |Enter a number greater than one to to divide the index into partitions across multiple nodes running the Search Service. - -|==== -. Click btn:[Update Index]. --- - -Couchbase Capella:: -+ --- -. From your organization page, select the database that has the index you want to edit. -. Go to menu:Data Tools[Search]. -. Click the index that you want to edit. -. Expand *Advanced Configuration*. -. Expand *General Settings*. -. Configure any of the following advanced settings for your index: -|==== -|Option |Description - -|Default Type |Change the default type assigned to documents in the index. The default value is `_default`. - -|Default Analyzer a| - -Change the default analyzer assigned to type mappings in the index. - -For more information about the available default analyzers, see xref:search/default-analyzers-reference.adoc[]. - -|Default Date/Time Parser |Change the default date/time parser used for date data. - -|[[all-field-capella]]Default Field a| - -When you xref:search/create-child-field.adoc[create a child field] in a type mapping, you can choose to include that field in an `_all` field. - -You can add fields to the `_all` field to search their contents without specifying their field name in your search query. - -Enter a value in the *Default Field* field to change the name of this default field. - -|Store Dynamic Fields |Select *Store Dynamic Fields* to include field values in search results from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping] in the index. - -|Index Dynamic Fields |Select *Index Dynamic Fields* to include fields from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping] in the index. - -|DocValues for Dynamic Fields |Select *DocValues for Dynamic Fields* to include the values of each field from a xref:search/customize-index.adoc#type-mappings[dynamic type mapping] in the index. - -|Index Replicas a| - -Set the number of replicas that the Search Service creates for the index. - -For more information about replication and the Search Service, see xref:[]. - -|Index Type |This setting is included for compatibility only. For new indexes, this setting is always *Version 6.0 (Scorch)*. - -|Index Partitions |Enter a number greater than one to to divide the index into partitions across multiple nodes running the Search Service. - -|==== -. Click btn:[Submit]. --- -==== \ No newline at end of file diff --git a/modules/search/pages/set-type-identifier.adoc b/modules/search/pages/set-type-identifier.adoc index 4b669baf6..e2e7c182e 100644 --- a/modules/search/pages/set-type-identifier.adoc +++ b/modules/search/pages/set-type-identifier.adoc @@ -1,47 +1,106 @@ -= Set the Type Identifier for a Search Index += Set a Document Filter :page-topic-type: guide -:tabs: +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use a document filter with a type mapping to add an extra filter to the documents you want to include in a Search index. +:page-toclevels: 3 + +[abstract] +{description} + +For more information about document filters and type mappings, see xref:customize-index.adoc#type-identifiers[Search Index Features]. == Prerequisites -* You've created an index. -For more information, see xref:search/create-search-index-ui.adoc[]. - -* You've logged in to the Couchbase Server Web Console or Capella UI. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have started to create or already created an index in xref:create-search-indexes.adoc#advanced-mode[Advanced Mode Editing]. + +* You have created at least one type mapping in your Search index. +For more information, see xref:create-search-index-ui.adoc[]. + +* You have logged in to the Couchbase {page-ui-name}. == Procedure -[{tabs}] -==== -Couchbase Server:: +To set a document filter for a Search index with the {page-ui-name}: + +. On the *Operational Clusters* page, select the operational cluster where you want to work with the Search Service. +. Go to menu:Data Tools[Search]. +. Do one of the following: +.. To work with an existing Search index, click the name of the index where you want to create a document filter. +.. To create a new Search index, click btn:[Create Search Index]. +. Make sure to select *Enable Advanced Options*. +. Expand *Global Index Settings*. +. Do one of the following: +.. <> +.. <> +.. <> + +[#json-type] +=== Create a JSON Type Field Document Filter + +To only add documents to your Search index that contain a specific field with a specified string value: + +. Under *Choose Document Filter*, click btn:[JSON Type Field] +. In the *JSON Type Field* field, enter the name of the field in your documents that you want to use to filter documents in your Search index. ++ +For example, if your documents include a `type` field, you could enter `type` in the *JSON Type Field* field. ++ +NOTE: You cannot use a field as a document filter if the field name contains a period (.). +. Under *Type Mappings*, next to the type mapping where you want to add the document filter, go to menu:More Options (⋮)[Edit]. +. In the *Name* field, add a period (.) to the end of the current type mapping name. +. After the period, add the exact string from the document field that you want to use as a filter. ++ +For example, if you wanted your Search index to only return documents that had a `type` value of `hotel`, you could enter `hotel`. +. Click btn:[Submit]. +. Click btn:[Update Index]. + +[#doc-id-sep] +=== Create a Doc ID Up To Separator Document Filter + +To only add documents to your Search index that have IDs that match a specified prefix: + +. Under *Choose Document Filter*, click btn:[Doc ID up to Separator]. +. In the *Doc ID up to Separator* field, enter the separator character from the ID prefix in your document ID values. + --- -. Go to *Search*. -. Click the index where you want to set a type identifier. -. Click btn:[Edit]. -. Expand *Customize Index*. -. Expand *Type Identifier*. -. Do one of the following: -.. To use the value of a field in the document as the document's type, select *JSON type field*. -.. To use the document's ID value, up to a given separator, as the document's type, select *Doc ID up to separator*. -.. To use the document's ID value with a regular expression applied as the document's type, select *Doc ID with regex*. -. Enter the field name, separator, or regular expression in the corresponding field. +For example, if you know all of your document ID values are prefixed by a string and an underscore (\_), enter `_`. +. Under *Type Mappings*, next to the type mapping where you want to add the document filter, go to menu:More Options (⋮)[Edit]. +. In the *Name* field, add a period (.) to the end of the current type mapping name. +. After the period, add the exact prefix from the document's ID value that you want to use as a filter. ++ +For example, if you wanted your Search index to only return documents that have an prefix of `landmark_`, you could enter `landmark`. +. Click btn:[Submit]. . Click btn:[Update Index]. --- -Couchbase Capella:: +[#doc-id-regex] +=== Create a Doc ID with Regex Document Filter + +To only add documents to your Search index that have IDs that match a specified https://github.com/google/re2/wiki/Syntax[RE2] regular expression: + +. Under *Choose Document Filter*, click btn:[Doc ID with Regex]. +. In the *Doc ID with Regex* field, enter the regular expression that you want to use to filter documents in your Search index. + --- -. From your organization page, select the database that has the index you want to edit. -. Go to menu:Data Tools[Search]. -. Click the index where you want to set a type identifier. -. Expand *Advanced Configuration*. -. Expand *General Settings*. -. Do one of the following: -.. To use the value of a field in the document as the document's type, select *JSON type field*. -.. To use the document's ID value, up to a given separator, as the document's type, select *Doc ID up to separator*. -.. To use the document's ID value with a regular expression applied as the document's type, select *Doc ID with regex*. -. Enter the field name, separator, or regular expression in the corresponding field. +For example, if you wanted documents with ID values that contained `\_40`, you could enter `_[3-5]0` as your regular expression. +. Under *Type Mappings*, next to the type mapping where you want to add the document filter, go to menu:More Options (⋮)[Edit]. +. In the *Name* field, add a period (.) to the end of the current type mapping name. +. After the period, add a match for the regular expression from the document's ID value that you want to use as a filter. ++ +For example, if you wanted your Search index to only return documents with ID values that contained `_40`, you could enter `_40`. . Click btn:[Submit]. --- -==== +. Click btn:[Update Index]. + +== Next Steps + +After you set the document filter for your Search index, you can continue to customize your Search index: + +* xref:create-custom-analyzer.adoc[] +* xref:create-custom-character-filter.adoc[] +* xref:create-custom-token-filter.adoc[] +* xref:create-custom-tokenizer.adoc[] + +To run a search and test the contents of your Search index, see xref:simple-search-ui.adoc[]. diff --git a/modules/search/pages/simple-search-rest-api.adoc b/modules/search/pages/simple-search-rest-api.adoc deleted file mode 100644 index 672171fef..000000000 --- a/modules/search/pages/simple-search-rest-api.adoc +++ /dev/null @@ -1,39 +0,0 @@ -= Run a Simple Search with the REST API and cURL/HTTP -:page-topic-type: guide - -== Prerequisites - -* You have the Search Service enabled on a node in your database. - -* Your user account has the `Search Admin` or `Search Reader` role. - -* You installed the Couchbase command-line tool (CLI). - -* You have the hostname or IP address for your database. - -* You have created a Search index. -+ -For more information about how to create a Search index, see xref:search/create-search-index-ui.adoc[] or xref:search/create-search-index-rest-api.adoc[]. - -== Procedure - -. In the command-line tool, start a `curl` command with the `XPOST` verb. -. Set your header content to include `Content-Type: application/json`. -. Enter your username, password, and the Search Service endpoint on port `8094` with the name of the index you want to query: -+ -[source,console] ----- -include::example$run-search-header.sh[] ----- -. Enter the JSON payload for your query. -+ -TIP: You can copy the JSON for Query Request from the Couchbase Server or Couchbase Capella UI to use in your REST API call. -For more information about how to perform a search with the UI, see xref:search/simple-search-ui.adoc[]. - -+ -In the following example, the JSON payload queries an index named `landmark-content-index` on the `travel-sample` bucket for the strings `view`, `food`, and `beach`: -+ -[source,console] ----- -include::example$run-search-payload.sh[] ----- \ No newline at end of file diff --git a/modules/search/pages/simple-search-ui.adoc b/modules/search/pages/simple-search-ui.adoc index fb57bd9a3..624a76253 100644 --- a/modules/search/pages/simple-search-ui.adoc +++ b/modules/search/pages/simple-search-ui.adoc @@ -1,53 +1,70 @@ -= Run a Simple Search With The UI -:page-topic-type: guide += Run A Simple Search with the {page-ui-name} +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Run a Search query from the Couchbase {page-ui-name} to preview the search results from a Search index. -== Prerequisites +[abstract] +{description} + +For more information about how the Search Service scores documents in search results, see xref:run-searches.adoc#scoring[Scoring for Search Queries]. -* You have the Search Service enabled on a node in your database. +== Prerequisites -* Your user account has the `Search Admin` or `Search Reader` role. +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. * You have created a Search index. + -For more information about how to create a Search index, see xref:search/create-search-index-ui.adoc[]. +For more information about how to create a Search index, see xref:create-search-indexes.adoc[]. -* You have logged in to the Couchbase Server Web Console or Couchbase Capella UI. +* You have logged in to the Couchbase {page-ui-name}. == Procedure -[{tabs}] -==== -Couchbase Server:: -+ --- -. Go to *Search*. -. Click the index where you want to run a search. -. In the *Search this index* field, enter a search query. -+ +To run a simple search with the {page-ui-name}: + +. On the *Operational Clusters* page, select the operational cluster where you created your Search index. +. Go to menu:Data Tools[Search]. +. Next to your Search index or xref:index-aliases.adoc[index alias], click btn:[Search]. +. In the *Search* field, enter a search query. +. Press kbd:[Enter]. +. (Optional) To view a document and its source collection, click a document name in the search results list. + +=== Example: Simple Text Search + For example, the following query searches for the strings `view`, `food`, and `beach`: -+ + [source,json] ---- -include::examples$run-search-payload-ui.jsonc[tag=server] +include::example$run-search-payload-ui.jsonc[] ---- -The query payload enables scoring explanations and term highlighting. It also returns all available fields in the index, and returns 10 results per page. --- +The query payload enables scoring explanations and term highlighting. +It also returns all available fields in the index, and returns 10 results per page. -Couchbase Capella:: -+ --- -. From your organization page, select the database where you want to create a child field. -. Go to menu:Data Tools[Search]. -. On the index where you want to run a search, click the *More Options* (⋮) menu. -. Click *Search*. -. In the *Search* field, enter a search query. -+ -For example, the following query searches for the strings `view`, `food`, and `beach`: -+ +TIP: Use the xref:search-request-params.adoc#collections[`collections` parameter] in your request to specify an array of collections to search from the Search index. + +=== Example: Validate a Search Query + +[.status]#Couchbase Server 7.6.5# + +For example, the following query searches a Search index, `landmark-content-index`, using a xref:search-request-params.adoc#geopoint-queries-distance[Distance/Radius-Based Geopoint Query] on the `geo` field. +The query includes the xref:search-request-params.adoc#ctl[ctl object] with the `validate` property to validate the query: + +[source,json] ---- -+view +food +beach +include::example$run-search-validate-ui.jsonc[] ---- --- -==== \ No newline at end of file +Since the `landmark-content-index` does not include a mapping for the `geo` field and the `validate` property is included in the query, the Web Console returns the following error: + +---- +query_validate: field not indexed, name: geo, type: geopoint +---- + +== Next Steps + +If you do not get the search results you were expecting, you can change the xref:search-request-params.adoc[JSON payload for your Search query]. + +You can also xref:customize-index.adoc[]. \ No newline at end of file diff --git a/modules/search/pages/supported-languages.adoc b/modules/search/pages/supported-languages.adoc deleted file mode 100644 index e7429ec34..000000000 --- a/modules/search/pages/supported-languages.adoc +++ /dev/null @@ -1,58 +0,0 @@ -= Supported Languages -:page-topic-type: reference - -When you create an index and add a text field with the xref:search/create-quick-index.adoc[quick editor], you need to specify a language for the text. - -The following language options are available: - -|==== -|Language Option |Description - -|Unknown/Various |Select this option if the text in the field contains multiple languages, or doesn't match another language option. - -2+|English - -2+|Arabic - -2+|Chinese, Japanese, and Korean - -2+|Croatian - -2+|Danish - -2+|Dutch - -2+|Finnish - -2+|French - -2+|German - -2+|Hebrew - -2+|Hindi - -2+|Hungarian - -2+|Italian - -2+|Norwegian - -2+|Persian - -2+|Portuguese - -2+|Romanian - -2+|Russian - -2+|Sorani Kurdish - -2+|Spanish - -2+|Swedish - -2+|Turkish - -|Web |Select this option if the text in the field contains content like URLs, email addresses, Twitter usernames, or hashtags. -|==== \ No newline at end of file diff --git a/modules/search/pages/type-mapping-options.adoc b/modules/search/pages/type-mapping-options.adoc new file mode 100644 index 000000000..d7f64f11f --- /dev/null +++ b/modules/search/pages/type-mapping-options.adoc @@ -0,0 +1,278 @@ += Collection, Object, XATTRs, and Field Mapping Options +:page-topic-type: reference +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-aliases: quick-index-field-options.adoc, child-field-options-reference.adoc +:description: When you create a Search index in the {page-ui-name}, you must set options for each collection, object, Extended Attributes (XATTRs) object, or field mapping you add to your index. + +[abstract] +{description} + +You can create the following types of mappings in the {page-ui-name}: + +* <> +* <> +* <> +* <> + +TIP: Indexing an entire collection creates a dynamic type mapping for that collection. +Indexing a field creates a static type mapping for the parent collection. +For more information about static and dynamic type mappings, see xref:customize-index.adoc#type-mappings[Search Index Features]. + +For more information about how to create a Search index, see xref:create-search-index-ui.adoc[]. + +[#collection] +== Collection Type Mapping Options + +Configure an entire collection type mapping to add or remove all documents in that collection from your Search index. + +You can add <>, an <>, or <> for objects and fields inside your collection to change your collection type mapping from a xref:customize-index.adoc#dynamic[dynamic mapping] to a xref:customize-index.adoc#static[static mapping]. + +You can configure the following options for a type mapping that uses an entire collection: + +|==== +|Option |Description + +| Index everything from collection: "`$COLLECTION_NAME`" +a| You must select *Index everything from collection* to add a collection type mapping. + +The Search Service adds all documents inside the selected collection to your Search index. + +In the previous version of the Search Service UI, this option was the same as leaving *Only index specified fields* unchecked in Advanced Mode. + +It was not available in Quick Mode. + +| Use keyword analyzer for text +a| To index any *Text* type fields inside this collection with the xref:default-analyzers-reference.adoc#keyword[keyword analyzer], select *Use keyword analyzer for text*. + +To use other analyzers on text fields, clear *Use keyword analyzer for text*. + +For more information about analyzers, see xref:customize-index.adoc#analyzers[Search Index Features]. + +In the previous version of the Search Service UI, this option was named *Index text fields as identifiers* in Quick Mode. + +It was not available in Advanced Mode. + +|Analyzer/Language +a| If you do not select *Use keyword analyzer for text*, use the *Analyzer/Language* list to select an analyzer to use or the language of any content inside *Text* fields in the collection. + +For more information about the available language and analyzer options, see xref:default-analyzers-reference.adoc[]. + +In the previous version of the Search Service UI, this option was named *Analyzer/Language* in Quick Mode. + +In Advanced Mode, it was named *Default Analyzer*. + +|==== + +[#object] +== JSON Object Mapping Options + +Configure a JSON object mapping to add or remove a JSON object from your Search index. +This JSON object does not currently have to exist in your document schema. + +You can add <> for any fields under a JSON object to change your JSON object mapping from a xref:customize-index.adoc#dynamic[dynamic mapping] to a xref:customize-index.adoc#static[static mapping]. + +You can configure the following options for a JSON object mapping: + +|==== +|Option |Description + +| Index everything under: "`$OBJECT_NAME`" +a| Select *Index everything under* to create a xref:customize-index.adoc#dynamic[dynamic] object mapping in your Search index. + +The Search Service adds all document fields inside the object to your Search index. + +In the previous version of the Search Service UI, this option was not available. + +| Use keyword analyzer for text +a| To index any *Text* type fields inside this object with the xref:default-analyzers-reference.adoc#keyword[keyword analyzer], select *Use keyword analyzer for text*. + +To use other analyzers on text fields, clear *Use keyword analyzer for text*. + +For more information about analyzers, see xref:customize-index.adoc#analyzers[Search Index Features]. + +In the previous version of the Search Service UI, this option was not available for object mappings. + +|Analyzer/Language +a| If you do not select *Use keyword analyzer for text*, use the *Analyzer/Language* list to select the analyzer or language for the content inside any *Text* fields. + +For more information about the available language and analyzer options, see xref:default-analyzers-reference.adoc[]. + +In the previous version of the Search Service UI, this option was named *Analyzer/Language* in Quick Mode. + +In Advanced Mode, it was named *Default Analyzer*. + +|==== + +[#xattrs] +== XATTRs Mapping Options + +Configure an Extended Attributes (XATTRs) mapping to add or remove document metadata from your Search index. +The XATTRs object does not have to currently exist in your document schema. + +You can add <> for any fields under an XATTRs mapping to change your mapping from a xref:customize-index.adoc#dynamic[dynamic mapping] to a xref:customize-index.adoc#static[static mapping]. + +You can only configure 1 XATTRs mapping for each collection in your Search index. + +You can configure the following options for an XATTRs mapping: + +|==== +|Option |Description + +| Index everything under: "`$xattrs`" +a| Select *Index everything under: "$xattrs"* to create a xref:customize-index.adoc#dynamic[dynamic] XATTRs mapping in your Search index. + +The Search Service adds all metadata fields inside the XATTRs object to your Search index. + +In the previous version of the Search Service UI, this option was the same as leaving *Only index specified fields* unchecked in Advanced Mode. + +This option was not available in Quick Mode. + +| Use keyword analyzer for text (Text Fields Only) +a| To index this field with the xref:default-analyzers-reference.adoc#keyword[keyword analyzer], select *Use keyword analyzer for text*. + +To use other analyzers on this text field, clear *Use keyword analyzer for text*. + +For more information about analyzers, see xref:customize-index.adoc#analyzers.adoc[Search Index Features]. + +In the previous version of the Search Service UI, this option was not available for XATTRs mappings. + +// |Include in search results +// | +// a|To include content from the field in search results, select *Include in search results*. + +// To exclude the field's content from search results, clear *Include in search results*. + +// |Support field agnostic search +// | +// a|To search the field's contents without specifying the field name in a search query, select *Support field agnostic search*. + +// To turn off field agnostic search, clear *Support field agnostic search*. + +// |Support sorting and faceting +// | +// a|To sort search results and use xref:search-request-params.adoc#facets[facets] with the field's contents, select *Support sorting and faceting*. + +// To turn off sorting and facets, clear *Support sorting and faceting*. + +// |Analyzer/Language (Text Fields Only) +// | +// a|If you do not select *Use keyword analyzer for text*, use the *Analyzer/Language* list to select the analyzer or language for the content inside any *Text* fields. + +// For more information about the available language and analyzer options, see xref:default-analyzers-reference.adoc[]. + +|==== + +[#field] +== Field Type Mapping Options + +Configure a single field type mapping to add or remove that field from your Search index. + +You can configure the following options for a type mapping that uses a single field: + +|==== +|Option |Description + +| Type +a| Set the data type of the contents of the field. + +The *Type* you choose changes the options you have available for that field. + +For more information about the available field data types, see xref:field-data-types-reference.adoc[]. + +In the previous version of the Search Service UI, this option had the same name. + +|Searchable As +a| Set a different name that you can use to search the field's contents in a query. + +The default value is the field's name. + +In the previous version of the Search Service UI, this option had the same name. + +| Use keyword analyzer for text (Text Fields Only) +a|To index this field with the xref:default-analyzers-reference.adoc#keyword[keyword analyzer], select *Use keyword analyzer for text*. + +To use other analyzers on this text field, clear *Use keyword analyzer for text*. + +For more information about analyzers, see xref:customize-index.adoc#analyzers.adoc[Search Index Features]. + +In the previous version of the Search Service UI, this option was named *Index this field as an identifier* in Quick Mode. + +This option was not available in Advanced Mode. + +|Analyzer/Language (Text Fields Only) +a| If you do not select *Use keyword analyzer for text*, use the *Analyzer/Language* list to select the analyzer or language for the content inside any *Text* fields. + +For more information about the available language and analyzer options, see xref:default-analyzers-reference.adoc[]. + +In the previous version of the Search Service UI, this option was named *Analyzer/Language* in Quick Mode. + +In Advanced Mode, it was named *Default Analyzer*. + +|[[dimension]]Dimension (Vector Fields Only) +a| include::partial$vector-search-field-descriptions.adoc[tag=dimension] + +In the previous version of the Search Service UI, this option had the same name. + +|Similarity Metric (Vector Fields Only) +a| include::partial$vector-search-field-descriptions.adoc[tag=similarity_metric] + +In the previous version of the Search Service UI, this option had the same name. + +|Optimized For (Vector Fields Only) +a| include::partial$vector-search-field-descriptions.adoc[tag=optimized_for] + +In the previous version of the Search Service UI, this option had the same name. + +|Include in search results +a| To include content from the field in search results, select *Include in search results*. + +To exclude the field's content from search results, clear *Include in search results*. + +In the previous version of the Search Service UI, this option was named *Include in search results* in Quick Mode. + +In Advanced mode, it was named *Store*. + +// |Support highlighting +// a| The Search Service can highlight matching search terms in search results from an index. + +// To enable highlighting in search results, select *Support highlighting*. + +// To turn off highlighting in search results, clear *Support highlighting*. + +// NOTE: To enable *Support highlighting*, you must also enable *Include in search results*. + +// In the previous version of the Search Service UI, this option was named *Support highlighting* in Quick Mode. +// In Advanced mode, this was not available as a single option. +// You needed to turn on both *Include Term Vectors* and *Store*. + +|[[term-vectors]]Support phrase matching +a| To support searches for whole phrases, select *Support phrase matching*. + +To turn off phrase matching, clear *Support phrase matching*. + +NOTE: To enable *Support phrase matching*, you must also enable *Include in search results*. + +In the previous version of the Search Service UI, this option was named *Support phrase matching* in Quick Mode. + +In Advanced Mode, it was named *Include Term Vectors*. + +|Support field agnostic search +a|To search the field's contents without specifying the field name in a search query, select *Support field agnostic search*. + +To turn off field agnostic search, clear *Support field agnostic search*. + +In the previous version of the Search Service UI, this option was named *Support field agnostic search* in Quick Mode. + +In Advanced Mode, it was named *Include in _all field*. + +|Support sorting and faceting +a| To support sorting search results based on this field and use xref:search-request-params.adoc#facets[facets] with the field's contents, select *Support sorting and faceting*. + +To turn off sorting and facets, clear *Support sorting and faceting*. + +In the previous version of the Search Service UI, this option was named *Support sorting and faceting* in Quick Mode. + +In Advanced Mode, it was named *Doc Values*. + +|==== \ No newline at end of file diff --git a/modules/search/partials/create-child-field-steps.adoc b/modules/search/partials/create-child-field-steps.adoc deleted file mode 100644 index 7166c98fd..000000000 --- a/modules/search/partials/create-child-field-steps.adoc +++ /dev/null @@ -1,73 +0,0 @@ -. In the *Field* field, enter the name of a field in your documents that you want to add or remove from the index. -+ -NOTE: The field must contain either a single value or an array. -. In the *Type* list, select the data type for the field: -+ -For more information about the available data types, see xref:search/field-data-types-reference.adoc[]. - -. Configure optional settings for the child field: -+ -|==== -|Option |Description - -|Searchable As a| - -Set a different name that you can use to search the field's contents in a query. - -The default value is the value set in *Field*. - -|Analyzer a| - -Choose an analyzer for the content in the child field. - -You can choose a default analyzer or a custom analyzer. - -For more information about the available default analyzers, see xref:search/default-analyzers-reference.adoc[]. - -For more information about how to create a custom analyzer, see xref:search/create-custom-analyzer.adoc[]. - -|Index a| - -To include the child field in the index, select *Index*. - -To remove the child field from the index, clear *Index*. - -|[[store]]Store a| - -To store the values from the field in the index and return them in search results, select *Store*. -This increases your index's size and indexing time. - -To remove the field's values from the index, clear *Store*. - -|Include in _all field a| - -The `_all` field is a composite field that has the content from multiple fields in an index. -It allows searches to query the content of a field without specifying the field's name. - -To include this field in the `_all` field, select *Include in _all field*. - -To exclude this field from the `_all` field, clear *Include in _all field*. - -TIP: To change the name of the `_all` field, see xref:search/set-advanced-settings.adoc#all-field[Default Field]. - -|Include Term Vectors a| - -Term vectors store the location of terms in a field for an index. -You can use term vectors to highlighting matching search terms in search results, and perform phrase searches. -Term vectors increase your index's size and indexing time. - -To enable term vectors for this field, select *Include Term Vectors*. - -To turn off term vectors, clear *Include Term Vectors*. - -NOTE: To enable term vectors, you must also enable <>. - -|Doc Values a| - -Doc values are the value for each instance of the field in an index. -Use doc values for Search xref:[Facets] and sorting search results. - -To store doc values, select *Doc Values*. - -To exclude doc values from the index, clear *Doc Values*. -|==== diff --git a/modules/search/partials/custom-analyzer-first-steps.adoc b/modules/search/partials/custom-analyzer-first-steps.adoc deleted file mode 100644 index 6330dd21c..000000000 --- a/modules/search/partials/custom-analyzer-first-steps.adoc +++ /dev/null @@ -1,6 +0,0 @@ -. Expand *Analyzers*. -. Click btn:[Add Analyzer]. -. In the *Name* field, enter a name for the new custom analyzer. -. To remove specific characters from search input before tokenizing, in the *Character Filters* list, do one of the following: -.. Select a default character filter. For more information about the available character filters, see xref:search/customize-index.adoc#character-filters[Character Filters]. -.. Select your own character filter. For more information about how to create a character filter, see xref:search/create-custom-character-filter.adoc[]. \ No newline at end of file diff --git a/modules/search/partials/custom-analyzer-tokenizer-steps.adoc b/modules/search/partials/custom-analyzer-tokenizer-steps.adoc deleted file mode 100644 index 1fc9fc522..000000000 --- a/modules/search/partials/custom-analyzer-tokenizer-steps.adoc +++ /dev/null @@ -1,6 +0,0 @@ -. In the *Tokenizer* list, do one of the following. -.. Select a default tokenizer. For more information about the available tokenizers, see xref:search/customize-index.adoc#tokenizers[Tokenizers]. -.. Select your own tokenizer. For more information about how to create a tokenizer, see xref:search/create-custom-tokenizer.adoc[]. -. To modify the tokens created by the tokenizer, in the *Token Filters* list, do one of the following: -.. Select a default token filter. For more information about the available token filters, see xref:search/default-token-filters-reference.adoc[]. -.. Select your own token filter. For more information about how to create a token filter, see xref:search/create-custom-token-filter.adoc[]. \ No newline at end of file diff --git a/modules/search/partials/custom-character-filter-first-steps.adoc b/modules/search/partials/custom-character-filter-first-steps.adoc deleted file mode 100644 index dcb6fe790..000000000 --- a/modules/search/partials/custom-character-filter-first-steps.adoc +++ /dev/null @@ -1,6 +0,0 @@ -. Expand *Custom Filters*. -. Click btn:[Add Character Filter]. -. In the *Name* field, enter a name for the character filter. -. In the *Regular Expression* field, enter the regular expression for the character filter. -. (Optional) In the *Replacement* field, enter a string that replaces any matches for the regular expression. -. Click btn:[Save]. \ No newline at end of file diff --git a/modules/search/partials/custom-token-filter-tf-list.adoc b/modules/search/partials/custom-token-filter-tf-list.adoc deleted file mode 100644 index 3f69ffcff..000000000 --- a/modules/search/partials/custom-token-filter-tf-list.adoc +++ /dev/null @@ -1,12 +0,0 @@ -You can create any of the following custom token filters: - -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> \ No newline at end of file diff --git a/modules/search/partials/custom-token-filters-descriptions.adoc b/modules/search/partials/custom-token-filters-descriptions.adoc new file mode 100644 index 000000000..76067d30f --- /dev/null +++ b/modules/search/partials/custom-token-filters-descriptions.adoc @@ -0,0 +1,275 @@ +// tag::dict[] +A `dict_compound` token filter uses a wordlist to find subwords inside an input token. +If the token filter finds a subword inside a compound word, it turns it into a separate token. + +// tag::dict_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=dict_compound] +---- +// end::dict_example[] + +For example, if you had a wordlist that contained `play` and `jump`, the token filter converts `playful jumping` into two tokens: `play` and `jump`. + +[plantuml,dict,svg] +.... +@startuml + +(playful jumping) as Start <> +(play) <> +(jump) <> +rectangle wordlist { + usecase "play" as WL1 + usecase "jump" as WL2 +} + +Start --> (play) +Start --> (jump) +@enduml +.... +// end::dict[] + +// tag::edge[] +An `edge_ngram` token filter uses a specified range to create new tokens. +You can also choose whether to create the new token from the start or backward from the end of the input token. + +// tag::edge_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=edge_ngram] +---- +// end::edge_example[] + +For example, if you had a miminum of four and a maximum of five with an input token of `breweries`, the token filter creates the tokens `brew` and `brewe`. + +[plantuml,edge,svg] +.... +@startuml + +(breweries) as Start <> +(brew) <> +(brewe) <> +rectangle range { + usecase "min: 4" as R1 + usecase "max: 5" as R2 +} + +Start --> (brew) +Start --> (brewe) +@enduml +.... +// end::edge[] + +// tag::elision[] +An `elision` token filter removes elisions from input tokens. + +// tag::elision_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=elision] +---- +// end::elision_example[] + +For example, if you had the `stop_fr` wordlist in an elision token filter, the token `je m'appelle John` becomes the tokens `je`, `appelle`, and `John`. + +[plantuml,elision,svg] +.... +@startuml + +(je m'appelle John) as Start <> +(je) <> +(appelle) <> +(John) <> +rectangle wordlist { + usecase "stop_fr" as WL1 +} + +Start --> (je) +Start --> (appelle) +Start --> (John) +@enduml +.... +// end::elision[] + +// tag::keyword[] +A `keyword_marker` token filter finds keywords in an input token and turns them into tokens. + +// tag::keyword_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=keyword_marker] +---- +// end::keyword_example[] + +For example, if you had a wordlist that contained the keyword `beer`, the token `beer and breweries` becomes the token `beer`. + +[plantuml,keyword,svg] +.... +@startuml + +(beer and breweries) as Start <> +(beer) <> +rectangle wordlist { + usecase "beer" as WL1 +} + +Start --> (beer) +@enduml +.... +// end::keyword[] + +// tag::length[] +A `length` token filter removes tokens that are shorter or longer than a set character length. + +// tag::length_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=length] +---- +// end::length_example[] + +For example, if you had a range with a minimum of two and a maximum of four, the token `beer and breweries` becomes the tokens `beer` and `and`. + +[plantuml,length,svg] +.... +@startuml + +(beer and breweries) as Start <> +(beer) <> +(and) <> + +Start --> (beer) +Start --> (and) +@enduml +.... +// end::length[] + +// tag::ngram[] +An `ngram` token filter uses a specified character length to split an input token into new tokens. + +// tag::ngram_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=ngram] +---- +// end::ngram_example[] + +For example, if you had a range with a minimum of four and a maximum of five, the token `beers` becomes the tokens `beer`, `beers`, and `eers`. + +[plantuml,ngram,svg] +.... +@startuml + +(beers) as Start <> +(beer) <> +(beers) <> +(eers) <> + +Start --> (beer) +Start --> (beers) +Start --> (eers) +@enduml +.... +// end::ngram[] + +// tag::normalize[] +A `normalize_unicode` token filter uses a specified Unicode Normalization form to create new tokens. + +// tag::normalize_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=normalize_unicode] +---- +// end::normalize_example[] +// end::normalize[] + +// tag::shingle[] +A `shingle` token filter uses a specified character length and separator to create new tokens. + +// tag::shingle_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=shingle] +---- +// end::shingle_example[] + +For example, if you use a xref:search:default-tokenizers-reference.adoc#whitespace[whitespace tokenizer], a range with a minimum of two and a maximum of three, and a space as a separator, the token `abc def` becomes `abc`, `def`, and `abc def`. + +[plantuml,shingle,svg] +.... +@startuml + +(abc def) as Start <> + +(abc) <> +(def) <> +(abc def) <> + +Start --> (abc) +Start --> (def) +Start --> (abc def) +@enduml +.... +// end::shingle[] + +// tag::stop[] +A `stop_tokens` token filter uses a wordlist to remove specific tokens from input. + +// tag::stop_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=stop_tokens] +---- +// end::stop_example[] + +For example, if you have a wordlist that contains the word `and`, the token `beers and breweries` becomes `beers` and `breweries`. + +[plantuml,stop,svg] +.... +@startuml + +(beers and breweries) as Start <> +(beers) <> +(breweries) <> + +rectangle wordlist { + usecase "and" as WL1 +} + +Start --> (beers) +Start --> (breweries) +@enduml +.... +// end::stop[] + +// tag::truncate[] +A `truncate_token` token filter uses a specified character length to shorten any input tokens that are too long. + +// tag::truncate_example[] +[source,json] +---- +include::example$complex-search-index-payload.jsonc[tag=truncate_token] +---- +// end::truncate_example[] + +For example, if you had a `length` of four, the token `beer and breweries` becomes `beer`, `and`, and `brewe`. + +[plantuml,truncate,svg] +.... +@startuml + +(beer and breweries) as Start <> +(beer) <> +(and) <> +(brewe) <> + +rectangle length { + usecase "4" as L1 +} + +Start --> (beer) +Start --> (and) +Start --> (brewe) +@enduml +.... +// end::truncate[] \ No newline at end of file diff --git a/modules/search/partials/custom-tokenizer-regexp-steps.adoc b/modules/search/partials/custom-tokenizer-regexp-steps.adoc deleted file mode 100644 index 1252686f7..000000000 --- a/modules/search/partials/custom-tokenizer-regexp-steps.adoc +++ /dev/null @@ -1,5 +0,0 @@ -. Expand *Custom Filters*. -. In the *Name* field, enter a name for the custom tokenizer. -. In the *Type* field, select *regexp*. -. In the *Regular Expression* field, enter a regular expression to split input strings into tokens. -. Click btn:[Save]. \ No newline at end of file diff --git a/modules/search/partials/nav.adoc b/modules/search/partials/nav.adoc index 6f96b7230..8bc7ab468 100644 --- a/modules/search/partials/nav.adoc +++ b/modules/search/partials/nav.adoc @@ -1,27 +1,29 @@ - ** xref:server:search:search.adoc[] - *** xref:server:search:create-search-indexes.adoc[] - **** xref:server:search:create-search-index-ui.adoc[] - **** xref:server:search:create-search-index-rest-api.adoc[] - ***** xref:server:search:search-index-params.adoc[] - **** xref:server:search:create-quick-index.adoc[] - ***** xref:server:search:quick-index-field-options.adoc[] - ***** xref:server:search:supported-languages.adoc[] - *** xref:server:search:run-searches.adoc[] - **** xref:server:search:simple-search-rest-api.adoc[] - ***** xref:server:search:search-request-params.adoc[] - **** xref:server:search:simple-search-ui.adoc[] - *** xref:server:search:customize-index.adoc[] - **** xref:server:search:set-type-identifier.adoc[] - **** xref:server:search:create-type-mapping.adoc[] - **** xref:server:search:create-child-field.adoc[] - **** xref:server:search:create-child-mapping.adoc[] - **** xref:server:search:create-custom-analyzer.adoc[] - **** xref:server:search:create-custom-character-filter.adoc[] - **** xref:server:search:create-custom-tokenizer.adoc[] - **** xref:server:search:create-custom-token-filter.adoc[] - **** xref:server:search:create-custom-wordlist.adoc[] - **** xref:server:search:set-advanced-settings.adoc[] - **** xref:server:search:default-analyzers-reference.adoc[] - **** xref:server:search:default-token-filters-reference.adoc[] - **** xref:server:search:default-wordlists-reference.adoc[] - **** xref:server:search:field-data-types-reference.adoc[] \ No newline at end of file +* xref:cloud:search:search.adoc[] + ** xref:cloud:search:create-search-indexes.adoc[] + *** xref:cloud:search:customize-index.adoc[] + *** xref:cloud:search:create-search-index-ui.adoc[] + **** xref:cloud:search:create-type-mapping.adoc[] + ***** xref:cloud:search:type-mapping-options.adoc[] + **** xref:cloud:search:set-type-identifier.adoc[] + **** xref:cloud:search:create-custom-analyzer.adoc[] + ***** xref:cloud:search:create-custom-character-filter.adoc[] + ***** xref:cloud:search:create-custom-tokenizer.adoc[] + ***** xref:cloud:search:create-custom-token-filter.adoc[] + ***** xref:cloud:search:default-analyzers-reference.adoc[] + ***** xref:cloud:search:default-character-filters-reference.adoc[] + ***** xref:cloud:search:default-token-filters-reference.adoc[] + ***** xref:cloud:search:default-tokenizers-reference.adoc[] + ***** xref:cloud:search:default-wordlists-reference.adoc[] + **** xref:cloud:search:create-custom-date-time-parser.adoc[] + ***** xref:cloud:search:default-date-time-parsers-reference.adoc[] + *** xref:cloud:search:import-search-index.adoc[] + *** xref:cloud:search:search-index-params.adoc[] + ** xref:cloud:search:run-searches.adoc[] + *** xref:cloud:search:simple-search-ui.adoc[] + *** xref:cloud:search:geo-search-ui.adoc[] + *** xref:cloud:search:search-request-params.adoc[] + ** xref:cloud:search:search-query-auto-complete.adoc[] + *** xref:cloud:search:search-query-auto-complete-ui.adoc[] + *** xref:cloud:search:search-query-auto-complete-code.adoc[] + ** xref:cloud:search:index-aliases.adoc[] + *** xref:cloud:search:create-search-index-alias.adoc[] diff --git a/modules/search/partials/sdks-fts-links.adoc b/modules/search/partials/sdks-fts-links.adoc new file mode 100644 index 000000000..89979d57b --- /dev/null +++ b/modules/search/partials/sdks-fts-links.adoc @@ -0,0 +1,9 @@ +xref:dotnet-sdk:howtos:full-text-searching-with-sdk.adoc[.NET] + | xref:go-sdk:howtos:full-text-searching-with-sdk.adoc[Go] + | xref:java-sdk:howtos:full-text-searching-with-sdk.adoc[Java] + | xref:kotlin-sdk:howtos:full-text-search.adoc[Kotlin] + | xref:nodejs-sdk:howtos:full-text-searching-with-sdk.adoc[Node.js] + | xref:php-sdk:howtos:full-text-searching-with-sdk.adoc[PHP] + | xref:python-sdk:howtos:full-text-searching-with-sdk.adoc[Python] + | xref:ruby-sdk:howtos:full-text-searching-with-sdk.adoc[Ruby] + | xref:scala-sdk:howtos:full-text-searching-with-sdk.adoc[Scala] \ No newline at end of file diff --git a/modules/search/partials/vector-search-field-descriptions.adoc b/modules/search/partials/vector-search-field-descriptions.adoc new file mode 100644 index 000000000..c44680162 --- /dev/null +++ b/modules/search/partials/vector-search-field-descriptions.adoc @@ -0,0 +1,58 @@ +// tag::optimized_for[] +For a `vector` child field, choose whether the Search Service should prioritize recall, latency, or memory efficiency when returning similar vectors in search results: + +* *recall*: The Search Service prioritizes returning the most accurate result. +This may increase resource usage for Search queries. ++ +The Search Service uses an `nprobe` value to calculate the number of centroids to search when using recall priority. +This value is calculated by taking the square root of the number of centroids in the index. + +* *latency*: The Search Service prioritizes returning results with lower latency. +This may reduce the accuracy of results. ++ +The Search Service uses half the `nprobe` value calculated for *recall* priority. + +* *memory-efficient*: From Couchbase Server version 7.6.5 and later, choose this option to prioritize reducing memory usage and optimize search operations for less resources. +This may reduce both accuracy (recall) and latency. ++ +The Search Service uses either an inverted file index with scalar quantization, or a directly mapped index with exact vector comparisons, depending on the number of vectors in your data. + +For more information about Vector Search indexes, see xref:vector-search:vector-search.adoc[] or xref:vector-search:create-vector-search-index-ui.adoc[]. +// end::optimized_for[] +// tag::similarity_metric[] +For a `vector` child field, choose the method to calculate the similarity between the vector embedding in a Vector Search index and the vector embedding in a Vector Search query. + +NOTE: It's recommended to choose the same similarity metric for your Search index as the one used in your embedding model. + +* *dot_product*: Calculated by adding the result of multiplying a vector's components, or the product of the magnitudes of the vectors and the cosine of the angle between them. +The dot product of 2 vectors is affected by the length and direction of each of the vectors, rather than just taking a straight-line distance. ++ +Dot product similarity is commonly used by Large Language Models (LLMs). +Use *dot_product* to get the best results with an embedding model that uses dot product similarity. + +* *l2_norm*: Also known as Euclidean distance. +Uses the straight-line distance between 2 vectors to calculate similarity. +Smaller euclidean distances mean that the values of each coordinate in the vectors are closer together. ++ +It's best to use *l2_norm* similarity when your embeddings contain information about the count or measure of specific things, and your embedding model uses the same similarity metric. + +* *cosine*: From Couchbase Server version 7.6.5 and later, the *cosine* similarity metric is calculated by adding the result of multiplying a vector's components, or the product of the magnitudes of the vectors and the cosine of the angle between them. +This metric is not affected by the size of the vectors being measured. ++ +Use *cosine* similarity to get the best results with an embedding model that uses cosine similarity. +Cosine similarity works well for semantic search, document classification, and recommendation systems. ++ +The Search Service will normalize any vectors in your documents before indexing when using cosine similarity. +It will also normalize any vectors in your queries if the field for those queries uses cosine similarity. +Use *dot_product* similarity if your vectors are already normalized. + +For more information about Vector Search indexes, see xref:vector-search:vector-search.adoc[] or xref:vector-search:create-vector-search-index-ui.adoc[]. +// end::similarity_metric[] +// tag::dimension[] +For a `vector` child field, enter the total number of elements in the vector embedding array. + +From Couchbase Server version 7.6.2 and later, Vector Search indexes can support arrays with up to 4096 elements. +Arrays can be an array of arrays. + +For more information about Vector Search indexes, see xref:vector-search:vector-search.adoc[] or xref:vector-search:create-vector-search-index-ui.adoc[]. +// end::dimension[] \ No newline at end of file diff --git a/modules/third-party/pages/integrations.adoc b/modules/third-party/pages/integrations.adoc new file mode 100644 index 000000000..b0d5a0646 --- /dev/null +++ b/modules/third-party/pages/integrations.adoc @@ -0,0 +1 @@ +include::7.6@server:third-party:integrations.adoc[] \ No newline at end of file diff --git a/modules/third-party/partials/nav.adoc b/modules/third-party/partials/nav.adoc new file mode 100644 index 000000000..d3008fca1 --- /dev/null +++ b/modules/third-party/partials/nav.adoc @@ -0,0 +1 @@ +* xref:third-party:integrations.adoc[] \ No newline at end of file diff --git a/modules/tutorials/examples/AddEnrollments.java b/modules/tutorials/examples/AddEnrollments.java new file mode 100644 index 000000000..66e66b68d --- /dev/null +++ b/modules/tutorials/examples/AddEnrollments.java @@ -0,0 +1,102 @@ +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.json.JsonArray; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryOptions; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.query.QueryScanConsistency; +import com.couchbase.client.java.ClusterOptions; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class AddEnrollments { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + // Retrieves the student bucket you set up. + Bucket bucket = cluster.bucket("student-bucket"); + + // Forces the application to wait until the bucket is ready. + bucket.waitUntilReady(Duration.ofSeconds(10)); + + // Retrieves the `art-school-scope` collection from the scope. + Scope scope = bucket.scope("art-school-scope"); + Collection student_records = scope.collection("student-record-collection"); + + // Retrieves Hilary's student record, the `graphic design` course record, and the `art history` course record. + // Each method uses a SQL++ call to retrieve a single record from each collection. + JsonObject hilary = retrieveStudent(cluster,"Hilary Smith"); + JsonObject graphic_design = retrieveCourse(cluster, "graphic design"); + JsonObject art_history = retrieveCourse(cluster, "art history"); + + // Couchbase does not have a native date type, so the common practice is to store dates as strings. + String currentDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE); + + // Stores the `enrollments` inside the student record as an array. + // `JsonArray.create()` creates an empty list structure. + JsonArray enrollments = JsonArray.create(); + + // Adds two JSON elements to the `enrollments` array: the course that the enrollment relates to, and the date that the student enrolled in the course. + // To avoid repeating data all over the cluster, you store a reference to the course instead of the entire course record itself in this field. + // This means that you do not have to search through every single record if the course details change. + enrollments.add(JsonObject.create() + .put("course-id", graphic_design.getString("id")) + .put("date-enrolled", currentDate)); + enrollments.add(JsonObject.create() + .put("course-id", art_history.getString("id")) + .put("date-enrolled", currentDate)); + + // Adds the `enrollments` array to Hilary's student record. + hilary.put("enrollments", enrollments); + + // Commits the changes to the collection. + // The `upsert` function call takes the key of the record you want to insert or update and the record itself as parameters. + // If the `upsert` call finds a document with a matching ID in the collection, it updates the document. + // If there is no matching ID, it creates a new document. + student_records.upsert(hilary.getString("id"), hilary); + + cluster.disconnect(); + + } + + private static JsonObject retrieveStudent(Cluster cluster, String name) throws CouchbaseException { + + QueryOptions studentQueryOptions = QueryOptions.queryOptions(); + studentQueryOptions.parameters(JsonObject.create().put("name", name)); + studentQueryOptions.scanConsistency(QueryScanConsistency.REQUEST_PLUS); + + final QueryResult result = cluster.query("select META().id, src.* " + + "from `student-bucket`.`art-school-scope`.`student-record-collection` src " + + "where src.`name` = $name", studentQueryOptions); + + return result.rowsAsObject().get(0); + + } + + private static JsonObject retrieveCourse(Cluster cluster, String course) throws CouchbaseException { + + QueryOptions courseQueryOptions = QueryOptions.queryOptions(); + courseQueryOptions.parameters(JsonObject.create().put("courseName", course)); + courseQueryOptions.scanConsistency(QueryScanConsistency.REQUEST_PLUS); + + final QueryResult result = cluster.query("select META().id, crc.* " + + "from `student-bucket`.`art-school-scope`.`course-record-collection` crc " + + "where crc.`course-name` = $courseName", courseQueryOptions); + + return result.rowsAsObject().get(0); + + } +} \ No newline at end of file diff --git a/modules/tutorials/examples/ArtSchoolRetriever.java b/modules/tutorials/examples/ArtSchoolRetriever.java new file mode 100644 index 000000000..af2d24657 --- /dev/null +++ b/modules/tutorials/examples/ArtSchoolRetriever.java @@ -0,0 +1,48 @@ +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryOptions; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.ClusterOptions; + +public class ArtSchoolRetrieverParameters { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + + retrieveCourses(cluster); + + cluster.disconnect(); + } + + private static void retrieveCourses(Cluster cluster) { + + try { + + // This SQL++ statement takes the parameter `$creditPopints`, + // which is then substituted by the value in the second parameter when the statement is called. + final QueryResult result = cluster.query("select crc.* " + + "from `student-bucket`.`art-school-scope`.`course-record-collection` crc " + + "where crc.`credit-points` < $creditPoints", + + // The second parameter in the function call, with a value that replaces `$creditPoints`. + QueryOptions.queryOptions() + .parameters(JsonObject.create().put("creditPoints", 200))); + + for (JsonObject row : result.rowsAsObject()) { + System.out.println("Found row: " + row); + } + + } catch (CouchbaseException ex) { + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/tutorials/examples/ArtSchoolRetrieverAll.java b/modules/tutorials/examples/ArtSchoolRetrieverAll.java new file mode 100644 index 000000000..673c5275b --- /dev/null +++ b/modules/tutorials/examples/ArtSchoolRetrieverAll.java @@ -0,0 +1,37 @@ +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.ClusterOptions; + +public class ArtSchoolRetriever { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + retrieveCourses(cluster); + + cluster.disconnect(); + } + + private static void retrieveCourses(Cluster cluster) { + + try { + final QueryResult result = cluster.query("select crc.* from `student-bucket`.`art-school-scope`.`course-record-collection` crc"); + + for (JsonObject row : result.rowsAsObject()) { + System.out.println("Found row: " + row); + } + + } catch (CouchbaseException ex) { + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/tutorials/examples/ConnectStudent.java b/modules/tutorials/examples/ConnectStudent.java new file mode 100644 index 000000000..ea2eb26fb --- /dev/null +++ b/modules/tutorials/examples/ConnectStudent.java @@ -0,0 +1,47 @@ +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.ClusterOptions; +import java.time.Duration; + +public class ConnectStudent { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + //Connecting to the cluster + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + // Use the pre-configured profile below to avoid latency issues with your connection. + .environment(env -> env.applyProfile("wan-development")) + ); + + // The `cluster.bucket` retrieves the bucket you set up for the student cluster. + Bucket bucket = cluster.bucket("student-bucket"); + + // Most of the Couchbase APIs are non-blocking. + // When you call one of them, your application carries on and continues to perform other actions while the function you called executes. + // When the function has finished executing, it sends a notification to the caller and the output of the call is processed. + // While this usually works, in this code sample the application carries on without waiting for the bucket retrieval to complete after you make the call to `cluster.bucket`. + // This means that you now have to try to retrieve the scope from a bucket object that has not been fully initialized yet. + // To fix this, you can use the `waitUntilReady` call. + // This call forces the application to wait until the bucket object is ready. + bucket.waitUntilReady(Duration.ofSeconds(10)); + + // The `bucket.scope` retrieves the `art-school-scope` from the bucket. + Scope scope = bucket.scope("art-school-scope"); + + // The `scope.collection` retrieves the student collection from the scope. + Collection student_records = scope.collection("student-record-collection"); + + // A check to make sure the collection is connected and retrieved when you run the application. + // You can see the output using maven. + System.out.println("The name of this collection is " + student_records.name()); + + // Like with all database systems, it's good practice to disconnect from the Couchbase cluster after you have finished working with it. + cluster.disconnect(); + } +} \ No newline at end of file diff --git a/modules/tutorials/examples/InsertCourses.java b/modules/tutorials/examples/InsertCourses.java new file mode 100644 index 000000000..e923fbb43 --- /dev/null +++ b/modules/tutorials/examples/InsertCourses.java @@ -0,0 +1,47 @@ +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.ClusterOptions; + +import java.time.Duration; + +public class InsertCourses { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + Bucket bucket = cluster.bucket("student-bucket"); + bucket.waitUntilReady(Duration.ofSeconds(10)); + Scope scope = bucket.scope("art-school-scope"); + + // The code here is similar to creating a student record, but it writes to a different collection. + Collection course_records = scope.collection("course-record-collection"); + + addCourse(course_records, "ART-HISTORY-000001", "art history", "fine art", 100); + addCourse(course_records, "FINE-ART-000002", "fine art", "fine art", 50); + addCourse(course_records, "GRAPHIC-DESIGN-000003", "graphic design", "media and communication", 200); + + cluster.disconnect(); + } + + private static void addCourse(Collection collection, String id, String name, + String faculty, int creditPoints) { + + JsonObject course = JsonObject.create() + .put("course-name", name) + .put("faculty", faculty) + .put("credit-points", creditPoints); + + collection.upsert(id, course); + + } +} \ No newline at end of file diff --git a/modules/tutorials/examples/InsertStudent.java b/modules/tutorials/examples/InsertStudent.java new file mode 100644 index 000000000..ebee46410 --- /dev/null +++ b/modules/tutorials/examples/InsertStudent.java @@ -0,0 +1,44 @@ +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.ClusterOptions; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class InsertStudent { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + Bucket bucket = cluster.bucket("student-bucket"); + bucket.waitUntilReady(Duration.ofSeconds(10)); + Scope scope = bucket.scope("art-school-scope"); + Collection student_records = scope.collection("student-record-collection"); + + // This `JsonObject` class creates and populates the student record. + JsonObject hilary = JsonObject.create() + .put("name", "Hilary Smith") + .put("date-of-birth", + LocalDate.of(1980, 12, 21) + .format(DateTimeFormatter.ISO_DATE)); + + // The `upsert` function inserts or updates documents in a collection. + // The first parameter is a unique ID for the document, similar to a primary key used in a relational database system. + // If the `upsert` call finds a document with a matching ID in the collection, it updates the document. + // If there is no matching ID, it creates a new document. + student_records.upsert("000001", hilary); + + cluster.disconnect(); + } +} \ No newline at end of file diff --git a/modules/tutorials/examples/art-history-course.json b/modules/tutorials/examples/art-history-course.json new file mode 100644 index 000000000..23c7683ef --- /dev/null +++ b/modules/tutorials/examples/art-history-course.json @@ -0,0 +1,6 @@ +{ + "course-name": "art history", + "faculty": "fine art", + "credit-points" : 100 +} + diff --git a/modules/tutorials/examples/fine-art-course.json b/modules/tutorials/examples/fine-art-course.json new file mode 100644 index 000000000..2119ee1f6 --- /dev/null +++ b/modules/tutorials/examples/fine-art-course.json @@ -0,0 +1,6 @@ +{ + "course-name": "fine art", + "faculty": "fine art", + "credit-points" : 50 +} + diff --git a/modules/tutorials/examples/graphic-design-course.json b/modules/tutorials/examples/graphic-design-course.json new file mode 100644 index 000000000..e0b285135 --- /dev/null +++ b/modules/tutorials/examples/graphic-design-course.json @@ -0,0 +1,6 @@ +{ + "course-name": "graphic design", + "faculty": "media and communication", + "credit-points" : 200 +} + diff --git a/modules/tutorials/examples/hilary-smith-basic.json b/modules/tutorials/examples/hilary-smith-basic.json new file mode 100644 index 000000000..2b2ac79a6 --- /dev/null +++ b/modules/tutorials/examples/hilary-smith-basic.json @@ -0,0 +1,4 @@ +{ + "name": "Hilary Smith", + "date-of-birth": "21-12-1980" +} diff --git a/modules/tutorials/examples/hilary-smith.json b/modules/tutorials/examples/hilary-smith.json new file mode 100644 index 000000000..1e3913f67 --- /dev/null +++ b/modules/tutorials/examples/hilary-smith.json @@ -0,0 +1,14 @@ +{ + "name": "Hilary Smith", + "date-of-birth": "21-12-1980", + "enrollments": [ + { + "course-id": "ART-HISTORY-00003", + "date-enrolled": "07-9-2021" + }, + { + "course-id": "GRAPHIC-DESIGN-00001", + "date-enrolled": "15-9-2021" + } + ] +} diff --git a/modules/tutorials/examples/pom.xml b/modules/tutorials/examples/pom.xml new file mode 100644 index 000000000..2e7555159 --- /dev/null +++ b/modules/tutorials/examples/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + org.example + couchbase-java + 1.0-SNAPSHOT + + + 16 + 16 + UTF-8 + ${encoding} + ${encoding} + ${encoding} + ${encoding} + + + + + + com.couchbase.client + java-client + 3.7.9 + + + org.slf4j + slf4j-api + 2.0.9 + + + org.slf4j + slf4j-simple + 2.0.9 + + + + \ No newline at end of file diff --git a/modules/tutorials/images/access-security-certificate.png b/modules/tutorials/images/access-security-certificate.png new file mode 100644 index 000000000..3b6a06839 Binary files /dev/null and b/modules/tutorials/images/access-security-certificate.png differ diff --git a/modules/tutorials/images/add-allowed-ip.png b/modules/tutorials/images/add-allowed-ip.png new file mode 100644 index 000000000..44cbdfc7d Binary files /dev/null and b/modules/tutorials/images/add-allowed-ip.png differ diff --git a/modules/tutorials/images/add-bucket.png b/modules/tutorials/images/add-bucket.png new file mode 100644 index 000000000..d82242f20 Binary files /dev/null and b/modules/tutorials/images/add-bucket.png differ diff --git a/modules/tutorials/images/add-collection-link.png b/modules/tutorials/images/add-collection-link.png new file mode 100644 index 000000000..85d30be26 Binary files /dev/null and b/modules/tutorials/images/add-collection-link.png differ diff --git a/modules/tutorials/images/add-course-record-collection.png b/modules/tutorials/images/add-course-record-collection.png new file mode 100644 index 000000000..f4dfd0a10 Binary files /dev/null and b/modules/tutorials/images/add-course-record-collection.png differ diff --git a/modules/tutorials/images/add-student-bucket.png b/modules/tutorials/images/add-student-bucket.png new file mode 100644 index 000000000..4a6c3b5a8 Binary files /dev/null and b/modules/tutorials/images/add-student-bucket.png differ diff --git a/modules/tutorials/images/add-student-record-collection.png b/modules/tutorials/images/add-student-record-collection.png new file mode 100644 index 000000000..7f2c1db60 Binary files /dev/null and b/modules/tutorials/images/add-student-record-collection.png differ diff --git a/modules/tutorials/images/attempt-first-query.png b/modules/tutorials/images/attempt-first-query.png new file mode 100644 index 000000000..86e7e6724 Binary files /dev/null and b/modules/tutorials/images/attempt-first-query.png differ diff --git a/modules/tutorials/images/bucket-list.png b/modules/tutorials/images/bucket-list.png new file mode 100644 index 000000000..4c87b5054 Binary files /dev/null and b/modules/tutorials/images/bucket-list.png differ diff --git a/modules/tutorials/images/capella-add-allowed-ip-address.png b/modules/tutorials/images/capella-add-allowed-ip-address.png new file mode 100644 index 000000000..8a6166851 Binary files /dev/null and b/modules/tutorials/images/capella-add-allowed-ip-address.png differ diff --git a/modules/tutorials/images/click-on-query.png b/modules/tutorials/images/click-on-query.png new file mode 100644 index 000000000..f041b3cc4 Binary files /dev/null and b/modules/tutorials/images/click-on-query.png differ diff --git a/modules/tutorials/images/click-scopes-and-collections.png b/modules/tutorials/images/click-scopes-and-collections.png new file mode 100644 index 000000000..e5bb5077b Binary files /dev/null and b/modules/tutorials/images/click-scopes-and-collections.png differ diff --git a/modules/tutorials/images/cluster-details.png b/modules/tutorials/images/cluster-details.png new file mode 100644 index 000000000..04e06c50e Binary files /dev/null and b/modules/tutorials/images/cluster-details.png differ diff --git a/modules/tutorials/images/completed-access-page.png b/modules/tutorials/images/completed-access-page.png new file mode 100644 index 000000000..d1e2806c2 Binary files /dev/null and b/modules/tutorials/images/completed-access-page.png differ diff --git a/modules/tutorials/images/completed-art-school-scope.png b/modules/tutorials/images/completed-art-school-scope.png new file mode 100644 index 000000000..c5227fb2b Binary files /dev/null and b/modules/tutorials/images/completed-art-school-scope.png differ diff --git a/modules/tutorials/images/configure-new-cluster.png b/modules/tutorials/images/configure-new-cluster.png new file mode 100644 index 000000000..c59025cde Binary files /dev/null and b/modules/tutorials/images/configure-new-cluster.png differ diff --git a/modules/tutorials/images/connect-to-cluster-console-output.png b/modules/tutorials/images/connect-to-cluster-console-output.png new file mode 100644 index 000000000..b52b11bcc Binary files /dev/null and b/modules/tutorials/images/connect-to-cluster-console-output.png differ diff --git a/modules/tutorials/images/couchbase-capella-download-page.png b/modules/tutorials/images/couchbase-capella-download-page.png new file mode 100644 index 000000000..cf9e8c985 Binary files /dev/null and b/modules/tutorials/images/couchbase-capella-download-page.png differ diff --git a/modules/tutorials/images/couchbase-download-page.png b/modules/tutorials/images/couchbase-download-page.png new file mode 100644 index 000000000..dffa703b8 Binary files /dev/null and b/modules/tutorials/images/couchbase-download-page.png differ diff --git a/modules/tutorials/images/couchbase-server-in-applications-folder.png b/modules/tutorials/images/couchbase-server-in-applications-folder.png new file mode 100644 index 000000000..93c7965bf Binary files /dev/null and b/modules/tutorials/images/couchbase-server-in-applications-folder.png differ diff --git a/modules/tutorials/images/create-bucket.png b/modules/tutorials/images/create-bucket.png new file mode 100644 index 000000000..2d9666e9f Binary files /dev/null and b/modules/tutorials/images/create-bucket.png differ diff --git a/modules/tutorials/images/create-cluster-credentials.png b/modules/tutorials/images/create-cluster-credentials.png new file mode 100644 index 000000000..c82d0e864 Binary files /dev/null and b/modules/tutorials/images/create-cluster-credentials.png differ diff --git a/modules/tutorials/images/create-cluster.png b/modules/tutorials/images/create-cluster.png new file mode 100644 index 000000000..dfe387ed5 Binary files /dev/null and b/modules/tutorials/images/create-cluster.png differ diff --git a/modules/tutorials/images/create-project.png b/modules/tutorials/images/create-project.png new file mode 100644 index 000000000..9b2355d14 Binary files /dev/null and b/modules/tutorials/images/create-project.png differ diff --git a/modules/tutorials/images/create-scope.png b/modules/tutorials/images/create-scope.png new file mode 100644 index 000000000..a59ac134d Binary files /dev/null and b/modules/tutorials/images/create-scope.png differ diff --git a/modules/tutorials/images/data-tools.png b/modules/tutorials/images/data-tools.png new file mode 100644 index 000000000..ac26ca3cc Binary files /dev/null and b/modules/tutorials/images/data-tools.png differ diff --git a/modules/tutorials/images/download-couchbase-community-edition.png b/modules/tutorials/images/download-couchbase-community-edition.png new file mode 100644 index 000000000..4c3c84f22 Binary files /dev/null and b/modules/tutorials/images/download-couchbase-community-edition.png differ diff --git a/modules/tutorials/images/enter-cluster-details.png b/modules/tutorials/images/enter-cluster-details.png new file mode 100644 index 000000000..12e2304d0 Binary files /dev/null and b/modules/tutorials/images/enter-cluster-details.png differ diff --git a/modules/tutorials/images/hilarys-record-in-admin-console.png b/modules/tutorials/images/hilarys-record-in-admin-console.png new file mode 100644 index 000000000..dcfac6aea Binary files /dev/null and b/modules/tutorials/images/hilarys-record-in-admin-console.png differ diff --git a/modules/tutorials/images/launch-couchbase-server-page.png b/modules/tutorials/images/launch-couchbase-server-page.png new file mode 100644 index 000000000..1c50e20b2 Binary files /dev/null and b/modules/tutorials/images/launch-couchbase-server-page.png differ diff --git a/modules/tutorials/images/multi-level-data-containment.png b/modules/tutorials/images/multi-level-data-containment.png new file mode 100644 index 000000000..d5dc08189 Binary files /dev/null and b/modules/tutorials/images/multi-level-data-containment.png differ diff --git a/modules/tutorials/images/new-cluster-access.png b/modules/tutorials/images/new-cluster-access.png new file mode 100644 index 000000000..b93fa92d1 Binary files /dev/null and b/modules/tutorials/images/new-cluster-access.png differ diff --git a/modules/tutorials/images/new-cluster.png b/modules/tutorials/images/new-cluster.png new file mode 100644 index 000000000..33ffe5cb0 Binary files /dev/null and b/modules/tutorials/images/new-cluster.png differ diff --git a/modules/tutorials/images/new-course-collection.png b/modules/tutorials/images/new-course-collection.png new file mode 100644 index 000000000..280bbe709 Binary files /dev/null and b/modules/tutorials/images/new-course-collection.png differ diff --git a/modules/tutorials/images/new-course-records.png b/modules/tutorials/images/new-course-records.png new file mode 100644 index 000000000..a31c31a44 Binary files /dev/null and b/modules/tutorials/images/new-course-records.png differ diff --git a/modules/tutorials/images/new-student-record.png b/modules/tutorials/images/new-student-record.png new file mode 100644 index 000000000..bc88a08f3 Binary files /dev/null and b/modules/tutorials/images/new-student-record.png differ diff --git a/modules/tutorials/images/prepare-to-add-scope.png b/modules/tutorials/images/prepare-to-add-scope.png new file mode 100644 index 000000000..e1198d26e Binary files /dev/null and b/modules/tutorials/images/prepare-to-add-scope.png differ diff --git a/modules/tutorials/images/query-editor-filters.png b/modules/tutorials/images/query-editor-filters.png new file mode 100644 index 000000000..676dad57d Binary files /dev/null and b/modules/tutorials/images/query-editor-filters.png differ diff --git a/modules/tutorials/images/record-retrieval-console-output.png b/modules/tutorials/images/record-retrieval-console-output.png new file mode 100644 index 000000000..900b831a8 Binary files /dev/null and b/modules/tutorials/images/record-retrieval-console-output.png differ diff --git a/modules/tutorials/images/record-retrieval-parameters-console-output.png b/modules/tutorials/images/record-retrieval-parameters-console-output.png new file mode 100644 index 000000000..fba8d7cb7 Binary files /dev/null and b/modules/tutorials/images/record-retrieval-parameters-console-output.png differ diff --git a/modules/tutorials/images/retrieve-courses-cli.png b/modules/tutorials/images/retrieve-courses-cli.png new file mode 100644 index 000000000..ac09272ed Binary files /dev/null and b/modules/tutorials/images/retrieve-courses-cli.png differ diff --git a/modules/tutorials/images/select-cbimport.png b/modules/tutorials/images/select-cbimport.png new file mode 100644 index 000000000..aa22bf9d5 Binary files /dev/null and b/modules/tutorials/images/select-cbimport.png differ diff --git a/modules/tutorials/images/select-project.png b/modules/tutorials/images/select-project.png new file mode 100644 index 000000000..2b4c69a3c Binary files /dev/null and b/modules/tutorials/images/select-project.png differ diff --git a/modules/tutorials/images/set-query-filters.png b/modules/tutorials/images/set-query-filters.png new file mode 100644 index 000000000..322a1ece7 Binary files /dev/null and b/modules/tutorials/images/set-query-filters.png differ diff --git a/modules/tutorials/images/settings-menu.png b/modules/tutorials/images/settings-menu.png new file mode 100644 index 000000000..93e458a01 Binary files /dev/null and b/modules/tutorials/images/settings-menu.png differ diff --git a/modules/tutorials/images/student-cluster-dashboard.png b/modules/tutorials/images/student-cluster-dashboard.png new file mode 100644 index 000000000..4303b1ba2 Binary files /dev/null and b/modules/tutorials/images/student-cluster-dashboard.png differ diff --git a/modules/tutorials/images/student-record-collection-console-output.png b/modules/tutorials/images/student-record-collection-console-output.png new file mode 100644 index 000000000..d8d2f270f Binary files /dev/null and b/modules/tutorials/images/student-record-collection-console-output.png differ diff --git a/modules/tutorials/images/updated-student-record.png b/modules/tutorials/images/updated-student-record.png new file mode 100644 index 000000000..d3ddf0db6 Binary files /dev/null and b/modules/tutorials/images/updated-student-record.png differ diff --git a/modules/tutorials/images/view-data.png b/modules/tutorials/images/view-data.png new file mode 100644 index 000000000..1b4f942e5 Binary files /dev/null and b/modules/tutorials/images/view-data.png differ diff --git a/modules/tutorials/pages/buckets-scopes-and-collections.adoc b/modules/tutorials/pages/buckets-scopes-and-collections.adoc new file mode 100644 index 000000000..4b81f668c --- /dev/null +++ b/modules/tutorials/pages/buckets-scopes-and-collections.adoc @@ -0,0 +1,61 @@ += Implement the Data Model +:description: Learn how to logically partition your data in Capella Operational using buckets, scopes, and collections. +:imagesdir: ../images +:page-pagination: full +:page-topic-type: tutorial + +[abstract] +{description} + +== Buckets, Scopes, and Collections + +To organize and manage your data in Couchbase, you can create buckets, scopes, and collections inside your cluster. + +A bucket is equivalent to a database in a relational database management system, while scopes and collections are used to provide separation between documents of different types. + +[plantuml,couchbase-hierarchy,svg] +.... +include::partial$diagrams/couchbase-hierarchy.puml[] +.... + +[horizontal] +bucket:: Stores and retrieves data in the server. +scope:: Stores collections. When you create a new bucket, Couchbase provides you with a default scope called `_default`. +collection:: Contains a set of documents. Couchbase provides you with a default collection called `_default`. + +For more information, see xref:cloud:clusters:data-service/about-buckets-scopes-collections.adoc[Buckets, Scopes, and Collections]. + +== Create a Bucket, Scope, and Collection + +To continue this tutorial, you must create a bucket to hold all student data, a scope to narrow down the data into only data related to an art school, and two collections to narrow it down further into art school students and art school courses. + +To create the data model from the Capella UI: + +. On the *Operational* tab, select *student-cluster*. + +. Click the *Data Tools* tab. + +. In the left pane, click btn:[+ Create]. + +. Under *Bucket*, select *New* and enter the name `student-bucket`. Keep the default 100 MiB memory quota. + +. Under *Scope*, enter the name `art-school-scope`. + +. Under *Collection*, enter the name `student-record-collection` for your first collection. + +. Click btn:[Create]. + +To create the second collection, follow the above steps but use the existing `student-bucket` and `art-school-scope`, and then create a collection with the name `course-record-collection`. + +The two collections allow you to use the relational model and the document model at the same time to achieve the best design and performance possible. + +The `student-record-collection` contains student records, and each student record contains a list of that student’s enrollments. +Unlike the standard relational model decomposition where a link table is created between students and courses, a document model stores the enrollments as part of the student records. + +The `course-record-collection`, on the other hand, uses the relational model to link the enrollment records to the course records they apply to. +This allows you to retrieve other details like the full title of the course or the number of credits students receive upon completing the course. + +== Next Steps + +After implementing the data model, you can xref:java-tutorial/install-couchbase-java-sdk.adoc[set up a Couchbase SDK and connect it to your cluster to write your first application]. + diff --git a/modules/tutorials/pages/couchbase-tutorial-student-records.adoc b/modules/tutorials/pages/couchbase-tutorial-student-records.adoc new file mode 100644 index 000000000..5610e112d --- /dev/null +++ b/modules/tutorials/pages/couchbase-tutorial-student-records.adoc @@ -0,0 +1,127 @@ += Developer Tutorial: Student Record System +:description: Learn how to create and deploy a student records database on Capella Operational and connect it to your application. +:page-topic-type: tutorial +:page-pagination: next +:page-toclevels: 2 + +[abstract] +{description} + +== Introduction +Couchbase is a schema-less JSON document database designed for high performance, scalability, and fast development. +This tutorial teaches you about the key concepts behind Couchbase and how they differ from traditional SQL database systems like MySQL and Oracle. + +IMPORTANT: This tutorial is designed for use with Capella Operational cloud services. +If you wish to use a standalone or Docker installation of Couchbase, see the xref:server:tutorials:couchbase-tutorial-student-records.adoc[Server Developer Tutorial]. + +[#database-design] +== Data Model + +The model consists of three record types: + +[horizontal] +*student*:: Information about individual students, like name and date of birth. + +*course*:: Courses the students can take. Includes course name, faculty, and the number of credit points associated with the course. +Students can take more than one course at a time. + +*enrollment*:: Information related to courses the students are taking. +In a relational database, this is usually a link record that creates a relationship between a student and a course. + +=== Relational Model + +In a relational model, the database contains a list of students and a list of courses. +Each student can enroll in multiple courses. + +A student’s enrollment record is stored in a separate table called `enrollment`, which links that record to the courses they are enrolling in. + +[plantuml,student-record-erd,svg] +.... +include::partial$diagrams/student-record-erd.puml[] +.... + +The `enrollment` table highlights a challenge with the relational model, each table is based on a fixed schema that only supports a single data object type, which means you cannot store a student in the same table as their enrollment record. + +=== Document Model + +Couchbase uses a document model that stores each record as a JSON document. +The document model: + +- Contains simple scalar types and complex types, like nested records and arrays + +- Lets you store complex types without decomposing them to a second table + +In this tutorial, the document model stores the list of enrollment records with the student records. +Each enrollment record contains a reference to the course that it relates to. + +[plantuml,student-document-database-design,svg] +.... +include::partial$diagrams/student-document-database-design.puml[] +.... + +With JSON, you can change the structure of the document without having to rebuild schemas. +For example, you can add a new field to store students' email addresses without migrating existing data to a new schema. + +In a document database, a student’s record and their course records can look similar to this: + +.Student record +[source, json] +---- +{ + "student-id": "000001", + "name": "Hilary Smith", + "date-of-birth": "21-12-1980", + "enrollments": [ + { + "course-id": "ART-HISTORY-00003", + "date-enrolled": "07-9-2021" + }, + { + "course-id": "GRAPHIC-DESIGN-00001", + "date-enrolled": "15-9-2021" + } + ] +} +---- + +.Art history course record +[source, json] +---- +{ + "course-id": "ART-HISTORY-00003", + "course-name": "art history", + "faculty": "fine art", + "credit-points" : 100 +} +---- + +.Graphic design course record +[source, json] +---- +{ + "course-id": "GRAPHIC-DESIGN-00001", + "course-name": "graphic design", + "faculty": "media and communication", + "credit-points" : 200 +} +---- + +Hilary’s enrollment is stored in the same document as her student details, which means child information is stored with its parent. +This structure lets you access and retrieve all of Hilary’s details with one search and without the need for complex table joins. + +NOTE: You should not store a student with their course record as it can lead to data duplication and make it difficult to maintain your data. +For example, you would need to access every single student record in your cluster to change the `credit-points`. + +== Next Steps + +To complete this tutorial, follow these steps: + +[horizontal] +Step 1:: xref:create-couchbase-cluster.adoc[Create and Deploy a Cluster with Capella Free Tier] +Step 2:: xref:buckets-scopes-and-collections.adoc[Implement a Data Model] +Step 3:: xref:java-tutorial/install-couchbase-java-sdk.adoc[Set Up and Connect the Couchbase Java SDK] +Step 4:: xref:java-tutorial/create-records.adoc[Create Student and Course Records] +Step 5:: xref:java-tutorial/retrieving-documents.adoc[Retrieve Records] +Step 6:: xref:java-tutorial/adding-course-enrollments.adoc[Add Course Enrollments] + +For troubleshooting information, see the xref:java-tutorial/tutorial-troubleshooting.adoc[troubleshooting page]. \ No newline at end of file diff --git a/modules/tutorials/pages/create-couchbase-cluster.adoc b/modules/tutorials/pages/create-couchbase-cluster.adoc new file mode 100644 index 000000000..6c5e9d9a0 --- /dev/null +++ b/modules/tutorials/pages/create-couchbase-cluster.adoc @@ -0,0 +1,48 @@ += Create and Deploy a Cluster with Capella Free Tier +:description: Learn how to create and deploy a cluster using Capella Operational Free Tier. +:page-topic-type: tutorial +:page-pagination: full +:page-toclevels: 2 +:navtitle: Create and Deploy a Cluster + +[abstract] +{description} + +== Prerequisites + +Before starting this tutorial, you must have a Couchbase Capella account. +If you do not have one already, xref:cloud:get-started:create-account.adoc[Create an Account]. + +== Create and Deploy a Cluster + +Every Capella account includes one free tier operational cluster. +In this tutorial, you will use the free tier cluster to create and manage student records. + +To create and deploy a cluster: + +. Sign in to https://cloud.couchbase.com/[Couchbase Capella]. + +. On the *Operational Clusters* page, click btn:[Create Cluster]. + +. Select *My First Project* as the project for your cluster. +(If you've already created a project, you can select that instead.) + +. Under *Cluster Option*, select btn:[Free]. + +. In the *Cluster Name* field, enter *student-cluster*. + +. (Optional) Provide a description of your cluster. + +. Select one of the available cloud service providers. + +. Select an available geographic region for your cluster. ++ +TIP: If you are unsure which cloud provider and region to choose, select the default options, for example *AWS* and *US East*. + +. Accept the default *CIDR Block* for your cluster. + +. Click btn:[Create Cluster] to deploy the cluster. + +== Next Steps +The cluster may take a few minutes to deploy. +When the cluster is deployed, you can xref:buckets-scopes-and-collections.adoc[implement a data model]. \ No newline at end of file diff --git a/modules/tutorials/pages/java-tutorial/adding-course-enrollments.adoc b/modules/tutorials/pages/java-tutorial/adding-course-enrollments.adoc new file mode 100644 index 000000000..982c70df8 --- /dev/null +++ b/modules/tutorials/pages/java-tutorial/adding-course-enrollments.adoc @@ -0,0 +1,45 @@ += Add Course Enrollments +:description: Add enrollment information to the student records using the Couchbase SDK. +:page-topic-type: tutorial +:page-pagination: full +:page-toclevels: 2 +:imagesdir: ../../images + +[abstract] +{description} + +== Add Enrollment Details + +To add enrollment details to a student record: + +. In your `java` directory, create a new file called `AddEnrollments.java`. +. Paste the following code block into your `AddEnrollments.java` file: ++ +[source, java] +---- +include::example$AddEnrollments.java[] +---- ++ +NOTE: Because this is a tutorial, you do not need to add an error check to make sure that your collection has returned an item. +In a live application, error checks must be made to prevent errors and keep the application running. ++ +. In the `AddEnrollments.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to insert the student record into the collection: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="AddEnrollments" -Dexec.cleanupDaemonThreads=false +---- ++ +. From the Capella UI, go to your student cluster. +. Go to the `student-record-collection` and click the document ID to see the new information you just added to Hilary's student record. ++ +image::updated-student-record.png[alt="Updated student record with course enrollment" width="600" height="800"] + +If you come across errors in your console, see the xref:java-tutorial/tutorial-troubleshooting.adoc[troubleshooting page]. + +== Next Steps + +Now that you have finished following the Student Record System tutorial, you can explore more of Capella Operational by checking out the rest of the xref:develop:intro.adoc[developer documentation]. \ No newline at end of file diff --git a/modules/tutorials/pages/java-tutorial/create-records.adoc b/modules/tutorials/pages/java-tutorial/create-records.adoc new file mode 100644 index 000000000..84de643e9 --- /dev/null +++ b/modules/tutorials/pages/java-tutorial/create-records.adoc @@ -0,0 +1,81 @@ += Create Student and Course Records +:description: Learn how to use the SDK to create student and course records. +:page-pagination: full +:page-topic-type: tutorial + +[abstract] +{description} + +== Create a Student Record + +After connecting to the cluster, you can create a student record in the form of a JSON document inserted into the `student-record-collection`. + +To create a student record: + +. In your `java` directory, create a new file called `InsertStudent.java`. +. Paste the following code block into your `InsertStudent.java` file: ++ +[source, java] +---- +include::example$InsertStudent.java[] +---- ++ +. In the `InsertStudent.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to insert the student record into the collection: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="InsertStudent" -Dexec.cleanupDaemonThreads=false +---- ++ +. From the Capella UI, go to your student cluster and check the `student-record-collection` for the new student record you just added: +.. Go to menu:Data Tools[Documents]. +.. Under *Get documents from*, select `student-bucket`, `art-school-scope`, and `student-record-collection`. +.. Click btn:[Get Documents]. ++ +image::new-student-record.png[alt="Student added to the student-record-collection in the cluster"] + + +== Create Course Records + +Creating course records is similar to creating student records. +To create course records: + +. In your `java` directory, create a new file called `InsertCourses.java`. +. Paste the following code block into your `InsertCourses.java` file: ++ +[source, java] +---- +include::example$InsertCourses.java[] +---- ++ +. In the `InsertCourses.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to insert the student record into the collection: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="InsertCourses" -Dexec.cleanupDaemonThreads=false +---- ++ +. From the Capella UI, go to your student cluster and check the `course-record-collection` for the new course records you just added. ++ +image::new-course-records.png[alt="Courses added to the course-record-collection in the cluster"] + +If you come across errors in your console, see the xref:java-tutorial/tutorial-troubleshooting.adoc[troubleshooting page]. + + + + + + + + + + + + + diff --git a/modules/tutorials/pages/java-tutorial/install-couchbase-java-sdk.adoc b/modules/tutorials/pages/java-tutorial/install-couchbase-java-sdk.adoc new file mode 100644 index 000000000..d3eb781e7 --- /dev/null +++ b/modules/tutorials/pages/java-tutorial/install-couchbase-java-sdk.adoc @@ -0,0 +1,160 @@ += Set Up and Connect the Couchbase Java SDK +:description: Learn how to configure the cluster connection and set up the Couchbase Java SDK to connect and interact with your student cluster. +:page-pagination: full +:page-topic-type: tutorial + +[abstract] +{description} + +== Prerequisites + +Before continuing this tutorial, you must first: + +* xref:create-couchbase-cluster.adoc[Create a Capella Operational Cluster] +* xref:buckets-scopes-and-collections.adoc[Implement the Data Model] +* Install the Java Software Development Kit (version 8, 11, 17, or 21). +** The recommended version is the latest Java LTS release, which is currently JDK 21. +** Ensure to install the highest available patch for the LTS version. +* Install Apache Maven (version 3+) + +[TIP] +==== +The easiest way to install and manage Java SDKs and Maven on your machine is through https://sdkman.io/install[SDKMan^]. + +After following the instructions to install SDKMan, open a terminal window and run the commands `sdk install java` and `sdk install maven` to install the latest versions of Java and Maven. +==== + +For more information about the Java SDK installation, see the xref:java-sdk:project-docs:sdk-full-installation.adoc[full installation page]. + +== Configure the Cluster Connection + +Before you can establish a connection to your cluster, you must obtain the connection string, add an allowed IP address, and configure the cluster access credentials. + +To configure the connection: + +. On the *Operational Clusters* page, select *student-cluster*. + +. Go to menu:Connect[SDKs]. + +. Make a note of the *Public Connection String*. +You will need this to connect to the cluster. + +. Add an allowed IP address. + +.. From menu:Connect[SDKs], click the *Allowed IP Addresses* link to go to the *Allowed IP Addresses* page. + +.. Click btn:[Add Allowed IP]. + +.. On the *Add Allowed IP* page, select btn:[Add Current IP Address] to automatically populate your public IP address. ++ +image::add-allowed-ip.png[alt="Add an allowed IP address"] + +.. Click btn:[Add Allowed IP]. ++ + +. Create new cluster access credentials. + +.. From menu:Connect[SDKs], click the *Cluster Access* link to go to the *Cluster Access* page. + +.. Click btn:[Create Cluster Access]. + +.. Enter an access name, for example `administrator`, and make a note of it for later. + +.. Enter a password, for example `Admin@123`, and again make a note of it for later. + +.. Under *Bucket-Level Access*, select *student-bucket* and *art-school-scope*, and set the access to *Read/Write*. ++ +image::create-cluster-credentials.png[alt="Create cluster access credentials"] + +.. Click btn:[Create Cluster Access]. + +You can now set up a Couchbase Java SDK and connect it to your cluster. + +== Set Up the Java SDK + +To set up the Java SDK: + +. Create the following directory structure on your computer: ++ +.... +📂 ~ (your home directory) + 📂 student + 📂 src + 📂 main + 📂 java +.... ++ +. In the `student` directory, create a new file called `pom.xml`. ++ +.... +📂 ~ (your home directory) + 📂 student + 📃 pom.xml ⬅ here! + 📂 src + 📂 main + 📂 java +.... ++ +. Paste the following code block into your `pom.xml` file: ++ +[source, xml] +---- +include::example$pom.xml[] +---- ++ +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and finish your SDK setup. + +Next, connect your Java SDK to your cluster. + + +[#connect-to-the-cluster] +== Connect the SDK to Your Cluster + +To connect to the cluster: + +. In your `java` directory, create a new file called `ConnectStudent.java`. ++ +.... +📂 ~ (your home directory) + 📂 student + 📃 pom.xml + 📂 src + 📂 main + 📂 java + 📃 ConnectStudent.java ⬅ here! +.... ++ +. Paste the following code block into your `ConnectStudent.java` file: ++ +[source, java] +---- +include::example$ConnectStudent.java[] +---- + +. In the `ConnectStudent.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. ++ +[IMPORTANT] +==== +You must re-run `mvn install` in your `student` directory whenever you make a change to a java file to rebuild your application. +==== ++ +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to check that the connection works: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="ConnectStudent" -Dexec.cleanupDaemonThreads=false +---- ++ +If the connection is successful, the collection name outputs in the console log. ++ +image::student-record-collection-console-output.png[alt="Console showing successful connection to server"] + +If you come across errors in your console, see the xref:java-tutorial/tutorial-troubleshooting.adoc[troubleshooting page]. + + +== Next Steps + +After setting up and connecting the Java SDK, you can xref:java-tutorial/create-records.adoc[add student and course records to your cluster]. \ No newline at end of file diff --git a/modules/tutorials/pages/java-tutorial/retrieving-documents.adoc b/modules/tutorials/pages/java-tutorial/retrieving-documents.adoc new file mode 100644 index 000000000..213d1db11 --- /dev/null +++ b/modules/tutorials/pages/java-tutorial/retrieving-documents.adoc @@ -0,0 +1,222 @@ += Retrieve Records +:description: Retrieve records or documents from your collections using {sqlpp}, Couchbase's SQL-based query language. +:page-topic-type: tutorial +:page-pagination: full +:page-toclevels: 2 +:imagesdir: ../../images + +[abstract] +{description} +You can retrieve your records using the <<#retrieve-with-query-editor,query editor>> or the <<#retrieve-with-sdk,SDK>>. + +[#retrieve-with-query-editor] +== With the Query Editor + +To retrieve the records with the Query Editor, you must first define an index. + +=== Define an Index + +Before you can retrieve your records with the query editor, you must first define an index in your bucket. +The index helps your cluster find specific data when you run a query. + +To define an index: + +. On the *Operational Clusters* page, select *student-cluster*. + +. Go to menu:Data Tools[Query]. + +. Select *student-bucket* and *art-school-scope* in the *Context* drop-down. ++ +Using these filters, you can narrow down the scope of your queries. +You do not need to add the names of your bucket and scope to your queries. ++ +image::query-editor-filters.png[alt="Filters in the Query Editor"] ++ +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +create primary index course_idx on `course-record-collection` +---- ++ +. Click btn:[Run] to create a single index called `course_idx` in your `course-record-collection`. + +=== Retrieve Your Records + +You can use the Query Editor to retrieve all course records at once, or narrow your search down to retrieve records based on specific criteria. + +==== Retrieve All Course Records + +To retrieve all of your course records using the query editor: + +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +select crc.* from `course-record-collection` crc +---- ++ +. Click btn:[Run] to retrieve all course records. ++ +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art" + }, + { + "course-name": "graphic design", + "credit-points": 200, + "faculty": "media and communication" + } +] +---- + +==== Retrieve Course Records with Less than 200 Credits + +You can expand your query to narrow your search down further. +To retrieve only courses with less than 200 `credit-points` using the query editor: + +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +select crc.* from `course-record-collection` crc where crc.`credit-points` < 200 +---- ++ +. Click btn:[Run] to retrieve all courses with less than 200 credits. ++ +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art" + } +] +---- + +=== Retrieve Record IDs + +The `id` field is not automatically returned when you retrieve all of your course information. + +The `id` is part of a document's meta structure, and to retrieve it you must adjust your {sqlpp} query and run it again: + +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +select META().id, crc.* from `course-record-collection` crc where crc.`credit-points` < 200 +---- ++ +The `META()` function call returns any property contained inside the document's metadata, including the ID. ++ +. Click btn:[Run] to retrieve course records and their IDs. ++ +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art", + "id": "ART-HISTORY-000001" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art", + "id": "FINE-ART-000002" + } +] +---- + + +[#retrieve-with-sdk] +== With the SDK + +You can also use {sqlpp} queries to retrieve your records with the SDK. +Unlike the query editor, you must include the name of the bucket and the scope to fully qualify the name of the collection in the {sqlpp} statement in your application. +For example: + +[source, sqlpp] +---- +select crc.* from `student-bucket`.`art-school-scope`.`course-record-collection` crc +---- + +=== Retrieve Your Records + +You can use the SDK to retrieve all course records at once, or narrow your search down to retrieve records based on specific criteria. + +==== Retrieve All Course Records + +To retrieve all of your course records using the Java SDK: + +. In your `java` directory, create a new file called `ArtSchoolRetriever.java`. +. Paste the following code block into your `ArtSchoolRetriever.java` file: ++ +[source, java] +---- +include::example$ArtSchoolRetrieverAll.java[] +---- ++ +. In the `ArtSchoolRetriever.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to retrieve all course records: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="ArtSchoolRetriever" -Dexec.cleanupDaemonThreads=false +---- ++ +If the retrieval is successful, the course information outputs in the console log. ++ +image::record-retrieval-console-output.png[alt="Console showing successful course retrieval using the SDK"] + +==== Retrieve Course Records with Less than 200 Credits + +You can set parameters in your code to narrow your search down further. +To retrieve only courses with less than 200 `credit-points` using the Java SDK: + +. In your `java` directory, create a new file called `ArtSchoolRetrieverParameters.java`. +. Paste the following code block into your `ArtSchoolRetrieverParameters.java` file: ++ +[source, java] +---- +include::example$ArtSchoolRetriever.java[] +---- ++ +. In the `ArtSchoolRetrieverParameters.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to retrieve all course records: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="ArtSchoolRetrieverParameters" -Dexec.cleanupDaemonThreads=false +---- ++ +If the retrieval is successful, the course information with your parameters outputs in the console log. ++ +image::record-retrieval-parameters-console-output.png[alt="Console showing successful course retrieval using parameters using the SDK"] + +If you come across errors in your console, see the xref:java-tutorial/tutorial-troubleshooting.adoc[troubleshooting page]. + + +== Next Steps + +After retrieving student and course records, you can xref:java-tutorial/adding-course-enrollments.adoc[add enrollment details to the student records using the SDK]. diff --git a/modules/tutorials/pages/java-tutorial/tutorial-troubleshooting.adoc b/modules/tutorials/pages/java-tutorial/tutorial-troubleshooting.adoc new file mode 100644 index 000000000..20b339b64 --- /dev/null +++ b/modules/tutorials/pages/java-tutorial/tutorial-troubleshooting.adoc @@ -0,0 +1,20 @@ += Troubleshooting +:description: This page addresses errors you might come across when following the Student Record System tutorial. +:page-topic-type: tutorial + +[abstract] +{description} + +== Authentication Error + +If you get an authentication error when running Maven commands in your console, confirm that the username and password in your Java file matches the username and password you used when setting up the Capella Operational cluster in your browser. + +If they do not match, you can edit the Java file to add the correct username or password and try compiling and running the Maven command again. + +== Unknown Host Exception + +If you get an `UnknownHostException` error in your console, go to your Java file and confirm that the connection string matches the one provided by the Capella Operational cluster. + +== Other Build Errors + +For any other build errors in your console, run `mvn install` and try the original command again. \ No newline at end of file diff --git a/modules/tutorials/pages/migration-tutorial-capella/sql-migration-tutorial-capella.adoc b/modules/tutorials/pages/migration-tutorial-capella/sql-migration-tutorial-capella.adoc new file mode 100644 index 000000000..3e692e39d --- /dev/null +++ b/modules/tutorials/pages/migration-tutorial-capella/sql-migration-tutorial-capella.adoc @@ -0,0 +1,236 @@ += Migrating your Data from MySQL to Capella +:description: Using MySQL as a starting point, this guide demonstrates \ +how to migrate your existing data from SQL tables to a Couchbase Capella instance. +:page-topic-type: tutorial +:page-pagination: full + +[abstract] +{description} + +== Introduction + +In this tutorial, +you will make use of `cbimport` to migrate an example test database from MySQL to Couchbase Capella. + +== Prerequisites + +Before you make a start, you will need a Capella instance to run the tutorial. +If you do not currently have an instance, +then you can create a Capella trial here =>{nbsp}https://www.couchbase.com/downloads/?family=capella[Capella Trial] + +You will also need to download and install the Server Development Tools package, +which includes the `cbimport` command line application. +You will find installation instructions for the Server Development Tools package here =>{nbsp}xref:cli:cli-intro.adoc#server-developer-tools-package[Server Development Tools package] + +If you're running through the examples, +then you will also need an existing MySQL installation with the preexisting table structure +defined in xref:student-record-sql-database-section[the following section]. + +IMPORTANT: This tutorial makes use of the MySQL JSON functions that were introduced in version `5.7.22`. +Make sure you have installed MySQL version `5.7.22` or later. + +include::server:tutorials:partial$migration-tutorial/student-database-example.adoc[] + +include::server:tutorials:partial$migration-tutorial/extract-sql-data.adoc[] + + +== Create your cluster, bucket, scope, and collections + +Working on your Capella instance, you must first create the cluster (or use an existing cluster if you have one available). +We will assume that you are creating a cluster from scratch. +You will also need to create the bucket, scope, and collections to accept the student data. + +''' +.Create the cluster. + +. Sign in to your Capella instance. +You will be presented showing the operational clusters along with the project that the cluster is attached to. + +. Press the btn:[Create Cluster] button. + +. Now create a new project with a name of your choice. + +. You will now be given the opportunity to create a new cluster which will be attached to your project. +For this exercise, we're going to create a new project for our data migration, +so click on the link to take you to the Project list. ++ +image::tutorials:select-project.png[,60%] ++ +. Press the btn:[Create Project] button on the top right of the list. +This will take you to a dialog from where you can fill in the name of your new project. ++ +image::tutorials:create-project.png[,60%] ++ +. Enter a name for your project, then press btn:[Create Project] +. Capella will create a new project for you and then switch back to the Project List. +You can navigate to your project by clicking on the link in the top left of the screen. ++ +TIP: You can also navigate to your project by finding it in the Project List and clicking on its link. ++ +. On your project page, click on btn:[Create Cluster] ++ +image::tutorials:create-cluster.png[,60%] ++ +. Select your cluster options (you may use the _free_ option if it's available), then press btn:[Create Cluster]. + +After a short interval, your new cluster will be provisioned. ++ +image::tutorials:new-cluster.png[,60%] + +''' + +.Create a bucket, scope, and collection for each cluster + +Now that we have created the cluster, we need to add a location to hold the migrated data. + +. Click on the name of your cluster from the Operational Clusters page. +This will take you to the Cluster details page. ++ +image::tutorials:cluster-details.png[,60%] +. From here, click on the btn:[Import Data] button. +This will take you to the menu:Data Tools[] page. ++ +image::tutorials:data-tools.png[,60%] ++ +. Select btn:[Load with cbimport] in the central panel. +. Click on the btn:[+Create] button in the panel on the left. +You will now be presented with a dialog for creating a bucket. ++ +image::tutorials:create-bucket.png[,60%] ++ +. Fill in `student-bucket` for the name of your bucket. +. Fill in `art-school-scope` for the scope. +. Fill in `student-record-collection` for the collection inside the scope. +. Click on btn:[Create] +. We still need to create another collection to hold the course records, so press btn:[+Create] again. ++ +image::tutorials:add-course-record-collection.png[,60%] ++ +. Make sure that you are adding to an _existing_ bucket (`student-bucket`) and scope (`art-school-scope`). +Now add another collection: `course-record-collectiomn`. + +''' + +[#allow-ip-address] +.Allow your IP Address + +Before running `cbimport` from your local machine, +you need to add your machine's IP address to Capella's allowed list. +Navigate to your cluster's security settings and add your IP to the "Allowed IP addresses" list. + +. Click on menu:Settings[] from the top level menu. ++ +image::tutorials:settings-menu.png[,60%] ++ +. From the left-hand menu, select menu:Networking[Allowed IP Addresses] +. Click the btn:[+ Add Allowed IP] button. +. From the menu:Allowed IP[] screen, click on btn:[Add Current IP address], then click btn:[Add Allowed IP] ++ +image::tutorials:capella-add-allowed-ip-address.png[,60%] + +''' + +[#set-up-cluster-access-credentials] +.Set up cluster access credentials + +When running `cbimport`, authentication credentials are required, which you can set up +from menu:Security[] in Capella. + +. From the menu:Settings[] page, select menu:Security[Cluster Access] +. Click on the btn:[+ Create Cluster Access] button. ++ +image::tutorials:new-cluster-access.png[] ++ +. Type `import` into the `Cluster Access Name` field with. +. Add a password. +. In the `Bucket Level Access` section, select `student-bucket` for the bucket, +`All Scopes` for the scope, and `Read/Write` for Access: ++ +image::tutorials:completed-access-page.png[,60%] ++ +. Click on btn:[Create Cluster Access] when you're done. + +''' +[#download-security-certificate] +.Download your security certificate +To run `cbimport`, you will need to supply the security certificate for your Capella instance, +which you can download from the menu:settings[] page. + +. From the top menu, click on menu:Settings[] ++ +image::tutorials:settings-menu.png[,60%] ++ +. Now, from the menu:Cluster Settings[] screen, click on menu:Security[Security Certificates] in the left-hand menu. ++ +image::tutorials:access-security-certificate.png[,60%] ++ +. On the menu:Security Certificate[] page, click on btn:[Download] to download your security certificate for the local machine. ++ +TIP: Make a note of the location where you stored it. ++ +. Return to the menu:Data Tools[] page by clicking on the link in the top level menu. + +== Generate and execute your `cbimport` command. + +The data tooling page can generate a correctly formatted `cbimport` command line based on your import data. +All you need to do is copy the command to your command line environment +and fill in details such as your access password and the location of your security certificate. + +''' + +.Create the `cbimport` command. + +. From the menu:Data Tools[] page, click on btn:[Load with cbimport] in the central panel. ++ +image::tutorials:select-cbimport.png[,60%] ++ +. Locate the `courses` JSON file you created in the xref:extract-sql-data[] section, +then drag it into the `Upload Sample File` section in the central panel. ++ +TIP: Alternatively, you can click on `Choose a file` and load the file directly from the file chooser. ++ +. In the `Choose your target` section, select the `student-bucket`, `art-school-scope`, and the `course-record-collection`. +. For `Document keys`, select `Field`, then pick the `course-id` field from the dropdown list. + +''' +The `Copy generated command` field will contain the `cbimport` statement you will need to execute the import: + +[source, shell] +.`cbimport` command +---- +cbimport json --format lines --cluster couchbases://cb.wrrmzje92urkkyn.customsubdomain.nonprod-project-avengers.com --username <> --password '<>' --bucket "student-bucket" --scope-collection-exp "art-school-scope.course-record-collection" --dataset 'file://<>/courses.json' --generate-key '%`course-id`%' --cacert <> +---- + +Before you can run the command, you will need to fill in the placeholders with information from your cluster: + +* Username and password. These are the details you created in the xref:set-up-cluster-access-credentials[] section. +* the full path to your input source (`courses.json`) +* the full path to your downloaded security certificate, +which you downloaded in the xref:download-security-certificate[] section. + +Your command should resemble the following: + +[source,shell] +---- +./cbimport json --format lines \ +--cluster couchbases://cb.wrrmzje92urkkyn.customsubdomain.nonprod-project-avengers.com \ +--username import --password 'Password' \ +--bucket "student-bucket" --scope-collection-exp "art-school-scope.course-record-collection" \ +--dataset 'file:///Users/test/courses.json' \ +--generate-key '%`course-id`%' \ +--cacert /Users/test/Cluster-1-root-certificate.txt +---- + +You can repeat the same process to generate and run a `cbimport` command for the `students.json` file. +Remember to: + +. Change the `--scope-collection-exp` parameter to point to `art-school-scope.student-record-collection`. +. Set the `--dataset` parameter to point to the `students.json` file. +. Set the `--generate-key` parameter to `pass:v['%`course-id`%']` + + +== Check your data + +You can use Capella's menu:Data Tools[] to check your data has been imported correctly. + +image::tutorials:view-data.png[] + diff --git a/modules/tutorials/pages/python-tutorial/.install-couchbase-python-sdk.adoc b/modules/tutorials/pages/python-tutorial/.install-couchbase-python-sdk.adoc new file mode 100644 index 000000000..e65cf880b --- /dev/null +++ b/modules/tutorials/pages/python-tutorial/.install-couchbase-python-sdk.adoc @@ -0,0 +1,23 @@ += Installing the Couchbase Python SDK +:description: pass:q[In this tutorial, you're going to create a skeleton application for interacting with the student database you created in xref:install-couchbase-server.adoc[]] +ifndef::flag-devex-python-tutorial[] +:page-embargo: EMBARGOED +endif::flag-devex-python-tutorial[] +:page-pagination: full + +include::partial$tutorial-globals.adoc[] + +[abstract] +{description} + +== Prerequisites + +Before you begin, you will need Python Version {minimum-python-version} installed on your machine. +If you don't have a Python installed (or you have version 2 or less) then you will have to install Python3 + +For further information on installing Python, take a look at xref:python-sdk:hello-world:start-using-sdk.adoc[Install and Start Using the Python SDK with Couchbase Server]. + +NOTE: xref:python-sdk:hello-world:start-using-sdk.adoc[Install and Start Using the Python SDK with Couchbase Server] will also show you how to install the Couchbase SDK. + +== Install the Couchbase Python SDK +If you have not already done so, then you can install the Couchbase Python SDK by running the following command inside a terminal window: diff --git a/modules/tutorials/partials/diagrams/couchbase-hierarchy.puml b/modules/tutorials/partials/diagrams/couchbase-hierarchy.puml new file mode 100644 index 000000000..8698dfd20 --- /dev/null +++ b/modules/tutorials/partials/diagrams/couchbase-hierarchy.puml @@ -0,0 +1,42 @@ +@startuml + +node "Couchbase cluster" as cluster + +database "Bucket" as bucket + +rectangle "Scope" as scope + +folder "Collection" as collection + + + +file "Document 1" as document1 +file "Document 2" as document2 +file "Document 3" as document3 + +cluster --> bucket +bucket --> scope +scope --> collection +collection --> document1 +collection --> document2 +collection --> document3 + +note right of bucket + + Maximum of 30 per cluster + +end note + +note left of scope + + Maximum of 1000 per cluster + +end note + +note right of collection + + Maximum of 1000 per cluster + +end note + +@enduml diff --git a/modules/tutorials/partials/diagrams/student-document-database-design.puml b/modules/tutorials/partials/diagrams/student-document-database-design.puml new file mode 100644 index 000000000..882546c34 --- /dev/null +++ b/modules/tutorials/partials/diagrams/student-document-database-design.puml @@ -0,0 +1,36 @@ +@startuml +left to right direction + + + database "student-bucket" { + + node "art-school-scope" { + + folder "student-record-collection" { + + file "Hilary's record" as hilary { + file "enrollment details" as hilary_enrollment + } + + file "Ashley's record" as ashley { + file "enrollment details" as ashley_enrollment + + } + + } + + folder "course-record-collection" { + + file "ART-HISTORY-000001" as art_history + file "GRAPHIC-DESIGN-000003" as graphic_design + file "FINE_ART-000002" as fine_art + } + + hilary_enrollment --> art_history + hilary_enrollment --> graphic_design + ashley_enrollment -->fine_art + } + + } + +@enduml diff --git a/modules/tutorials/partials/diagrams/student-record-erd.puml b/modules/tutorials/partials/diagrams/student-record-erd.puml new file mode 100644 index 000000000..137a44e9f --- /dev/null +++ b/modules/tutorials/partials/diagrams/student-record-erd.puml @@ -0,0 +1,31 @@ +@startuml +skinparam linetype ortho +entity student { + * student-id +-- + name + date-of-birth +} + + +entity course { + * course-id + course-name + faculty + credit-points +} + +entity enrollment { + + * student-id + * course-id +-- + * date-enrolled + date-completed +} + + +student --o{ enrollment +course --o{ enrollment + +@enduml diff --git a/modules/tutorials/partials/insert-documents-using-query-workbench-section.adoc b/modules/tutorials/partials/insert-documents-using-query-workbench-section.adoc new file mode 100644 index 000000000..e69de29bb diff --git a/modules/tutorials/partials/nav.adoc b/modules/tutorials/partials/nav.adoc new file mode 100644 index 000000000..392165e8b --- /dev/null +++ b/modules/tutorials/partials/nav.adoc @@ -0,0 +1,11 @@ +* xref:tutorials:couchbase-tutorial-student-records.adoc[Developer Tutorial] + ** xref:tutorials:create-couchbase-cluster.adoc[] + ** xref:tutorials:buckets-scopes-and-collections.adoc[] + ** xref:tutorials:java-tutorial/install-couchbase-java-sdk.adoc[] + ** xref:tutorials:java-tutorial/create-records.adoc[] + ** xref:tutorials:java-tutorial/retrieving-documents.adoc[] + ** xref:tutorials:java-tutorial/adding-course-enrollments.adoc[] + ** xref:tutorials:java-tutorial/tutorial-troubleshooting.adoc[] +* Migration Tutorial + ** xref:tutorials:migration-tutorial-capella/sql-migration-tutorial-capella.adoc[] + \ No newline at end of file diff --git a/modules/tutorials/partials/retrieve-documents-using-query-bench-section.adoc b/modules/tutorials/partials/retrieve-documents-using-query-bench-section.adoc new file mode 100644 index 000000000..09dd9619f --- /dev/null +++ b/modules/tutorials/partials/retrieve-documents-using-query-bench-section.adoc @@ -0,0 +1,119 @@ += Using the Query Editor + +Return to the admin console, and click on the menu:Query[] item on the left-hand menu. + +This will take you to the query workbench. The workbench has a few filter fields that'll make it much easier to narrow down our search criteria. + +image::set-query-filters.png[alt="The console query editor"] + +Use the two dropdown items to select the `student-bucket` and the `art-school-scope`. This narrows the scope of the queries, meaning you don't have to add the name of the bucket and the scope to your queries. + +Okay, let's try a simple query to retrieve all the course in our collection. + +Type the following query into the query editor field: + +[source, sqlpp] +---- +select crc.* from `course-record-collection` crc +---- + +NOTE: {sqlpp} is very similar to standard SQL. Once you have mastered the document database model, you'll find it very easy to adapt. + +image::attempt-first-query.png[alt="Query to retrieve the course collection"] + +What happens when you hit btn:[Execute]? + +You should get a result: + +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art" + }, + { + "course-name": "graphic design", + "credit-points": 200, + "faculty": "media and communication" + } +] +---- + +== Creating an index + +To improve the speed of your queries, you can use the query editor to add an index to the bucket. +To do this, enter the following command into the editor and press btn:[Enter]. + +[source, sqlpp] +---- +create primary index course_idx on `course-record-collection` +---- + +This will create a single index (`course_idx`) on your `course-record-collection`. + +Okay, now try something else: returning the courses with `credit-points` of less than 200: + +[source, sqlpp] +---- +select crc.* from `course-record-collection` crc where crc.`credit-points` < 200 +---- + +which will bring back: + +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art" + } +] +---- + +=== But what about the primary id field? + +Good question. You may want to get hold of `id` field, which as you can see, isn't returned with the document, even if we're asking for all the fields in the call. The primary key exists as part of the document's "meta" structure, which can be interrogated along with the rest of the document. Make the following small adjustment to the `{sqlpp}` statement and run the query again: + +[source, sqlpp] +---- +select META().id, crc.* from `course-record-collection` crc where crc.`credit-points` < 200 +---- + +The `META()` function call will return any property contained in the document's metadata, including its id: + +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art", + "id": "ART-HISTORY-000001" // <1> + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art", + "id": "FINE-ART-000002" // <1> + } +] +---- + +<1> id fields added to the returned document. + +ifdef::flag-devex-query[] +You can find a full rundown of the {sqlpp} language here: xref:n1ql:n1ql-language-reference/index.adoc[]. +endif::flag-devex-query[] diff --git a/modules/tutorials/partials/student-database-diagrams.adoc b/modules/tutorials/partials/student-database-diagrams.adoc new file mode 100644 index 000000000..cb21329d8 --- /dev/null +++ b/modules/tutorials/partials/student-database-diagrams.adoc @@ -0,0 +1,14 @@ +[plantuml,student-record-erd,svg] +.... +include::diagrams/student-record-erd.puml[] +.... + +[plantuml,student-document-database-design,svg] +.... +include::diagrams/student-document-database-design.puml[] +.... + +[plantuml,couchbase-hierarchy,svg] +.... +include::diagrams/couchbase-hierarchy.puml[] +.... diff --git a/modules/tutorials/partials/student-mvn-directory-structure.adoc b/modules/tutorials/partials/student-mvn-directory-structure.adoc new file mode 100644 index 000000000..37d0dc1d6 --- /dev/null +++ b/modules/tutorials/partials/student-mvn-directory-structure.adoc @@ -0,0 +1,44 @@ +// # tag::basic[] +.... +📂 ~ (your home directory) + 📂 student + 📂 src + 📂 main + 📂 java +.... +// # end::basic[] + + +// # tag::point-to-java-dir[] +.... +📂 ~ (your home directory) + 📂 student + 📂 src + 📂 main + 📂 java ⬅ here! +.... +// # end::point-to-java-dir[] + + +// # tag::location-of-pom.xml[] +.... +📂 ~ (your home directory) + 📂 student + 📃 pom.xml ⬅ here! + 📂 src + 📂 main + 📂 java +.... +// # end::location-of-pom.xml[] + +// # tag::location-of-student.java[] +.... +📂 ~ (your home directory) + 📂 student + 📃 pom.xml + 📂 src + 📂 main + 📂 java + 📃 ConnectStudent.java ⬅ here! +.... +// # end::location-of-student.java[] diff --git a/modules/tutorials/select-cbimport.png b/modules/tutorials/select-cbimport.png new file mode 100644 index 000000000..aa22bf9d5 Binary files /dev/null and b/modules/tutorials/select-cbimport.png differ diff --git a/modules/vector-search/examples/run-hybrid-search-payload-ui.jsonc b/modules/vector-search/examples/run-hybrid-search-payload-ui.jsonc new file mode 100644 index 000000000..3a69e5372 --- /dev/null +++ b/modules/vector-search/examples/run-hybrid-search-payload-ui.jsonc @@ -0,0 +1,17 @@ +{ + "fields": ["*"], + "query": { + "min": 70, + "max": 80, + "inclusive_min": false, + "inclusive_max": true, + "field": "brightness" + }, + "knn": [ + { + "k": 1, + "field": "colorvect_l2", + "vector": [ 0, 0, 128 ] + } + ] +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-pre-filtered-vector-search-ui.json b/modules/vector-search/examples/run-pre-filtered-vector-search-ui.json new file mode 100644 index 000000000..d3bbcfe16 --- /dev/null +++ b/modules/vector-search/examples/run-pre-filtered-vector-search-ui.json @@ -0,0 +1,21 @@ +{ + "fields": ["*"], + "query": { + "min": 70, + "max": 80, + "inclusive_min": false, + "inclusive_max": true, + "field": "brightness" + }, + "knn": [ + { + "k": 10, + "field": "colorvect_l2", + "vector": [ 176, 0, 176 ], + "filter": { + "field": "color", + "match": "navy" + } + } + ] +} diff --git a/modules/vector-search/examples/run-vector-search-generate-embed.go b/modules/vector-search/examples/run-vector-search-generate-embed.go new file mode 100644 index 000000000..4894d3ead --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-generate-embed.go @@ -0,0 +1,138 @@ +package main + +import ( + "fmt" + "log" + "time" + "os" + "github.com/couchbase/gocb/v2" + // Include this import if you want to run a Search query using regular Search index features. + // "github.com/couchbase/gocb/v2/search" + "github.com/couchbase/gocb/v2/vector" + "bytes" + "encoding/json" + "io/ioutil" + "net/http" +) + +type OpenAIResponse struct { + Data []struct { + Embedding []float32 `json:"embedding"` + } `json:"data"` +} + +// generateVector makes a request to OpenAI's API to get an embedding vector for the given input text. +// Make sure to replace OPENAI_API_KEY with your own API Key. +func generateVector(inputText string) ([]float32, error) { + openaiAPIKey := os.Getenv("OPENAI_API_KEY") + if openaiAPIKey == "" { + return nil, fmt.Errorf("OPENAI_API_KEY environment variable is not set") + } + + requestBody, err := json.Marshal(map[string]interface{}{ + "input": inputText, + "model": "text-embedding-ada-002", + }) + if err != nil { + return nil, fmt.Errorf("error marshaling request body: %w", err) + } + + request, err := http.NewRequest("POST", "https://api.openai.com/v1/embeddings", bytes.NewBuffer(requestBody)) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + + request.Header.Set("Content-Type", "application/json") + request.Header.Set("Authorization", "Bearer "+openaiAPIKey) + + client := &http.Client{} + response, err := client.Do(request) + if err != nil { + return nil, fmt.Errorf("error making request: %w", err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + bodyBytes, _ := ioutil.ReadAll(response.Body) + return nil, fmt.Errorf("API request failed with status %d: %s", response.StatusCode, string(bodyBytes)) + } + + var openAIResponse OpenAIResponse + if err := json.NewDecoder(response.Body).Decode(&openAIResponse); err != nil { + return nil, fmt.Errorf("error decoding response: %w", err) + } + + if len(openAIResponse.Data) == 0 || len(openAIResponse.Data[0].Embedding) == 0 { + return nil, fmt.Errorf("no embedding vector found in response") + } + + return openAIResponse.Data[0].Embedding, nil +} +// Make sure to change CB_USERNAME, CB_PASSWORD, and CB_HOSTNAME to the username, password, and hostname for your database. +func main() { + connstr := "couchbases://" + os.Getenv("CB_HOSTNAME") + username := os.Getenv("CB_USERNAME") + password := os.Getenv("CB_PASSWORD") + // Make sure to change the bucket, and scope names to match where you stored the sample data in your database. + bucket_name := "vector-sample" + scope_name := "color" + + cluster, err := gocb.Connect(connstr, gocb.ClusterOptions{ + Authenticator: gocb.PasswordAuthenticator{ + Username: username, + Password: password, + }, + SecurityConfig: gocb.SecurityConfig{ + TLSSkipVerify: true, // Disables TLS certificate verification + }, + }) + if err != nil { + log.Fatal(err) + } + + bucket := cluster.Bucket(bucket_name) + err = bucket.WaitUntilReady(5*time.Second, nil) + if err != nil { + log.Fatal(err) + } + + scope := bucket.Scope(scope_name) + // Change the question to whatever you want to ask. + question := "What color hides everything like the night?" + vect, err := generateVector(question) + if err != nil { + log.Fatalf("Error generating vector: %v", err) + } + + request := gocb.SearchRequest{ + VectorSearch: vector.NewSearch( + []*vector.Query{ + vector.NewQuery("embedding_vector_dot", vect), + }, + nil, + ), + } + // Change the limit value to return more results. Change the fields array to return different fields from your Search index. + opts := &gocb.SearchOptions{Limit: 2, Fields: []string{"color","description"}} + + // Make sure to change the index name to match your Search index. + matchResult, err := scope.Search("color-index", request, opts) + if err != nil { + log.Fatal(err) + } + + for matchResult.Next() { + row := matchResult.Row() + docID := row.ID + var fields interface{} + err := row.Fields(&fields) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Document ID: %s, Fields: %v\n", docID, fields) + } + + if err = matchResult.Err(); err != nil { + log.Fatal(err) + } +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-generate-embed.java b/modules/vector-search/examples/run-vector-search-generate-embed.java new file mode 100644 index 000000000..183d14514 --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-generate-embed.java @@ -0,0 +1,116 @@ +import com.couchbase.client.core.error.*; +import com.couchbase.client.java.*; +import com.couchbase.client.java.kv.*; +import com.couchbase.client.java.json.*; +import com.couchbase.client.java.search.*; +import com.couchbase.client.java.search.queries.*; +import com.couchbase.client.java.search.result.*; +import com.couchbase.client.java.search.vector.*; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.List; + +import java.time.Duration; +import java.util.Map; + +public class RunVectorSearchGenerateEmbed { + // Make sure to replace OPENAI_API_KEY with your own API Key. + private static final String OPENAI_API_KEY = System.getenv("OPENAI_API_KEY"); + private static final String OPENAI_URL = "https://api.openai.com/v1/embeddings"; + + public static float[] generateVector(String inputText) { + HttpClient client = HttpClient.newHttpClient(); + + JsonObject jsonBody = JsonObject.create() + .put("input", inputText) + .put("model", "text-embedding-ada-002"); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(OPENAI_URL)) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer " + OPENAI_API_KEY) + .POST(HttpRequest.BodyPublishers.ofString(jsonBody.toString())) + .build(); + + try { + HttpResponse response = client.send(request, BodyHandlers.ofString()); + + JsonObject jsonResponse = JsonObject.fromJson(response.body()); + List embeddingList = jsonResponse.getArray("data") + .getObject(0) + .getArray("embedding") + .toList(); + + return toFloatArray(embeddingList); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return null; // or handle more gracefully + } + } + + private static float[] toFloatArray(List list) { + float[] result = new float[list.size()]; + for (int i = 0; i < list.size(); i++) { + result[i] = ((Number) list.get(i)).floatValue(); + } + return result; + } + + public static void main(String[] args) { +// Make sure to change CB_USERNAME, CB_PASSWORD, and CB_HOSTNAME to the username, password, and hostname for your database. + String endpoint = "couchbases://" + System.getenv("CB_HOSTNAME") + "?tls_verify=none"; + String username = System.getenv("CB_USERNAME"); + String password = System.getenv("CB_PASSWORD"); +// Make sure to change the bucket, scope, collection, and index names to match where you stored the sample data in your database. + String bucketName = "vector-sample"; + String scopeName = "color"; + String collectionName = "rgb"; + String searchIndexName = "color-index"; + + try { + // Connect to database/cluster with specified credentials + Cluster cluster = Cluster.connect( + endpoint, + ClusterOptions.clusterOptions(username, password).environment(env -> { + // Use the pre-configured profile below to avoid latency issues with your connection. + env.applyProfile("wan-development"); + }) + ); + + Bucket bucket = cluster.bucket(bucketName); + bucket.waitUntilReady(Duration.ofSeconds(10)); + Scope scope = bucket.scope(scopeName); + Collection collection = scope.collection(collectionName); + // Change the question to whatever you want to ask. + String question = "What color hides everything like the night?"; + float[] vector = generateVector(question); + + SearchRequest request = SearchRequest + .create(VectorSearch.create( + VectorQuery.create("embedding_vector_dot", vector).numCandidates(2))); + // Make sure to change the index name to match your Search index. + SearchResult result = scope.search("color-index", request, + // Change the limit value to return more results. Change the value or values in fields to return different fields from your Search index. + SearchOptions.searchOptions().limit(3).fields("color","description")); + + for (SearchRow row : result.rows()) { + System.out.println("Found row: " + row); + System.out.println(" Fields: " + row.fieldsAs(Map.class)); + } + + } catch (UnambiguousTimeoutException ex) { + boolean authFailure = ex.toString().contains("Authentication Failure"); + if (authFailure) { + System.out.println("Authentication Failure Detected"); + } else { + System.out.println("Error:"); + System.out.println(ex.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-generate-embed.py b/modules/vector-search/examples/run-vector-search-generate-embed.py new file mode 100644 index 000000000..4a80dc62c --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-generate-embed.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +import os +import sys +from couchbase.cluster import Cluster +from couchbase.options import ClusterOptions +from couchbase.auth import PasswordAuthenticator +from couchbase.exceptions import CouchbaseException +import couchbase.search as search +from couchbase.options import SearchOptions +from couchbase.vector_search import VectorQuery, VectorSearch +from openai import OpenAI + +# Change the question to whatever you want to ask +question = "What color hides everything like the night?" + +# Make sure to replace OPENAI_API_KEY with your own API Key +openai_api_key = os.getenv("OPENAI_API_KEY") +client = OpenAI() + +# Make sure to change CB_USERNAME, CB_PASSWORD, and CB_HOSTNAME to the username, password, and hostname for your database. +pa = PasswordAuthenticator(os.getenv("CB_USERNAME"), os.getenv("CB_PASSWORD")) +cluster = Cluster("couchbases://" + os.getenv("CB_HOSTNAME") + "/?ssl=no_verify", ClusterOptions(pa)) +# Make sure to change the bucket, scope, and index names to match where you stored the sample data in your database. +bucket = cluster.bucket("vector-sample") +scope = bucket.scope("color") +search_index = "color-index" +try: + vector = client.embeddings.create(input = [question], model="text-embedding-ada-002").data[0].embedding + search_req = search.SearchRequest.create(search.MatchNoneQuery()).with_vector_search( + VectorSearch.from_vector_query(VectorQuery('embedding_vector_dot', vector, num_candidates=2))) + # Change the limit value to return more results. Change the fields array to return different fields from your Search index. + result = scope.search(search_index, search_req, SearchOptions(limit=13,fields=["color", "description"])) + for row in result.rows(): + print("Found row: {}".format(row)) + print("Reported total rows: {}".format( + result.metadata().metrics().total_rows())) +except CouchbaseException as ex: + import traceback + traceback.print_exc() \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-long-payload-ui.jsonc b/modules/vector-search/examples/run-vector-search-long-payload-ui.jsonc new file mode 100644 index 000000000..d7c2d9a93 --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-long-payload-ui.jsonc @@ -0,0 +1,1553 @@ +// tag::partial[] +{ + "fields": ["*"], + "knn": [ + { + "field": "embedding_vector_dot", + "k": 3, + "vector": [ + 0.024032991379499435, + -0.009131478145718575, + 0.013961897231638432, + -0.024734394624829292, + -0.020605377852916718, + 0.006739427801221609, + -0.012539239600300789, + 0.0063192471861839294, + 0.000004374724539957242, + -0.030252983793616295, + -0.010944539681077003, + -0.0012845275923609734, + 0.0059850881807506084, + -0.006388725712895393, + -0.016304319724440575, + 0.03046472743153572, + 0.029988301917910576, + -0.013121536932885647, + 0.01815708354115486, + -0.011096730828285217, + -0.0423753522336483, + -0.0023523480631411076, + -0.00022332418302539736, + -0.0024681459181010723, + -0.02911485731601715, +// end::partial[] + -0.01983780413866043, + 0.025263754650950432, + -0.02444324642419815, + 0.001819678582251072, + -0.01301566418260336, + 0.021015632897615433, + -0.006084343418478966, + -0.027394432574510574, + -0.02503877691924572, + -0.0030520972795784473, + 0.0020049549639225006, + -0.006124045234173536, + 0.01994367688894272, + 0.0008941238629631698, + 0.005230748560279608, + 0.004694770555943251, + 0.0074507566168904305, + 0.007325033191591501, + -0.01629108563065529, + -0.000024400234906352125, + 0.002851932542398572, + 0.007550011854618788, + -0.005564908031374216, + -0.002355656586587429, + -0.0024466405156999826, + 0.025422563776373863, + 0.042851775884628296, + -0.016185212880373, + -0.02908838912844658, + -0.002714629517868161, + 0.006143896374851465, + -0.011930474080145359, + 0.027685582637786865, + -0.008377138525247574, + 0.0012580595212057233, + 0.0012944531626999378, + -0.02789732627570629, + -0.02935306914150715, + -0.000022397038264898583, + -0.015377937816083431, + -0.00907854177057743, + -0.022788992151618004, + 0.027526773512363434, + 0.00034181008231826127, + 0.018964359536767006, + 0.010951156727969646, + 0.01720423437654972, + 0.007000799756497145, + 0.018104147166013718, + 0.02603132836520672, + 0.0017601253930479288, + -0.012863473035395145, + 0.0016286122845485806, + 0.012876707129180431, + -0.000903222244232893, + 0.004208420403301716, + -0.0030984163749963045, + -0.021280312910676003, + 0.010673241689801216, + 0.015801426023244858, + -0.004473100882023573, + -0.015788191929459572, + -0.0008205096237361431, + -0.0007990042795427144, + -0.005336620844900608, + -0.01697925478219986, + 0.013975131325423717, + 0.014120705425739288, + 0.016820447519421577, + -0.013187706470489502, + 0.01565585285425186, + 0.021968482062220573, + 0.020353931933641434, + 0.006928012706339359, + 0.006497906520962715, + 0.02543579787015915, + 0.005733641795814037, + -0.028611963614821434, + -0.005538439843803644, + -0.01806444488465786, + -0.000736969814170152, + -0.002863512374460697, + -0.0022233163472265005, + 0.012605409137904644, + 0.0006480537122115493, + -0.04531330242753029, + 0.02698417939245701, + 0.02319924719631672, + -0.07024621218442917, + 0.011996644549071789, + -0.018024742603302002, + 0.018448231741786003, + -0.020909760147333145, + 0.012962727807462215, + -0.028876643627882004, + -0.006253077182918787, + 0.02842668816447258, + 0.04396343231201172, + -0.011407730169594288, + 0.01753508485853672, + -0.008132308721542358, + -0.003953665029257536, + -0.023013969883322716, + -0.033482085913419724, + -0.0037981653586030006, + 0.017455680295825005, + 0.0035533360205590725, + -0.012499537318944931, + 0.012605409137904644, + 0.007960266433656216, + 0.005336620844900608, + -0.01569555513560772, + 0.020181888714432716, + 0.01462359819561243, + -0.003325049066916108, + 0.022087588906288147, + 0.025713711977005005, + -0.00886679720133543, + 0.005432567559182644, + -0.017415978014469147, + 0.01001815777271986, + 0.006309321615844965, + 0.006451587658375502, + 0.0034673146437853575, + -0.00044209917541593313, + 0.028082601726055145, + -0.008165393956005573, + 0.04393696412444115, + 0.014200109988451004, + -0.010223285295069218, + 0.020380400121212006, + -0.006474747322499752, + 0.012651728466153145, + -0.02260371670126915, + 0.007060352712869644, + -0.008562414906919003, + -0.006196832749992609, + 0.011639325879514217, + 0.0041852607391774654, + 0.015589682385325432, + 0.017455680295825005, + 0.009535115212202072, + 0.00853594671934843, + 0.0044929515570402145, + 0.015457342378795147, + -0.029564812779426575, + 0.004856887273490429, + -0.01381632313132286, + 0.016926318407058716, + 0.01664840430021286, + 0.03329680860042572, + 0.03544072061777115, + 0.0004168718005530536, + -0.001428447663784027, + -0.0028668208979070187, + -0.008350670337677002, + 0.015100023709237576, + 0.02648128569126129, + -0.015430874191224575, + 0.004459866788238287, + 0.011136433109641075, + 0.042957648634910583, + -0.016211681067943573, + 0.0009454057435505092, + -0.0006463994504883885, + 0.002449949039146304, + 0.019229039549827576, + -0.011374644935131073, + -0.025978391990065575, + -0.651749312877655, + -0.010838666930794716, + -0.020115718245506287, + -0.013445770367980003, + 0.022418439388275146, + 0.022775758057832718, + 0.02382124587893486, + 0.010554135777056217, + -0.022749289870262146, + -0.02069801650941372, + -0.0025756722316145897, + 0.010620305314660072, + 0.004258047789335251, + -0.004555813502520323, + -0.025687243789434433, + -0.017164532095193863, + 0.006683182902634144, + -0.004039686173200607, + 0.006755969952791929, + -0.001948710298165679, + 0.014491258189082146, + 0.02924719639122486, + -0.03925212100148201, + -0.013101685792207718, + 0.013856025412678719, + 0.014822108671069145, + -0.0013556604972109199, + -0.002663347637280822, + -0.01099085807800293, + 0.0030239748302847147, + -0.017098361626267433, + 0.02619013749063015, + -0.011288624256849289, + 0.007768373005092144, + 0.052724357694387436, + -0.005472269840538502, + -0.027950262650847435, + 0.02911485731601715, + -0.004092622548341751, + 0.047298409044742584, + 0.007298565004020929, + 0.00609426898881793, + 0.008403606712818146, + -0.02016865462064743, + -0.0014532614732161164, + 0.020486271008849144, + 0.004552504979074001, + -0.028109069913625717, + 0.025343159213662148, + -0.012843621894717216, + 0.026269542053341866, + -0.005389557220041752, + 0.005214205943048, + 0.012625260278582573, + 0.010527667589485645, + -0.009455711580812931, + 0.026110732927918434, + -0.016661638393998146, + -0.017230700701475143, + 0.021769972518086433, + 0.01143419835716486, + 0.01828942447900772, + -0.005220822989940643, + -0.01529853418469429, + -0.01018358301371336, + 0.044333986937999725, + -0.029723621904850006, + -0.009257201105356216, + -0.009667456150054932, + -0.01136802788823843, + -0.016674872487783432, + 0.018315890803933144, + -0.013617812655866146, + -0.006435045041143894, + 0.00004895555684925057, + -0.0009371344349347055, + 0.009925519116222858, + 0.019930442795157433, + -0.00006508452497655526, + 0.01435891818255186, + -0.00855579786002636, + -0.019559890031814575, + -0.008330819196999073, + 0.0074309054762125015, + 0.022524312138557434, + -0.0004739435389637947, + -0.029750090092420578, + -0.03112642839550972, + 0.01635725609958172, + 0.015735257416963577, + 0.03221162036061287, + 0.01529853418469429, + -0.0031728576868772507, + -0.018170317634940147, + -0.018368827179074287, + 0.019599592313170433, + -0.01393542904406786, + -0.013842791318893433, + -0.016463128849864006, + -0.01426627952605486, + -0.006759278476238251, + -0.03874922916293144, + -0.022286098450422287, + 0.009422626346349716, + 0.009462328627705574, + 0.007966883480548859, + 0.0047907172702252865, + 0.02681213617324829, + 0.008403606712818146, + -0.017191000282764435, + 0.015470576472580433, + -0.003626123070716858, + -0.015576448291540146, + 0.010110795497894287, + 0.01095777377486229, + -0.03300565853714943, + 0.015576448291540146, + 0.004181952215731144, + -0.005713790655136108, + -0.031470514833927155, + 0.021822908893227577, + -0.013882492668926716, + -0.0054855034686625, + -0.0008444962440989912, + 0.004516111221164465, + 0.013339897617697716, + -0.008999137207865715, + -0.007232395000755787, + 0.016939552500844002, + -0.0021885770838707685, + 0.02667979523539543, + 0.024866733700037003, + 0.010640156455338001, + 0.00876754242926836, + -0.008648435585200787, + -0.011626091785728931, + -0.021756738424301147, + -0.032158683985471725, + -0.0016699685947969556, + -0.016171978786587715, + -0.003808090928941965, + -0.006808906327933073, + -0.011096730828285217, + 0.0059156096540391445, + -0.011242304928600788, + -0.04578972980380058, + -0.027235625311732292, + -0.001535146962851286, + -0.030120642855763435, + -0.005214205943048, + -0.02289486490190029, + -0.013121536932885647, + -0.024337373673915863, + 0.040019694715738297, + 0.011447432450950146, + 0.0007717091357335448, + -0.02802966721355915, + -0.009779945015907288, + 0.0006215856410562992, + 0.011817985214293003, + 0.006484672427177429, + 0.02089652605354786, + -0.025157883763313293, + 0.011725346557796001, + -0.00974024273455143, + -0.035652466118335724, + -0.011996644549071789, + 0.037425823509693146, + -0.02694447711110115, + -0.027447368949651718, + 0.008747691288590431, + 0.009965221397578716, + 0.007530160713940859, + 0.01865997724235058, + 0.011844453401863575, + 0.015523511916399002, + -0.015589682385325432, + -0.02718268893659115, + -0.007788224145770073, + -0.024403544142842293, + 0.01283038780093193, + 0.013829557225108147, + -0.03345561772584915, + -0.009018988348543644, + 0.060982391238212585, + 0.000804794195573777, + 0.009680690243840218, + 0.023609502241015434, + 0.006474747322499752, + -0.004674919415265322, + 0.006090960465371609, + 0.000341189734172076, + -0.0031877460423856974, + 0.007569862529635429, + -0.005925535224378109, + 0.0037981653586030006, + 0.006110811606049538, + 0.00162695802282542, + 0.011566538363695145, + 0.013009047135710716, + 0.015192661434412003, + -0.02388741634786129, + 0.01214221864938736, + 0.0037518462631851435, + 0.02109503746032715, + -0.0071596079505980015, + 0.01191062293946743, + -0.012367197312414646, + 0.009191030636429787, + 0.036711186170578, + 0.015139725059270859, + -0.01605287380516529, + -0.004539270885288715, + -0.028903111815452576, + 0.023940352723002434, + 0.00964098796248436, + 0.001996683655306697, + 0.027950262650847435, + -0.00865505263209343, + -0.006564076989889145, + 0.030226515606045723, + 0.024138862267136574, + 0.020062783733010292, + 0.006431736517697573, + 0.007556628901511431, + -0.004145558457821608, + 0.021611163392663002, + -0.01704542525112629, + -0.01731010526418686, + -0.011870920658111572, + -0.010712943971157074, + 0.021637631580233574, + -0.012724515981972218, + 0.0007100881775841117, + -0.021412653848528862, + -0.003788239788264036, + 0.021637631580233574, + -0.025343159213662148, + 0.016952786594629288, + -0.005138110369443893, + -0.009462328627705574, + 0.011321709491312504, + -0.00962113682180643, + -0.003376330714672804, + 0.04375169053673744, + 0.0035764954518526793, + 0.016608702018857002, + 0.008674903772771358, + -0.02470792643725872, + -0.01157977245748043, + -0.0007167052244767547, + 0.010090944357216358, + 0.0015897373668849468, + -0.012856855988502502, + 0.015483810566365719, + 0.006226608995348215, + 0.03046472743153572, + 0.0045194197446107864, + 0.00031430809758603573, + 0.01122245378792286, + 0.02826787903904915, + -0.01930844411253929, + -0.013095068745315075, + -0.02158469520509243, + 0.012737750075757504, + -0.00013575215416494757, + -0.0029578048270195723, + -0.0021836142987012863, + 0.0074441395699977875, + -0.017429212108254433, + -0.009700540453195572, + -0.002613720018416643, + 0.005379631649702787, + -0.02964421734213829, + 0.013095068745315075, + 0.003794856835156679, + -0.002913139993324876, + 0.0006728675216436386, + 0.02487996779382229, + 0.0037055271677672863, + -0.008066138252615929, + -0.03287332132458687, + 0.023371288552880287, + 0.03676412254571915, + -0.01757478527724743, + -0.02871783636510372, + -0.03162932023406029, + 0.009270435199141502, + -0.006329172756522894, + 0.035652466118335724, + 0.009965221397578716, + 0.014173641800880432, + -0.007338267285376787, + -0.008165393956005573, + -0.010878369212150574, + -0.01648959517478943, + 0.020539207383990288, + 0.006051258184015751, + 0.010501199401915073, + 0.016185212880373, + 0.020446570590138435, + -0.020737718790769577, + -0.01711159572005272, + 0.011361410841345787, + 0.02362273633480072, + 0.020406868308782578, + 0.00044127204455435276, + 0.006491289474070072, + 0.007397820241749287, + -0.009316754527390003, + -0.0038610270712524652, + -0.0034640063531696796, + -0.004406930413097143, + -0.0034640063531696796, + 0.031735192984342575, + 0.004211728926748037, + -0.010600454173982143, + -0.007463990710675716, + 0.04571032524108887, + -0.014941215515136719, + 0.010924688540399075, + -0.023305119946599007, + -0.02665332704782486, + -0.003354825545102358, + 0.07643973082304001, + -0.006398651283234358, + -0.007695585954934359, + 0.012439983896911144, + -0.009091775864362717, + -0.009085158817470074, + -0.03761110082268715, + -0.00696771452203393, + 0.018183551728725433, + 0.022947801277041435, + 0.019268741831183434, + -0.00004192498090560548, + -0.01859380677342415, + 0.011950325220823288, + 0.006415193900465965, + -0.0043870797380805016, + 0.013425919227302074, + -0.024668224155902863, + -0.02056567557156086, + -0.018540870398283005, + -0.0038279418367892504, + 0.0013523519737645984, + -0.0003715866187121719, + 0.01462359819561243, + -0.0010727832559496164, + 0.019851038232445717, + 0.029961833730340004, + 0.012532622553408146, + 0.015616150572896004, + -0.01605287380516529, + 0.002143912250176072, + 0.01839529536664486, + -0.01921580545604229, + 0.012512771412730217, + -0.007027267478406429, + -0.006315938662737608, + -0.01957312412559986, + 0.015510277822613716, + 0.009746859781444073, + -0.01924227364361286, + 0.028320815414190292, + 0.00909839291125536, + 0.0005922226700931787, + -0.0003314709756523371, + 0.015126491896808147, + -0.009224115870893002, + 0.004671610891819, + 0.0048535787500441074, + -0.0031000706367194653, + -0.00907854177057743, + 0.0035401019267737865, + -0.02415209636092186, + -0.013167855329811573, + 0.013432536274194717, + 0.006841991096735001, + 0.021597929298877716, + 0.0002160868316423148, + -0.0038180164992809296, + 0.0008908153395168483, + -0.018315890803933144, + -0.019652528688311577, + -0.008893265388906002, + -0.0016608702717348933, + -0.018540870398283005, + -0.014438321813941002, + -0.04007263109087944, + 0.005839514080435038, + -0.03292625769972801, + -0.01275098416954279, + 0.013240642845630646, + 0.010243135504424572, + -0.01592053286731243, + -0.034699615091085434, + 0.013617812655866146, + 0.031496983021497726, + 0.014332449994981289, + 0.0037386121693998575, + -0.01435891818255186, + 0.007258863188326359, + -0.010971006937325, + 0.013194323517382145, + -0.014901513233780861, + 0.0035698784049600363, + -0.016436660662293434, + 0.003374676452949643, + -0.01809091307222843, + 0.004377154167741537, + -0.000208849465707317, + -0.019599592313170433, + 0.013908960856497288, + 0.011215836741030216, + -0.020089251920580864, + 0.034302596002817154, + -0.01934814639389515, + -0.031708724796772, + -0.009773327969014645, + -0.009554966352880001, + 0.003394527593627572, + -0.01961282640695572, + -0.005234057083725929, + 0.005826279986649752, + -0.02036716602742672, + -0.012439983896911144, + -0.022722821682691574, + 0.008218330331146717, + -0.010196817107498646, + -0.010699709877371788, + 0.010646773502230644, + -0.02898251637816429, + 0.012029729783535004, + 0.007199310231953859, + -0.039728544652462006, + -0.007199310231953859, + 0.008330819196999073, + 0.0016079341294243932, + -0.004658377263695002, + -0.024694692343473434, + 0.031099960207939148, + -0.005783269181847572, + -0.025475500151515007, + 0.014305981807410717, + -0.03345561772584915, + 0.005670779850333929, + 0.01757478527724743, + -0.030358854681253433, + 0.018607040867209435, + 0.004691462032496929, + -0.005588067229837179, + -0.007550011854618788, + 0.009965221397578716, + -0.011235687881708145, + 0.013220791704952717, + -0.03250276669859886, + -0.01655576564371586, + -0.030808812007308006, + -0.006772512570023537, + -0.012598792091012001, + -0.012975961901247501, + -0.016436660662293434, + -0.009224115870893002, + 0.010679858736693859, + 0.02233903482556343, + -0.009958604350686073, + -0.020009847357869148, + -0.02417856454849243, + -0.03385263681411743, + 0.011990027502179146, + 0.01905699633061886, + -0.01799827441573143, + 0.02368890680372715, + -0.006666640285402536, + -0.015457342378795147, + -0.011440815404057503, + 0.00642511947080493, + 0.004370537120848894, + -0.0013837828300893307, + 0.0035764954518526793, + 0.0028883260674774647, + 0.0052903019823133945, + -0.010732795111835003, + 0.003748537739738822, + 0.030517663806676865, + 0.033905573189258575, + 0.004787408746778965, + -0.004565739072859287, + 0.010110795497894287, + -0.004837036598473787, + -0.0074375225231051445, + -0.0013746843906119466, + 0.018104147166013718, + 0.005558290984481573, + 0.017693892121315002, + 0.0018974284175783396, + 0.022166993468999863, + 0.007841160520911217, + 0.032026343047618866, + 0.0003720001841429621, + -0.006302704568952322, + -0.02720915712416172, + -0.05537116527557373, + -0.006709651090204716, + 0.0031447354704141617, + 0.0028122304938733578, + 0.014530960470438004, + -0.009713774546980858, + -0.0021968481596559286, + 0.01786593534052372, + -0.013399451039731503, + -0.021200908347964287, + 0.0005690631223842502, + 0.021611163392663002, + 0.013035515323281288, + 0.04565738886594772, + -0.03599654883146286, + 0.014583896845579147, + -0.007953649386763573, + -0.018104147166013718, + -0.0044995686039328575, + -0.013492089696228504, + 0.002600486157462001, + -0.00028287729946896434, + 0.022034652531147003, + -0.004033069126307964, + 0.014067769050598145, + 0.014319215901196003, + 0.007583096623420715, + 0.006626938469707966, + 0.00865505263209343, + 0.010024774819612503, + -0.014279513619840145, + -0.022299332544207573, + -0.030279450118541718, + -0.025118181481957436, + -0.01421334408223629, + 0.014094237238168716, + 0.003205942688509822, + -0.024919670075178146, + 0.022921333089470863, + -0.02089652605354786, + 0.0013085142709314823, + 0.02260371670126915, + -0.011334942653775215, + 0.022881630808115005, + -0.0006025617476552725, + 0.0510568730533123, + -0.003523559309542179, + -0.016410192474722862, + 0.008251414634287357, + 0.004138941410928965, + -0.010507816448807716, + -0.0068552251905202866, + 0.022656651213765144, + 0.004645143169909716, + -0.004919749218970537, + -0.006673257332295179, + 0.02566077560186386, + 0.007364735472947359, + -0.02789732627570629, + -0.008800626732409, + 0.009846115484833717, + 0.01329357922077179, + 0.00919764768332243, + -0.02105533517897129, + 0.008085989393293858, + -0.011090113781392574, + 0.02362273633480072, + 0.004691462032496929, + -0.0005132320802658796, + 0.01157977245748043, + -0.018276190385222435, + 0.0013589690206572413, + 0.03192047029733658, + -0.008416840806603432, + 0.01852763630449772, + -0.012876707129180431, + -0.029935365542769432, + -0.015669086948037148, + -0.012711281888186932, + -0.021703802049160004, + -0.004674919415265322, + -0.0062630027532577515, + 0.03642003983259201, + 0.0009627753752283752, + 0.0018461465369910002, + 0.015205895528197289, + -0.0014615326654165983, + -0.0010810544481500983, + -0.013505322858691216, + 0.006703034043312073, + 0.027659114450216293, + -0.007583096623420715, + 0.0034805487375706434, + 0.0031397726852446795, + -0.008039670996367931, + 0.019586358219385147, + -0.021796440705657005, + 0.0024830340407788754, + -0.006514449138194323, + -0.01181136816740036, + -0.013882492668926716, + 0.019229039549827576, + -0.0074507566168904305, + -0.014345684088766575, + 0.017124829813838005, + -0.0029710386879742146, + -0.0005082692950963974, + -0.03914624825119972, + -0.007100054994225502, + 0.009832881391048431, + -0.011685644276440144, + -0.026071030646562576, + -0.024363841861486435, + -0.0008626930648460984, + 0.0023937043733894825, + -0.008674903772771358, + -0.0371876135468483, + -0.01569555513560772, + 0.010243135504424572, + -0.031470514833927155, + 0.02059214375913143, + 0.00004500085560721345, + 0.017958572134375572, + -0.021333249285817146, + 0.00919764768332243, + -0.0006501215393655002, + -0.01562938466668129, + 0.025157883763313293, + 0.010951156727969646, + -0.03491136059165001, + -0.015417640097439289, + 0.005095100030303001, + 0.0034739316906780005, + 0.02319924719631672, + -0.014226577244699001, + -0.022299332544207573, + 0.023609502241015434, + 0.01862027496099472, + 0.0018411838682368398, + -0.008516095578670502, + 0.003245644737035036, + -0.013035515323281288, + 0.0021273696329444647, + 0.010534284636378288, + -0.034540805965662, + 0.004119090735912323, + -0.016463128849864006, + -0.025806350633502007, + -0.009733625687658787, + -0.030358854681253433, + -0.0068684592843055725, + -0.010309305973351002, + 0.03327034041285515, + 0.007258863188326359, + -0.013114919885993004, + 0.009052073583006859, + -0.005879215896129608, + -0.011301858350634575, + 0.019520187750458717, + -0.0032820384949445724, + 0.00023759211762808263, + -0.010679858736693859, + 0.016727808862924576, + 0.03504370152950287, + 0.014279513619840145, + -0.022775758057832718, + -0.024602053686976433, + -0.024324139580130577, + -0.005022312980145216, + -0.020115718245506287, + 0.014583896845579147, + 0.0023242258466780186, + 0.027553241699934006, + 0.0035996551159769297, + -0.04375169053673744, + -0.014994150958955288, + 0.014610364101827145, + -0.022908098995685577, + -0.028585495427250862, + 0.006683182902634144, + 0.014385386370122433, + 0.008562414906919003, + 0.023715374991297722, + 0.0015450725331902504, + 0.01921580545604229, + -0.00023200901341624558, + 0.0017535084625706077, + -0.015245597809553146, + 0.02718268893659115, + -0.03006770648062229, + -0.04261356219649315, + 0.0012952802935615182, + -0.007913947105407715, + -0.02016865462064743, + -0.009607902728021145, + 0.01625138334929943, + -0.003731995355337858, + 0.0004545060801319778, + 0.01957312412559986, + -0.01468976866453886, + 0.0017402743687853217, + -0.0008258859161287546, + 0.02882370725274086, + 0.03583774343132973, + 0.015854362398386, + 0.0024334064219146967, + -0.028479622676968575, + 0.0027940336149185896, + -0.004939599893987179, + 0.008899882435798645, + -0.03366736322641373, + 0.017601253464818, + 0.007861011661589146, + 0.002329188631847501, + -0.015933766961097717, + -0.007093437947332859, + 0.007126522716134787, + -0.00860211718827486, + 0.009124861098825932, + 0.022616950795054436, + 0.010110795497894287, + -0.024800565093755722, + 0.020049549639225006, + 0.012102516368031502, + 0.0019503645598888397, + -0.011407730169594288, + -0.023119842633605003, + 0.010382093489170074, + -0.020539207383990288, + 0.013419302180409431, + -0.026163669303059578, + 0.025885755196213722, + -0.03557306155562401, + 0.0066037788055837154, + -0.01181136816740036, + -0.019109932705760002, + -0.011116581968963146, + -0.011851070448756218, + -0.01447802409529686, + 0.02300073765218258, + 0.01115628331899643, + -0.013346514664590359, + 0.014279513619840145, + -0.03395850956439972, + -0.014279513619840145, + -0.011282007209956646, + 0.004674919415265322, + -0.011070262640714645, + -0.02286839671432972, + 0.0014052881160750985, + -0.009105009958148003, + -0.013002430088818073, + -0.01393542904406786, + 0.0022994119208306074, + -0.020406868308782578, + 0.022709587588906288, + 0.010600454173982143, + 0.21873198449611664, + 0.018911423161625862, + -0.014504492282867432, + 0.042719434946775436, + 0.01435891818255186, + 0.004827111028134823, + 0.029300132766366005, + 0.0004511975566856563, + -0.008747691288590431, + 0.02977655827999115, + 0.011798134073615074, + 0.016264617443084717, + -0.02497260645031929, + 0.012433366850018501, + 0.0011579772690311074, + -0.013657514937222004, + -0.01332666352391243, + -0.009495413862168789, + -0.02922072820365429, + -0.023172779008746147, + 0.007986734621226788, + -0.01625138334929943, + -0.006537608802318573, + -0.022855162620544434, + 0.029591280966997147, + 0.019851038232445717, + 0.012870090082287788, + -0.003679059213027358, + -0.0006195178139023483, + 0.011182751506567001, + -0.024813799187541008, + 0.001568232080899179, + 0.01258555892854929, + 0.005058706272393465, + -0.019652528688311577, + -0.0051314933225512505, + -0.013253876939415932, + -0.013313430361449718, + 0.010481348261237144, + 0.021280312910676003, + 0.0018841944402083755, + 0.019652528688311577, + -0.0052903019823133945, + 0.007788224145770073, + 0.019864272326231003, + 0.01819678582251072, + -0.021703802049160004, + -0.007291948422789574, + 0.011738580651581287, + 0.005330003798007965, + -0.027394432574510574, + 0.010838666930794716, + 0.012168686836957932, + 0.03329680860042572, + -0.002430097898468375, + 0.01207604818046093, + 0.019454017281532288, + -0.0028750922065228224, + -0.006239843089133501, + -0.013697216287255287, + -0.02293456718325615, + 0.026891540735960007, + 0.0013457350432872772, + 0.01846146583557129, + 0.012248090468347073, + 0.030517663806676865, + -0.02718268893659115, + -0.03631416708230972, + -0.0065409173257648945, + 0.007325033191591501, + 0.02674596570432186, + 0.0019652529153972864, + -0.013240642845630646, + -0.0008949509938247502, + 0.003151352284476161, + -0.01535146962851286, + 0.018607040867209435, + 0.01589406467974186, + 0.01523236371576786, + 0.01737627573311329, + -0.016820447519421577, + 0.003904037643224001, + -0.006755969952791929, + 0.023384522646665573, + 0.006097577512264252, + -0.02484026551246643, + -0.013591344468295574, + -0.00997183844447136, + 0.0009396158275194466, + 0.012552473694086075, + 0.013313430361449718, + 0.008846946060657501, + -0.009091775864362717, + 0.007192693185061216, + 0.015669086948037148, + 0.0004962759558111429, + 0.01596023514866829, + 0.007205926813185215, + -0.022855162620544434, + -0.013386216945946217, + -0.015311767347157001, + 0.01110334787517786, + 0.029882431030273438, + 0.04017850384116173, + -0.007172842044383287, + 0.010620305314660072, + -0.011857687495648861, + -0.009581434540450573, + 0.005191046744585037, + -0.023781543597579002, + -0.0014648411888629198, + -0.01421334408223629, + -0.005157961510121822, + -0.019731933251023293, + -0.015338235534727573, + 0.00039578007999807596, + -0.0022530928254127502, + -0.026494519785046577, + 0.009071924723684788, + -0.0018180243205279112, + -0.0018494550604373217, + -0.026415115222334862, + 0.0005885005812160671, + 0.01717776618897915, + 0.013492089696228504, + -0.013710450381040573, + -0.030385322868824005, + 0.016661638393998146, + 0.0007212543860077858, + -0.04346054047346115, + 0.013518556952476501, + -0.009515264071524143, + 0.02457558549940586, + -0.014345684088766575, + -0.012135601602494717, + 0.004807259887456894, + 0.01770712621510029, + -0.013220791704952717, + 0.006557459942996502, + -0.0002204292395617813, + -0.013518556952476501, + -0.010653390549123287, + 0.02280222624540329, + 0.004962759558111429, + 0.009105009958148003, + -0.03329680860042572, + -0.02464175596833229, + -0.012466452084481716, + -0.02306690625846386, + -0.02098916471004486, + -0.0017634339164942503, + -0.026401881128549576, + -0.008939584717154503, + -0.018712911754846573, + 0.0027592943515628576, + 0.0013399451272562146, + -0.010084327310323715, + 0.009151328355073929, + 0.01245321799069643, + 0.03030591830611229, + -0.018607040867209435, + 0.019586358219385147, + 0.05807090550661087, + -0.01572202332317829, + -0.005684013944119215, + -0.0054027908481657505, + -0.16833680868148804, + 0.041501905769109726, + 0.014663300476968288, + -0.022841928526759148, + -0.005048780702054501, + 0.003020666306838393, + 0.006190215703099966, + -0.009799796156585217, + -0.017654189839959145, + 0.013657514937222004, + 0.010746029205620289, + 0.0064714387990534306, + -0.03597008064389229, + -0.008522712625563145, + -0.010732795111835003, + 0.003278729971498251, + -0.007470607757568359, + 0.00561122689396143, + 0.014160407707095146, + 0.001894119894132018, + 0.020671548321843147, + -0.02648128569126129, + 0.021280312910676003, + -0.0006691454327665269, + -0.004516111221164465, + -0.013280345126986504, + -0.015219129621982574, + 0.015616150572896004, + -0.0029164485167711973, + -0.009508647955954075, + -0.013134771026670933, + -0.002851932542398572, + 0.00010080605716211721, + 0.015047087334096432, + -0.005561599507927895, + 0.008972669020295143, + -0.016621936112642288, + -0.018911423161625862, + -0.012526005506515503, + 0.006315938662737608, + 0.014861810952425003, + 0.010646773502230644, + 0.02266988530755043, + 0.004324217792600393, + -0.010342391207814217, + 0.04168717935681343, + 0.04343407228589058, + 0.007113288622349501, + 0.02685183845460415, + -0.02056567557156086, + -0.005144727416336536, + -0.002031422918662429, + 0.015192661434412003, + -0.0022712897043675184, + 0.012069431133568287, + 0.027712050825357437, + 0.01072617806494236, + 0.028320815414190292, + 0.004899898078292608, + -0.014769172295928001, + -0.001813061535358429, + -0.011255539022386074, + 0.001765088178217411, + 0.006392034236341715, + 0.02023482508957386, + 0.006679874379187822, + 0.00832420215010643, + 0.004582281224429607, + 0.011731963604688644, + 0.009025605395436287, + 0.014345684088766575, + -0.022788992151618004, + 0.012856855988502502, + -0.013009047135710716, + 0.01885848678648472, + 0.0074441395699977875, + -0.011235687881708145, + 0.008688137866556644, + -0.014345684088766575, + -0.0009172834106720984, + -0.020512739196419716, + 0.013359748758375645, + -0.019983379170298576, + -0.0054855034686625, + -0.003305197926238179, + 0.02398005500435829, + -0.01535146962851286, + 0.003318432020023465, + -0.005419333465397358, + -0.005538439843803644, + 0.017561553046107292, + -0.035811275243759155, + -0.017389509826898575, + -0.02517111785709858, + -0.006676565855741501, + -0.005942077375948429, + -0.0035268678329885006, + 0.02076418697834015, + 0.0006819659029133618, + -0.014875045046210289, + 0.02030099555850029, + -0.011672411113977432, + 0.0013465621741488576, + -0.0037187612615525723, + 0.04385755956172943, + 0.01970546506345272, + -0.013803089037537575, + 0.017323339357972145, + 0.04213713854551315, + 0.034196723252534866, + -0.02379477769136429, + 0.03422319144010544, + 0.0415283739566803, + 0.001535146962851286, + -0.030835280194878578, + 0.011996644549071789, + 0.009535115212202072, + -0.02253754623234272, + 0.00016025577497202903, + 0.004344068933278322, + 0.03663178160786629, + -0.003272112924605608, + -0.0056310780346393585, + -0.0014276205329224467, + -0.007748521864414215, + -0.021902313455939293, + -0.10444293171167374, + 0.007861011661589146, + -0.008707989007234573, + -0.011182751506567001, + 0.010944539681077003, + 0.02102886699140072, + -0.006203449796885252, + -0.014980916865170002, + 0.0035731869284063578, + 0.026891540735960007, + -0.005561599507927895, + -0.017217466607689857, + -0.0008002449758350849, + -0.019136400893330574, + 0.01914963498711586, + -0.0007324205944314599, + 0.012883324176073074, + -0.011420964263379574, + -0.015444108285009861, + 0.012711281888186932, + -0.002456566086038947, + -0.01629108563065529, + -0.011526836082339287, + -0.017217466607689857, + 0.01611904427409172, + -0.014173641800880432, + -0.026137201115489006, + 0.0017435828922316432, + 0.007113288622349501, + 0.002567400922998786, + 0.012360580265522003, + -0.016304319724440575, + -0.004135632887482643, + -0.01937461458146572, + -0.02678566798567772, + -0.016966020688414574, + -0.016436660662293434, + -0.004092622548341751, + 0.005581450182944536, + -0.018051210790872574, + 0.0062431516125798225, + 0.020486271008849144, + 0.020446570590138435, + -0.03332327678799629, + 0.021637631580233574, + -0.0037783144507557154, + 0.004651760216802359, + 0.003000815398991108, + 0.01914963498711586, + 0.0014648411888629198, + -0.014438321813941002, + -0.01115628331899643, + -0.01678074523806572, + -0.01711159572005272, + 0.015470576472580433, + -0.0034110702108591795, + 0.01569555513560772, + 0.005300227086991072, + -0.02043333649635315, + 0.010673241689801216, + -0.002790725091472268, + 0.017349807545542717, + -0.020049549639225006, + 0.02415209636092186, + -0.0071529909037053585, + -0.008145542815327644, + 0.005862673278898001, + -0.005184429697692394, + 0.02619013749063015, + -0.04547211155295372, + -0.041634246706962585, + -0.0004208006721455604, + -0.018434997648000717, + 0.02490643598139286, + -0.041369564831256866, + 0.006405268330127001, + -0.029670685529708862, + -0.002838698448613286, + 0.016039639711380005, + -0.006815523374825716, + -0.009839498437941074, + -0.010540901683270931, + 0.0033498627599328756, + -0.027817921712994576, + 0.008992520160973072, + 0.04348700866103172, + -0.005750184413045645, + 0.001955327345058322, + 0.0018560721073299646, + -0.021902313455939293, + -0.0027890708297491074, + 0.01872614584863186, + 0.021306781098246574, + -0.01426627952605486, + 0.002851932542398572, + 0.025224052369594574, + 0.013366365805268288, + -0.004913132172077894, + 0.02247137576341629, + 0.013432536274194717, + -0.01462359819561243, + 0.0004383771156426519, + -0.052194997668266296, + 0.032688044011592865, + -0.004585589747875929, + -0.015060321427881718, + 0.01572202332317829, + -0.00045037042582407594, + 0.02174350433051586, + -0.02898251637816429, + -0.01832912489771843, + -0.008138925768435001, + -0.0026666561607271433, + 0.017429212108254433, + -0.009224115870893002, + -0.013068600557744503, + -0.03504370152950287, + 0.016185212880373, + 0.014464790001511574, + -0.011070262640714645, + 0.014464790001511574, + 0.010878369212150574, + -0.020618611946702003, + 0.0003798578982241452, + 0.022219929844141006, + -0.007861011661589146, + -0.028109069913625717, + -0.008039670996367931, + -0.006815523374825716, + -0.010157114826142788, + -0.02326541766524315, + 0.00040053605334833264, + 0.024165330454707146, + -0.021333249285817146, + 0.008066138252615929, + 0.07749845832586288, + -0.005760109517723322, + -0.03409085050225258, + 0.002539278706535697, + 0.03046472743153572, + 0.02333158813416958, + -0.022484609857201576, + -0.012942877598106861, + -0.018964359536767006, + -0.005455727223306894, + -0.035228975117206573, + -0.016873382031917572, + 0.02922072820365429, + -0.02355656586587429, + 0.00033105743932537735, + 0.024813799187541008, + 0.00412901584059, + 0.00717945909127593, + 0.02039363421499729, + 0.010382093489170074, + -0.01400159951299429, + 0.013028898276388645, + -0.023583034053444862, + 0.0017948647728189826, + 0.017482148483395576, + 0.019255507737398148, + -0.007768373005092144, + 0.0015343198319897056, + 0.01700572296977043, + 0.005250599700957537, + -0.021280312910676003, + 0.020711250603199005, + -0.007854394614696503, + -0.00907854177057743, + 0.0051314933225512505, + -0.004327526316046715, + -0.025488734245300293, + -0.01549704372882843, + 0.011546687223017216, + 0.009647605009377003, + 0.004430090077221394, + 0.02592545561492443, + -0.01865997724235058, + 0.028373751789331436, + -0.02289486490190029, + -0.0005934633663855493, + 0.03684352710843086, + -0.02924719639122486, + -0.004909823648631573, + -0.03475255146622658, + 0.020062783733010292, + 0.04428105056285858, + 0.004774174652993679, + -0.018540870398283005, + -0.0002136054536094889, + -0.00023903959663584828, + 0.012089282274246216, + 0.016410192474722862, + -0.0011257192818447948, + -0.014822108671069145, + 0.009502030909061432, + -0.01750861667096615, + -0.014676534570753574, + -0.009601285681128502, + -0.018990827724337578, + -0.02579311653971672, + 0.03925212100148201, + -0.0030388631857931614, + -0.003904037643224001, + 0.009389541111886501, + -0.04668964445590973, + -0.007999968715012074, + -0.0042282710783183575, + -0.010249752551317215, + -0.012215006165206432, + -0.01093792263418436, + 0.010236518457531929, + 0.010540901683270931, + -0.004684844985604286, + -0.0028254645876586437, + 0.0071463738568127155, + 0.003768388880416751, + -0.013339897617697716, + -0.02098916471004486, + -0.02398005500435829, + -0.011877537705004215, + 0.02346392720937729, + 0.013260493986308575, + 0.028903111815452576, + 0.025263754650950432, + 0.016820447519421577, + -0.010124029591679573, + -0.016595467925071716, + 0.01136802788823843, + -0.009343221783638, + 0.018633509054780006, + 0.017415978014469147, + 0.015205895528197289, + -0.018898189067840576, + -0.023993289098143578, + -0.001014884328469634, + -0.022762523964047432, + -0.0063060130923986435, + -0.005253908224403858, + 0.01629108563065529, + -0.010554135777056217, + 0.06299396604299545, + 0.02734149806201458, + -0.019070230424404144, + 0.018302656710147858, + -0.009839498437941074, + 0.01855410449206829, + 0.01700572296977043, + -0.0015103331534191966, + -0.009382924064993858, + -0.01066000759601593, + 0.00022849372180644423, + -0.00116790272295475, + 0.028850175440311432, + -0.006408576853573322, + -0.02789732627570629, + 0.01393542904406786, + -0.026468051597476006, + -0.002397012896835804, + -0.018342358991503716, + -0.013975131325423717, + 0.004026452545076609, + 0.0065409173257648945, + 0.013736918568611145, + 0.00021009016199968755, + -0.006292779464274645, + -0.025846052914857864, + 0.008906499482691288, + 0.0015591336414217949, + -0.008304351009428501, + -0.0012588866520673037, + 0.02869136817753315, + 0.014650066383183002, + -0.03316446766257286, + -0.01691308431327343, + 0.010468114167451859, + -0.02539609558880329, + 0.008780776523053646, + -0.014517726376652718, + 0.003695601597428322, + 0.02244490757584572, + -0.025885755196213722, + -0.0031447354704141617, + -0.004803951364010572, + -0.034699615091085434, + -0.005455727223306894, + 0.00227459822781384, + 0.0015450725331902504, + 0.010461497120559216, + 0.0034673146437853575 + ] + } + ], + "query": { + "match_none": {} + }, + "sort": ["-_score"] + } \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-payload-base64-ui.jsonc b/modules/vector-search/examples/run-vector-search-payload-base64-ui.jsonc new file mode 100644 index 000000000..b340251f1 --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-payload-base64-ui.jsonc @@ -0,0 +1,10 @@ +{ + "fields": ["*"], + "knn": [ + { + "field": "embedding_vector_dot", + "k": 3, + "vector_base64": "1uDEPDKcFbxxwGQ8yZ/KvJzMqLxr1tw7YnFNvLARzzuZypI2G9X3vLpQM7yYXai6jx7EO4RY0bujkIW8KpH5PAeq9Ty3+1a8Kr6UPBDPNbzHkS292ikauyEsarmewCG7SILuvOSCorzv9c48ND3IvEiC7jqnP1W8+iisPCxfx7tKauC8Hx7NvLIFSLuQZQM7N6zIu+xgozyjY2o6s2arO5fWmTt6JfQ71QbwO+J0hbwbr8y3fec6Oxdm9zvVWba7XGEau9FXILv7QtA8WIUvPdqWhLzGSu687ecxu71SyTsJeEO84MziPERACbx55aQ6pKqpOu+I5LzZdfC8RuG7t7/ze7wqvhS8+6+6vNR/4Tz5NLM5JVubPHtsMzzl74w892blOyZPlDynP9U8ArTmOlHBUrwpd9U60/hSPDjGbLrK5ok7zQ5Luw1UrrzS3i48/nGBPBeTkrs9VoG8eBdXukV0UbrS3q67FBiLvPP3ZDyIWmc8CcuJPEARWLy0QIA8P/ezPEq9pjxiBOM7ZOzUO7xe0DxG4bs7o2PqvM17tbvj+5O8NTFBusSpO7sPtRG764ZOPCbiKTpxmjm97Q3dPFkMvjw/3Y+9k41EPKCok7y/IJc88kqrvJ9hVDy2juy8nebMuxbf6DwAEzQ9fec6vL2ljzxgPQW8v42Bu8uHvLyDJAm9pOp4uzf/jjwW32g73MpMvOuGTjzHawI80t6uO/eTgLx9VKU80ZdvPBHpWbsI8bQ8kKXSPAtGEbyuA7I79KuOvDMjJDxtvs4712fTO+M7YzuMyee5fA3mPCXIBbw/9zM9lKdoPJF/J7zM9KY8HirUuzJJTzxuK7m8iFrnO19JDLzNDsu737I+PIMkiTvea388N/+OPCw5HDxb2gs8nDmTO8tAfTzoMfK8hiafO9xdYrwQqYo8PGKIPDxiCD1KKhE9lo/aOcA6u7pG4Tu7QNEIvBdmdzxI79g8x9F8vBMkkjuWdTY8XPQvPVzOhLwb1Xc6InMpulOPIDs4hp08uFw6vKPQ1LwL2Sa/qpQxvLjJpLymS1y84Ka3PDqUujzGJMM8QessPLhcurzjjqm8nMwou8oALjwYh4s770iVuw5u0ryinIy8mv7aO1hfhLsvYd073mv/ur5sbTzRl+881cYgvXSoVrxiBGM8bthyPGuwsbqPiy67ABM0vOEtRjvdEYy8s4zWPOzzOLzWjf47f/VXPbpQs7vz9+S8SILuPGgbhrv6u0E9zSjvO2+yxztIrwk8vDilvF17vrrT0qc8Li2VO/5E5rx1nM88Dm5SvDkz1zzimrC77tuqOy7aTjw9fCw8IewavC3m1Tz9fYi8ZieNvPFWsjyBVjs8tNOVPHATq7u0pnq8C9kmvI6XNT30fvO8hKsXvEBkHrz3QDq8vpmIvDULljw/HV+8Et3Su6FVTTgHqnW6pZ4iPCtFozz9fYi4q0FrPJ4tDLwQPKC8/X0IvPR+8zvohLg8oHv4uXa287za/P68p/+FPDrngDxV8AM9tKZ6PLjvT7vr2ZS8OXqWvFOPoDxtUWS84MxivK/dhrwdvWm88Hzdu4O3Hr1Wkba8XGEaPOIHGzyIhwI8c/ucOyCl2zxIrwk8JNSMvE14fTxApG27XDR/vMCnJTw8iDM88TAHvVw0fzzCCIk7wDq7uzrnAL31xbI8ZXNjvL2/s7svYV264/uTO5aPWjwecRO8uv3su9HEijw7bg+7lo/aPFK1yzwNVC48vaUPPCuyDbxdez68MDuyvNO4A73Z4tq6GXuEvCqRebs/Hd+7EM81vLvXwTulMTi8A447vT8d37z8Nsm6kb/2vO7bqrsDjru8t/tWvCxfx7yx6yM9A447PIZMSjp5nuW8EDwgvOjxIjo5oEE8YH3UOzEvqzzoF868qxtAPIqVH7xSCBK9k41EvNJLGT2quty8TtngvHpSDzwrRSM8kb/2O8/cmDw9D0I8VFZ+PN5rf7w7rt68XDT/u/Hpx7yMNlI8XpViPMIICb1hxBO8rMh5PdP4UjrCmx48t2jBPB4q1DsRMJm7rpbHO7bhsjmB6VC7nAz4O/4qwruk6ng7ND3IO6c/1TqUgT085iNVPKTqeDyLr8O8KPBGPInhdTuAz6w8JZvqu8YkQzzJn0q8+pUWPHheFj2cDHg8UYGDvCq+lLs4xuy8jx7EPDz1HTzL2gI78/fkPOzNDbx4F9e7mZ33PN2+xTy1WqQ8UcHSO5md9zt314e75QmxPNmii7zszY28QH5CvFiFL7xnQbE8fXpQvDYlOjqXaa+8HkR4u2dBsTx1nM+8kuCKPJhdqLviBxu8sX45PPmhHbxuRV27+TQzPaNjajv5Dog8LyEOPEdoyrwWuT28RuE7un1UJTy8XtA6kKVSvM+vfTyVCMw7KpH5PKQXlDu4yaQ5Yt43PAqS5zy+LJ68s4xWvGPSsLz/sVA8sVgOubvXQbv4Gg+7+O3zO7XHjrwE7x688koru59HsDtu2PK8s4xWPCKzeDth6j67YGMwOhPRyzxu2HI71icEvC2mBr0ldb88+pUWPf/4j7yrQeu8v40BvQbjFzzzZM+7UggSPStFIzyQOGg82XXwuyXIBbwwOzK8MBWHvNdBqDyiScY7OQ0sPNqWhDyRf6c8JuKpvJ4tjLw2JTo8eITBPE4spzyIWuc54rTUO2pp8jtNpRi8SQl9u2IEY7sDaJC7YgRju8P8AT2LAoo7h60tvH6U9LvAOjs9AMx0vHf9Mjxh6r68FFjavKLcW7tvjJw9x6vRu0Er/LsT0Us8rPUUvOvZFLwZDhq9bVHku6z1lDwH/bs8e9mdPJvYL7gKUpi8TMtDPIw20jt+wY+7Y/hbPAQVyrxZeai8BuOXvDXeertnQbE6g9HCudGXbzyinIy6pZ6iPIVy9TyhVU084tp/PFGBg7zhgAw7u7GWPHdqnbxeAk08/kTmu+/1zrvRV6C80h5+PEuxHzz5oZ28DgHoPG0RFTxkPxs6SMmtuRvVdzy/IBe8UBSZO8UKnzuOKku7Kr4UvA4BaDue2sW8/b1XvCQUXDzIMuA7JO6wPF6VYjmwN3q7m4VpOjULlrxX/qC8D7URvI+x2boG45e8to5svDMjJL1lWb87r90GvYHpULxI71g809InPMdrgrwvIQ69Px1fPPsCAT2n0mo8gQN1O6tBa7zC2+07vb8zvAEtWDx6JXS8n/RpOy2mhrytKV07ZTOUvDtujzua/lq5U4+gvGniYzyhwjc8N5KkvOGADD0BgJ68AuEBvU8gILxvjBy8uXZeOxSroLx0gqu7Yeq+OwvZprwT0Uu8NiW6vC2mBjyNECe81k0vvM5vLjy+bO28WBhFPDHo6ztmuiK9Mejru/19CDxRwdI6TaWYu4ZMyrxYxf48lIG9u/+x0LyjY2o8wggJvfPRuTv/+I88IrP4vMttmDzWupk7Gxy3uxdm97srRSM85BU4vAWcWDyfIQW99Z+HvMNi/Lz06927KmtOvCGZVLwtpoa8vyAXvJP6LjxaALc8aikjvLHro7wgEsa8EKkKvdJxRDxrHZw8HnGTvD0PwjzVc9q7y0B9vEJyO7zPidI7uTaPOwxgtbqjY2o7Eko9O0VarTub2C+8B6p1Oy4A+jyS4Ao9st+cOzKclbvApyU8AYCeu3a287vBLrS6Jk+UPFMitjvI8pA8IrP4Oo6XtTw2eAA8Di4DPQUJwznrhs67veXevODMYr2i3Nu76BdOO2ZNODtEE248hiYfvP/4D7uVW5I8X4lbvIetrbwuLRU65QmxPOqSVTw+Azs9HnETvUzxbjwGUAK8Jk+UvB5xk7vtDV2862wqOyZPlLkEgrQ81ieEu4B8Zjwlm2o8oHv4O8om2TvszQ089D4kPJ/0abwXrba8nAz4vKXEzbwW32i8hOtmPMsaUjtWJMy8hcW7PDEvq7x0gqs6biu5PDK2ObxCcrs8PPUdugMhUT2E62a7q26GvPEwBzz1n4c7+igsvMyh4Ltxmrk8STaYO9k1obtXq9q7jDbSPOFT8TvviOS8gTAQvJpRITxQzVk8u7EWPD18rLwZewQ8T7M1vHiEwTzWupk7bIoGuha5PTzzt5W8bx+yOgq/Aj3K5gm8RceXPNP4UrwDO/W8dVyAvPtCULwszLG8ETCZu+A5zbsuLRU9w2J8Omb68TomInk85pC/uiuyjbpuRV28IKXbO16V4jyge/i76xlkO6XETTvTuAO8knOgPHOOsrxmuiI7KXfVu3iEQbxlc2O8OIadPHol9LspCmu8X0mMPMK1QrtgPQW60VcgvZSn6LsYGiE8JXU/vOqS1byulse8WiZiurLfHDsvIQ68ClIYvfeTgLzT0ic8OucAvduwqDxNvzw42x2TPBHDrry7sRY862wqujIJgLzoF848e2wzPDf/Dr1Fmny8zPSmO+eqYztZDL48lxZpvBettry3aME8jImYPOFT8ToYhwu84rRUO+qSVbxXaws7/pcsPKl6Db1w+YY7r92GvNdn07zJeR+8IrP4vNAQ4btd6Ci8e0YIPcLb7Tv231a8Jk8UPHCmwLtuKzm8zeifPHgXV7smInk5k/ouvMIIiTz8iQ89n/RpPDqUurw/ism8a0PHvDeSpLu4yaS8TPFuPApSGDtWt+E8MehrO/k0M70HqnW8T2BvPMSpu7whLOq8mv7aO6+wazxfSQw8v0bCPAiEyjp3ap08ckdzufvV5TqsyHm8O67ePI1Q9ryPiy69ZcapOoCpAby8OKW8d2odvJ8hhTx+lHS7xkruOdFXoDxbrXC86xnkOkSAWLqyH+w8mcoSPQLhgTzJeR87GU7pvBscNzte3KG70NARPMrmCb2BMJA8ecsAPE2lGDuIh4K8EnDou5uF6Tvl7wy8cYAVPC9HuTzApyU8jirLvPQ+pDyiSUY8YKP/On3nOrzTZb28qBkqPNdBqLyi3Fs8MVXWvF0O1DwPtRG9g2TYO3iEQbxvjJy8UyI2vP4qQrw8NW28C2y8PNjINjxXq1q8n/RpPBQYC72f9Gm8K9g4vBEwmTsMYDW8gVa7vKUxuDouLRW8JQhVvG1RZLy7sRY7TiynvHUJujyHrS08R/tfPiHsmjxApG28k/ouPatBazy+LJ471QbwPLaO7Dl6Ug+8+O3zPPZMQTxgPYU8WpPMvFK1SzxFx5c6xcNfvBRYWrynkhu8T2DvvNfUvbzL2gI8nyGFvHA51rvAOru8amnyPKWeojwS3VI8XxxxuyNnIrrcNzc8T0bLvCONzTqpM048gcOlO1f+oLwWJqi7yiZZvJMgWrz2uSs8DVSuPBP39jpX/qA8RVqtu1w0/ztmuqI8bRGVPCzMsbxM8e67LVNAPFCnrjtKauC8qpQxPCxfRzw8Ygg9R0Ifu57aRTwIXp88C2w8u5l3zLtKamC8RuG7vKZL3DxgY7A6gDyXPDesSDwuAPo8O67evCq+FL0xVda71QbwO1sa2zx5ywA7SO9YvCWbarrrhk47u4R7vMttmDxFNII8KpF5PLFYjjwJy4m84tp/Oy9h3bvmkL88MM7HO9B9y7w7rl687GAjvI1QdjrkqE08kyBaPMjyEDys9RS8r7DrO3VcgDyEGAI6Cr+CPLIf7DvAOru83VFbvDXeerzR6jU8AMz0PDeSJD0pCuu7ygAuPL9GQrxz+xy8qBmqO4PRwrzq/7+6Ft9ovB4EqbvdpKG8OU17vLSAzzmgqBO7CQvZvGmiFDzGSu66amnyuoNk2LybRRo6Y7iMPO0NXTzMoWC8pOr4vP19iDyQEj06rgMyvfB8XTzp5Ru8vVLJPCkKa7xn1Ea8OIadO4kOkTwFnFi89t/WOwYjZ7nwfF28j4suvLzLujylnqI7Li0VPDxiCL2C3cm8F0BMvM/2vLx48au8BiPnusJI2LxWdxK80kuZvEfVNDsZoa86vDglvHTvFTyVCEw8HkT4PMttmLySc6A8wtttPXnLgLz3QLq75Qmxu3xgLL7n/Sk9Vz5wPP8eu7w+cKW7X/ZFO0vXyjtTjyC8hZ+QvMXDXzwdEDA8XQ7UO11VE73Zogu8m9gvvPbfVjsAzPS7Yt63Ow4BaDweRPg6YVepPEjv2LwNVK48l2kvuuP7k7vOlVm8qFl5vOLafzzjIT+7KcobvDkzV7x95zq712fTOA+IdjwUPra7GgITPLoqiLwh7Jq84DlNvO/1zjv0fnM8zm8uPDK2uTwrso07InMpvC3AKj3t5zE9lxbpO2P42zxZeai8GpWou58hBbuk6ng869kUu92+RTxiBOM82rwvPA4B6DxTj6A7ZvpxvECk7bonaTi8iFrnOkV00TuBw6U82eLaOzxiCDz2JpY7bDdAPCLgEzwpCms8+6+6vJClUjzmI1W8HX2aPPjt8zvkFTi8sVgOPCkKa7zZdXC6VQqovNniWjwvtKO8vb+zuwWcWLvSccQ8u4R7vA16WTuqlLG7zXu1uz/djzzYrhK9cnSOvKkzzrwYx9q7wrXCuwYjZ7uoGao89cUyOna2c7xGTqY8pD0/vCF/sDp2tnO7/KMzPVttoTxaJmK8remNPP6XLD3dEQw9RO3CvJ4tDD2oGSo9/DbJOkWa/LyTjUQ8LDkcPKmguLxVCig5sViOOzULFj3ycFa76IS4u/8eu7pQ5/27e2yzvC3m1b15ywA89KsOvNw3N7y6UDM8u0SsPE9Gy7uFcnW8ISxqO6ZL3DwUPra7pQuNvIjHUbrxw5y8st+cPOr/P7qUFFM8/x47vEkJfbz7QlA8V/4gu+J0hbwO2zy8pQuNvBYMhDyQOGi8rx3WvO+I5DqXFuk710EoOwiESjyjkIW8NISHu4O3nryebdu8U/yKvC2mhrxoG4a7meS2OyLgk7xak8w709KnPJF/pzz9fQi9Z0GxPJmdd7vLbZg7VKlEO7LfnDzq/786to5svNjINrzGd4m8ni2MvE14fTxDjF+795OAPIetrTvQY6e80t4uPJnkNrsvIY489D6kvJ7axTyjY+q74nQFvKsbwDsm4qm7s4zWPPdAOr2siCq96Z7cuf4El7yVCMw8InMpvUnj0TvwD/O8dQk6u5BlgzzBVN+72TUhvL+zLLxfiVs7aeLjvF1VEzxvHzI9C2y8u/MkADtyR/M6e2yzvNjINruTZ5k8j4uuPB29abx95zo7rKLOPJr+WjxX/qC75BW4PCQUXDzRl2+8+9XlOWzKVb3m4wU9t0KWu5G/drx5y4A8sh/suW8fsjy+bO289iaWvCFZBbwRwy67tceOPL8gF7yvHVa8/IkPvdqWhDy6/Ww8DGA1vLr9bDwwOzI8XeiovKonxzmSBrY8ecsAvP5E5rzTuAO8wVTfuwdqJrwel768Cv/ROV/2xTwRw6681icEPIO3nj1Nv7y72aILvQdqJjsqkfk84yG/PKUxuLxdDlS8JVubvPXFsrtCTBC9DDqKvE9g7zyz+cC8x5GtOU9GyzyyTIc7q0HrO40QpzyoGSo892ZlvCl3VTw1McG8q0HrOrk2jzy6vZ081o3+uzsbyTqWT4s8OQ2sOw1Urrykqqk8uK8AvCq+FLwWJqg77M2Nu8DN0LxQ5328US49PP0QHjxKKpE7n2HUPM/cmLwScOg8A467vKeSG7o96RY90ZfvvJbioLuxWA69tVqkPAxgNT2ucJw7BuOXvEf7X7m0pnq5IBJGPKtuhjzfjJO6bthyvGiuGzw7bo+82XVwvLZOHbynkpu8FkzTvNXGID2qJ0e74tp/u5fWGTykPT+9TRIDvE+NiruU7ie8cyFIvPk0M7wStyc8v7MsPFSDmbtuKzm7ISzqOxP3djuWj1q8ePGrvNJxxLwBmkK8bDfAPItCWTw4xuw87/XOPAnLiTxC3yW8OPOHvPdAOjxQFBm8TaWYPPSrjjwmInk8YNCavJONxLzeBYW6eXi6vKyizrv6KKy74nSFPEHrLLz7AoE9R/vfPCw5nLx075U82TUhvMf+lzyWT4s8X/bFuta6GbxQpy680ZdvOVAUmbo0V+w8Cv/Ru++I5LxtUWQ8h9PYvDQXHbu3Qpa88/dkvFXwgzsxVdY70BBhPKZLXDmpM867GrvTvJHsETzYW8w6+Q4IvDoBpbopCus81QZwPHfXB71PjYq8dIIrPHkL0Lw/3Q88wtttvOgxcjti3rc8XQ7UvOgXTrt3ap27LyEOvfXFsrttERU7CITKOrNmKzzjO2M7" + } + ] +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-payload-ui.jsonc b/modules/vector-search/examples/run-vector-search-payload-ui.jsonc new file mode 100644 index 000000000..af9060e70 --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-payload-ui.jsonc @@ -0,0 +1,10 @@ +{ + "fields": ["*"], + "knn": [ + { + "k": 2, + "field": "colorvect_l2", + "vector": [ 0, 0, 128 ] + } + ] +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-simple-color.go b/modules/vector-search/examples/run-vector-search-simple-color.go new file mode 100644 index 000000000..9f56e35df --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-simple-color.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + "log" + "time" + "os" + "github.com/couchbase/gocb/v2" + // Include this import if you want to run a Search query using regular Search index features. + // "github.com/couchbase/gocb/v2/search" + "github.com/couchbase/gocb/v2/vector" +) +// Make sure to change CB_USERNAME, CB_PASSWORD, and CB_HOSTNAME to the username, password, and hostname for your database. +func main() { + connstr := "couchbases://" + os.Getenv("CB_HOSTNAME") + username := os.Getenv("CB_USERNAME") + password := os.Getenv("CB_PASSWORD") + // Make sure to change the bucket, and scope names to match where you stored the sample data in your database. + bucket_name := "vector-sample" + scope_name := "color" + + cluster, err := gocb.Connect(connstr, gocb.ClusterOptions{ + Authenticator: gocb.PasswordAuthenticator{ + Username: username, + Password: password, + }, + SecurityConfig: gocb.SecurityConfig{ + TLSSkipVerify: true, // Disables TLS certificate verification + }, + }) + if err != nil { + log.Fatal(err) + } + + bucket := cluster.Bucket(bucket_name) + err = bucket.WaitUntilReady(5*time.Second, nil) + if err != nil { + log.Fatal(err) + } + + scope := bucket.Scope(scope_name) + + request := gocb.SearchRequest{ + VectorSearch: vector.NewSearch( + []*vector.Query{ + // You can change the RGB values {0.0, 0.0, 128.0} to search for a different color. + vector.NewQuery("colorvect_l2", []float32{0.0, 0.0, 128.0}), + }, + nil, + ), + } + // Change the limit value to return more results. Change the fields array to return different fields from your Search index. + opts := &gocb.SearchOptions{Limit: 3, Fields: []string{"color"}} + + // Make sure to change the index name to match your Search index. + matchResult, err := scope.Search("color-index", request, opts) + if err != nil { + log.Fatal(err) + } + + for matchResult.Next() { + row := matchResult.Row() + docID := row.ID + var fields interface{} + err := row.Fields(&fields) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Document ID: %s, Fields: %v\n", docID, fields) + } + + if err = matchResult.Err(); err != nil { + log.Fatal(err) + } +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-simple-color.java b/modules/vector-search/examples/run-vector-search-simple-color.java new file mode 100644 index 000000000..9ff873d4d --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-simple-color.java @@ -0,0 +1,66 @@ +import com.couchbase.client.core.error.*; +import com.couchbase.client.java.*; +import com.couchbase.client.java.kv.*; +import com.couchbase.client.java.json.*; +import com.couchbase.client.java.search.*; +import com.couchbase.client.java.search.queries.*; +import com.couchbase.client.java.search.result.*; +import com.couchbase.client.java.search.vector.*; + +import java.time.Duration; +import java.util.Map; + +public class RunVectorSearchSimpleColor { + + public static void main(String[] args) { + // Make sure to change CB_USERNAME, CB_PASSWORD, and CB_HOSTNAME to the username, password, and hostname for your database. + String endpoint = "couchbases://" + System.getenv("CB_HOSTNAME") + "?tls_verify=none"; + String username = System.getenv("CB_USERNAME"); + String password = System.getenv("CB_PASSWORD"); + // Make sure to change the bucket, scope, collection, and index names to match where you stored the sample data in your database. + String bucketName = "vector-sample"; + String scopeName = "color"; + String collectionName = "rgb"; + String searchIndexName = "color-index"; + + try { + // Connect to database/cluster with specified credentials + Cluster cluster = Cluster.connect( + endpoint, + ClusterOptions.clusterOptions(username, password).environment(env -> { + // Use the pre-configured profile below to avoid latency issues with your connection. + env.applyProfile("wan-development"); + }) + ); + + Bucket bucket = cluster.bucket(bucketName); + bucket.waitUntilReady(Duration.ofSeconds(10)); + Scope scope = bucket.scope(scopeName); + Collection collection = scope.collection(collectionName); + + SearchRequest request = SearchRequest + .create(VectorSearch.create( + // Change the floats in the array to search for a different color. + VectorQuery.create("colorvect_l2", new float[]{ 0.0f, 0.0f, 128.0f } + ).numCandidates(3))); + // Make sure to change the index name to match your Search index. + SearchResult result = scope.search("color-index", request, + // Change the limit value to return more results. Change the value or values in fields to return different fields from your Search index. + SearchOptions.searchOptions().limit(3).fields("color","brightness")); + + for (SearchRow row : result.rows()) { + System.out.println("Found row: " + row); + System.out.println(" Fields: " + row.fieldsAs(Map.class)); + } + + } catch (UnambiguousTimeoutException ex) { + boolean authFailure = ex.toString().contains("Authentication Failure"); + if (authFailure) { + System.out.println("Authentication Failure Detected"); + } else { + System.out.println("Error:"); + System.out.println(ex.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/modules/vector-search/examples/run-vector-search-simple-color.py b/modules/vector-search/examples/run-vector-search-simple-color.py new file mode 100644 index 000000000..ee0869c13 --- /dev/null +++ b/modules/vector-search/examples/run-vector-search-simple-color.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +import os +import sys +from couchbase.cluster import Cluster +from couchbase.options import ClusterOptions +from couchbase.auth import PasswordAuthenticator +from couchbase.exceptions import CouchbaseException +import couchbase.search as search +from couchbase.options import SearchOptions +from couchbase.vector_search import VectorQuery, VectorSearch + +# You can change the RGB values to search for a different color +vector = [0.0,0.0,128.0] + +# Make sure to change CB_USERNAME, CB_PASSWORD, and CB_HOSTNAME to the username, password, and hostname for your database. +pa = PasswordAuthenticator(os.getenv("CB_USERNAME"), os.getenv("CB_PASSWORD")) +cluster = Cluster("couchbases://" + os.getenv("CB_HOSTNAME") + "/?ssl=no_verify", ClusterOptions(pa)) +# Make sure to change the bucket, scope, and index names to match where you stored the sample data in your database. +bucket = cluster.bucket("vector-sample") +scope = bucket.scope("color") +search_index = "color-index" +try: + search_req = search.SearchRequest.create(search.MatchNoneQuery()).with_vector_search( + VectorSearch.from_vector_query(VectorQuery('colorvect_l2', vector, num_candidates=3))) + # Change the limit value to return more results. Change the fields array to return different fields from your Search index. + result = scope.search(search_index, search_req, SearchOptions(limit=13,fields=["color", "id"])) + for row in result.rows(): + print("Found row: {}".format(row)) + print("Reported total rows: {}".format( + result.metadata().metrics().total_rows())) +except CouchbaseException as ex: + import traceback + traceback.print_exc() \ No newline at end of file diff --git a/modules/vector-search/examples/sample-vector-search-index-payload.json b/modules/vector-search/examples/sample-vector-search-index-payload.json new file mode 100644 index 000000000..daa18b953 --- /dev/null +++ b/modules/vector-search/examples/sample-vector-search-index-payload.json @@ -0,0 +1,117 @@ +{ + "name": "color-test", + "type": "fulltext-index", + "params": { + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "scope.collection.type_field", + "type_field": "type" + }, + "mapping": { + "default_analyzer": "standard", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "default_mapping": { + "dynamic": true, + "enabled": false + }, + "default_type": "_default", + "docvalues_dynamic": false, + "index_dynamic": true, + "store_dynamic": false, + "type_field": "_type", + "types": { + "color.rgb": { + "dynamic": false, + "enabled": true, + "properties": { + "description": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "name": "description", + "type": "text", + "store": true, + "index": true, + "include_term_vectors": true, + "include_in_all": false, + "docvalues": true + } + ] + }, + "brightness": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "docvalues": true, + "index": true, + "name": "brightness", + "store": true, + "type": "number" + } + ] + }, + "color": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "docvalues": true, + "include_term_vectors": true, + "index": true, + "name": "color", + "store": true, + "type": "text" + } + ] + }, + "colorvect_l2": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "dims": 3, + "index": true, + "name": "colorvect_l2", + "similarity": "l2_norm", + "type": "vector", + "vector_index_optimized_for": "recall" + } + ] + }, + "embedding_vector_dot": { + "enabled": true, + "dynamic": false, + "fields": [ + { + "dims": 1536, + "index": true, + "name": "embedding_vector_dot", + "similarity": "dot_product", + "type": "vector", + "vector_index_optimized_for": "recall" + } + ] + } + } + } + } + }, + "store": { + "indexType": "scorch", + "segmentVersion": 16 + } + }, + "sourceType": "gocbcore", + "sourceName": "color-vector-sample", + "sourceParams": {}, + "planParams": { + "maxPartitionsPerPIndex": 1024, + "indexPartitions": 1, + "numReplicas": 0 + }, + "uuid": "42676f35cc30b84a" + } diff --git a/modules/vector-search/examples/vector-search-base64-document-example.json b/modules/vector-search/examples/vector-search-base64-document-example.json new file mode 100644 index 000000000..6a76dc8e9 --- /dev/null +++ b/modules/vector-search/examples/vector-search-base64-document-example.json @@ -0,0 +1,15 @@ +{ + "id": "#000080", + "color": "navy", + "brightness": 14.592, + "colorvect_l2": "AACA", + "wheel_pos": "other", + "verbs": [ + "deep", + "rich", + "sophisticated" + ], + "description": "Navy is a deep, rich color that exudes sophistication. It is a dark shade of blue that is often associated with authority, stability, and elegance. Navy is a versatile color that can be both bold and understated, making it a popular choice in fashion and interior design. It is a timeless color that never goes out of style and adds a touch of sophistication to any look or space.", + "embedding_model": "text-embedding-ada-002-v2", + "embedding_vector_dot": "i2YKOzXJwrsL+RQ77hrZuyqurLwbCXk8dzvIvC/qkLyVlzy8d8yIvBNleLwZfMc7ngAMvHp+z7xf0Q29RLigPD/V3zwQpLi8UWDoPP09Rbxmv7i7RaIEPffyZ7yIIwO80jmJvPi3NrvUfJA79UChvOlKIDzBB6S8FsoAPKQpaLz2mcS6udLivLEJzTw8ObW7oWiovMEHJLxXnMw7XNgwuzdWdDwDVRQ7vdo4vBt1JDt6NKW8jfM7vG4ZDztzM3K8IdadOyAgyDxAZiA9pATTPE56Eznapey83tJXPCdGEDxFooS8mtMgPS8PpjyLsLS7ksN0u44CNbrVRPO7weKOPM173bufo9m8yaukvCdrpTyi5uC8CAC4PP7zmjx/cAk9EbOxPPL9mTyn2Jo8da4WPGz7HLxZBGk8g+eevICklzqkBNM7qOeTvDlA2LyEZVc7M2GmOxN4gDz5kiG873N8PJrToLxy2s675WdfPLa08DyllRM8bohOO3Jrj7yllZM81ouJPDBDtDxAQYs8DC2jvCuYEDySw/Q8J0YQvelvNTkV4Jy8RLigvJyqfLzbNq07G3WkPJEgp7yvfJu8b3IyPTvgkTw5QNi80ahIPEG/wzqhQxM8PbdtvO/fJ7zmdti8KJ+zvICklzxtCpY8v5+HvKOGGjyVcqc8JHLIO3YHOr0v6pC8NaQturPzMD0y0OU8AFw3PKgMqTwDn768ypWIPMvJFr3/J6k87ynSunuNSLx10ys7bmM5PJJ5SrzSgzO7R571u6pANzwEZI08ex4JPCWm1rmfDwW82t0JPSGxiDuEZdc8auwjPMvuq7woDvM8iVeRPJmfkrxeZWK7W+7MPI+A7boeAlY7GCMkPNTrT7unswU9pCloPMayRzy2j1u8DWExvGknVTzNe128A5++PFvuTLzjtRg867I8PAY76Tz/TD490oOzuv1iWrzSgzO7CX5wvJA2wzucqny7tN2UvGsgMjoOlb87AWswPeOQgzwTQOM74AbmO/YqBbyfo9k8IPuyvLxcgDzY8yW/0SqQvIRAQrpM/+68BPjhPC1v7Dw50Zg7ahG5PA08nDss8TM8lXKnvD4yEjx6fs+732OYvPcX/brd6PO51wnCOna9j7sekxY8j7gKPIMxybwOBH88WDyGvAPEU7szPJE8g+eePO2cILvG/PG7914TvJ+j2TrjkAO99xd9PCnTwTw8Xko8o9BEPQkPsbojiGS8U9sMPQGQxTuiwUs8uWMjOw4EfzyISBg7jT1mu+6rmTt38R081KGlOnycwbzcRaY7V8FhOlt/DT2M5EK8yaskPA5wKjxhqOk8y11rvLtNhzxRYGi8jamRvOxokjyxU/e76UogO7qXMbtW5va8MI1evEiIWT34tza9eg+QvKzN6Lx71/K8+RBavCY3Fzw59q26psmhvAN6qTyVTRK7JjcXPTKrUDzb7IK8p7OFPE8d4bs457S82t2JvMmGj7xYYRs9sb8iPPVltryw1T6845ADPd3D3rzsaJI8cMvVO6Lm4LpPrqG87XeLvKezBT3VRHM5Dt9pvB7dwLqszWi75OkmvO6rmTpteVW7YyOOPMO5arvNoHI7myxEu5mfEj2OArU75A68vIMxSTxKl1K8zgyevNCZTzuu61q7R1TLvE1GBT3nz3u8hXRQPIc5H7yoVlM8/C5MvBUFsjpRhX08SrznOi62ArwKaFS7cE0dvJ9+xLv71ai6hgWRPGHN/jwZDQg9w2/APPLYhLvcaju61rAeuwCBzDuhC/Y7ddMrvQZzhjzgBmY8TulSvGjOMbt1iQG8RJMLvSLAgb3J0Dm8K70lvXoPEDyUYy68mQ5SvIQbLbwxd0I9tRGjPIRl17t4lOu8iXymOkCLtTsvNDs8sb8iO/vVqDyvxkW8zjEzO4x1A7xGRdK8Q901vSsH0DzmLC68O+ARvbRMVDxjSKM82qXsO/jcy7v+zoW8mem8PM5WSL2E9he8tHHputcu17sUrA48CQ+xPBW7h7zIGuQ6hZnlPEZF0jyWXAs9Pnw8PeXTCrw6dOa62+yCPApDP7xmvzg60wFsuqCNvbwAEo27ddOrvGtq3Do9/oM8HamyPCM+ujz0isu79/LnO9I5CTzgchE8hPYXvKFDkzyFKiY8Zi74OaFDEzwYxnE7LzQ7vANVlLxgBRy7YahpPEI9/Dva3Qm8GkGWulyOhjvKup28IdadPMF2Y7xjIw481HwQO9aLCb2GBZG8Iz46PAHa77sPJgC9EMnNvEG/Qzz/J6k84AbmO+3myruNPea8RwqhPNqA1zxLXCG9RvsnPP8nKTtb7sw77XeLPFFgaDkna6W8HgJWPf7OBbs17tc8CmjUuvKR7rsqrqy8KA7zu7XsDTwf7Lm8wVFOvEpNqDrvc3y8BjvpPMDTFTtqx4485R01PH0a+jxKTai8WDwGPLOphjt/lR49ST6vuxdtzrtAizW7BGQNvRdtzrzHnCu7H8ckvHWJgTwaZis6hzkfvKhW07z8eHY8YpJNvAl+8DzkxJE8yxPBuyuYkLyNPWY8gntzPAG1WjrbNq28iG2tvLURozwKxQa9Zi74PBGOnDyBIlA8/rt9vHfxHbzG/HG8mQ5SvF3ClDzplMq7rkgNOxB/o7p+hiU9KOldvFz9xbyXta67pCloPO6rmTyXJG47/5ZoPGGo6TqNYnu8CVnbvIJ7c7zTSIK5zXtdvIPCiTxNa5o82gIfvNqA17wbv848mkJgO4yamDypiuG8tyAcvKLByzuOJ0o9FbsHvKFDk7xRmIW7LzQ7PJ4lobzKlQi9wK4APb8dwDyUY647w0qrPFkp/juxv6I8DFI4vJH7Ebnl+B88p/2vu0s3DLzFNI+7ruvavKLmYLyTCou8Qj18u9X6SLx1rpY7VA+bO21UwDwwHh88s84bPQN6qbykKWi72gIfPdEqkDrCYEe8dHoIvW9yMrtw8Gq8T4mMPH/fyLmTiEO8M2GmPBbvlbwVuwc6Tp8ovJpCYDwYody87eZKu4detDyCsxA7GTIdvSu9pbyfyG67HifrvHZRZLz/AhQ7Zi54OxihXLyw+tM8xX45PHKQJL0WFKs7d8wIvFAs2jusqFM6+NzLvCIKLL3xyQu8dxYzvLsV6rzCFp27ORtDO6sFBrz5bQy8Lw+mPJkO0jx24iS77GgSvB2EnbybLMS72gIfPMF2YzwRaQe8LW9suoW+erwU0SM8DAiOvGzWh7sW7xW8WZUpvFkE6Tz6xq88ABKNvIl8pjycvYS77GgSvIc5nzzvTuc7QvPRvJiQGTxG1pK8qyqbPJWXvLvlZ1+8n8juvP67/TxkfLG81R9evPSKSzzUxrq8PSOZuwfxPjygjb28OMIfPK9XhrwZDYi8uC+VvBCkuLwb5OM8VOqFu6yDvrznz3s734itvGAqMTxUDxs8zXtdvBpmqzx99WQ8MI1eOstd67yX/1g8fmGQPMF2YzgE+GG99NT1vB4n67zvTuc7HxFPPCZcrDtg4Ia8udLivBocAbx+hiW7gww0vPv6vbxw8Go8VA+bvKS6qLv43Eu8VkOpvCsH0Dx6D5C8nRaoOfeoPbyP3Z879pnEu8U0j7k/1d+8d/EdPPqhGj12UeQ8ffVku9O3wTwRszE8+7CTOqmK4Tb38ue7f5UeOojc7Ls3syY7YE9GO92eyTyAE1c81osJvMd3FjzYYmU8Hm4BPSBFXbz8U+E7MLLzvKezBb1ozjG8P/r0O7Hkt7u0cek8F21OvKzNaDt3FrM80JnPu1ZDKTyISBg8TunSPKOGmjtPrqE8GQ0IvFGYBTyHg8m7IGryvLRx6bxc/UW8KOndvDeOkTya06A8TnoTvIc5nzyo55M7LzS7PA8mALv8CTe7vf9NPIH9OrxhqOm76n6uuy7bl7wVuwe9kMcDvIJ7czyu61q8sNW+PFt/Db1M/268to9bOjdWdLvLONY8BhZUvLtNBz2inDa8CkO/u1t/DTwbv047uzr/OwQd97tXLQ091URzPHBNHTz9v4w8Wd/TOxB/I7zGske6PW3DvFVovjzq7W28ZKHGOzIIA71LN4w7Xxs4vQSuNzwPSxW8/hiwu7VbTTzfK/s7aSdVvNiH+jx2B7o1U9uMPFg8hjwjrfk7mq6Lur+fBz00lTS7wXZju/SvYLsJDzE8KlF6OzvgEbztC+A8r3wbPcZDiDyVl7y6yYYPPM+K1jxz6ce8trTwOhjGcTya+DU8mZ+SPOHLNLzpbzW8FbsHvc4MnrymE0y7YAUcPBxQj7zyIq+73i+KPPIiL7oDeik8nIXnvGYJ4zvFo0485WffO1nfU72AOGy8rhDwOtDj+Tv/ApS70ON5vNaLiTvqWZk8J7XPvD0jGT3LyRa98zEoPB/sOb3/TD48X9GNO9BPJb1KTag8ZHyxuydGEL09t+27jWL7O/zkIbzfPoO7MVKtOyOt+bjXmgK71rCevMU0D7yzqQa9bojOPLyBlbx1dvk7vumxPNxqu7yFTzu8X/YivasFhrzoFhK84fDJvOYHGb2wi5S8MVKtPOyNpzxs1oe8/s4FOz6h0Tson7O8uC+VPIeDSTyeb0u8MGhJPNfkrDwtb+w8mmf1O4cUCrz+u326y11rvEpyPbxcItu7yD95PBsJ+Tui5uA8t/sGPUee9bwXSLm8yBpkPOrI2LsqUXq8ST4vu0qX0jwYoVw8XCJbPImhOzv3zdI8Fl7VvF5lYjv6oZq8o9BEPDn2LTsOcCq8ydC5O8ayR7xChBK9ZUGAOR/suTwbCXk7iG0tu6xeqTuzqQa8CX7wt6ezBbwO3+k8QhhnPH315Dv0iss8NzFfvUWihLwAEg29GCMkOw2Gxrw6Krw88ckLvDOGOzzx7qC8nkq2vDpPUbpytbm8qDE+PFirxTw0lTQ8qyobuoB/Aj1bf408/FPhO94virwBkMW8nRaoukFQhLy8pio8pyJFvMukgbsAXDe9A3qpPJqui7woeh68QwLLOieQurykTn28SOULPNyP0DvxyQu8pZUTPCpkgry8XAC9JSievGVmlbxmLvg6RwqhvKjnEzzu0K67B6eUO8xHz7w2/VA8QGYgvJZcC7ykuqg8V3c3PrmIODxP+Ms8uHm/PNX6SLzLyRY8osHLPG6tYzvuhoQ8j7gKPHuyXTyjqy892D1QvFmVqTt71/I8DRcHvZmfEr2ffsS81URzuvC6ErwKxQY4tkWxvIhtrbsGFtS7LSVCPHp+TzyFmeW5F23OPL9C1Tsw+Yk8a2pcvLk+Dr0874o7gKQXuw9LlbtpTOq7cabAO5yFZ7zYYmU8weIOPKdH2jt71/K7udJiOkS4IDv0r+C7gzHJPIdeNLyE9pe75ULKO0qX0jsU0aO81HwQvLcgHD1CPfw8f7qzu3+Vnjz38mc8798nPFQPGz2NYvs8cTeBvLIYxjxXd7e7Tx3hPNOSLDxFEUQ8WnAUPCzMHr0qrqy68RO2OmEUFTx6Wbo6LtuXvAY76Tsy9fo6ESLxvPSKSzyzzps8ZHwxuyIvwTwyq9A7mq4LvKsqm7yI3Oy6OawDPJLD9Lw0ukm8NzFfvE7EvTt4lGs5tVvNO2WLKrvQvuS7H6IPPHhKQTzBLLk8c5+dPGhx/ztIY0S8ruvaO44CtbxuYzk8T0J2PGrHDj1+q7o7k4jDuxjGcTyIIwO85nbYO8ecKzuM5MK7osFLO4htLTyfWa+83yv7u2BPRjq9kI68J0YQvY2pkTyUPpm7pE59vKakjLxPiYy8w0qru9B0Ojz668S88ckLvdknNDwQfyM7upcxvVt/jTzYYuU7LMyePHfMCL1ZKf67Z3WOPJ07PTwJNMa7/b8MO1ecTLzZJzQ75dMKvW0vqzrd6HM8lAZ8PESTC7yJfKa86SULu8O5arxzDl28jRhRvCUonrxeinc74aYfvN3o8zq17I28xtdcvAi2DbmcvQQ7n6NZu5ARLr3HnKs8unIcPf9MPrskTTO8Oiq8OpnEJ74o6V09tewNPEpNKDziSe27caZAPCsHUDxTSsw7bVTAvIl8pruz87A7r8bFOwseqrwZMh28rPJ9uwl+cLttL6s8qYrhO06fqDx2LM88p/0vPUnhfLz/ApQ49NR1O1DiL7yOArW6foalu/eDqDysOZS8ZUGAutyPUDxZur67uxVqPFirRTxQvZq7QGYgPJKeX7t6NKU88zEouyBq8jys8v26sS5iPM/2gTzQdDo8CQ+xvCIvwTvLXWs8ouZgPPMMkzt6Wbq8I4jkOn315LzzVj06z4pWu3kAFz2II4M8U9uMPBCkuLtAQYs76n6uvCJU1rzzDJO8o6svvMsTwTwiVNY63cNevLvwVLzfPgM8NEuKvNC+ZLufo1m8F0i5OTRLCrzBdmM7/0w+PClVibxwKIi7Ne5XPEIYZzseJ+s7+7ATvJck7jtHLza7BZgbux4n6ztq7KM8M4a7vPKRbrxWQ6m8GTKdut+ILTxYPAa915oCu2ipHLuvVwa8F0i5u8ukgTwrmJA7zlZIvAOfPjkF4sU8whadumVBALyXta635Yx0PKLmYDxwy9U7T0L2O+YsLj0i5RY8MLLzvOGmnztgKrE8CsUGPEs3jLyfyG46SeH8O/VltrwItg07JabWu8IWHT1BUIS8JHJIvK9XhjxFEcQ8NaStvK/Gxb0xd8K7AFy3PNe/FztLNww8s5Z+PKtPMLyWgSA8iVeRPMrfsjxZ39O4LrYCvAWYGzy+M1y85lFDPLZqRrvq7W07GhyBu7PzsLzQvuQ8Sk0ou8qViLt+q7q8s6mGvPdek7tlZhU7/Hj2vFkpfjySnt88kp7fPFpwlDyYkBm6wmBHOp+j2bxlZhW9jamRuw5wKjxJ9IS71ouJPGaao7xI5Qu7WQTpO+13izv8eHa9+Lc2O+LarTslKJ68q08wPUnhfLwJDzE8LKcJvLaP2zziJNi6grOQvEF1GT0Itg28L1nQPLmIOLqpiuG82Bi7u1z9RbzGaJ08JctrvKbJoTwly+u8zXtdu8td67zhgQq8urxGPBEi8bwXSLm8K70lPPTUdbx9LQI9Lw8mvRxQDzwb5OO8OMKfPAWYmzxz6ce63i8Ku2bkzTr8Lsy69iqFvDWkrbtjxls9y6SBuxYUK7pBUAQ8Y8bbvLsVarvD3v88zjEzPBt1JL2NYvs4OfYtPEnhfDy2j1u8uWOjux4na7yB/Tq86W81vN4vCr3Kup083z4DvFwi27w3jpE8Ef1bvN9jGLy/HcC721vCO9iH+jtw8Gq8VKPvOxgjpLzcaju8JHJIvDmsAzww+Yk8jORCvANVFLzBByQ7tAIqu8QllruJVxE9Xop3u5LD9LzGjTI7BjvpueGmHzxwKAi809xWvLFT9zsF4sU7ki8gPJ5vSz1GIL28/Am3vGipHLwF4sU8GhwBPCRNs7tNaxq8VKPvvBzOxzvuGlm8RiC9vH6rOrwqZAK9E0BjPPzkoTuFmeW7K5gQPTBoSTzwupK6MGjJvPKR7jv6xi+93Z5JPPwuTDz7+j08jHWDOm7SeDzl04q87DD1PNbVM7yD5548dztIPD/69LyaZ/U8W8k3PMCbeLz6fAU8+TXvum5juTy+WHE7foYlPEpyvbzuqxk8f5WevNxqu7w9Ixk9oUMTu+yNJzxIiNm8BjvpPE1GBTxHnvU7yD95vJ3xkjtu0ng8NHAfPOYsLrzDb0A69RsMva2SNzy7FWq8O+CRvBocgbsVuwc7CkO/vHuyXT3VRPM77ynSO4gjg7vKlQi9N1Z0vBYUq7zBLDm8bXnVuiBqcjzx7iA8SOULPBUFMrxCGOe8icZQPEiI2byM5EK7LrYCvXMz8rympAy8tEzUPMayxzucqvw81rAePa7r2rngcpE7VKNvPJXhZjwgRd28gMksOzRLCj0ntU88gzHJvMtda7uEZdc8cVyWvMayxznlHbU84OHQPPcX/TooxEg9IbGIO36GJb0mXKw734itOzb9UDwwHh88OMKfu5JUNTtKl1I8eQAXuwrFBrzt5ko8wK4AvE56E70PJgC7gBPXvMEHJD3+GLC8ZUGAvPSvYDyb4pm7KlF6PN6twjsR/Vu79NR1vAx3zTxXLY27GQ2IvJxg0rzt5so8xTSPvLRMVL0ganK8G5o5vELzUbupr/Y6cPBqvDSVtLuyGMY8FSpHPI2pET3LpIG8L+qQvLnS4jy6l7G60SqQvEI9/LsPS5W8" +}, \ No newline at end of file diff --git a/modules/vector-search/examples/vector-search-index-payload.jsonc b/modules/vector-search/examples/vector-search-index-payload.jsonc new file mode 100644 index 000000000..fe4ccce3a --- /dev/null +++ b/modules/vector-search/examples/vector-search-index-payload.jsonc @@ -0,0 +1,123 @@ +{ + "type": "fulltext-index", + "name": "vector-sample.color.color-index", + "sourceType": "gocbcore", + "sourceName": "vector-sample", + "planParams": { + "maxPartitionsPerPIndex": 512, + "indexPartitions": 1 + }, + "params": { + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "scope.collection.type_field", + "type_field": "type" + }, + "mapping": { + "analysis": {}, + "default_analyzer": "standard", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "default_mapping": { + "dynamic": false, + "enabled": false + }, + "default_type": "_default", + "docvalues_dynamic": false, + "index_dynamic": false, + "store_dynamic": false, + "type_field": "_type", + "types": { + "color.rgb": { + "dynamic": false, + "enabled": true, + "properties": { + "brightness": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "index": true, + "name": "brightness", + "store": true, + "type": "number" + } + ] + }, + "color": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "analyzer": "en", + "index": true, + "name": "color", + "store": true, + "type": "text" + } + ] + }, + "colorvect_dot": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "dims": 3, + "index": true, + "name": "colorvect_dot", + "similarity": "dot_product", + "type": "vector" + } + ] + }, + "colorvect_l2": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "dims": 3, + "index": true, + "name": "colorvect_l2", + "similarity": "l2_norm", + "type": "vector" + } + ] + }, + "description": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "analyzer": "en", + "index": true, + "name": "description", + "store": true, + "type": "text" + } + ] + }, + "embedding_vector_dot": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "dims": 1536, + "index": true, + "name": "embedding_vector_dot", + "similarity": "dot_product", + "type": "vector" + } + ] + } + } + } + } + }, + "store": { + "indexType": "scorch", + "segmentVersion": 16 + } + }, + "sourceParams": {} +} \ No newline at end of file diff --git a/modules/vector-search/pages/create-vector-search-index-ui.adoc b/modules/vector-search/pages/create-vector-search-index-ui.adoc new file mode 100644 index 000000000..ebbf3a42b --- /dev/null +++ b/modules/vector-search/pages/create-vector-search-index-ui.adoc @@ -0,0 +1,117 @@ += Create a Vector Search Index in Quick Mode +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:page-toclevels: 2 +:description: Use Quick Mode to create a Vector Search index in Couchbase Capella. + +[abstract] +{description} + +Quick Mode works best when you need to create a basic Search index to start testing and prototyping with the Search Service. +You must use Advanced Mode to have greater control over how the Search Service returns such results, such as changing your xref:search:customize-index.adoc#analyzers[analyzer]. + +For more information about how to create a Search index in Advanced Mode, see xref:search:create-search-index-ui.adoc[]. + +TIP: Vector Search indexes can include all the same features and settings as a Search index. +For more information about Search indexes, see the xref:search:search.adoc[Search documentation]. + +You must create a Vector Search index before you can xref:run-vector-search-ui.adoc[run a search] that supports vector comparisons. + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have documents in a keyspace inside your bucket that contain vector embeddings. +Embeddings can be an array of floats or a base64 encoded string. ++ +[TIP] +-- +include::partial$download-sample-partial.adoc[] +-- + +* You have logged in to the Couchbase {page-ui-name}. + +== Procedure + +To create a Vector Search index with Quick Mode in Capella: + +. On the *Operational Clusters* page, select the operational cluster where you want to create a Search index. +. Go to menu:Data Tools[Search]. +. Click btn:[Create Search Index]. +. In the *Index Name* field, enter a name for the Vector Search index. ++ +[NOTE] +==== +Your index name must start with an alphabetic character (a-z or A-Z). It can only contain alphanumeric characters (a-z, A-Z, or 0-9), hyphens (-), or underscores (_). + +For Couchbase Server version 7.6 and later, your index name must be unique inside your selected bucket and scope. You cannot have 2 indexes with the same name inside the same bucket and scope. +==== +. In the *Bucket* and *Scope* lists, choose the bucket and scope where you want to create your Search index. +. In the *Collections* list, select the collection or collections that contain documents with vector embeddings. +. Under *Type Mappings*, in your document schema, expand a collection that contains these documents. +. In your document schema, select the child field that contains your vector embeddings. +. Configure the options for the child field as follows: +.. In the *Type* list, select one of the following: +... If your child field contains vector embeddings as an array, click *vector*. ++ +Vector embeddings formatted as arrays appear as `\{field-name} [ number ]` in the Capella Quick Mode editor. +... (Couchbase Server version 7.6.2 or later) If your child field contains vector embeddings formatted as a base64 encoded string, click *vector_base64*. ++ +Vector embeddings formatted as base64 strings appear as `\{field-name} [ string ]` in the Capella Quick Mode editor. +.. In the *Dimension* field, check that the value matches the total number of elements in your vector embeddings array. ++ +The Search Service supports arrays up to 2048 elements. +Capella automatically fills in the dimension value for your selected child field when you choose the *vector* or *vector_base64* type. +.. In the *Similarity metric* list, choose the method to use to calculate the similarity between search term and Search index vectors. ++ +For more information, see xref:search:type-mapping-options.adoc#field[Field Type Mapping Options]. +.. In the *Optimized for* list, choose whether the Search Service should optimize Search queries for accuracy (*recall*) or speed (*latency*). ++ +For more information, see xref:search:type-mapping-options.adoc#field[Field Type Mapping Options]. +.. Select *Include in search results*. +. Click btn:[Add To Index]. +. (Optional) Add additional collections or child field type mappings to your index. ++ +For example, you could add the text field that you used to generate your vector embeddings. +For more information, see xref:search:create-search-index-ui.adoc#add-mapping[Add Type Mappings and Mappings]. +. Click btn:[Create Index]. + +[#example] +=== Example: Creating a Vector Search Index for Vector Search Query Examples + +If you want to use the sample dataset for the examples in xref:run-vector-search-ui.adoc[] and xref:run-vector-search-sdk.adoc[], then you can xref:search:import-search-index.adoc[import] the following Search index definition into {page-ui-name}: + +[source,json] +---- +include::example$sample-vector-search-index-payload.json[] +---- + +NOTE: Make sure you imported the sample dataset with the recommended settings. + +This Vector Search index has a type mapping for a `color.rgb` collection and includes the following fields: + +* The *brightness number* field, which is included in search results and supports sorting and faceting. +* The *color string* and *description string* fields, which are included in search results, support highlighting, phrase matching, and sorting and faceting. +* The *colorvect_l2 [ number ]* field, which has a Dimension of `3` and uses the *l2_norm* Similarity Metric. +* The *embedding_vector_dot [ number ]* field, which has a dimension of `1536` and uses the *dot_product* Similarity Metric. + +== Next Steps + +This basic Vector Search index includes the vector embeddings from the child field you specified in your type mapping. +If you chose to add additional child fields and enabled *Include in search results*, the Search Service can also return data from those fields when you run a Vector Search query. + +For example, if you used the Vector Search sample data, you might want to add another child field for the *color* string field to your Vector Search index, to return color names with your Search query. +For more information about how to add additional child fields to your index, see xref:search:create-search-index-ui.adoc#add-mapping[Add Type Mappings and Mappings]. + +You can customize your Vector Search index like any other Search index to add additional data and improve search results. +For more information about how to customize an index, see xref:search:customize-index.adoc[]. + +CAUTION: Some Search index features are only available in Advanced Mode. +If you edit your Search index in Advanced Mode, you cannot make any additional edits in Quick Mode without losing all Advanced Mode settings. + +For more information about how to run a search against a Vector Search index, see xref:run-vector-search-ui.adoc[]. \ No newline at end of file diff --git a/modules/vector-search/pages/fine-tune-vector-search.adoc b/modules/vector-search/pages/fine-tune-vector-search.adoc new file mode 100644 index 000000000..235784d17 --- /dev/null +++ b/modules/vector-search/pages/fine-tune-vector-search.adoc @@ -0,0 +1,150 @@ += Fine-Tuning a Vector Search Query +:stem: asciimath +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Add additional parameters to a Vector Search query object to tune the search for recall or accuracy. + +[abstract] +{description} + + + +The Search Service automatically tunes your Vector Search indexes to achieve a balance between: + +* Recall, or the quality of your search results +* Latency, or your search response time +* Memory efficiency + +This tuning occurs during indexing and querying. +You do not need to adjust these parameters manually. + +Specifically, the Search Service dynamically adjusts two critical vector parameters: + +`nlist`, also known as `Centroid` count:: +The number of clusters used for indexing. +Centroids are used to quickly find the surrounding closest matches in the Vector Search index. +Increasing the number of centroids will increase accuracy but will decrease the speed of the search. ++ +The `nlist` is determined dynamically based on the size of the dataset, or the number of vectors in a partition: ++ +[%header, cols="3*a"] +|=== +| Number of vectors in partition (`nvec`) +| `Centroid count` (`nlist` calculation) +| Notes + +| stem:["nvec " ge " 200,000"] +| stem:[4 xx sqrt("nvec")] +| This formula is designed to handle larger datasets + where increasing the number of datasets does not yield significant improvements in recall. + +| stem:["1000" le "nvec" le "200,000" ] +| stem:["nvec" / 100] +| This formula targets approximately 100 vectors per cluster, +which balances between too few and too many clusters, ensuring efficient indexing. + +| stem:["nvec" lt 1000] +| N/A +| For a number of vectors less than 1000, the Search Service will carry out a straight forward one-to-one mapping between IDs and vectors with an exact vector comparison. +Vectors are directly stored without the need for additional processing for the `nlist` calculation. + +|=== + +`nprobes` (or `probes`):: +This is the number of `centroids` that a Search query will check for similar vectors. +The `nprobe` value is only set when the Search Service is using an Inverted File Index. The Search Service will select the best index type and comparison method depending on the size of the dataset and your `vector_index_optimized_for` setting. ++ +For more information on the `vector_index_optimized_for` setting, see xref:search:search-index-params.adoc#vector-index-optimized-param[Search Index JSON properties]. ++ ++ +[%header, cols="3*a"] +|=== +| Query optimization +| `nprobe` calculation +| Notes + + +| Default calculation +| stem:[sqrt("nlist")] +| This provides a balanced tradeoff between recall and latency by adjusting the number of clusters probed during queries. + +| Latency-optimized calculation (`vector_index_optimized_for: latency`) +| stem:[sqrt("nlist") / 2] +| A minimum value of 1 is enforced to avoid setting `nprobe` too low. + +|=== + +== Default `nlist` and `nprobe` calculations on a Vector Search Index + + +The cluster maintains two dynamically adjusted parameters that will affect the speed, accuracy, and resources used during a search: + +`ivf_nprobe_pct`:: +The percentage of clusters searched during queries, allowing for fine-tuning of the balance between recall and performance. +If the value of `nprobe` is 5% of `nlist` (the centroid count), then setting the value of `ivf_nprobe_pct` higher than 5% will have the search cover a higher percentage of clusters, which will improve the accuracy of the search. + +`ivf_max_codes_pct`:: +The value represents the percentage of `centroids` that will be visited during a search. +Reducing the value reduces the number of centroids visited, which will decrease accuracy and recall, but will result in faster compute times. The default value is 100 (i.e 100% of the centroids will be visited during the search). + + +.Default calculation +==== +If you have a Vector Search index with `vector_index_optimized_for` set to `"recall"` and `indexPartitions` set to `5`, then the `centroid count` (`nlist`) and `nprobe` are determined based on the current vector count in a given partition. +[options="noheader", frame="none", grid="none" cols="1,1"] + +|=== +| Total vectors in index (optimization = recall) +| 10,000,000 + +| Average vectors in a partition for 5 partitions total +| 2,000,000 + +| centroid count (`nlist`) = stem:[4 times sqrt("total vectors in index")] +| 5657 + +| nprobes = stem:[sqrt(nlist)] +| 75 + +| Calculated default: `ivf_nprobe_pct` +| 1.325% + +| Calculated default: `ivf_max_codes_pct` +| 100% (default value) + +|=== + +==== + +== Fine-Tuning Query Parameters + + +You can set the values of `ivf_nprobe_pct` and `ivf_max_codes_pct` in your Vector Search queries to tune the recall or accuracy of your search. + +You can add the following parameters to your query: + +[source, json] +.Using tuning parameters +---- +{ + "fields": ["*"], + "knn": [{ + "k": 10, + "params": { + "ivf_nprobe_pct": 1, + "ivf_max_codes_pct": 0.2 + }, + "field": "embedding", + "vector": [0.024901132253900747, . . .] + }] +} +---- + +In the preceding example, the Search request returns results from any available fields in the index, but specifically searches the `embedding` field for the `10` closest matches to the vector `[0.024901132253900747, . . .]`. +The vector in the Search request has been truncated to reduce the display size of the example. +The parameters have been set to search 1% of the clusters, and 0.2 per cent of the centroids. + + + + + diff --git a/modules/vector-search/pages/pre-filtering-vector-search.adoc b/modules/vector-search/pages/pre-filtering-vector-search.adoc new file mode 100644 index 000000000..f259fcf06 --- /dev/null +++ b/modules/vector-search/pages/pre-filtering-vector-search.adoc @@ -0,0 +1,61 @@ += Pre-filtering Vector Searches +:page-topic-type: guide +:page-ui-name: {ui-name} +:description: You can specify filters as part of a Vector Search query object to restrict the documents searched in a Search index. + +[abstract] +{description} + +== About Pre-filtering + +Using pre-filtering as part of your vector search offers two key advantages: + +. *Enhanced precision and relevance:* +Narrow your search results based on specific criteria, such as organization, date/time ranges, or geospatial locations. + +. *Performance optimization:* +Reduce the search space before executing queries to improve query execution time and reduce computational overhead. + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have a bucket with scopes and collections in your operational cluster. +For more information, see xref:cloud:clusters:data-service/manage-buckets.adoc[]. + +* You have created a Vector Search index. ++ +For more information about how to create a Vector Search index, see xref:create-vector-search-index-ui.adoc[]. ++ +[TIP] +-- +include::partial$download-sample-partial.adoc[] + +For the best results, consider using the sample Vector Search index from xref:create-vector-search-index-ui.adoc#example[Create a Vector Search Index with the {page-ui-name}]. +-- + +== Procedure + +To add pre-filtering to a Vector Search query: + +. On the *Operational Clusters* page, select the operational cluster where you created your Search index. +. Go to menu:Data Tools[Search]. +. Next to your Vector Search index, click btn:[Search]. +. In the *Search* field, enter a search query that includes a `filter` object with your `knn` object. ++ +For more information about the `filter` object, see xref:search:search-request-params.adoc#filter[filter]. +. Press kbd:[Enter] or click btn:[Search]. +. (Optional) To view a document and its source collection, click a document name in the search results list. + +=== Example: Pre-Filter A Vector Search Query For The Color "Navy" + +For example, the following Vector Search query tries to find matches to a color with an RGB value of `[176, 0, 176]` with a minimum brightness of `70` and a maximum of `80`. +A pre-filter on the query will narrow the documents searched inside the Vector Search index to documents that have a `color` field value that closely matches `navy`: + +[source, json] +---- +include::example$run-pre-filtered-vector-search-ui.json[] +---- + + diff --git a/modules/vector-search/pages/run-vector-search-sdk.adoc b/modules/vector-search/pages/run-vector-search-sdk.adoc new file mode 100644 index 000000000..64a16553f --- /dev/null +++ b/modules/vector-search/pages/run-vector-search-sdk.adoc @@ -0,0 +1,210 @@ += Run a Vector Search with a Couchbase SDK +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Using a Couchbase SDK, you can run a simple or more complex vector search against a Vector Search index. +:tabs: +:tabs-sync-option: + +[abstract] +{description} + +For more information about how the Search Service scores documents in search results, see xref:search:run-searches.adoc#scoring[Scoring for Search Queries]. + +[TIP] +==== +Not all available Couchbase SDK languages are covered by the examples on this page. + +For additional Vector Search examples, see the SDK documentation: + +xref:dotnet-sdk:howtos:full-text-searching-with-sdk.adoc#vector-search[.NET] | xref:cxx-sdk:howtos:vector-searching-with-sdk.adoc[C++] | xref:kotlin-sdk:howtos:full-text-search.adoc#vector-search[Kotlin] | xref:nodejs-sdk:howtos:full-text-searching-with-sdk.adoc#vector-search[Node.js] | xref:php-sdk:howtos:full-text-searching-with-sdk.adoc#vector-search[PHP] | xref:ruby-sdk:howtos:full-text-searching-with-sdk.adoc#vector-search[Ruby] | xref:scala-sdk:howtos:vector-searching-with-sdk.adoc[Scala] + +==== + +== Prerequisites + +Choose your preferred programming language to view the applicable prerequisites for the examples on this page. + +[{tabs}] +==== +Go:: ++ +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have the hostname for the node in your operational cluster that's running the Search Service. ++ +Go to your operational cluster settings and click btn:[Nodes] to view node hostnames. + +* You have created a Vector Search index. ++ +For more information about how to create a Vector Search index, see xref:create-vector-search-index-ui.adoc[]. ++ +[TIP] +-- +include::partial$download-sample-partial.adoc[] + +For the best results, consider using the sample Vector Search index from xref:create-vector-search-index-ui.adoc#example[Create a Vector Search Index in Quick Mode]. +-- + +* You have installed the Couchbase Go SDK. ++ +For more information about installing and using the Couchbase Go SDK, see xref:go-sdk:hello-world:start-using-sdk.adoc[]. + +Java:: ++ +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have the hostname for the node in your operational cluster that's running the Search Service. ++ +Go to your operational cluster settings and click btn:[Nodes] to view node hostnames. + +* You have created a Vector Search index. ++ +For more information about how to create a Vector Search index, see xref:create-vector-search-index-ui.adoc[]. ++ +[TIP] +-- +include::partial$download-sample-partial.adoc[] + +For the best results, consider using the sample Vector Search index from xref:create-vector-search-index-ui.adoc#example[Create a Vector Search Index in Quick Mode]. +-- + +* You have installed the Couchbase Java SDK. ++ +For more information about installing and using the Couchbase Java SDK, see xref:java-sdk:hello-world:start-using-sdk.adoc[]. + +Python:: ++ +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have the hostname for the node in your operational cluster that's running the Search Service. ++ +Go to your operational cluster settings and click btn:[Nodes] to view node hostnames. + +* You have created a Vector Search index. ++ +For more information about how to create a Vector Search index, see xref:create-vector-search-index-ui.adoc[]. ++ +[TIP] +-- +include::partial$download-sample-partial.adoc[] + +For the best results, consider using the sample Vector Search index from xref:create-vector-search-index-ui.adoc#example[Create a Vector Search Index in Quick Mode]. +-- + +* You have installed the Couchbase Python SDK. ++ +For more information about installing and using the Couchbase Python SDK, see xref:python-sdk:hello-world:start-using-sdk.adoc[]. + +* You have created and activated a virtual environment using `venv` and installed packages. ++ +For more information about how to set up your virtual environment, see https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/[the Python Packaging User Guide]. + +* You have made a `requirements.txt` file with the following: ++ +---- +couchbase==4.1.12 +openai==1.12.0 +---- + +* You have pulled in all dependencies for the Couchbase Python SDK by running: ++ +---- +pip install -r requirements.txt +---- +==== + +== Example: Searching for a Similar Color Vector + +The sample dataset inside `rgb.json` has small embedding vectors inside the `colorvect_l2` field. +These embedding vectors describe a color using RGB values. +For example, the color red has an embedding vector of `[255, 0, 0]`. + +The following example code searches for the color navy (`[0.0, 0.0, 128.0]`) in the `rgb.json` dataset: + +[{tabs}] +==== +Go:: ++ +[source,go] +---- +include::example$run-vector-search-simple-color.go[] +---- + +Java:: ++ +[source,Java] +---- +include::example$run-vector-search-simple-color.java[] +---- + +Python:: ++ +[source,python] +---- +include::example$run-vector-search-simple-color.py[] +---- +==== + + + +[#semantic] +== Example: Semantic Search with Color Descriptions + +[NOTE] +==== +The following code sample requires you to have a paid subscription to the OpenAI API to generate an embedding vector from a sample text string. +For more information about pricing for the OpenAI API, see https://openai.com/pricing[OpenAI's Pricing page^] for embedding models. + +The `rgb.json` sample data contains ready-made embedding vectors for each color's `description` text. +For an example of how to use a ready-made vector with Vector Search, see xref:run-vector-search-ui.adoc[]. +==== + +If you use the sample dataset inside `rgb.json`, you can use the OpenAI API to generate an embedding from any text string. + +The following code generates an embedding vector with the question `What color hides everything like the night?`: + +[{tabs}] +==== +Go:: ++ +[source,go] +---- +include::example$run-vector-search-generate-embed.go[] +---- + +Java:: ++ +[source,java] +---- +include::example$run-vector-search-generate-embed.java[] +---- + +Python:: ++ +[source,python] +---- +include::example$run-vector-search-generate-embed.py[] +---- +==== + +== Next Steps + +You can xref:search:create-search-index-ui.adoc#add-mapping[create an additional mapping] to update your Vector Search index to include the `description` field with your search results. + +For example, you could use the following JSON Vector Search index payload to create your Search index. +It includes two child field mappings, `colorvect_l2` and `embedding_vector_dot` on two different vector fields in the keyspace's documents. +It also adds 3 normal Search index fields (`brightness`, `color`, and `description`) to add more usable data to the Vector Search index: + +[source,json] +---- +include::example$vector-search-index-payload.jsonc[] +---- + +Run the example in <> again to see the `description` paragraphs in your results. + +Vector Search indexes can use the same settings and features as regular Search indexes. +If you want to add additional fields and features to your index, see xref:search:customize-index.adoc[]. \ No newline at end of file diff --git a/modules/vector-search/pages/run-vector-search-ui.adoc b/modules/vector-search/pages/run-vector-search-ui.adoc new file mode 100644 index 000000000..d42342608 --- /dev/null +++ b/modules/vector-search/pages/run-vector-search-ui.adoc @@ -0,0 +1,127 @@ += Run a Vector Search with the {page-ui-name} +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Run a Vector Search query from the Couchbase {page-ui-name} to preview and test the search results from a Vector Search index. + +[abstract] +{description} + +For more information about how the Search Service scores documents in search results, see xref:run-searches.adoc#scoring[Scoring for Search Queries]. + +== Prerequisites + +* You have the Search Service enabled on a node in your operational cluster. +For more information about how to change Services on your operational cluster, see xref:cloud:clusters:modify-database.adoc[]. + +* You have created a Vector Search index. ++ +For more information about how to create a Vector Search index, see xref:create-vector-search-index-ui.adoc[]. ++ +[TIP] +-- +include::partial$download-sample-partial.adoc[] + +For the best results, consider using the sample Vector Search index from xref:create-vector-search-index-ui.adoc#example[Create a Vector Search Index in Quick Mode]. +-- + +* You have logged in to the Couchbase {page-ui-name}. + +== Procedure + +To run a Vector Search with the {page-ui-name}: + +. On the *Operational Clusters* page, select the operational cluster where you created your Search index. +. Go to menu:Data Tools[Search]. +. Next to your Vector Search index, click btn:[Search]. +. In the *Search* field, enter a search query. +. Press kbd:[Enter] or click btn:[Search]. +. (Optional) To view a document and its source collection, click a document name in the search results list. + +[#similarity] +=== Example: Running a Simple Vector Similarity Query + +For example, the following query searches for the top 2 vectors similar to the vector `[ 0, 0, 128 ]` in the `colorvect_l2` field: + +[source,json] +---- +include::example$run-vector-search-payload-ui.jsonc[] +---- + +The Search query is only a Vector Search query. +It only returns the `k` number of similar vectors. + +The Search Service combines the Vector search results from a `knn` object with the traditional `query` object by using an `OR` function. +If the same documents match the `knn` and `query` objects, the Search Service ranks those documents higher in search results. + +The document for the color `navy` should be the first result, followed by a similar color. + +[#hybrid] +=== Example: Running a Simple Hybrid Search Query + +The following hybrid Search query searches for the top vector similar to the vector `[ 0, 0, 128 ]` in the `colorvect_l2` field. +It also runs a xref:search:search-request-params.adoc#numeric-range-queries[Numeric Range Query] on the `brightness` field to only return colors that have a brightness value between `70` and `80`: + +[source,json] +---- +include::example$run-hybrid-search-payload-ui.jsonc[] +---- + +The Search Service combines the Vector search results from a `knn` object with the traditional `query` object by using an `OR` function. +If the same documents match the `knn` and `query` objects, the Search Service ranks those documents higher in search results. + +The document for the color `navy` should be the first result, followed by colors that are similar and match the `brightness` field query. + +[#large] +=== Example: Running a Semantic Search Query with a Large Embedding Vector + +The following query searches for matches to a large embedding vector, generated by the https://platform.openai.com/docs/guides/embeddings[OpenAI embedding model^], `text-embedding-ada-002-v2`. + +TIP: You can find generated embedding vectors for each color's `description` field in `rgb.json`. + +This query should return the document for the color `navy`, based on a generated embedding vector for: + +---- +What is a classic, refined hue that exudes elegance and is often linked to power and stability? +---- + +The following shows part of the sample Search query: + +[source,json] +---- +include::example$run-vector-search-long-payload-ui.jsonc[tag=partial] +---- +[NOTE] +==== +Due to the size of the embedding vector, only part of the full query is being displayed in the documentation. + +Click btn:[View on GitHub] to view and copy the entire Vector Search query payload. +Make sure you remove the lines for `// tag::partial[]` and `// end::partial[]`. +==== + +[#base64] +=== Example: Running a Semantic Search Query with a base64 Encoded String + +If your operational cluster is running Couchbase Server version 7.6.2 or later, you can use vectors encoded as base64 strings with Vector Search. +For example, the following document describes the color `navy`, with base64 encoded strings in the `embedding_vector_dot` and `colorvect_l2` fields instead of arrays: + +[source,json] +---- +include::example$vector-search-base64-document-example.json[] +---- + +The following query uses a base64 encoded string for the same query as <> to return the document for `navy`: + +[source,json] +---- +include::example$run-vector-search-payload-base64-ui.jsonc[] +---- + +NOTE: You can only use base64 encoded strings in your Vector Search queries if your documents use base64 encoded strings, indexed with the *vector_base64* field data type. +You cannot search for and return vectors you indexed as arrays with the *vector* field data type by using a Search query with a base64 encoded string. + +== Next Steps + +If you do not get the search results you were expecting, you can change the xref:search:search-request-params.adoc[JSON payload for your Search query]. + +You can also xref:search:customize-index.adoc[add additional features to your Search index]. \ No newline at end of file diff --git a/modules/vector-search/pages/vector-search.adoc b/modules/vector-search/pages/vector-search.adoc new file mode 100644 index 000000000..e64100ba0 --- /dev/null +++ b/modules/vector-search/pages/vector-search.adoc @@ -0,0 +1,55 @@ += Use Vector Search for AI Applications +:page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use Couchbase {page-product-name}'s Vector Search features to add fast and accurate semantic search to your applications. + +[abstract] +{description} + +== About Vector Search + +Vector Search builds on Couchbase {page-product-name}'s xref:search:search.adoc[Search Service] to provide vector index support. +You can use these new Vector Search indexes for Retrieval Augmented Generation (RAG) with an existing Large Language Model (LLM). + +Using {page-product-name}'s Vector Search, an embedding model, and your chosen LLM, you can develop AI applications while giving context and up-to-date information from your own data. + +You can develop applications that include: + +* *Similarity search:* Search for documents, products, images, and more that are similar to a given query using vector embeddings. +By using vector embeddings, you can search based on descriptions, rather than using specific keywords and get intuitive and relevant results across data types. + +* *Semantic search*: Use natural language processing to deliver more accurate results based on an understanding of the intent and context behind a given search query, rather than simple keyword matches. + +* *Generative AI:* Create new original content, such as text and images, based on a prompt or a vector search given to an LLM. +Use generative AI to get tailored and dynamic responses across your applications. + +Vector Search supports integrations with frameworks like https://python.langchain.com/docs/get_started/introduction[LangChain^] to support AI application development. +For more information about all frameworks and integrations supported by Vector Search and {page-product-name}, see xref:third-party:integrations.adoc[]. + +== Using Vector Search Indexes + +To get started using Vector Search in {page-product-name}: + +. *Store data*: Store the data you want to use for your search or AI project in a {page-product-name} operational cluster. +. *Generate embeddings*: Generate vector embeddings from your data with your preferred embedding model. +. *Store your embeddings*: Store your vector embeddings in an array inside the documents in your {page-product-name} operational cluster. +. *Create a Vector Search index*: Create an index to use your embeddings and identify similar documents with vector similarity. + +In addition to supporting integrations with frameworks like LangChain and LlamaIndex, you can also use the API for an existing LLM and one of their embedding models to generate vector embeddings for your data. +For example, the OpenAI `embeddings` endpoint can generate embeddings for a text string using a specified embedding model. +You can then store that embedding as a new field in your documents. +For more information about how to generate and obtain embeddings for text strings using the OpenAI API, see the https://platform.openai.com/docs/guides/embeddings/what-are-embeddings[Embeddings documentation]. + +NOTE: When you create a Vector Search index, the xref:search:type-mapping-options.adoc#dimension[dimension] of your data vector embeddings must match the dimension for any search query vectors. +Otherwise, a Vector Search query fails to return any results. + +For more information about how to create a Vector Search index, see xref:create-vector-search-index-ui.adoc[]. + +For information about how to run a Vector Search query, see xref:run-vector-search-ui.adoc[]. + +== See Also + +* xref:search:search.adoc[] +* xref:create-vector-search-index-ui.adoc[] +* xref:run-vector-search-ui.adoc[] \ No newline at end of file diff --git a/modules/vector-search/partials/download-sample-partial.adoc b/modules/vector-search/partials/download-sample-partial.adoc new file mode 100644 index 000000000..3786ab73a --- /dev/null +++ b/modules/vector-search/partials/download-sample-partial.adoc @@ -0,0 +1,4 @@ +You can import a sample dataset to use with the procedure or examples on this page. + +Go to menu:Data Tools[Import] from your cluster and xref:clusters:data-service/import-data-documents.adoc#import-sample-data[import the vector-sample] sample data. + diff --git a/modules/vector-search/partials/nav.adoc b/modules/vector-search/partials/nav.adoc new file mode 100644 index 000000000..d76ee5320 --- /dev/null +++ b/modules/vector-search/partials/nav.adoc @@ -0,0 +1,6 @@ +* xref:cloud:vector-search:vector-search.adoc[] +** xref:cloud:vector-search:create-vector-search-index-ui.adoc[] +** xref:cloud:vector-search:pre-filtering-vector-search.adoc[] +** xref:cloud:vector-search:run-vector-search-ui.adoc[] +** xref:cloud:vector-search:run-vector-search-sdk.adoc[] +** xref:cloud:vector-search:fine-tune-vector-search.adoc[] diff --git a/preview/AV-68634-tutorial-feature-branch.yml b/preview/AV-68634-tutorial-feature-branch.yml new file mode 100644 index 000000000..fbcb9168f --- /dev/null +++ b/preview/AV-68634-tutorial-feature-branch.yml @@ -0,0 +1,6 @@ +sources: + docs-capella: + branches: [AV-68634-dev-tutorial-navigation] +override: + site: + startPage: cloud:get-started:intro.adoc diff --git a/preview/HEAD.yml b/preview/HEAD.yml new file mode 100644 index 000000000..8f4d638c9 --- /dev/null +++ b/preview/HEAD.yml @@ -0,0 +1,6 @@ +sources: + docs-capella: + branches: [main] +override: + site: + startPage: cloud:get-started:intro.adoc