CouchDB indexes to connect the dots between documents - couchdb

I have the following documents:
{ _id: "123", type: "project", worksite_id: "worksite_1" }
{ _id: "456", type: "document", project_id: "123" }
{ _id: "789", type: "signature", document_id: "456" }
My goal is to run a query and to inevitably do a filtered replication of all documents that have a connection with worksite_id: worksite_1.
Example:
Because this project has the worksite I am looking for
document has that project
signature has that document
I should be able to retrieve all of these documents if I want everything from that worksite.
Normally I would just add a worksite_id to my type:document and type:signature. However, worksite's can change in a project for various reasons.
I was wondering if there is a way to create an index or do something I am not thinking about to show these resemblances.
This feels like it is on the right path but the explanation puts documents inside other documents where I just want them to be separate.

A map function only considers one document at a time, so unless that document knows about other documents, you can't link them together. Your structure implies a three-table join in SQL terms.
With your structure, the best you can hope for is a two-request solution. You can create a view that shows signed documents only:
function (doc) {
if (doc && doc.type && doc.type === "signature" && doc.document_id) {
emit(doc.document_id, {_id: doc.document_id})
}
}
and using the same technique, link projects to documents -- but you can't get all three linked.

I think I have what you are looking for.
Here's some data:
{
"docs": [
{
"_id": "123",
"type": "project",
"code": "p001"
},
{
"_id": "1234",
"type": "worksitelog",
"documents": [
{
"timestamp": "20180921091501",
"project_id": "123",
"document_id": "457",
"signature_id": "789"
},
{
"timestamp": "20180921091502",
"project_id": "123",
"document_id": "457",
"signature_id": "791"
},
{
"timestamp": "20180921091502",
"project_id": "123",
"document_id": "458",
"signature_id": "791"
},
{
"timestamp": "20180921091502",
"project_id": "123",
"document_id": "456",
"signature_id": "790"
}
],
"worksite_id": "worksite_2"
},
{
"_id": "1235",
"type": "worksitelog",
"documents": [
{
"timestamp": "20180913101502",
"project_id": "125",
"document_id": "459",
"signature_id": "790"
}
],
"worksite_id": "worksite_1"
},
{
"_id": "124",
"type": "project",
"code": "p002"
},
{
"_id": "125",
"type": "project",
"code": "p003"
},
{
"_id": "456",
"type": "document",
"code": "d001",
"project_id": "123",
"worksite_id": "worksite_2"
},
{
"_id": "457",
"type": "document",
"code": "d002",
"project_id": "123",
"worksite_id": "worksite_2"
},
{
"_id": "458",
"type": "document",
"code": "d003",
"project_id": "123",
"worksite_id": "worksite_2"
},
{
"_id": "459",
"type": "document",
"code": "d001",
"project_id": "125",
"worksite_id": "worksite_1"
},
{
"_id": "789",
"type": "signature",
"user": "alice",
"pubkey": "65ab64c64ed64ef41a1bvc7d1b",
"code": "s001"
},
{
"_id": "790",
"type": "signature",
"user": "carol",
"pubkey": "tlmg90834kmn90845kjndf98734",
"code": "s002"
},
{
"_id": "791",
"type": "signature",
"user": "bob",
"pubkey": "asdf654asdf6854awer654awer654eqr654wra6354f",
"code": "s003"
},
{
"_id": "_design/projDocs",
"views": {
"docsPerWorkSite": {
"map": "function (doc) {\n if (doc.type && ['worksitelog', 'document', 'project', 'signature'].indexOf(doc.type) > -1) {\n if (doc.type == 'worksitelog') {\n emit([doc.worksite_id, 0], null);\n for (var i in doc.documents) {\n emit([doc.worksite_id, Number(i)+1, 'p'], {_id: doc.documents[i].project_id});\n emit([doc.worksite_id, Number(i)+1, 'd'], {_id: doc.documents[i].document_id});\n emit([doc.worksite_id, Number(i)+1, 's'], {_id: doc.documents[i].signature_id});\n }\n }\n }\n}"
}
},
"language": "javascript"
}
]
}
Save that data to disk as stackoverflow_53752001.json.
Use Fauxton to create a database called stackoverflow_53752001.
Here's a bash script to load the data from the file stackoverflow_53752001.json into the databasestackoverflow_53752001`. You'll need to edit the first three parameters, obviously. Fix it, then paste it into a (Unix) terminal window:
USRID="you";
USRPWD="yourpwd";
HOST="yourdb.yourpublic.work";
COUCH_DATABASE="stackoverflow_53752001";
FILE="stackoverflow_53752001.json";
#
COUCH_URL="https://${USRID}:${USRPWD}#${HOST}";
FULL_URL="${COUCH_URL}/${COUCH_DATABASE}";
curl -H 'Content-type: application/json' -X POST "${FULL_URL}/_bulk_docs" -d #${FILE};
In Fauxton, select database stackoverflow_53752001 and then, in the left-hand menu select "Design Documents" >> "projDocs" >> "Views" >> "docsPerWorkSite".
You'll see data like this:
{"total_rows":17,"offset":0,"rows":[
{"id":"1235","key":["worksite_1",0],"value":null},
{"id":"1235","key":["worksite_1",1,"d"],"value":{"_id":"459"}},
: :
: :
{"id":"1234","key":["worksite_2",4,"p"],"value":{"_id":"123"}},
{"id":"1234","key":["worksite_2",4,"s"],"value":{"_id":"790"}}
]}
If you then click on the "Options" button, in the top right, you'll get an option sheet for modifying the raw query. Pick:
"Include Docs"
"Between Keys"
"Start key" : ["worksite_1", 0]
"End key" : ["worksite_1", 9999]
Hit "Run Query", and you should see:
{"total_rows":17,"offset":0,"rows":[
{"id":"1235","key":["worksite_1",0],"value":null,"doc":{"_id":"1235","_rev":"1-de2b919591c70f643ce1005c18da1c54","type":"worksitelog","documents":[{"timestamp":"20180913101502","project_id":"125","document_id":"459","signature_id":"790"}],"worksite_id":"worksite_1"}},
{"id":"1235","key":["worksite_1",1,"d"],"value":{"_id":"459"},"doc":{"_id":"459","_rev":"1-5422628e475bab0c14e5722a1340f561","type":"document","code":"d001","project_id":"125","worksite_id":"worksite_1"}},
{"id":"1235","key":["worksite_1",1,"p"],"value":{"_id":"125"},"doc":{"_id":"125","_rev":"1-312dd8a9dd432168d8608b7cd9eb92cd","type":"project","code":"p003"}},
{"id":"1235","key":["worksite_1",1,"s"],"value":{"_id":"790"},"doc":{"_id":"790","_rev":"1-be018df4ecdf2e6add68a2758b9bd12a","type":"signature","user":"carol","pubkey":"tlmg90834kmn90845kjndf98734","code":"s002"}}
]}
If you then change the start and end keys to ["worksite_2", 0] and ["worksite_2", 9999] you will see the data for the second work site.
For this to work, each time you have written a new document and signature to the database, you'll need to:
prepare an object {
"timestamp": "20180921091502",
"project_id": "123",
"document_id": "457",
"signature_id": "791"
}
get the corresponding work site log record
append the object to the documents array
put back the altered work site log record
I assumed there are multiple signatures per document, so you'll have to write a log record for each and every one of them. If that grows too big you can change worksite_id to something like worksite_1_201812, which would give one log per work site per month with out breaking the query logic, I think.

