1

I'm having confusion about whether to use selector or views, or both, when try to get a result from the following scenario:

I need to do a wildsearch for a book and return the result of the books plus the price and the details of the store branch name.

So I tried using selector to do wildsearch using regex

"selector": {
              "_id": {
                "$gt": null
              },
              "type":"product",
              "product_name": {
                "$regex":"(?i)"+search
              }
            },
            "fields": [
              "_id",
              "_rev",
              "product_name"
           ]

I am able to get the result. The idea after getting the result is to use all the _id's from the result set and query to views to get more details like price and store branch name on other documents, which I feel is kind of odd and I'm not certain is that the correct way to do it.

Below is just the idea once I get the result of _id's and insert it as a "productId" variable.

  var input = {
        method : 'GET',
        returnedContentType : 'json',
        path : 'test/_design/app/_view/find_price'+"?keys=[\""+productId+"\"]",      

              };
              return WL.Server.invokeHttp(input);

so I'm asking for input from an expert regarding this.

Another question is how to get the store_branch_name? Can it be done in a single view where we can get the product detail, prices and store branch name? Or do I need to have several views to achieve this?

expected result

product_name (from book document) :   Book 1 
branch_name  (from branch array in Store document) : store 1 branch one    
price ( from relationship document) : 79.9

References:

Book

  "_id": "book1",
  "_rev": "1...b",
  "product_name": "Book 1",
  "type": "book"

  "_id": "book2",
  "_rev": "1...b",
  "product_name": "Book 2 etc",
  "type": "book"

relationship

  "_id": "c...5",
  "_rev": "3...",
  "type": "relationship",
  "product_id": "book1",
  "store_branch_id": "Store1_branch1",
  "price": "79.9"

Store

{
  "_id": "store1",
  "_rev": "1...2",
  "store_name": "Store 1 Name",
  "type": "stores",
  "branch": [
    {
      "branch_id": "store1_branch1",
      "branch_name": "store 1 branch one",
      "address": {
        "street": "some address",
        "postalcode": "33490",
        "type": "addresses"
      },
      "geolocation": {
        "coordinates": [
          42.34493,
          -71.093232
        ],
        "type": "point"
      },
      "type": "storebranch"
    },
    {
      "branch_id": "store1_branch2",
      "branch_name": 
        **details ommit...**

    }
  ]
}
Joshua Beckers
  • 857
  • 1
  • 11
  • 24
kkurni
  • 15
  • 1
  • 2

1 Answers1

2

In Cloudant Query, you can specify two different kinds of indexes, and it's important to know the differences between the two.

For the first part of your question, if you're using Cloudant Query's $regex operator for wildcard searches like that, you might be better off creating a Cloudant Query index of type "text" instead of type "json". It's in the Cloudant docs, but see the intro blog post for details: https://cloudant.com/blog/cloudant-query-grows-up-to-handle-ad-hoc-queries/ There's a more advanced post on this that covers the tradeoffs between the two types of indexes https://cloudant.com/blog/mango-json-vs-text-indexes/

It's harder to address the second part of your question without understanding how your application interacts with your data, but there are a couple pieces of advice.

1) Consider denormalizing some of this information so you're not doing the JOINs to begin with.

2) Inject more logic into your document keys, and use the traditional MapReduce View indexing system to emit a compound key (an array), that you can use to emulate a JOIN by taking advantage of the CouchDB/Cloudant index sorting rules.

That second one's a mouthful, but check out this example on YouTube: https://youtu.be/0al1KnCKjlA?t=23m39s

Here's a preview (example map function) of what I'm talking about:

'map' : function(doc)
    {
        if (doc.type==="user") {
                emit( [doc._id], null );
        }
        else if (doc.type==="edge:follower") {
            emit( [doc.user, doc.follows], {"_id":doc.follows} );
        }
    }

The resulting secondary index here would take advantage of the rules outlined in http://wiki.apache.org/couchdb/View_collation -- that strings sort before arrays, and arrays sort before objects. You could then issue range queries to emulate the results you'd get with a JOIN.

I think that's as much detail that's appropriate for here. Hope it helps!

brobes
  • 706
  • 3
  • 7
  • thank you for the answer and sorry for just replying back now, probably I'm not really clear enough about what I'm trying to do in my explanation. in summary, I only want to list out the list of the books with the store branch and the prices. with the documents given above. I actually already denormalize the store and store branch by combining them into 1 documents. but the rest I don't think I can denormalize it again. – kkurni Apr 01 '16 at 16:05
  • Regarding the 2nd question, I actually have the difficulties to reference the store branch id in single query. my "Relationship" docs having product_id, store_branch_id, and price. The issue is I don't know how to references the store_branch_id with branch[].branch_id in Store document because is a nested object – kkurni Apr 01 '16 at 16:12