couchdbpouchdb

PouchDB/CouchDB Group By Value in Array


I am using PouchDB and I have a dataset representing a social network in a graph. People are documents, and the people they follow are in an array of the _id of the person followed. Here is a sample of the data:

[
    {
        "_id": "mc0001",
        "name": "Jill Martin",
        "joined": "2020-01-15",
        "follows": []
    },
    {
        "_id": "mc0002",
        "name": "Elena Markova",
        "joined": "2020-01-21",
        "follows": ["mc0001"]
    },
    {
        "_id": "mc0003",
        "name": "Carlos Sanchez",
        "joined": "2020-01-27",
        "follows": ["mc0001", "mc0002"]
    },
    {
        "_id": "mc0004",
        "name": "Ai Sato",
        "joined": "2020-02-21",
        "follows": ["mc0001", "mc0003"]
    },
    {
        "_id": "mc0005",
        "name": "Ming Wu",
        "joined": "2020-03-21",
        "follows": ["mc0002", "mc0003", "mc0004"]
    }
]

What I would like to do is query for each person, and get a list of followers. I am looking for something like this:

[
    {
        "_id": "mc0001",
        "followers": ["mc0002", "mc0003", "mc0004"]
    },
    {
        "_id": "mc0002",
        "followers": ["mc0003", "mc0005"]
    },
    {
        "_id": "mc0003",
        "followers": ["mc0004", "mc0005"]
    },
    {
        "_id": "mc0004",
        "followers": ["mc0005"]
    },
    {
        "_id": "mc0005",
        "followers": []
    }
]

Is there a way to do this without changing the data structure (e.g. moving the followers array into the doc of the person being followed)?


Solution

  • Create a Map/Reduce view that loops through the follows array in each document and emits those; like this:

    function (doc) {
      for(var i =0; i<doc.follows.length; i++) {
        emit(doc.follows[i], null);
      }
      
    }
    

    You end up with an index keyed on a user and where each row has the id of a follower of that user. You can then query the index, supplying the key of the user whose followers you want to find, like this:

    $URL/users/_design/users/_view/by-follower?key="mc0001"&reduce=false
    

    You will get something like this:

    {"total_rows":8,"offset":0,"rows":[
    {"id":"mc0002","key":"mc0001","value":null},
    {"id":"mc0003","key":"mc0001","value":null},
    {"id":"mc0004","key":"mc0001","value":null}
    ]}
    
    

    This is not exactly the format of the data you have in your question, but you can see that the id field in each object contains a follower of your desired user, so you can go from there.