Related

How to find data based on sub-field name in MongoDB using Mongoose?

There is a sub-field called 'name' in MongoDB Collection (User):
[
{
"teacher": {
"name": "Alex",
"email": "alex#domain.com"
},
"waiter": {
"name": "Feliks",
"email": "feliks#domain.com"
},
"pilot": [
{
"name": "Sam",
"email": "sam#domain.com"
},
{
"name": "alice",
"email": "alice#domain.com"
}
],
},
{
"teacher": {
"name": "max",
"email": "max#domain.com"
},
"waiter": {
"name": "Sam",
"email": "sam#domain.com"
},
"pilot": [
{
"name": "richard",
"email": "richard#domain.com"
},
{
"name": "alice",
"email": "alice#domain.com"
}
],
}
]
How can I find data based on the field 'name'. For example, when I'm looking for 'Sam', it should return me the all documents since 'Sam' is in "waiter" and "pilot" in first and second documents respectively.
I cannot do something like:
User.find({"teacher.name": "Sam", "waiter.name": "Sam", "pilot.name": "Sam" })
This will return me nothing as it is an AND logic. What I need is an OR logic.
You can use the $or operator.
So the query should look like this:
User.find({ $or: [
{ "teacher.name": "Sam" },
{ "waiter.name": "Sam" },
{ "pilot.name": "Sam" }
]
});
Read here for me details.

