Andrew
Andrew

Reputation: 63

couchdb match multiple inconsistent keys

Considering the following two documents:

{
   "_id": "a6b8d3d7e2d61c97f4285220c103abca",
   "_rev": "7-ad8c3eaaab2d4abfa01abe36a74da171",
   "File":"/store/document/scan_bgd123.jpg",
   "Commend": "Describes a person",
   "DateAdded": "2014-07-17T14:13:00Z",
   "Name": "Joe",
   "LastName": "Soap",
   "Height": "192cm",
   "Age": "25"
}

{
   "_id": "a6b8d3d7e2d61c97f4285220c103c4a9",
   "_rev": "1-f43410cb2fe51bfa13dfcedd560f9511",
   "File":"/store/document/scan_adf123.jpg",
   "Comment": "Describes a car",
   "Make": "Ford",
   "Year": "2011",
   "Model": "Focus",
   "Color": "Blue"
}

How would I find a document based on multiple criteria, say for example "Make"="Ford" and "Color"="Blue". I realize I need a view for this, but I don't know what the key is going to be, and as you can see from the two documents, the key/value pairs aren't consistent. The only consistent item will be the "File" key.

I'm attempting to create couchDB database that will store the location of files, but tagged with Key/Value pairs.

EDIT:

Perhaps I should reconsider my data structure. modify it slightly?

{
    "_id": "a6b8d3d7e2d61c97f4285220c103c4a9",
    "_rev": "1-f43410cb2fe51bfa13dfcedd560f9511",
    "File": "/store/document/scan_adf123.jpg",
    "Tags": {
        "Comment": "Describes a car",
        "Make": "Ford",
        "Year": "2011",
        "Model": "Focus",
        "Color": "Blue"
    }
}

So, I need to find by the Key>Value pair in the tag or any number of Key>Value pairs to filter which document I want. The problem here is, I want to tag objects with a key>value pair. These tags could be very different per view, so the next document will have a whole diff set of Key>Value pairs.

Upvotes: 1

Views: 159

Answers (1)

Akshat Jiwan Sharma
Akshat Jiwan Sharma

Reputation: 16000

Couchdb supports flexible schema. There is no need for the documents to be consistent for them to be query-able. The view for your scenario is pretty straightforward. Here is the map function that should do the trick.

function(doc){
if(doc.Make&&doc.Color)
emit([doc.Make,doc.Color],null);
}

This gives you a view which you can then query like

/view-name/key=["Ford","Blue"]&include_docs=true

This should give you the desired result.

Edit based on comment

For that you will need two separate views. Every view in couchdb is designed to fulfil a specific query need. This means that you have to think about access strategy of your data. It is a lot more work on your part initially but for the trouble you are rewarded with data that is indexed and has very fast access times.

So to answer your question directly. Create two views. One for Make like we have already done and other for Name like

function(doc){
if(doc.Name&&doc.LastName)
emit([doc.Name,doc.Name],null);
}

Now the Name view will index only those documents that have name in it. Where as Make view will index those documents that have make in it.

What happens when a requirement comes in future for which you don't have a query?

You can try a few things.

  1. This is probably the easiest solution. Use couchdb-lucene for your dynamic queries. In this case your architecture will be like couchdb views for queries that you know your application would need. Lucene index for queries that you don't know you might need. So for instance you have indexed name and last name in the in couchdb query. But a requirement arises and you might need to query by age then simply dump the age field in lucene and it will take care of the rest.

  2. Another approach is using the PPP technique where you exploit the fact that creating views is a one time cost and you can create views on less active hours and deploy them in a production service once they are built.

  3. Combine steps 1 and 2! lucene to handle adhoc request while you are building views using the ppp technique.

Upvotes: 1

Related Questions