0

My goals is to link two documents together and get back their details.

What are your CouchDB documents?

Car

{
    "_id": "car.123",
    "type": "car",
    "name": "Tesla",
    "model": "Semi Truck"
},
{
    "_id": "car.456",
    "type": "car",
    "name": "Tesla",
    "model": "Roadster"
}

Manufacturer

{
"_id": "manu.123",
"type": "manufacturer",
"name": "Tesla Inc.",
"cars": ["car.123", "car.456"]
}

How should the result look like?

Here I would like to use a List-Function and produce a HTML table as a result.

Name (Manufacturer) | Name (Car) | Model (Car)
------------------- | ---------- | ----------------
Tesla Inc.          | Tesla      | Semi Truck
Tesla Inc.          | Tesla      | Roadster 

Where do you stuck?

I'm having a hard time wrapping my head around the map function. This is as far as I got yet:

function(doc) {
    if (doc) {
        // Give me the ID and the name of the manufacturer 
        emit(doc._id, doc.name); 
        // Check if the document has at least one car in its array
        if (doc.cars < 0) {
            // Give me for every car their details (eg. name & model)
            for (var i in doc.cars) {
                emit(doc.name, {_id: doc.cars[i]});
            }
        }
    }
}

The query I use:
http://localhost:5984/my-db/_design/my-design/_view/my-view?key="Tesla Inc."&include_docs=true

The result from the list function:

ID       | Key        | Value
-------- | ---------- | ---------------
manu.123 | Tesla Inc. | [object Object]
manu.123 | Tesla Inc. | [object Object]

I use this list function:

function(head, req){
    start({
        'headers': {
            'Content-Type': 'text/html'
        }
    });
    send('<html><body><table>');
    send('<tr><th>ID</th><th>Key</th><th>Value</th></tr>')
    while(row = getRow()){
        send(''.concat(
            '<tr>',
            '<td>' + row.id + '</td>',
            '<td>' + row.key + '</td>',
            '<td>' + row.value + '</td>',
            '</tr>'
        ));
    }
    send('</table></body></html>');
}

The json output:

{
  "total_rows": 10,
  "offset": 8,
  "rows": [
    {
      "id": "manu.123",
      "key": "Tesla Inc.",
      "value": {
        "_id": "car.123"
      },
      "doc": {
        "_id": "car.123",
        "_rev": "1-7291266e7f81917fef1d0cfa104a39ca",
        "type": "car",
        "name": "Tesla",
        "model": "Semi Truck"
      }
    },
    {
      "id": "manu.123",
      "key": "Tesla Inc.",
      "value": {
        "_id": "car.456"
      },
      "doc": {
        "_id": "car.456",
        "_rev": "1-c5c67f5d5abeda1b77c02f003ec72a9f",
        "type": "car",
        "name": "Tesla",
        "model": "Roadster"
      }
    }
  ]
}

What is your exact question?

How can I replace [object Object] with the actual values of my cars (eg. name & model)?


The following resources I already conducted but they didn't help me:
CouchDB's Linked Documents in a View
couchdb views tied between two databases?
combine multiple documents in a couchdb view
Couchdb join two documents using key
CouchDB's Linked Documents in a View
Best way to do one-to-many "JOIN" in CouchDB

Magiranu
  • 299
  • 4
  • 27

2 Answers2

1

In your example, row.value equals to an object, in one of the cases:{ "_id": "car.123" }. In JavaScript, when you try to concatenate a string with an object, you will get [object Object], which is happening in your list function: '<td>' + row.value + '</td>'.

So, if you wanted to display the _id, you could do: '<td>' + row.value._id + '</td>'. But you are asking to display name and model. Looking into the json file, that information is under the doc key. So it seems what you are looking for is:

'<td>' + row.doc.name + ' ' + row.doc.model + '</td>'

Ignacio
  • 688
  • 5
  • 17
1

In addition to the previous answer by Ignacio, you can improve two things in your document design.

  • Add the manufacturer's _id to the car, not an array of car _id to the manufacturer. This way, you don't have to deal with inconsistent data: When you delete a car document you don't have to also edit the manufacturer. This is especially important in multi-user scenarios. What if one user adds a car, while another removes a car of the same manufacturer? This might lead to conflicts and inconsistent data.
  • You can also denormalize your data by additionally putting the manufacturer's name into the car document. This way, you don't have to join the documents. CouchDB excels when data is mostly read (such as in typical web or mobile applications), so you should normally also optimize for reading. Also the map/reduce queries will be MUCH easier to write.
Bernhard Gschwantner
  • 1,547
  • 11
  • 12