How to query nested object in mongodb

I'm new to mongodb and I've been trying to query this doc for awhile now.
Im trying to query all the rooms that have a room name of 100.
json
{
"count": 3,
"reviews": [
{
"_id": "5f9d42a0a8e71e004643f584",
"user": {
"_id": "5f7308cde0a4a7a66bc3d184",
"name": "Guest"
},
"room": {
"_id": "5f98f9321fd5bb0045b3d886",
"name": "100",
},
"rating": 4,
},
{
"_id": "5f9d431ea8e71e004643f585",
"user": {
"_id": "5f7308cde0a4a7a66bc3d184",
"name": "Guest",
},
"room": {
"_id": "5f98f9321fd5bb0045b3d886",
"name": "100",
},
"rating": 5,
},
{
"_id": "5f9e74fea6c06a0046d3cae2",
"user": {
"_id": "5f7308cde0a4a7a66bc3d184",
"name": "Guest",
},
"room": {
"_id": "5f98fa8b1fd5bb0045b3d88a",
"name": "300",
},
"rating": 5,
}
]}
what I've tried
1. find({},{"reviews.room.name": {$eq: "100"}}) // getting a projection error
2. find({"reviews.room.name": "100"}) // getting null
Any help to the right direction would be greatly appreciated.
Check out the docs about how to use find:
https://docs.mongodb.com/manual/reference/method/db.collection.find/
and try this
db.reviews.find({
"room.name": "100"
})
Here is the playground with your example: https://mongoplayground.net/p/dPfH5fSOePq
did u try this ? const response = await Room.find({name: "100"})

How to query all documents where array field have at least one object-element with property equal 'X'?

I have some MongoDB documents like that:
{
"group": "P32666",
"order": [{
"_id": {
"$oid": "5e8e9b40e7999f6b90fd88bf"
},
"name": "Dmitriy A",
"login": "example",
"password": "example",
"email": "example",
"level": "user",
"uuid": "b6a19744-bb20-4d39-9e1e-0ca5b464f890"
}, {
"_id": {
"$oid": "5e8ea03f5a21c26b90983de4"
},
"name": "Dmitriy B",
"login": "example",
"password": "example",
"email": "example",
"level": "user",
"uuid": "556924c3-605c-44cc-8a26-d32f58222e89"
}, {
"_id": {
"$oid": "5e8ea0645a21c26b90983de5"
},
"name": "Dmitriy C",
"login": "example",
"password": "example",
"email": "example",
"level": "user",
"uuid": "aef00707-ef00-4ce9-918b-5cef17e7280b"
}]}
I'm working with Mongo in Mongoose and can't understand how to query all documents(like above) where field(array) "order" has at least one object within where field, for example, "login" is queal to "example". How can I do this?
I tried something like this:
export async function getQueues(request: Request, response: Response) {
const returningQueues = await queues.find({order: [login: request.params.login]});
response.json(returningQueues);
But TypeScript error (56 missing properties(mostly internal Mongoose's) of type "User", which I store within an array) says that's I am wrong in my thoughts.
If you just have one condition on the array field, you can simply do:
queues.find({"order.login": request.params.login})
But if you have multiple conditions, you can use $elemMatch:
queues.find({
order: { $elemMatch: { login: request.params.login, name: request.params.name } }
})

convert to asc order of array data using MongoDB

how to make this data to asc order by user's first name and user's last name.
I got the response, want to sort the records by user's first name but it is taking from creation date I guess when using sort how can I make it base on user's first name and user's last name please guide
{
"response": {
"items": [
{
"_id": "5e71f86bd300b313df52fb2f",
"last_message": {
"text": "Alex",
"users": [
{
"_id": "5e4a8d2d3952132a08ae5764",
"first_name": "zack",
"last_name": "Write"
}
]
},
"texter": [
"alex",
"$0ctg"
],
"title": "New group1",
"group": true,
"members": [
{
"_id": "5e4a8afc3952132a08ae575e",
"first_name": "test3",
"last_name": "test4"
}
],
"managers": [
"5e4a8afc3952132a08ae575e"
],
"member": {
"_id": "5e4a8afc3952132a08ae575e",
"first_name": "test3",
"last_name": "test4"
}
},
{
"_id": "5e4e740f380054797d9db621",
"last_message": {
"text": "",
"users": [
{
"_id": "5e4a8d2d3952132a08ae5764",
"first_name": "yuhan",
"last_name": "jacob"
}
]
},
"texter": [
"",
"",
"",
"",
"",
"new iphone x\n brand new iphone wv wwvqzwzvq had sqswgscq wow you wholeheartedly q \n $600.00",
"helo",
"hello",
"hi"
],
"members": [
{
"_id": "5e4d0973babf2b74ca868f4d",
"first_name": "alex",
"last_name": "hales"
}
],
"managers": [],
"member": {
"_id": "5e4d0973babf2b74ca868f4d",
"first_name": "alex",
"last_name": "hales"
}
}
]
}
}
Tried
{
$sort: {
users: 1,
}
},
doesn't help much
Also if I would like to add two field asc desc order what would be the process in MongoDB
Try this hope this will help you !
{
$sort: { "users.first_name": 1 }
},

Commercetools - Use query predicates to filter on a collection attribute

I'd like to get all the Category items that have between their ancestors an ancestor with a certain "id".
Here is the JSON of one of the categories returned by GETting from /categories:
{
"id": "4627f3b0-fe52-4cc6-b03e-3fd72e701342",
"version": 1,
"lastMessageSequenceNumber": 1,
"createdAt": "2019-02-18T13:48:51.677Z",
"lastModifiedAt": "2019-02-18T13:48:51.677Z",
"lastModifiedBy": {
"clientId": "_anonymous"
},
"createdBy": {
"clientId": "_anonymous"
},
"key": "snowboard-gloves",
"name": {
"en": "Snowboard Gloves"
},
"slug": {
"en": "snowboard-gloves"
},
"description": {
"en": "Gloves specifically designed for snowboarding"
},
"ancestors": [
{
"typeId": "category",
"id": "b27086d2-33f2-43c3-aad1-4c01b2b9a886"
}
],
"parent": {
"typeId": "category",
"id": "b27086d2-33f2-43c3-aad1-4c01b2b9a886"
},
"orderHint": "0.000016",
"metaTitle": {
"en": "Snowboard Gloves"
},
"metaDescription": {
"en": "Gloves specifically designed for snowboarding"
},
"assets": []
}
I'd like to call the /categories API with a where clause on ancestors[x].id = "b27086d2-33f2-43c3-aad1-4c01b2b9a886" but from the documentation I don't understand how I should write the query predicate.
Can anyone help me?
The query predicate follows the structure of the json response. Nested fields are accessed with () brackets.
Try this out
ancestors(id = "idb27086d2-33f2-43c3-aad1-4c01b2b9a886")

Resources