diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 43b7a3c..82acf96 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,6 +1,8 @@ services: couchdb: - image: couchdb:3.1.1 + build: + context: .. + dockerfile: Dockerfile environment: - COUCHDB_USER=admin - COUCHDB_PASSWORD=secret @@ -9,6 +11,12 @@ services: - ../seed:/opt/couchdb/seed:ro ports: - "5984:5984" + healthcheck: + test: ["CMD", "curl", "-sf", "http://localhost:5984/_up"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 15s networks: - statusdb-network @@ -20,7 +28,8 @@ services: networks: - statusdb-network depends_on: - - couchdb + couchdb: + condition: service_healthy volumes: couchdb-data: diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 58e02cc..d44f241 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -22,6 +22,7 @@ env: jobs: build-and-push: + if: false # Disable this job for now runs-on: ubuntu-latest permissions: contents: read diff --git a/.gitignore b/.gitignore index 89e7a05..bfe67f2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ venv/ ENV/ env.bak/ venv.bak/ +design_docs_build/ DS_Store diff --git a/DATABASES.md b/DATABASES.md new file mode 100644 index 0000000..77956af --- /dev/null +++ b/DATABASES.md @@ -0,0 +1,228 @@ +# Database Documentation + +This file documents the purpose and contents of each CouchDB database in the seed data. + +--- + +## `agreement_templates` + +Storing templates used to create user agreements. One document per template. Seems to be both versions (different documents) and editions (updates of document)? + +--- + +## `agreements` + +Stores user agreements created in Genomics Status, connected to the cost calculator implementation in Genoimcs Status. + +--- + +## DEPRECATED: `analysis` + +Summary statistics from various analysis, likely updated from `Piper` or similar since its not updated anymore. Likely stopped being updated around 2020 or similar. + +--- + +## `application_categories` + +Listing our application categories and abrevation, with one document per application. Used by the statistics api of genstat which in turn feeds the dashboard. + +--- + +## `bioinfo_analysis` + +Listing status flags for bioinfo tab on Genomics Status. One document per sample-flowcell-lane combination, which gets problematic when setting a status on flowcell level when there is a lot of samples on many lanes. +Documents are created by ngi-pipeline or TACA and statuses can be set from Genomics Status UI. + +--- + +## `biomek_logs` + +Short log messages from the biomek runs. + +--- + +## `charon` + +Huge database tracking sample status on the bioinfo side. Database for the Charon web application which has up to 2025 also been used by the Uppsala node of NGI. Lots of different types of documents with different content and structure. + +--- + +## `cost_calculator` + +Storing the prices for our different offerings. One document per version of the cost calculator. Updated from Genomics Status and used by Genomics Status to display cost and generate agreements. + +--- + +## `cronjobs` + +Storing the output of `crontab -l` for different users and servers, updated by TACA in a cronjob, and displayed on Genomics Status. One document per server, with different users appended to the document. + +--- + +## `element_runs` + +Flowcells database for the Element Bioisciences sequencing instrument. Created by TACA and displayed on Genomics Status. + +--- + +## DEPRECATED `expected_yields` + +One document per run mode and sequencer. Not sure where this is used. + +--- + +## [NOT UPDATED] `flowcells` + +Illumina flowcells database used for pre HiSeq-X. Not updated after 2016. But still searchable in genstat and also likely possible to list in project lists. + +## `flowcell_status` + +A database to track the transfer status of all flowcells handled by the transfer script introduced with Project Helix. Updated every hour using a cronjob on ngi-preproc. Was previously called y_flowcells, because we tried to be funny. + +--- + +## `gs_configs` + +Miscelaneous config files used for genomics status. + +--- + +## `gs_links` + +Tracking the links added to projects on Genomics Status. One project link per document. + +--- + +## `gs_users` + +Genomics Status users, one document for each user. Keeps track of Initials, roles and user presets. + +--- + +## DEPRECATED `instrument_logs` + +Instrument logs very similar to the biomek_logs databse, but seems to have been used by the Bravo computers, last update was August 2025 but I think the Bravo computers were taken offline after that. + +--- + +## `instruments` + +Might be out of date, used by fc_trends plot to name the instruments. A database to list all sequencing instrument IDs and corresponding names. Can be replaced with a gs_config document. + +--- + +## `nanopore_runs` + +The flowcells database for ONT. One document per flowcell and run. A reused flowcell will generate a new document. + +--- + + +## `people_assignments` + +Keeps track of assignment of people to projects. Used in Genomics Status project cards and the project page introduced around 2025. + +--- + +## [DEPRECATED] `pricing_components` + +Was used for cost calculator on Genstat before it was actually launched. The information is now instead baked into cost_calculator documents. + +--- + +### `pricing_exchange_rates` + +Tracking exchange rates USD to SEK and EUR to SEK. Keeping a historical record so we can rewind time when changing agreements that was generated some time ago and we would like to keep the same exchange rate. One document per update, updated weekly by a cronjob. + +--- + +## [DEPRECATED] `pricing_products` + +Was used for cost calculator on Genstat before it was actually launched. The information is now instead baked into cost_calculator documents. + +--- + +## `projects` + +One of the major databases that has been around from the start. One document per project. Since it has been around so long, there might be some differences in format/missing fields in documents from different years. + +--- + +## [Might be DEPRECATED] `reference` + +Seems to be a mapping between fields we use in genstat or in other places and how we fetch them from LIMS. Not sure if its used. + +--- + + +## `running_notes` + +Keeps all the running notes, one document per note. A partitioned database, which is a bit different, the partition key is the `parent` of the running note, which is commonly the specific project, workset or flowcell. + +--- + +## [WARNING] `sample_requirements` + +Never made it into use, was supposed to keep track of sample requirements for different preps. Still visible on Genomics Status. + +--- + +## [DEPRECATED] `samples` + +Seems to track and document QC runs. Seems to have stopped udpating around 2016. + +## `sensorpush` + +Uploades time series data for our freezers and fridges that are connected with a sensorpush sensor. One document per sensor and 24h. Data is uploaded by a script running on ngi_internal polling the sensorpush API. We suspect that the API isn't great and sometimes misses out data, but it could also be sensors that drop out. + +Data is visualized on Genomics Status. + +--- + +## `server_status` + +Tracking storage of server file systems, used to display status on Genomics Status index page. One document per server/system and day. Updated by a TACA command run as a cronjob on ngi-preproc. It's a bit broken since the script is using `df -h` and the network mounted storage systems are not always giving correct stats for that command. + +--- + +## `suggestion_box` + +Keeps track of which items have been added to the suggestion box. Keeps a link to the Jira item and whether its been archived or not. + +--- + +## [DEPRECATED] `taca_flowcells` + +Abandoned project for taca to uploade flowcells I think. Only one document and uploaded 2015. + +--- + +## `userman` + +Database to keep track of the Charon users. + +--- + +## `worksets` + +The worksets database populated by LIMS2DB. One document per workset. + +--- + +## `x_flowcells` + +The Illumina flowcells database, updated by TACA and visualised on Genomics Status. Was named `x` since it was introduced with the HiSeq X machines which had a very different metadata output from the previous generation. + +--- + +## [DEPRECATED] `y_flowcells` + +The name was chosen because it comes after x_flowcells. Was renamed to flowcell_status so that we understand what it is about. + +--- + +## `yggdrasil` + +Internal database used by yggdrasil for high level logging. + +--- \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c694abb..5d055b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,12 +3,18 @@ FROM couchdb:3.4 # Install curl for healthchecks and data loading RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ + python3-pip \ + python3-yaml \ && rm -rf /var/lib/apt/lists/* # Copy seed data and initialization scripts -COPY seed/ /opt/couchdb/seed/ +COPY seed_data/ /opt/couchdb/seed_data/ COPY scripts/ /opt/couchdb/scripts/ +# Copy views configuration and design documents +COPY views_config.yaml /opt/couchdb/views_config.yaml +COPY StatusDB_views/ /opt/couchdb/StatusDB_views/ + # Make scripts executable RUN chmod +x /opt/couchdb/scripts/*.sh diff --git a/README.md b/README.md index 477ebff..2c93bc9 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,111 @@ -# StatusDB Seed Data +# StatusDB NGI + +Holds views and test data to fire up a dev instance of StatusDB (CouchDB). This repository replaces the StatusDB_views repository which was kept private. +The [databases](/DATABASES.md) documentation attempts to give an overview of each database and explain its purpose. + +# Views +The first part of this repository is the code for the CouchDB views used for the NGI Stockholm StatusDB. The views are organised in the directory StatusDB_views and listed in the views_config.yaml. + +## History +StatusDB_views was kept private since it could contain some project details or other details that was not supposed to be public. However this decision was changed in 2026 since there is no real reason to keep sensitive information in this repository. The content of the repository was moved to StatusDB_NGI since the git history might still hide details which are not supposed to be made public. Here are the contributors of the old repository: + +## Contributors of historic StatusDB_Views repository +- @aanil +- @alneberg +- @galithil +- @kedhammar +- @chuan-wang +- @remiolsen +- @kate-v-stepanova +- @silverslott +- @ewels +- @vezzi +- @sylvinite +- @ssjunnebo +- @FranBonath +- @pekrau +- @mariogiov + +Thank you! + +## Views directory structure +The views are located in the directory `StatusDB_views` inside the repo and are subsequently organised into directories for databases and design documents. +Each view consists of one or two files, one for the map function and one (optional) for the reduce function. +They need to follow the naming pattern `.map.js` and `.reduce.js`. + +Each database, design document and view is listed in the config file `views_config.yaml`. + +## Checking and updating the views_config.yaml +To try to keep the views_config.yaml file up to date with the content of the repository, the script script/validate_views_config.py can be used: -Holds test data to fire up a dev instance of StatusDB (CouchDB). +``` +> python scripts/validate_views_config.py --config views_config.yaml --views-dir StatusDB_views --check +✅ Config is up to date with directory structure +``` + +And to update the config (default is that a new view will not be included in dev): +``` +> python scripts/validate_views_config.py --config views_config.yaml --views-dir StatusDB_views --update +``` + +# Seed Data +The second part of this repository is the seed data, which is mock data that can be used for testing and demoing a range of internal services that use StatusDB as its backend. The data is located in the seed_data directory and is used to populate the database when building the docker image. -## Docker Image +## Seed Data Structure -A pre-built Docker image with CouchDB and seed data is available: +The `seed_data/` directory contains JSON documents that are loaded into CouchDB on startup. -```bash -docker pull ghcr.io/scilifelab/statusdb_seed_data:latest +### Directory Structure + +``` +seed_data/ +├── / # Creates a database and loads all JSON files into it + ├── doc1.json + └── doc2.json +``` + +### Document Format + +Each JSON file should contain a single CouchDB document. If the document has an `_id` field, it will be used as the document ID. Otherwise, CouchDB will auto-generate an ID. + +Example document (`seed_data/example_project.json`): + +```json +{ + "_id": "project_001", + "type": "project", + "name": "Example Genomics Project", + "project_id": "P12345", + ... +} ``` -### Running the Image +# Docker Image + +The docker image is most commonly used in the docker-compose setup for genomics status, see [Using with Genomics Status](#using-with-genomics-status) In that case, the docker is built automatically as part of the setup. However, in case the docker image should be used standalone, it needs to be built using: + +``` +cd Statusdb_NGI +docker build . +``` + +And starting a container using ```bash docker run -d \ -p 5984:5984 \ -e COUCHDB_USER=admin \ -e COUCHDB_PASSWORD=admin \ - ghcr.io/scilifelab/statusdb_seed_data:latest + ghcr.io/scilifelab/StatusDB_NGI:latest ``` -CouchDB will be available at: +After this, CouchDB will be available at: - API: - Fauxton UI: - Credentials: `admin` / `admin` -The seed data is automatically loaded on first startup. +The seed data is automatically loaded on first startup along with all views in the Statusdb_Views directory. It's prepared to use different scenarios where only a subset of views and data could be loaded, but currently there is only one `stage` scenario where all views and data is loaded. ### Persisting Data @@ -38,61 +117,20 @@ docker run -d \ -e COUCHDB_USER=admin \ -e COUCHDB_PASSWORD=admin \ -v couchdb-data:/opt/couchdb/data \ - ghcr.io/scilifelab/statusdb_seed_data:latest + ghcr.io/scilifelab/StatusDB_NGI:latest ``` -## Development Container (VS Code) - -The easiest way to develop seed data is using the VS Code Dev Container: - -1. Install [VS Code](https://code.visualstudio.com/) and the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) -2. Open this repository in VS Code -3. When prompted, click "Reopen in Container" (or run `Dev Containers: Reopen in Container` from the command palette) -4. VS Code will build and start CouchDB automatically - -## Seed Data Structure - -The `seed/` directory contains JSON documents that are loaded into CouchDB on startup. - -### Directory Structure - -``` -seed/ -├── / # Creates a database and loads all JSON files into it -│ ├── doc1.json -│ └── doc2.json -└── *.json # Top-level JSON files are loaded into 'statusdb' database -``` - -### Document Format - -Each JSON file should contain a single CouchDB document. If the document has an `_id` field, it will be used as the document ID. Otherwise, CouchDB will auto-generate an ID. - -Example document (`seed/example_project.json`): - -```json -{ - "_id": "project_001", - "type": "project", - "name": "Example Genomics Project", - "project_id": "P12345", - ... -} -``` ## Building the Image Locally ```bash -docker build -t statusdb_seed_data . -docker run -p 5984:5984 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=admin statusdb_seed_data +docker build -t StatusDB_NGI . +docker run -p 5984:5984 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=admin StatusDB_NGI ``` -## Adding New Seed Data - -1. Add JSON files to the `seed/` directory (or subdirectories for specific databases) -2. Commit and push to `main` branch -3. GitHub Actions will automatically build and publish a new image +## Container registry +There is a github workflow file written to facilitate automatic build and publishing of the seed data container, but it is not yet in use. ## Using with Genomics Status -The [genomics-status](https://github.com/SciLifeLab/genomics-status) repository is configured to use this image in its dev container setup. When you open genomics-status in VS Code with Dev Containers, it will automatically pull this image and start CouchDB with the seed data. +The [genomics-status](https://github.com/SciLifeLab/genomics-status) repository is configured to use this image in its docker compose setup. When starting docker compose, it will automatically build the image and populate it with the seed data, using the stage scenario. diff --git a/StatusDB_views/agreement_templates/entire_document/by_version.map.js b/StatusDB_views/agreement_templates/entire_document/by_version.map.js new file mode 100644 index 0000000..f214d9d --- /dev/null +++ b/StatusDB_views/agreement_templates/entire_document/by_version.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc["edition"], doc); +} diff --git a/StatusDB_views/agreements/entire_document/project_id.map.js b/StatusDB_views/agreements/entire_document/project_id.map.js new file mode 100644 index 0000000..b075171 --- /dev/null +++ b/StatusDB_views/agreements/entire_document/project_id.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc.project_id, doc); +} diff --git a/StatusDB_views/agreements/project/project_id.map.js b/StatusDB_views/agreements/project/project_id.map.js new file mode 100644 index 0000000..e993bd1 --- /dev/null +++ b/StatusDB_views/agreements/project/project_id.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc.project_id, doc._id); + } \ No newline at end of file diff --git a/StatusDB_views/application_categories/general/app_cat.map.js b/StatusDB_views/application_categories/general/app_cat.map.js new file mode 100644 index 0000000..b72493b --- /dev/null +++ b/StatusDB_views/application_categories/general/app_cat.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.application, doc.category); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/pj_run_lane_sample_to_doc.map.js b/StatusDB_views/bioinfo_analysis/full_doc/pj_run_lane_sample_to_doc.map.js new file mode 100644 index 0000000..1216c74 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/pj_run_lane_sample_to_doc.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.project_id, doc.run_id, doc.lane, doc.sample], doc); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/pj_run_to_doc.map.js b/StatusDB_views/bioinfo_analysis/full_doc/pj_run_to_doc.map.js new file mode 100644 index 0000000..3406ad8 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/pj_run_to_doc.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.project_id, doc.run_id], doc); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/pj_sample_run_lane_to_doc.map.js b/StatusDB_views/bioinfo_analysis/full_doc/pj_sample_run_lane_to_doc.map.js new file mode 100644 index 0000000..1445472 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/pj_sample_run_lane_to_doc.map.js @@ -0,0 +1,4 @@ +function(doc) { +if ('sample' in doc && 'lane' in doc) { + emit([doc.project_id, doc.sample, doc.run_id, doc.lane], doc); +}} diff --git a/StatusDB_views/bioinfo_analysis/full_doc/proj_run_lane_to_doc.js b/StatusDB_views/bioinfo_analysis/full_doc/proj_run_lane_to_doc.js new file mode 100644 index 0000000..260c4c4 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/proj_run_lane_to_doc.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.project_id, doc.run_id, doc.lane], doc); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/proj_run_lane_to_doc.map.js b/StatusDB_views/bioinfo_analysis/full_doc/proj_run_lane_to_doc.map.js new file mode 100644 index 0000000..260c4c4 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/proj_run_lane_to_doc.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.project_id, doc.run_id, doc.lane], doc); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/project_to_doc.js b/StatusDB_views/bioinfo_analysis/full_doc/project_to_doc.js new file mode 100644 index 0000000..4901df5 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/project_to_doc.js @@ -0,0 +1,5 @@ +function(doc) { + if (doc.sample != null && doc.lane != null && doc.run_id != null) { + emit(doc.project_id, doc); + } +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/project_to_doc.map.js b/StatusDB_views/bioinfo_analysis/full_doc/project_to_doc.map.js new file mode 100644 index 0000000..4901df5 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/project_to_doc.map.js @@ -0,0 +1,5 @@ +function(doc) { + if (doc.sample != null && doc.lane != null && doc.run_id != null) { + emit(doc.project_id, doc); + } +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/run_id_to_doc.js b/StatusDB_views/bioinfo_analysis/full_doc/run_id_to_doc.js new file mode 100644 index 0000000..60561a0 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/run_id_to_doc.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.run_id], doc); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/full_doc/run_id_to_doc.map.js b/StatusDB_views/bioinfo_analysis/full_doc/run_id_to_doc.map.js new file mode 100644 index 0000000..60561a0 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/full_doc/run_id_to_doc.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.run_id], doc); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/general/incoming_projectids.map.js b/StatusDB_views/bioinfo_analysis/general/incoming_projectids.map.js new file mode 100644 index 0000000..599a8d2 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/general/incoming_projectids.map.js @@ -0,0 +1,5 @@ +function(doc) { + if (doc.status == "Incoming"){ + emit(doc.project_id, null); +} +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/general/incoming_projectids.reduce.js b/StatusDB_views/bioinfo_analysis/general/incoming_projectids.reduce.js new file mode 100644 index 0000000..42e5a14 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/general/incoming_projectids.reduce.js @@ -0,0 +1,3 @@ +function(key,values){ +return true; +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/general/not_ongoing_projectids.map.js b/StatusDB_views/bioinfo_analysis/general/not_ongoing_projectids.map.js new file mode 100644 index 0000000..91e641a --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/general/not_ongoing_projectids.map.js @@ -0,0 +1,5 @@ +function(doc) { +if (doc.status != "Ongoing"){ + emit(doc.run_id, doc); +} +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/general/not_ongoing_runids.map.js b/StatusDB_views/bioinfo_analysis/general/not_ongoing_runids.map.js new file mode 100644 index 0000000..91e641a --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/general/not_ongoing_runids.map.js @@ -0,0 +1,5 @@ +function(doc) { +if (doc.status != "Ongoing"){ + emit(doc.run_id, doc); +} +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/general/ongoing_projectids.map.js b/StatusDB_views/bioinfo_analysis/general/ongoing_projectids.map.js new file mode 100644 index 0000000..336d98e --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/general/ongoing_projectids.map.js @@ -0,0 +1,5 @@ +function(doc) { + if (doc.status == "Ongoing"){ + emit(doc.project_id, null); +} +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/general/ongoing_projectids.reduce.js b/StatusDB_views/bioinfo_analysis/general/ongoing_projectids.reduce.js new file mode 100644 index 0000000..42e5a14 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/general/ongoing_projectids.reduce.js @@ -0,0 +1,3 @@ +function(key,values){ +return true; +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/genomics_dashboard/run_lane_sample_status.js b/StatusDB_views/bioinfo_analysis/genomics_dashboard/run_lane_sample_status.js new file mode 100644 index 0000000..8fdbd55 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/genomics_dashboard/run_lane_sample_status.js @@ -0,0 +1,12 @@ +function(doc) { + if (doc.sample != null && doc.lane != null && doc.run_id != null) { + last_entry = "0000-00-00"; + for (entry in doc.values) { + if (entry > last_entry) { + last_entry = entry; + } + } + run_lane = doc.run_id + "_" + doc.lane; + emit([doc.project_id, run_lane], doc['values'][last_entry]); + } +} diff --git a/StatusDB_views/bioinfo_analysis/genomics_dashboard/run_lane_sample_status.map.js b/StatusDB_views/bioinfo_analysis/genomics_dashboard/run_lane_sample_status.map.js new file mode 100644 index 0000000..53c06f9 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/genomics_dashboard/run_lane_sample_status.map.js @@ -0,0 +1,12 @@ +function(doc) { + if (doc.sample != null && doc.lane != null && doc.run_id != null) { + last_entry = "0000-00-00"; + for (entry in doc.values) { + if (entry > last_entry) { + last_entry = entry; + } + } + run_lane = doc.run_id + "_" + doc.lane; + emit([doc.project_id, run_lane], doc['values'][last_entry]); + } +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/keys/pj_run.map.js b/StatusDB_views/bioinfo_analysis/keys/pj_run.map.js new file mode 100644 index 0000000..30a6fb3 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/keys/pj_run.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.project_id, doc.run_id], doc._id); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/keys/run_id.map.js b/StatusDB_views/bioinfo_analysis/keys/run_id.map.js new file mode 100644 index 0000000..793a389 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/keys/run_id.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit( doc.run_id, doc._id); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/latest_data/project_id.map.js b/StatusDB_views/bioinfo_analysis/latest_data/project_id.map.js new file mode 100644 index 0000000..e933bc0 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/latest_data/project_id.map.js @@ -0,0 +1,22 @@ +function(doc) { + summary={}; + summary[doc.run_id]={}; + default_date=new Date(1989,03,11) //Happy birthday + for (datestring in doc.values){ + new_date=new Date(datestring); + if (new_date>default_date){ + default_date=new_date; + for (key in doc.values[datestring]){ + summary[doc.run_id][key]=doc.values[datestring][key]; + } + //summary[doc.run_id]=doc.values[datestring]; + summary[doc.run_id].timestamp=default_date.toISOString(); + + } + } + summary[doc.run_id]["project_id"]=doc.project_id; + summary[doc.run_id]["status"]=doc.status; + + + emit(doc.project_id, summary); +} \ No newline at end of file diff --git a/StatusDB_views/bioinfo_analysis/latest_data/sample_id.map.js b/StatusDB_views/bioinfo_analysis/latest_data/sample_id.map.js new file mode 100644 index 0000000..ce9ae5e --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/latest_data/sample_id.map.js @@ -0,0 +1,21 @@ +function(doc) { + summary={}; + default_date=new Date(1989,03,11) //Happy birthday + for (datestring in doc.values){ + new_date=new Date(datestring); + if (new_date>default_date){ + default_date=new_date; + for (key in doc.values[datestring]){ + summary[key]=doc.values[datestring][key]; + } + //summary=doc.values[datestring]; + summary.timestamp=default_date.toISOString(); + + } + } + + if (doc.sample != null){ + emit([doc.project_id, doc.run_id, doc.lane, doc.sample], summary); + } +} + diff --git a/StatusDB_views/bioinfo_analysis/latest_data/sample_id_open.map.js b/StatusDB_views/bioinfo_analysis/latest_data/sample_id_open.map.js new file mode 100644 index 0000000..6b6f9c0 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/latest_data/sample_id_open.map.js @@ -0,0 +1,28 @@ +function(doc) { + summary={}; + default_date=new Date(1989,03,11) //Happy birthday + for (datestring in doc.values){ + new_date=new Date(datestring); + if (new_date>default_date){ + default_date=new_date; + for (key in doc.values[datestring]){ + summary[key]=doc.values[datestring][key]; + } + //summary=doc.values[datestring]; + summary.timestamp=default_date.toISOString(); + } + } + if('instrument_type' in doc){ + summary.instrument_type = doc.instrument_type; + } + else{ + summary.instrument_type = 'illumina'; + } + if('instrument' in doc){ + summary.instrument = doc.instrument; + } + // needed for the delivery page, to show only projects which were not closed + if (doc.sample != null && (summary['sample_status'] != 'Closed' && !doc.hasOwnProperty('project_closed'))) { + emit([doc.project_id, doc.run_id, doc.lane, doc.sample], summary); + } +} diff --git a/StatusDB_views/bioinfo_analysis/status/pj_run.map.js b/StatusDB_views/bioinfo_analysis/status/pj_run.map.js new file mode 100644 index 0000000..fb01b01 --- /dev/null +++ b/StatusDB_views/bioinfo_analysis/status/pj_run.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit([doc.project_id, doc.run_id], doc.status); +} \ No newline at end of file diff --git a/StatusDB_views/biomek_logs/dates/timestamp.map.js b/StatusDB_views/biomek_logs/dates/timestamp.map.js new file mode 100644 index 0000000..7150bc7 --- /dev/null +++ b/StatusDB_views/biomek_logs/dates/timestamp.map.js @@ -0,0 +1,4 @@ +function(doc) { + start_date = new Date(doc.start_time); + emit(start_date, doc); + } \ No newline at end of file diff --git a/StatusDB_views/biomek_logs/names/run_finished.map.js b/StatusDB_views/biomek_logs/names/run_finished.map.js new file mode 100644 index 0000000..460003f --- /dev/null +++ b/StatusDB_views/biomek_logs/names/run_finished.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit([doc.file_name, doc.inst_id], doc.run_finished); + } \ No newline at end of file diff --git a/StatusDB_views/charon/filters/deletedfilter.filter.js b/StatusDB_views/charon/filters/deletedfilter.filter.js new file mode 100644 index 0000000..7cd0473 --- /dev/null +++ b/StatusDB_views/charon/filters/deletedfilter.filter.js @@ -0,0 +1 @@ +function(doc, req) { return !doc._deleted; }; \ No newline at end of file diff --git a/StatusDB_views/charon/filters/nologfilter.filter.js b/StatusDB_views/charon/filters/nologfilter.filter.js new file mode 100644 index 0000000..e4c2a00 --- /dev/null +++ b/StatusDB_views/charon/filters/nologfilter.filter.js @@ -0,0 +1 @@ +function(doc, req) { return doc.charon_doctype !== 'log' }; \ No newline at end of file diff --git a/StatusDB_views/charon/internal/sampleids_to_projectids.map.js b/StatusDB_views/charon/internal/sampleids_to_projectids.map.js new file mode 100644 index 0000000..d55607f --- /dev/null +++ b/StatusDB_views/charon/internal/sampleids_to_projectids.map.js @@ -0,0 +1,8 @@ + +function(doc) { + if (doc.charon_doctype != 'sample'){ + return; +}else{ + emit(doc.sampleid, doc.projectid); +} +} \ No newline at end of file diff --git a/StatusDB_views/charon/libprep/count.map.js b/StatusDB_views/charon/libprep/count.map.js new file mode 100644 index 0000000..9958118 --- /dev/null +++ b/StatusDB_views/charon/libprep/count.map.js @@ -0,0 +1,8 @@ +/* Charon + Index libprep documents by [projectid, sampleid]. + Value: 1. +*/ +function(doc) { + if (doc.charon_doctype !== 'libprep') return; + emit([doc.projectid, doc.sampleid], 1); +} diff --git a/StatusDB_views/charon/libprep/count.reduce.js b/StatusDB_views/charon/libprep/count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/charon/libprep/count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/charon/libprep/libprepid.map.js b/StatusDB_views/charon/libprep/libprepid.map.js new file mode 100644 index 0000000..29293fc --- /dev/null +++ b/StatusDB_views/charon/libprep/libprepid.map.js @@ -0,0 +1,8 @@ +/* Charon + Index libprep documents by [projectid, sampleid, libprepid]. + Value: null. +*/ +function(doc) { + if (doc.charon_doctype !== 'libprep') return; + emit([doc.projectid, doc.sampleid, doc.libprepid], null); +} diff --git a/StatusDB_views/charon/libprep/modified.map.js b/StatusDB_views/charon/libprep/modified.map.js new file mode 100644 index 0000000..822fade --- /dev/null +++ b/StatusDB_views/charon/libprep/modified.map.js @@ -0,0 +1,11 @@ +/* Charon + Index libprep documents by modified. + Value: [projectid, sampleid, libprepid]. +*/ + + +function(doc) { + if (doc.charon_doctype !== 'libprep') return; + if (!doc.modified) return; + emit(doc.modified, [doc.projectid, doc.sampleid, doc.libprepid]); +} diff --git a/StatusDB_views/charon/log/doc.map.js b/StatusDB_views/charon/log/doc.map.js new file mode 100644 index 0000000..a70e1be --- /dev/null +++ b/StatusDB_views/charon/log/doc.map.js @@ -0,0 +1,9 @@ +/* Charon + Index log documents by doc. + Value: timestamp. +*/ + +function(doc) { + if (doc.charon_doctype !== 'log') return; + emit(doc.doc, doc.timestamp); +} diff --git a/StatusDB_views/charon/project/modified.map.js b/StatusDB_views/charon/project/modified.map.js new file mode 100644 index 0000000..72b2a98 --- /dev/null +++ b/StatusDB_views/charon/project/modified.map.js @@ -0,0 +1,10 @@ +/* Charon + Index project documents by modified. + Value: projectid. +*/ + +function(doc) { + if (doc.charon_doctype !== 'project') return; + if (!doc.modified) return; + emit(doc.modified, doc.projectid); +} diff --git a/StatusDB_views/charon/project/name.map.js b/StatusDB_views/charon/project/name.map.js new file mode 100644 index 0000000..d07d083 --- /dev/null +++ b/StatusDB_views/charon/project/name.map.js @@ -0,0 +1,9 @@ +/* Charon + Index project documents by name. + Value: projectid. +*/ +function(doc) { + if (doc.charon_doctype !== 'project') return; + if (!doc.name) return; + emit(doc.name, doc.projectid); +} diff --git a/StatusDB_views/charon/project/not_done.map.js b/StatusDB_views/charon/project/not_done.map.js new file mode 100644 index 0000000..6796c5b --- /dev/null +++ b/StatusDB_views/charon/project/not_done.map.js @@ -0,0 +1,6 @@ +/*emits only not done projects*/ +function(doc) { + if (doc.charon_doctype === 'project' && doc.status !== 'CLOSED'){ + emit(doc.projectid, doc); + } +} diff --git a/StatusDB_views/charon/project/projectid.map.js b/StatusDB_views/charon/project/projectid.map.js new file mode 100644 index 0000000..645e665 --- /dev/null +++ b/StatusDB_views/charon/project/projectid.map.js @@ -0,0 +1,8 @@ +/* Charon + Index project documents by projectid. + Value: projectname, or null. +*/ +function(doc) { + if (doc.charon_doctype !== 'project') return; + emit(doc.projectid, doc.projectname || null); +} diff --git a/StatusDB_views/charon/project/splitname.map.js b/StatusDB_views/charon/project/splitname.map.js new file mode 100644 index 0000000..efb8325 --- /dev/null +++ b/StatusDB_views/charon/project/splitname.map.js @@ -0,0 +1,12 @@ +/* Charon + Index project documents by name split at first dot '.'. + Value: projectid. +*/ +function(doc) { + if (doc.charon_doctype !== 'project') return; + if (!doc.name) return; + emit(doc.name, doc.projectid); + var parts = doc.name.split(".", 2); + if (parts.length < 2) return; + emit(parts[1], doc.projectid); +} diff --git a/StatusDB_views/charon/sample/analyzed_failed.map.js b/StatusDB_views/charon/sample/analyzed_failed.map.js new file mode 100644 index 0000000..ae9b406 --- /dev/null +++ b/StatusDB_views/charon/sample/analyzed_failed.map.js @@ -0,0 +1,7 @@ +/*Returns all samples taht have a 'FAILED' status*/ + +function(doc) { + if (doc.charon_doctype === 'sample' && (doc.analysis_status == 'FAILED' || doc.analysis_status == 'ANALYZED')){ + emit([doc.projectid, doc.sampleid], doc); + } +} diff --git a/StatusDB_views/charon/sample/count.map.js b/StatusDB_views/charon/sample/count.map.js new file mode 100644 index 0000000..03f0ba7 --- /dev/null +++ b/StatusDB_views/charon/sample/count.map.js @@ -0,0 +1,8 @@ +/* Charon + Index sample documents by projectid. + Value: 1. +*/ +function(doc) { + if (doc.charon_doctype !== 'sample') return; + emit(doc.projectid, 1); +} diff --git a/StatusDB_views/charon/sample/count.reduce.js b/StatusDB_views/charon/sample/count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/charon/sample/count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/charon/sample/count_delivered.map.js b/StatusDB_views/charon/sample/count_delivered.map.js new file mode 100644 index 0000000..eb9c0b0 --- /dev/null +++ b/StatusDB_views/charon/sample/count_delivered.map.js @@ -0,0 +1,7 @@ +/* Charon + Index sample documents by projectid. + Value: 1. +*/ +function(doc) { + if (doc.charon_doctype === 'sample' && doc.delivery_status === "DELIVERED") emit(doc.projectid, 1); +} diff --git a/StatusDB_views/charon/sample/count_delivered.reduce.js b/StatusDB_views/charon/sample/count_delivered.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/charon/sample/count_delivered.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/charon/sample/count_done.map.js b/StatusDB_views/charon/sample/count_done.map.js new file mode 100644 index 0000000..29cdfb5 --- /dev/null +++ b/StatusDB_views/charon/sample/count_done.map.js @@ -0,0 +1,7 @@ +/* Charon + Index sample documents by projectid. + Value: 1. +*/ +function(doc) { + if (doc.charon_doctype === 'sample' && doc.analysis_status === "ANALYZED") emit(doc.projectid, 1); +} diff --git a/StatusDB_views/charon/sample/count_done.reduce.js b/StatusDB_views/charon/sample/count_done.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/charon/sample/count_done.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/charon/sample/done.map.js b/StatusDB_views/charon/sample/done.map.js new file mode 100644 index 0000000..beb1899 --- /dev/null +++ b/StatusDB_views/charon/sample/done.map.js @@ -0,0 +1,7 @@ +/*Returns all samples taht have a 'not done' status*/ + +function(doc) { + if (doc.charon_doctype === 'sample' && doc.analysis_status == 'ANALYZED'){ + emit([doc.projectid, doc.sampleid], doc); + } +} diff --git a/StatusDB_views/charon/sample/failed.map.js b/StatusDB_views/charon/sample/failed.map.js new file mode 100644 index 0000000..0847eee --- /dev/null +++ b/StatusDB_views/charon/sample/failed.map.js @@ -0,0 +1,7 @@ +/*Returns all samples taht have a 'FAILED' status*/ + +function(doc) { + if (doc.charon_doctype === 'sample' && doc.analysis_status == 'FAILED'){ + emit([doc.projectid, doc.sampleid], doc); + } +} diff --git a/StatusDB_views/charon/sample/modified.map.js b/StatusDB_views/charon/sample/modified.map.js new file mode 100644 index 0000000..1eec17f --- /dev/null +++ b/StatusDB_views/charon/sample/modified.map.js @@ -0,0 +1,9 @@ +/* Charon + Index sample documents by modified. + Value: [projectid, sampleid]. +*/ +function(doc) { + if (doc.charon_doctype !== 'sample') return; + if (!doc.modified) return; + emit(doc.modified, [doc.projectid, doc.sampleid]); +} diff --git a/StatusDB_views/charon/sample/not_done.map.js b/StatusDB_views/charon/sample/not_done.map.js new file mode 100644 index 0000000..7c407ab --- /dev/null +++ b/StatusDB_views/charon/sample/not_done.map.js @@ -0,0 +1,6 @@ +/*Returns all samples taht have a 'not done' status*/ +function(doc) { + if (doc.charon_doctype === 'sample' && doc.analysis_status !== 'ANALYZED'){ + emit([doc.projectid, doc.sampleid], doc); + } +} diff --git a/StatusDB_views/charon/sample/running.map.js b/StatusDB_views/charon/sample/running.map.js new file mode 100644 index 0000000..e351561 --- /dev/null +++ b/StatusDB_views/charon/sample/running.map.js @@ -0,0 +1,7 @@ +/*Returns all samples taht have a 'UNDER_ANALYSIS' status*/ + +function(doc) { + if (doc.charon_doctype === 'sample' && doc.analysis_status == 'UNDER_ANALYSIS'){ + emit([doc.projectid, doc.sampleid], doc); + } +} diff --git a/StatusDB_views/charon/sample/sampleid.map.js b/StatusDB_views/charon/sample/sampleid.map.js new file mode 100644 index 0000000..91a6aa9 --- /dev/null +++ b/StatusDB_views/charon/sample/sampleid.map.js @@ -0,0 +1,8 @@ +/* Charon + Index sample documents by [projectid, sampleid]. + Value: null. +*/ +function(doc) { + if (doc.charon_doctype !== 'sample') return; + emit([doc.projectid, doc.sampleid], null); +} diff --git a/StatusDB_views/charon/sample/sequenced.map.js b/StatusDB_views/charon/sample/sequenced.map.js new file mode 100644 index 0000000..3067020 --- /dev/null +++ b/StatusDB_views/charon/sample/sequenced.map.js @@ -0,0 +1,5 @@ +function(doc) { + if (doc.charon_doctype === 'seqrun'){ + emit([doc.projectid, doc.sampleid], 1); + } +} \ No newline at end of file diff --git a/StatusDB_views/charon/sample/sequenced.reduce.js b/StatusDB_views/charon/sample/sequenced.reduce.js new file mode 100644 index 0000000..3eed19a --- /dev/null +++ b/StatusDB_views/charon/sample/sequenced.reduce.js @@ -0,0 +1,3 @@ +function(map, value, rereduce){ + return 1; +} \ No newline at end of file diff --git a/StatusDB_views/charon/sample/summary_count.map.js b/StatusDB_views/charon/sample/summary_count.map.js new file mode 100644 index 0000000..8442a26 --- /dev/null +++ b/StatusDB_views/charon/sample/summary_count.map.js @@ -0,0 +1,39 @@ +/* Charon + counts samples by type. + Value: 1. +*/ +function(doc) { + seq_sa=[]; + if (doc.charon_doctype === 'sample'){ + emit('TOTAL', 1); + if (doc.status === 'ABORTED'){ + emit('ABORTED', 1); + emit(doc.projectid+'_ABORTED', 1); + } + emit(doc.projectid+'_TOTAL', 1); + emit('TOTAL_COV', doc.total_autosomal_coverage); + emit(doc.projectid+'_TOTAL_COV', doc.total_autosomal_coverage); + if (doc.analysis_status === 'ANALYZED'){ + emit('ANALYZED', 1); + emit(doc.projectid+'_ANALYZED', 1); + if (doc.status !== 'ABORTED'){ + emit('ANALYZED_UNAB', 1); + emit(doc.projectid+'_ANALYZED_UNAB', 1); + } + } + else if (doc.analysis_status === 'UNDER_ANALYSIS'){ + emit('UNDER_ANALYSIS', 1); + emit(doc.projectid+'_UNDER_ANALYSIS', 1); + } + else if (doc.analysis_status === 'FAILED'){ + emit('FAILED', 1); + emit(doc.projectid+'_FAILED', 1); + } + }else if (doc.charon_doctype === 'seqrun'){ + if (seq_sa.indexOf(doc.sampleid) == -1){ + seq_sa.push(doc.sampleid); + emit('SEQUENCED', 1); + emit(doc.projectid+'_SEQUENCED', 1); + } + } +} \ No newline at end of file diff --git a/StatusDB_views/charon/sample/summary_count.reduce.js b/StatusDB_views/charon/sample/summary_count.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/charon/sample/summary_count.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/charon/sample/total_coverage.map.js b/StatusDB_views/charon/sample/total_coverage.map.js new file mode 100644 index 0000000..5d2e6a5 --- /dev/null +++ b/StatusDB_views/charon/sample/total_coverage.map.js @@ -0,0 +1,7 @@ + +function(doc) { + if (doc.charon_doctype === 'sample'){ + emit('TOTAL', doc.total_autosomal_coverage); + } +} + diff --git a/StatusDB_views/charon/sample/total_coverage.reduce.js b/StatusDB_views/charon/sample/total_coverage.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/charon/sample/total_coverage.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/charon/seqrun/count.map.js b/StatusDB_views/charon/seqrun/count.map.js new file mode 100644 index 0000000..32da0ae --- /dev/null +++ b/StatusDB_views/charon/seqrun/count.map.js @@ -0,0 +1,9 @@ +/* Charon + Index seqrun documents by [projectid, sampleid, libprepid]. + Value: 1. +*/ + +function(doc) { + if (doc.charon_doctype !== 'seqrun') return; + emit([doc.projectid, doc.sampleid, doc.libprepid], 1); +} diff --git a/StatusDB_views/charon/seqrun/count.reduce.js b/StatusDB_views/charon/seqrun/count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/charon/seqrun/count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/charon/seqrun/seqrunid.map.js b/StatusDB_views/charon/seqrun/seqrunid.map.js new file mode 100644 index 0000000..3bec431 --- /dev/null +++ b/StatusDB_views/charon/seqrun/seqrunid.map.js @@ -0,0 +1,8 @@ +/* Charon + Index seqrun documents by [projectid, sampleid, libprepid, seqrunid]. + Value: null. +*/ +function(doc) { + if (doc.charon_doctype !== 'seqrun') return; + emit([doc.projectid, doc.sampleid, doc.libprepid, doc.seqrunid], null); +} diff --git a/StatusDB_views/charon/test/test.map.js b/StatusDB_views/charon/test/test.map.js new file mode 100644 index 0000000..5b2acc9 --- /dev/null +++ b/StatusDB_views/charon/test/test.map.js @@ -0,0 +1,10 @@ +/* Charon + Index libprep documents by modified. + Value: [projectid, sampleid, libprepid]. +*/ + +function(doc) { + if (doc.charon_doctype !== 'libprep') return; + if (!doc.modified) return; + emit(doc.modified, [doc.projectid, doc.sampleid, doc.libprepid]); +} diff --git a/StatusDB_views/charon/user/api_token.map.js b/StatusDB_views/charon/user/api_token.map.js new file mode 100644 index 0000000..6225d9f --- /dev/null +++ b/StatusDB_views/charon/user/api_token.map.js @@ -0,0 +1,8 @@ +/* Charon + Index user documents by API token. + Value: email. +*/ +function(doc) { + if (doc.charon_doctype !== 'user') return; + emit(doc.api_token, doc.email); +} diff --git a/StatusDB_views/charon/user/email.map.js b/StatusDB_views/charon/user/email.map.js new file mode 100644 index 0000000..0f73562 --- /dev/null +++ b/StatusDB_views/charon/user/email.map.js @@ -0,0 +1,9 @@ +/* Charon + Index user documents by email. + Value: null. +*/ + +function(doc) { + if (doc.charon_doctype !== 'user') return; + emit(doc.email, null); +} diff --git a/StatusDB_views/charon/user/name.map.js b/StatusDB_views/charon/user/name.map.js new file mode 100644 index 0000000..8512d34 --- /dev/null +++ b/StatusDB_views/charon/user/name.map.js @@ -0,0 +1,15 @@ +/* Charon + Index user documents by name and parts of the name. + Value: email. +*/ +function(doc) { + if (doc.charon_doctype !== 'user') return; + if (!doc.name) return; + emit(doc.name, doc.email); + var parts = doc.name.split(" "); + if (parts.length > 1) { + for (var i=0; i 0) { + summary["lane_info"][lane_num] = {"projects": projects}; + } + } + } + } + + if (doc.hasOwnProperty('flowcell_id') && (doc.hasOwnProperty('metadata'))) { + if (doc.metadata.hasOwnProperty('first_generated')) { + summary['first_generated'] = doc.metadata.first_generated; + } + if (doc.metadata.hasOwnProperty('run_setup')) { + summary['run_setup'] = doc.metadata.run_setup; + } + if (doc.metadata.hasOwnProperty('instrument_type')) { + summary['instrument_type'] = doc.metadata.instrument_type; + } + if (doc.metadata.hasOwnProperty('run_mode')) { + summary['run_mode'] = doc.metadata.run_mode; + } + + emit([summary.first_generated, doc.flowcell_id], summary) + } +} \ No newline at end of file diff --git a/StatusDB_views/element_runs/dashboard/week_instr_bp.map.js b/StatusDB_views/element_runs/dashboard/week_instr_bp.map.js new file mode 100644 index 0000000..5796427 --- /dev/null +++ b/StatusDB_views/element_runs/dashboard/week_instr_bp.map.js @@ -0,0 +1,33 @@ +function (doc) { + const run_date = new Date(doc['instrument_generated_files']['RunParameters.json']['Date']); + const instr_name = doc['instrument_generated_files']['RunParameters.json']["InstrumentName"]; + const yd = doc['instrument_generated_files']['AvitiRunStats.json']["RunStats"]["TotalYield"]; + + var dw = run_date.getDay(); + if (dw===0){ + prev_monday=new Date(run_date.getFullYear(), run_date.getMonth(), (run_date.getDate()-6)); + }else{ + prev_monday=new Date(run_date.getFullYear(), run_date.getMonth(), (run_date.getDate() - run_date.getDay() + 1)); + } + + d_str=prev_monday.getDate().toString(); + + if (prev_monday.getDate()<10){ + d_str = "0"+d_str; + } + var m_str=(prev_monday.getMonth() + 1).toString(); + if (prev_monday.getMonth() + 1 < 10){ + m_str = "0"+m_str; + } + var prev_monday_str=prev_monday.getFullYear().toString() + "-" + m_str + "-" + d_str; + + + if (instr_name.indexOf('AV') != -1) { + key=[prev_monday_str, "Aviti"]; + emit(key, yd); + } + else { + // This does nothing. Change once the 24 is online and we know what to filter for + key=[prev_monday_str, "Aviti24"]; + } +} \ No newline at end of file diff --git a/StatusDB_views/element_runs/dashboard/week_instr_bp.reduce.js b/StatusDB_views/element_runs/dashboard/week_instr_bp.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/element_runs/dashboard/week_instr_bp.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/element_runs/info/id.map.js b/StatusDB_views/element_runs/info/id.map.js new file mode 100644 index 0000000..aa8e59e --- /dev/null +++ b/StatusDB_views/element_runs/info/id.map.js @@ -0,0 +1,8 @@ +function(doc) { + if (doc.hasOwnProperty('NGI_run_id')) { + var run_id = doc['NGI_run_id']; + emit(run_id, doc['_id']); + } else { + emit('NGI_run_id_missing', doc['_id']); + } +} diff --git a/StatusDB_views/element_runs/info/name.map.js b/StatusDB_views/element_runs/info/name.map.js new file mode 100644 index 0000000..dd8405b --- /dev/null +++ b/StatusDB_views/element_runs/info/name.map.js @@ -0,0 +1,10 @@ +function(doc) { + // This is made to mimic the x_flowcells info/name view + // need this since common code in TACA uses the info/name to get the document + if (doc.hasOwnProperty('NGI_run_id')) { + var run_id = doc['NGI_run_id']; + emit(run_id, doc); + } else { + emit('NGI_run_id_missing', doc); + } +} \ No newline at end of file diff --git a/StatusDB_views/element_runs/info/reads_yield.map.js b/StatusDB_views/element_runs/info/reads_yield.map.js new file mode 100644 index 0000000..f4367bf --- /dev/null +++ b/StatusDB_views/element_runs/info/reads_yield.map.js @@ -0,0 +1,38 @@ +function (doc) { + data={}; + data["id"] = doc.NGI_run_id; + data["total_yield"] = 0; + data["instrument"] =""; + data["cver"] = ""; + data['lanes']=[]; + if("instrument_generated_files" in doc){ + if("RunParameters.json" in doc["instrument_generated_files"]){ + data["instrument"] = doc["instrument_generated_files"]["RunParameters.json"]["InstrumentName"]; + data["cver"] = doc["instrument_generated_files"]["RunParameters.json"]["KitConfiguration"]+ '_'+ doc["instrument_generated_files"]["RunParameters.json"]["ThroughputSelection"]; + } + if("AvitiRunStats.json" in doc["instrument_generated_files"]){ + var aviti_run_stats = doc["instrument_generated_files"]["AvitiRunStats.json"]; + if("RunStats" in aviti_run_stats){ + if("TotalYield" in aviti_run_stats["RunStats"]) + data["total_yield"] = aviti_run_stats["RunStats"]["TotalYield"]; + if("PolonyCount" in aviti_run_stats["RunStats"]) + data["total_clusters"] = aviti_run_stats["RunStats"]["PolonyCount"]; + } + if("LaneStats" in aviti_run_stats){ + var onelane=null; + for (var lane in aviti_run_stats["LaneStats"]){ + laneobj={}; + onelane=aviti_run_stats["LaneStats"][lane]; + laneobj['lane']=onelane['Lane']; + laneobj['total_yield']=onelane['TotalYield']; + laneobj['total_clusters']=onelane['PolonyCount']; + + data['lanes'].push(laneobj); + } + } + } + } + if ("NGI_run_id" in doc){ + emit(doc.NGI_run_id, data); + } + } \ No newline at end of file diff --git a/StatusDB_views/element_runs/info/status.map.js b/StatusDB_views/element_runs/info/status.map.js new file mode 100644 index 0000000..4142425 --- /dev/null +++ b/StatusDB_views/element_runs/info/status.map.js @@ -0,0 +1,10 @@ +function(doc) { + if (doc.hasOwnProperty('NGI_run_id')) { + var NGI_run_id = doc['NGI_run_id']; + var status = "unknown"; + if (doc.hasOwnProperty('run_status')) { + status = doc['run_status']; + } + emit(NGI_run_id, status); + } +} \ No newline at end of file diff --git a/StatusDB_views/element_runs/info/summary.map.js b/StatusDB_views/element_runs/info/summary.map.js new file mode 100644 index 0000000..70db3b0 --- /dev/null +++ b/StatusDB_views/element_runs/info/summary.map.js @@ -0,0 +1,68 @@ +function (doc) { + var info = {}; // The object that will be emitted + + var instrument_generated_files = {}; + if (doc.hasOwnProperty('instrument_generated_files')) { + instrument_generated_files = doc['instrument_generated_files']; + } + + var run_parameters = {}; + if (instrument_generated_files.hasOwnProperty('RunParameters.json')){ + run_parameters = instrument_generated_files['RunParameters.json']; + } + + // Will not emit anything if the NGI_run_id is not available + if (doc.hasOwnProperty('NGI_run_id')) { + var NGI_run_id = doc['NGI_run_id']; + + info['doc_id'] = doc['_id']; + // Default values + info['RunDate'] = ""; + info['RunName'] = ""; + info['RunType'] = ""; + info['Side'] = ""; + info['Cycles'] = {}; + info['ThroughputSelection'] = ""; + info['KitConfiguration'] = ""; + info['ChemistryVersion'] = ""; + + if (run_parameters !== null){ + if (run_parameters.hasOwnProperty('run_date')) { + info['RunDate'] = run_parameters['run_date']; + } + if (run_parameters.hasOwnProperty('RunName')) { + info['RunName'] = run_parameters['RunName']; + } + if (run_parameters.hasOwnProperty('RunType')) { + info['RunType'] = run_parameters['RunType']; + } + if (run_parameters.hasOwnProperty('Side')) { + info['Side'] = run_parameters['Side']; + } + if (run_parameters.hasOwnProperty('Cycles')) { + info['Cycles'] = run_parameters['Cycles']; + } + if (run_parameters.hasOwnProperty('ThroughputSelection')) { + info['ThroughputSelection'] = run_parameters['ThroughputSelection']; + } + if (run_parameters.hasOwnProperty('KitConfiguration')) { + info['KitConfiguration'] = run_parameters['KitConfiguration']; + } + if (run_parameters.hasOwnProperty('ChemistryVersion')) { + info['ChemistryVersion'] = run_parameters['ChemistryVersion']; + } + } + + // Check if it is finished + info["Outcome"] = "ongoing"; + var run_uploaded = {}; + if (instrument_generated_files.hasOwnProperty('RunUploaded.json')){ + run_uploaded = instrument_generated_files['RunUploaded.json']; + if ((run_uploaded !== null ) && (run_uploaded.hasOwnProperty('outcome'))){ + info['Outcome'] = run_uploaded['outcome']; + } + } + + emit(NGI_run_id, info); + } +} \ No newline at end of file diff --git a/StatusDB_views/element_runs/names/project_ids_list.map.js b/StatusDB_views/element_runs/names/project_ids_list.map.js new file mode 100644 index 0000000..93a03a1 --- /dev/null +++ b/StatusDB_views/element_runs/names/project_ids_list.map.js @@ -0,0 +1,31 @@ +function (doc) { + // Function to match and extract project ID + function extractProjectId(str) { + const match = str.match(/(p|P)\d+/); + return match ? match[0] : null; + } + // Fetch key + var project_ids = []; + var p_id = null; + if('Element' in doc && 'Demultiplex_Stats' in doc['Element'] && 'Index_Assignment' in doc['Element']['Demultiplex_Stats']){ + if(doc['Element']['Demultiplex_Stats']['Index_Assignment']!==null){ + doc['Element']['Demultiplex_Stats']['Index_Assignment'].forEach(function(sample) { + p_id = extractProjectId(sample['SampleName']) + if(p_id!==null && project_ids.indexOf(p_id) === -1 ){ + project_ids.push(p_id) + } + }) + } + } + else{ + if('instrument_generated_files' in doc && 'RunManifest.json' in doc['instrument_generated_files'] && 'Samples' in doc['instrument_generated_files']['RunManifest.json']){ + doc['instrument_generated_files']['RunManifest.json']['Samples'].forEach(function(sample) { + p_id = extractProjectId(sample['SampleName']) + if(p_id!==null && project_ids.indexOf(p_id) === -1 ){ + project_ids.push(p_id) + } + }) + } + } + emit(doc.NGI_run_id, project_ids); +} \ No newline at end of file diff --git a/StatusDB_views/flowcell_status/events/all.map.js b/StatusDB_views/flowcell_status/events/all.map.js new file mode 100644 index 0000000..e3793de --- /dev/null +++ b/StatusDB_views/flowcell_status/events/all.map.js @@ -0,0 +1,10 @@ +function(doc) { + if (doc.events && Array.isArray(doc.events)) { + doc.events.forEach(function(event) { + emit( + [doc._id, event.event_type], + [event.timestamp, event.data] + ); + }); + } +} \ No newline at end of file diff --git a/StatusDB_views/flowcell_status/events/current_status_per_fcid.map.js b/StatusDB_views/flowcell_status/events/current_status_per_fcid.map.js new file mode 100644 index 0000000..5fb649f --- /dev/null +++ b/StatusDB_views/flowcell_status/events/current_status_per_fcid.map.js @@ -0,0 +1,49 @@ +function(doc) { + if (doc.flowcell_id && doc.events) { + var status = { + backed_up_to_pdc: false, + transfer_started: false, + transferred_to_hpc: false, + sequencing_finished: false, + cleaned_from_pdc: false, + cleaned_from_ngi_data: false, + cleaned_from_miarka: false, + retrieved_from_pdc: false, + samplesheet_updated: false + }; + + doc.events.forEach(function(event) { + switch (event.event_type) { + case "backed_up_to_pdc": + status.backed_up_to_pdc = true; + break; + case "transfer_started": + status.transfer_started = true; + break; + case "transferred_to_hpc": + status.transferred_to_hpc = true; + break; + case "sequencing_finished": + status.sequencing_finished = true; + break; + case "cleaned_from_pdc": + status.cleaned_from_pdc = true; + break; + case "cleaned_from_ngi_data": + status.cleaned_from_ngi_data = true; + break; + case "cleaned_from_miarka": + status.cleaned_from_miarka = true; + break; + case "retrieved_from_pdc": + status.retrieved_from_pdc = true; + break; + case "samplesheet_updated": + status.samplesheet_updated = true; + break; + } + }); + + emit(doc.flowcell_id, status); + } +} \ No newline at end of file diff --git a/StatusDB_views/flowcell_status/events/current_status_per_runfolder.map.js b/StatusDB_views/flowcell_status/events/current_status_per_runfolder.map.js new file mode 100644 index 0000000..7c10a79 --- /dev/null +++ b/StatusDB_views/flowcell_status/events/current_status_per_runfolder.map.js @@ -0,0 +1,49 @@ +function(doc) { + if (doc.runfolder_id && doc.events) { + var status = { + backed_up_to_pdc: false, + transfer_started: false, + transferred_to_hpc: false, + sequencing_finished: false, + cleaned_from_pdc: false, + cleaned_from_ngi_data: false, + cleaned_from_miarka: false, + retrieved_from_pdc: false, + samplesheet_updated: false + }; + + doc.events.forEach(function(event) { + switch (event.event_type) { + case "backed_up_to_pdc": + status.backed_up_to_pdc = true; + break; + case "transfer_started": + status.transfer_started = true; + break; + case "transferred_to_hpc": + status.transferred_to_hpc = true; + break; + case "sequencing_finished": + status.sequencing_finished = true; + break; + case "cleaned_from_pdc": + status.cleaned_from_pdc = true; + break; + case "cleaned_from_ngi_data": + status.cleaned_from_ngi_data = true; + break; + case "cleaned_from_miarka": + status.cleaned_from_miarka = true; + break; + case "retrieved_from_pdc": + status.retrieved_from_pdc = true; + break; + case "samplesheet_updated": + status.samplesheet_updated = true; + break; + } + }); + + emit(doc.runfolder_id, status); + } +} \ No newline at end of file diff --git a/StatusDB_views/flowcell_status/lookup/flowcell_id.map.js b/StatusDB_views/flowcell_status/lookup/flowcell_id.map.js new file mode 100644 index 0000000..00bb272 --- /dev/null +++ b/StatusDB_views/flowcell_status/lookup/flowcell_id.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc.flowcell_id); +} \ No newline at end of file diff --git a/StatusDB_views/flowcell_status/lookup/runfolder_id.map.js b/StatusDB_views/flowcell_status/lookup/runfolder_id.map.js new file mode 100644 index 0000000..5bf0a99 --- /dev/null +++ b/StatusDB_views/flowcell_status/lookup/runfolder_id.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc.runfolder_id); +} \ No newline at end of file diff --git a/StatusDB_views/flowcell_status/summary/date_flowcell_id.map.js b/StatusDB_views/flowcell_status/summary/date_flowcell_id.map.js new file mode 100644 index 0000000..ad76432 --- /dev/null +++ b/StatusDB_views/flowcell_status/summary/date_flowcell_id.map.js @@ -0,0 +1,198 @@ +function(doc) { + if (doc.flowcell_id && doc.events) { + var summary = { + backed_up_to_pdc: false, + backed_up_to_pdc_timestamp: null, + transfer_started: false, + transfer_started_timestamp: null, + transferred_to_hpc: false, + transferred_to_hpc_timestamp: null, + sequencing_started: false, + sequencing_started_timestamp: null, + sequencing_finished: false, + sequencing_finished_timestamp: null, + cleaned_from_pdc: false, + cleaned_from_pdc_timestamp: null, + cleaned_from_ngi_data: false, + cleaned_from_ngi_data_timestamp: null, + cleaned_from_miarka: false, + cleaned_from_miarka_timestamp: null, + retrieved_from_pdc: false, + retrieved_from_pdc_timestamp: null, + samplesheet_updated: false, + samplesheet_updated_timestamp: null + }; + + if (doc.runfolder_id) { + summary.runfolder_id = doc.runfolder_id; + } + + doc.events.forEach(function(event) { + switch (event.event_type) { + case "backed_up_to_pdc": + summary.backed_up_to_pdc = true; + if (!summary.backed_up_to_pdc_timestamp || event.timestamp < summary.backed_up_to_pdc_timestamp) { + summary.backed_up_to_pdc_timestamp = event.timestamp; + } + break; + case "transfer_started_to_hpc": + summary.transfer_started = true; + if (!summary.transfer_started_timestamp || event.timestamp < summary.transfer_started_timestamp) { + summary.transfer_started_timestamp = event.timestamp; + } + break; + case "transferred_to_hpc": + summary.transferred_to_hpc = true; + if (!summary.transferred_to_hpc_timestamp || event.timestamp < summary.transferred_to_hpc_timestamp) { + summary.transferred_to_hpc_timestamp = event.timestamp; + } + break; + case "sequencing_started": + summary.sequencing_started = true; + if (!summary.sequencing_started_timestamp || event.timestamp < summary.sequencing_started_timestamp) { + summary.sequencing_started_timestamp = event.timestamp; + } + break; + case "sequencing_finished": + summary.sequencing_finished = true; + if (!summary.sequencing_finished_timestamp || event.timestamp < summary.sequencing_finished_timestamp) { + summary.sequencing_finished_timestamp = event.timestamp; + } + break; + case "cleaned_from_pdc": + summary.cleaned_from_pdc = true; + if (!summary.cleaned_from_pdc_timestamp || event.timestamp < summary.cleaned_from_pdc_timestamp) { + summary.cleaned_from_pdc_timestamp = event.timestamp; + } + break; + case "cleaned_from_ngi_data": + summary.cleaned_from_ngi_data = true; + if (!summary.cleaned_from_ngi_data_timestamp || event.timestamp < summary.cleaned_from_ngi_data_timestamp) { + summary.cleaned_from_ngi_data_timestamp = event.timestamp; + } + break; + case "cleaned_from_miarka": + summary.cleaned_from_miarka = true; + if (!summary.cleaned_from_miarka_timestamp || event.timestamp < summary.cleaned_from_miarka_timestamp) { + summary.cleaned_from_miarka_timestamp = event.timestamp; + } + break; + case "retrieved_from_pdc": + summary.retrieved_from_pdc = true; + if (!summary.retrieved_from_pdc_timestamp || event.timestamp < summary.retrieved_from_pdc_timestamp) { + summary.retrieved_from_pdc_timestamp = event.timestamp; + } + break; + case "samplesheet_updated": + summary.samplesheet_updated = true; + if (!summary.samplesheet_updated_timestamp || event.timestamp < summary.samplesheet_updated_timestamp) { + summary.samplesheet_updated_timestamp = event.timestamp; + } + break; + } + }); + + // RunParameters parsing + if (doc.hasOwnProperty("files")){ + if (doc["files"].hasOwnProperty('RunParameters.xml')) { + if (doc["files"]["RunParameters.xml"].hasOwnProperty('RunParameters')){ + var runparameters = doc["files"]['RunParameters.xml']['RunParameters']; + + if (runparameters.hasOwnProperty('Setup')){ + summary["mode"] = runparameters['Setup']["RunMode"]; + summary["type"] = runparameters['Setup']['ApplicationName']; + summary["fctype"] = runparameters['Setup']['Flowcell']; + summary["appver"] = runparameters['Setup']['ApplicationVersion']; + //Miseq + if(runparameters.hasOwnProperty('ReagentKitVersion')){ + summary["kitver"]=runparameters['ReagentKitVersion']; + } + }else{ + if (runparameters.hasOwnProperty('ApplicationName')){ + summary["type"] = runparameters['ApplicationName']; + summary["mode"] = runparameters["RunMode"]; + }else if (runparameters.hasOwnProperty('InstrumentType')){ + // NovaSeq X Plus + summary["type"] = runparameters['InstrumentType']; + summary["mode"] = runparameters["RecipeName"]; + } + if (runparameters.hasOwnProperty('Flowcell')){ + summary["fctype"] = runparameters['Flowcell']; + }else{ + summary["fctype"] = runparameters['FlowCellName']; + } + summary["fctype"] = runparameters['Flowcell']; + summary["appver"] = runparameters['ApplicationVersion']; + } + } + } + } + + // to define tresholds for number of clusters + summary['run_mode']=''; + + if (doc.hasOwnProperty("files") && doc["files"].hasOwnProperty('RunParameters.xml') && doc["files"]["RunParameters.xml"].hasOwnProperty('RunParameters')){ + var runparameters = doc["files"]['RunParameters.xml']['RunParameters']; + + if (runparameters.hasOwnProperty('InstrumentType') && runparameters['InstrumentType'].indexOf('MiSeqi100Plus')!=-1) { + // MiSeqi100 + summary['run_mode']=runparameters['InstrumentType'] + ' ' + runparameters['RecipeName'].split("/")[0]; + } else if (runparameters.hasOwnProperty('ReagentKitVersion') && runparameters.hasOwnProperty('RunParametersVersion') && runparameters['RunParametersVersion'].indexOf('MiSeq') != -1) { + // Old MiSeq + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_type') && doc['lims_data']['run_type']!='null') { + summary['run_mode']='MiSeq ' + doc['lims_data']['run_type']; + } + else { + if (runparameters.hasOwnProperty('Setup') && runparameters['Setup'].hasOwnProperty('SupportMultipleSurfacesInUI') && runparameters['Setup'].hasOwnProperty('NumTilesPerSwath')) { + if (runparameters['Setup']['SupportMultipleSurfacesInUI']=='true' && runparameters['Setup']['NumTilesPerSwath']=='19') { + summary['run_mode']='MiSeq Version3'; + } + else if (runparameters['Setup']['SupportMultipleSurfacesInUI']=='true' && runparameters['Setup']['NumTilesPerSwath']=='14') { + summary['run_mode']='MiSeq Version2'; + } + else if (runparameters['Setup']['SupportMultipleSurfacesInUI']=='false' && runparameters['Setup']['NumTilesPerSwath']=='2') { + summary['run_mode']='MiSeq Version2Nano'; + } + else if (runparameters['Setup']['SupportMultipleSurfacesInUI']=='true' && runparameters['Setup']['NumTilesPerSwath']=='4') { + summary['run_mode']='MiSeq Version2Micro'; + } + else { + summary['run_mode']='MiSeq null'; + } + } + else { + summary['run_mode']='MiSeq ' + runparameters['ReagentKitVersion']; + } + } + } else if (runparameters.hasOwnProperty('Chemistry') && runparameters['Chemistry'].indexOf('NextSeq')!=-1) { + // NextSeq + summary['run_mode']=runparameters['Chemistry']; + } else if (runparameters.hasOwnProperty('InstrumentType')) { + if (runparameters.hasOwnProperty('FlowCellMode') && runparameters['InstrumentType'].indexOf('NextSeq 2000')!=-1) { + summary['run_mode']=runparameters['InstrumentType'] + ' ' + runparameters['FlowCellMode'].match(/P[1,2,3]/)[0]; + } else if (runparameters['InstrumentType'].indexOf('NovaSeqXPlus')!=-1) { + // NovaSeq X Plus + summary['run_mode']=runparameters['InstrumentType'] + ' ' + runparameters['RecipeName'].split(" ")[0]; + } + } else { + summary['run_mode']=''; + } + } + + + + // Extract run date from runfolder_id + var run_date = null; + if (doc.runfolder_id) { + var date_part = doc.runfolder_id.split('_')[0]; + // If only 6 digits, prepend '20' + if (date_part && date_part.length === 6 && /^\d{6}$/.test(date_part)) { + run_date = '20' + date_part; + } else if (date_part && /^\d+$/.test(date_part)) { + run_date = date_part; + } + } + + emit([run_date, doc.flowcell_id], summary); + } +} \ No newline at end of file diff --git a/StatusDB_views/flowcells/info/id.map.js b/StatusDB_views/flowcells/info/id.map.js new file mode 100644 index 0000000..8748f76 --- /dev/null +++ b/StatusDB_views/flowcells/info/id.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['RunInfo']['Id'], doc['_id']); +} diff --git a/StatusDB_views/flowcells/info/name.map.js b/StatusDB_views/flowcells/info/name.map.js new file mode 100644 index 0000000..ea1ce37 --- /dev/null +++ b/StatusDB_views/flowcells/info/name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['RunInfo']['Id'], null); +} diff --git a/StatusDB_views/flowcells/info/software_run_mode.map.js b/StatusDB_views/flowcells/info/software_run_mode.map.js new file mode 100644 index 0000000..26d06b3 --- /dev/null +++ b/StatusDB_views/flowcells/info/software_run_mode.map.js @@ -0,0 +1,9 @@ +function(doc) { + var hcs = doc['RunParameters']['Setup']['ApplicationName'] + " " + doc['RunParameters']['Setup']['ApplicationVersion']; + var rta = "RTA " + doc['RunParameters']['Setup']['RTAVersion'] + var mode = "NA" + if (doc['RunParameters']['Setup']['RunMode']) { + mode = doc['RunParameters']['Setup']['RunMode']; + } + emit(doc['name'],hcs + " / " + rta + " / " + mode); +} diff --git a/StatusDB_views/flowcells/info/storage_status.map.js b/StatusDB_views/flowcells/info/storage_status.map.js new file mode 100644 index 0000000..c803269 --- /dev/null +++ b/StatusDB_views/flowcells/info/storage_status.map.js @@ -0,0 +1,5 @@ +function(doc) { + if ("storage_status" in doc) { + emit(doc['RunInfo']['Id'], doc); + } +} diff --git a/StatusDB_views/flowcells/info/summary.map.js b/StatusDB_views/flowcells/info/summary.map.js new file mode 100644 index 0000000..eb82f11 --- /dev/null +++ b/StatusDB_views/flowcells/info/summary.map.js @@ -0,0 +1,60 @@ +/* + Used by genomics-status at: + /api/v1/flowcell_info, + /api/v1/flowcells +*/ + +function(doc) { + var summary = new Object(); + summary["startdate"] = doc["RunInfo"]["Date"]; + summary["instrument"] = doc["RunInfo"]["Instrument"]; + summary["flowcell"] = doc["RunInfo"]["Flowcell"]; + summary["run id"] = doc["RunInfo"]["Id"]; + summary["pos"] = doc["name"][7]; + summary["reads"] = doc["RunInfo"]["Reads"] + summary["number"] = doc["RunInfo"]["Number"] + summary["recipe"] = doc["run_setup"] + summary['demultiplexing']='Pending'; + summary["pdc_archived"] = doc["pdc_archived"]; + if (doc.hasOwnProperty("RunParameters")){ + if (doc["RunParameters"].hasOwnProperty('Setup')){ + summary["mode"] = doc["RunParameters"]['Setup']["RunMode"]; + summary["type"] = doc['RunParameters']['Setup']['ApplicationName']; + summary["fctype"] = doc['RunParameters']['Setup']['Flowcell']; + summary["appver"] = doc['RunParameters']['Setup']['ApplicationVersion']; + //Miseq + if(doc["RunParameters"].hasOwnProperty('ReagentKitVersion')){ + summary["kitver"]=doc["RunParameters"]['ReagentKitVersion']; + } + }else{ + summary["mode"] = doc["RunParameters"]["RunMode"]; + summary["type"] = doc['RunParameters']['ApplicationName']; + summary["fctype"] = doc['RunParameters']['Flowcell']; + summary["appver"] = doc['RunParameters']['ApplicationVersion']; + } + } + if (doc.hasOwnProperty('illumina') && doc.illumina.hasOwnProperty('Demultiplex_Stats') && doc.illumina['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics')){ + if(doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics') && doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'].length >0){ + summary['demultiplexing']='Done'; + } + /*yield is in Mb, but is displayed in Gb*/ + summary['yield']=0; + var undetermined={1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0}; + + for(barcode in doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics']){ + if (doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Index'] == 'Undetermined'){ + undetermined[doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Lane']]+=1; + } + intLocalYield=parseInt(doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Yield (Mbases)'].replace(/,/g, "")); + summary['yield']=summary['yield']+intLocalYield; + } + summary['yield']=summary['yield']/1000; + for (lane in undetermined){ + if (undetermined[lane]>1){ + /*if there is more than one undetermined indices, the actual yield is messed up, so we don't display it*/ + summary['yield']=0; + } + } + } + emit(doc["name"], summary); +} diff --git a/StatusDB_views/flowcells/info/summary2.map.js b/StatusDB_views/flowcells/info/summary2.map.js new file mode 100644 index 0000000..6bf18a2 --- /dev/null +++ b/StatusDB_views/flowcells/info/summary2.map.js @@ -0,0 +1,91 @@ + +/* + Used by genomics-status at: + /api/v1/flowcell_info2, +*/ + +function ( doc) { + sum=Object(); + sum['name']=doc['name']; + if (doc['illumina'].hasOwnProperty('Summary')&& doc['RunInfo'].hasOwnProperty('Date')){ + sum['seqdone']=doc['RunInfo']['Date']; + if (doc['illumina']['Summary'].hasOwnProperty('read3')){ + //error rates per read and per lane + sum['err1']=Array(-1,0,0,0,0,0,0,0,0); + sum['err2']=Array(-1,0,0,0,0,0,0,0,0); + sum['err3']=Array(-1,0,0,0,0,0,0,0,0); + for(i=1;i<4;i++){ + for(lane in doc['illumina']['Summary']['read'+i]){ + sum['err'+i][lane]=doc['illumina']['Summary']['read'+i][lane]['ErrRatePhiX']; + } + } + } + } + if (doc['illumina'].hasOwnProperty('Demultiplex_Stats') && doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics') && doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'].length >0){ + sum['lane']=Object(); + //lanes are arrays of subsets + sum['lane']['1']=Array(); + sum['lane']['2']=Array(); + sum['lane']['3']=Array(); + sum['lane']['4']=Array(); + sum['lane']['5']=Array(); + sum['lane']['6']=Array(); + sum['lane']['7']=Array(); + sum['lane']['8']=Array(); + sum['yields']=Array(-1,0,0,0,0,0,0,0,0); + sum['seq_qc']=Array(-1,0,0,0,0,0,0,0,0); + sum['demuldone']=true; + subsets=[]; + plist=[]; + + for (lane in doc['illumina']['run_summary']){ + sum['seq_qc'][lane]=doc['illumina']['run_summary'][lane]['qc']; + } + + for (sample in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics']){ + id=doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][sample]; + //if(id['Project']==='Undetermined_indices'){ + // continue; + //} + //subsets are sample objects" + Subset=Object(); + Subset['SampleName']=id['Sample ID']; + Subset['readsnb']=id['# Reads']; + proj_name = id['Project']; + plist.push(proj_name); + Subset['Project']=proj_name; + + lane = id['Lane']; + Subset['lane']=lane; + Subset['yield']=id['Yield (Mbases)']; + sum['yields'][lane]+=parseInt(id['Yield (Mbases)'].replace(",","")); + Subset['overthirty']=id['% of >= Q30 Bases (PF)']; + + Subset['barcode']=id['Index']; + Subset['desc']=id['Description']; + + if (doc.hasOwnProperty('lims_data') && doc.lims_data.run_summary[lane].hasOwnProperty('% phiX')){ + Subset['phix']=doc.lims_data.run_summary[lane]['% phiX']; + } + if (doc.hasOwnProperty('lims_data') && doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R1')){ + var er_rate=doc.lims_data.run_summary[lane]['% Error Rate R1']; + if (doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R2') && doc.lims_data.run_summary[lane]['% Error Rate R2'] != 0){ + er_rate=(er_rate+doc.lims_data.run_summary[lane]['% Error Rate R1'])/2; + } + Subset['er_rate']=er_rate; + } + subsets.push(Subset); + } + for (s in subsets){ + //order by lane + sum['lane'][subsets[s]['lane']].push(subsets[s]); + } + //clean duplicates + sum['plist']=plist.filter(function( item, index, inputArray ) { + return inputArray.indexOf(item) == index; + }); + + + } + emit(doc.name, sum) +} \ No newline at end of file diff --git a/StatusDB_views/flowcells/instr/unmatched.map.js b/StatusDB_views/flowcells/instr/unmatched.map.js new file mode 100644 index 0000000..c060e19 --- /dev/null +++ b/StatusDB_views/flowcells/instr/unmatched.map.js @@ -0,0 +1,9 @@ +function(doc) { + var unmatched = [] + for (lane in doc["lanes"]) { + if (doc["lanes"][lane]["bc_metrics"]["unmatched"]) { + unmatched.push(doc["lanes"][lane]["bc_metrics"]["unmatched"]); + }; + }; + emit([doc["RunInfo"]["Date"], doc["RunInfo"]["Instrument"]], unmatched); +}; diff --git a/StatusDB_views/flowcells/instrument/bp_yield.map.js b/StatusDB_views/flowcells/instrument/bp_yield.map.js new file mode 100644 index 0000000..9562d8f --- /dev/null +++ b/StatusDB_views/flowcells/instrument/bp_yield.map.js @@ -0,0 +1,14 @@ +/** + * Total yield per flowcell, based on Demultiplex counts, taking read length into account + */ +function(doc) { + tot = 0; + for (s in doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]) { + y = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][s]["Yield (Mbases)"]; + if (y == null) { + y = "0"; + } + tot += parseInt(y.replace(",",""))*1e6; + } + emit([doc["RunParameters"]["RunMode"],doc["RunInfo"]["Date"],doc["RunInfo"]["Id"]],tot); +} diff --git a/StatusDB_views/flowcells/instrument/clusters_raw.map.js b/StatusDB_views/flowcells/instrument/clusters_raw.map.js new file mode 100644 index 0000000..d1a04ef --- /dev/null +++ b/StatusDB_views/flowcells/instrument/clusters_raw.map.js @@ -0,0 +1,15 @@ +/* + Used by genomics-status at: + /api/v1/instrument_cluster_density, + /api/v1/instrument_cluster_density.png +*/ + +function(doc) { + var clusters = [] + for (lane in doc["illumina"]["Summary"]["read1"]) { + if (doc["illumina"]["Summary"]["read1"][lane]["ClustersRaw"]) { + clusters.push(+doc["illumina"]["Summary"]["read1"][lane]["ClustersRaw"]) + } + } + emit([doc["RunInfo"]["Date"], doc["RunInfo"]["Instrument"]], clusters); +} diff --git a/StatusDB_views/flowcells/instrument/error_rates.map.js b/StatusDB_views/flowcells/instrument/error_rates.map.js new file mode 100644 index 0000000..d732f50 --- /dev/null +++ b/StatusDB_views/flowcells/instrument/error_rates.map.js @@ -0,0 +1,17 @@ +/* + Used by genomics-status at: + /api/v1/instrument_error_rates + /api/v1/instrument_error_rates.png +*/ + +function(doc) { + var error_rates = []; + for (lane in doc["lanes"]) { + for (read in doc["RunInfo"]["Reads"]) { + if (doc["RunInfo"]["Reads"][read]["IsIndexedRead"] === "N") { + error_rates.push(+doc["illumina"]["Summary"]["read" + doc["RunInfo"]["Reads"][read]["Number"]][lane]["ErrRatePhiX"]); + }; + }; + }; + emit([doc["RunInfo"]["Date"], doc["RunInfo"]["Instrument"]], error_rates); +}; diff --git a/StatusDB_views/flowcells/instrument/unmatched.map.js b/StatusDB_views/flowcells/instrument/unmatched.map.js new file mode 100644 index 0000000..c4b4a37 --- /dev/null +++ b/StatusDB_views/flowcells/instrument/unmatched.map.js @@ -0,0 +1,15 @@ +/* + Used by genomics-status at: + /api/v1/instrument_unmatched, + /api/v1/instrument_unmatched.png +*/ + +function(doc) { + var unmatched = [] + for (lane in doc["lanes"]) { + if (doc["lanes"][lane]["bc_metrics"]["unmatched"]) { + unmatched.push(doc["lanes"][lane]["bc_metrics"]["unmatched"]); + }; + }; + emit([doc["RunInfo"]["Date"], doc["RunInfo"]["Instrument"]], unmatched); +}; diff --git a/StatusDB_views/flowcells/instrument/yield.map.js b/StatusDB_views/flowcells/instrument/yield.map.js new file mode 100644 index 0000000..cd0411a --- /dev/null +++ b/StatusDB_views/flowcells/instrument/yield.map.js @@ -0,0 +1,21 @@ +/* + Used by genomics-status at: + /api/v1/instrument_yield, + /api/v1/instrument_yield.png +*/ + +function(doc) { + var yields = [] + for (lane in doc["lanes"]) { + if (doc["illumina"]["Demultiplex_Stats"] !== undefined) { + var yield = 0 + for (sample in doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]) { + if (doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["Lane"] === lane) { + yield += 0.5*doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["# Reads"].replace(/,/g,"") + }; + }; + }; + yields.push(yield) + }; + emit([doc["RunInfo"]["Date"], doc["RunInfo"]["Instrument"]], yields); +}; diff --git a/StatusDB_views/flowcells/lanes/bp_yield.map.js b/StatusDB_views/flowcells/lanes/bp_yield.map.js new file mode 100644 index 0000000..7c18591 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/bp_yield.map.js @@ -0,0 +1,27 @@ +/** + * Total yield per lane, takes the read length into account + */ +function(doc) { + nreads = 0 + for (r in doc["RunInfo"]["Reads"]) { + if (doc["RunInfo"]["Reads"][r]["IsIndexedRead"] === "N") { + nreads += 1; + } + } + var lanes = doc["illumina"]["run_summary"]; + for (l in lanes) { + lane_yield = 0; + for (var r=1; r<=nreads; r++) { + y = doc["illumina"]["run_summary"][l]["Yield PF (Gb) R" + r.toString()]; + if (y == null) { + y = 0; + } + lane_yield += y; + } + var mode = doc["RunParameters"]["RunMode"]; + if(mode == null && doc["RunParameters"]["SampleSheetFolder"].indexOf("MiSeq") != -1) { + mode = "MiSeq"; + } + emit([mode, doc["RunInfo"]["Id"], l],lane_yield*1e9); + } +} diff --git a/StatusDB_views/flowcells/lanes/cluster_cont.map.js b/StatusDB_views/flowcells/lanes/cluster_cont.map.js new file mode 100644 index 0000000..271a91e --- /dev/null +++ b/StatusDB_views/flowcells/lanes/cluster_cont.map.js @@ -0,0 +1,7 @@ +function(doc) { + for (lane in doc["illumina"]["Summary"]["read1"]) { + if (doc["illumina"]["Summary"]["read1"][lane]["ClustersRaw"]) { + emit([doc["name"],lane], {"clusters_raw": doc["illumina"]["Summary"]["read1"][lane]["ClustersRaw"], "clusters_pf": doc["illumina"]["Summary"]["read1"][lane]["ClustersPF"]}); + } + } +} diff --git a/StatusDB_views/flowcells/lanes/cluster_count.map.js b/StatusDB_views/flowcells/lanes/cluster_count.map.js new file mode 100644 index 0000000..271a91e --- /dev/null +++ b/StatusDB_views/flowcells/lanes/cluster_count.map.js @@ -0,0 +1,7 @@ +function(doc) { + for (lane in doc["illumina"]["Summary"]["read1"]) { + if (doc["illumina"]["Summary"]["read1"][lane]["ClustersRaw"]) { + emit([doc["name"],lane], {"clusters_raw": doc["illumina"]["Summary"]["read1"][lane]["ClustersRaw"], "clusters_pf": doc["illumina"]["Summary"]["read1"][lane]["ClustersPF"]}); + } + } +} diff --git a/StatusDB_views/flowcells/lanes/clusters.map.js b/StatusDB_views/flowcells/lanes/clusters.map.js new file mode 100644 index 0000000..9123a64 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/clusters.map.js @@ -0,0 +1,17 @@ +/* + Used by genomics-status at: + /api/v1/plot/clusters_per_lane.png +*/ + +function(doc) { + for (lane in doc.illumina.run_summary) { + var data ={}; + + data['filtered_clusters']=doc.illumina.run_summary[lane]['Clusters PF R1']; + data['unfiltered_clusters']=doc.illumina.run_summary[lane]['Clusters Raw R1']; + + + emit([doc["name"], lane], data); + + }; +}; \ No newline at end of file diff --git a/StatusDB_views/flowcells/lanes/date_pf.map.js b/StatusDB_views/flowcells/lanes/date_pf.map.js new file mode 100644 index 0000000..8fc28d8 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/date_pf.map.js @@ -0,0 +1,35 @@ +/** + * reads/per_lane + */ +function(doc) { +// var lanes = doc["illumina"]["run_summary"]; + var num_lanes = 0; +// for (l in lanes) { +// num_lanes++; +// } + + var date = doc["RunParameters"]["RunStartDate"]; + var mode = doc["RunParameters"]["RunMode"]; + if(mode == null && doc["RunParameters"]["SampleSheetFolder"].indexOf("MiSeq") != -1) { + mode = "MiSeq"; + } + if (mode == "HighOutput") { + num_lanes = 8; + } else if (mode == "RapidRun") { + num_lanes = 2; + } else if (mode == "MiSeq") { + num_lanes = 1; + } + emit([date, mode, doc["RunInfo"]["Id"]],num_lanes); +// emit([date, mode, doc["RunInfo"]["Id"]],lanes); + +// for (l in lanes) { +// var reads = doc["illumina"]["run_summary"][l]["Clusters PF R1"]; +// var mode = doc["RunParameters"]["RunMode"]; +// if(mode == null && doc["RunParameters"]["SampleSheetFolder"].indexOf("MiSeq") != -1) { +// mode = "MiSeq"; +// } +// emit([mode, doc["RunInfo"]["Id"], l],reads); +// } + +} diff --git a/StatusDB_views/flowcells/lanes/date_pf.reduce.js b/StatusDB_views/flowcells/lanes/date_pf.reduce.js new file mode 100644 index 0000000..a105062 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/date_pf.reduce.js @@ -0,0 +1 @@ +_sum diff --git a/StatusDB_views/flowcells/lanes/demultiplex.map.js b/StatusDB_views/flowcells/lanes/demultiplex.map.js new file mode 100644 index 0000000..3c063bf --- /dev/null +++ b/StatusDB_views/flowcells/lanes/demultiplex.map.js @@ -0,0 +1,26 @@ +/* + Used by genomics-status at: + /api/v1/flowcell_demultiplex/:id, + /api/v1/plot/reads_per_lane.png +*/ + +function(doc) { + for (lane in doc["lanes"]) { + var demultiplex = Object() + var bc_metrics = doc["lanes"][lane]["bc_metrics"] + + matched = 0 + for (index in bc_metrics) { + if (index != "unmatched") { + matched += bc_metrics[index]; + } + } + + demultiplex["matched"] = matched; + demultiplex["yield"] = matched + bc_metrics["unmatched"]; + demultiplex["demultiplexed"] = demultiplex["matched"] / demultiplex["yield"]; + + emit([doc["name"], lane], demultiplex); + + }; +}; diff --git a/StatusDB_views/flowcells/lanes/err_rate_phix_yield.map.js b/StatusDB_views/flowcells/lanes/err_rate_phix_yield.map.js new file mode 100644 index 0000000..5f86fa8 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/err_rate_phix_yield.map.js @@ -0,0 +1,27 @@ +/* + Used by genomics-status at: + /api/v1/phix_err_rate +*/ + +function(doc) { + for (lane in doc["lanes"]) { + var sum = 0; + var count = 0; + var yield = null; + for (read in doc["RunInfo"]["Reads"]) { + if (doc["RunInfo"]["Reads"][read]["IsIndexedRead"] === "N") { + sum += 1*doc["illumina"]["Summary"]["read" + doc["RunInfo"]["Reads"][read]["Number"]][lane]["ErrRatePhiX"]; + count++; + }; + }; + if (doc["illumina"]["Demultiplex_Stats"] !== undefined) { + yield = 0 + for (sample in doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]) { + if (doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["Lane"] === lane) { + yield += 0.5*doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["# Reads"].replace(/,/g,"") + } + } + }; + emit([doc["name"], lane], {"err_rate_phix": (sum/count), "yield": yield}); + }; +}; diff --git a/StatusDB_views/flowcells/lanes/gtq30.map.js b/StatusDB_views/flowcells/lanes/gtq30.map.js new file mode 100644 index 0000000..e63d493 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/gtq30.map.js @@ -0,0 +1,25 @@ +/* + Used by genomics-status at: + /api/v1/flowcell_q30/:id, + /api/v1/plot/q30.png +*/ + +function(doc) { + var stats = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]; + var instrument = doc["RunInfo"]["Instrument"] + var runmode = doc["RunParameters"]["RunMode"] + + var setup = []; + for (read in doc["RunInfo"]["Reads"]) { + if (doc["RunInfo"]["Reads"][read]["IsIndexedRead"] === "N") { + setup.push(+doc["RunInfo"]["Reads"][read]["NumCycles"]); + } + } + + for (sample in stats) { + var q30 = stats[sample]["% of >= Q30 Bases (PF)"]; + + emit([doc["name"], runmode, stats[sample]["Lane"], stats[sample]["Index"]], + {"sum": +q30, "count": 1, "instrument": instrument, "setup": setup}); + }; +}; diff --git a/StatusDB_views/flowcells/lanes/gtq30.reduce.js b/StatusDB_views/flowcells/lanes/gtq30.reduce.js new file mode 100644 index 0000000..60d1a75 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/gtq30.reduce.js @@ -0,0 +1,13 @@ +function (key, values, rereduce) { + var result = {'sum': 0, 'count': 0, 'instrument': null, 'setup': null} + + for (v in values) { + result['count'] += values[v]['count'] || 0 + result['sum'] += values[v]['sum'] || 0 + result['instrument'] = values[v]['instrument'] + result['setup'] = values[v]['setup'] + } + + return result + +} diff --git a/StatusDB_views/flowcells/lanes/gtq30_old.map.js b/StatusDB_views/flowcells/lanes/gtq30_old.map.js new file mode 100644 index 0000000..d718ba6 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/gtq30_old.map.js @@ -0,0 +1,21 @@ +// Used by: genomics-status.scilifelab.se/q30 + +function(doc) { + var stats = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]; + var instrument = doc["RunInfo"]["Instrument"] + var runmode = doc["RunParameters"]["RunMode"] + + var setup = []; + for (read in doc["RunInfo"]["Reads"]) { + if (doc["RunInfo"]["Reads"][read]["IsIndexedRead"] === "N") { + setup.push(+doc["RunInfo"]["Reads"][read]["NumCycles"]); + } + } + + for (sample in stats) { + var q30 = stats[sample]["% of >= Q30 Bases (PF)"]; + + emit([doc["name"], stats[sample]["Lane"], stats[sample]["Index"]], + {"sum": +q30, "count": 1, "instrument": instrument, "setup": setup}); + }; +}; \ No newline at end of file diff --git a/StatusDB_views/flowcells/lanes/gtq30_old.reduce.js b/StatusDB_views/flowcells/lanes/gtq30_old.reduce.js new file mode 100644 index 0000000..60d1a75 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/gtq30_old.reduce.js @@ -0,0 +1,13 @@ +function (key, values, rereduce) { + var result = {'sum': 0, 'count': 0, 'instrument': null, 'setup': null} + + for (v in values) { + result['count'] += values[v]['count'] || 0 + result['sum'] += values[v]['sum'] || 0 + result['instrument'] = values[v]['instrument'] + result['setup'] = values[v]['setup'] + } + + return result + +} diff --git a/StatusDB_views/flowcells/lanes/project_lane_undemultiplex.map.js b/StatusDB_views/flowcells/lanes/project_lane_undemultiplex.map.js new file mode 100644 index 0000000..8f3a252 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/project_lane_undemultiplex.map.js @@ -0,0 +1,33 @@ +function(doc) { + var projects = {}; + var total = {}; + var undemux = {}; + var index = {}; + if ("Demultiplex_Stats" in doc["illumina"]) { + + for (sample in doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]) { + lane = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["Lane"]; + proj = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["Project"].replace("__","."); + idx = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["Index"].replace("-",""); + count = parseInt(doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"][sample]["# Reads"].replace(",","")); + + if (!(lane in total)) { + total[lane] = 0; + projects[lane] = {}; + index[lane] = {}; + } + +      total[lane] += count; + if (proj == "Undetermined_indices") { + undemux[lane] = count; + } + else { + projects[lane][proj] = 1; + index[lane][idx.length.toString()] = idx.length; + } + } + for (var lane in total) { + emit([Object.keys(projects[lane]).join(),doc["name"],lane],{"index_length": Object.keys(index[lane]).join(), "fraction_undemultiplexed": undemux[lane]/total[lane]}); + } + } +}; diff --git a/StatusDB_views/flowcells/lanes/projects.map.js b/StatusDB_views/flowcells/lanes/projects.map.js new file mode 100644 index 0000000..2f3b22f --- /dev/null +++ b/StatusDB_views/flowcells/lanes/projects.map.js @@ -0,0 +1,18 @@ +function(doc) { + lane_projs = Object() + for (sample in doc["samplesheet_csv"]){ + sample_id = doc["samplesheet_csv"][sample]["SampleID"] + proj_id = sample_id.split("_")[0] + lane = doc["samplesheet_csv"][sample]["Lane"] + if (typeof(lane_projs[lane]) === 'undefined'){ + lane_projs[lane] = [] + } + if (lane_projs[lane].indexOf(proj_id) === -1){ + lane_projs[lane].push(proj_id) + } + } + + for (lane in lane_projs){ + emit([doc["name"], lane], lane_projs[lane]) + } +} diff --git a/StatusDB_views/flowcells/lanes/qc.map.js b/StatusDB_views/flowcells/lanes/qc.map.js new file mode 100644 index 0000000..1cd1892 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/qc.map.js @@ -0,0 +1,15 @@ +/* + Used by genomics-status at: + /api/v1/flowcell_qc/:id +*/ + +function(doc) { + for (lane in doc["lanes"]) { + + var r1 = doc["illumina"]["Summary"]["read1"][lane]; + var r3 = doc["illumina"]["Summary"]["read3"][lane]; + + emit([doc["name"], lane], {"read1": r1, "read3": r3}); + + }; +}; diff --git a/StatusDB_views/flowcells/lanes/qtq30_old.map.js b/StatusDB_views/flowcells/lanes/qtq30_old.map.js new file mode 100644 index 0000000..7cb4ec8 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/qtq30_old.map.js @@ -0,0 +1,21 @@ +// Used by: genomics-status.scilifelab.se/q30 + +function(doc) { + var stats = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]; + var instrument = doc["RunInfo"]["Instrument"] + var runmode = doc["RunParameters"]["RunMode"] + + var setup = []; + for (read in doc["RunInfo"]["Reads"]) { + if (doc["RunInfo"]["Reads"][read]["IsIndexedRead"] === "N") { + setup.push(+doc["RunInfo"]["Reads"][read]["NumCycles"]); + } + } + + for (sample in stats) { + var q30 = stats[sample]["% of >= Q30 Bases (PF)"]; + + emit([doc["name"], stats[sample]["Lane"], stats[sample]["Index"]], + {"sum": +q30, "count": 1, "instrument": instrument, "setup": setup}); + }; +}; diff --git a/StatusDB_views/flowcells/lanes/unmatched.map.js b/StatusDB_views/flowcells/lanes/unmatched.map.js new file mode 100644 index 0000000..0edff71 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/unmatched.map.js @@ -0,0 +1,13 @@ +/* + Used by genomics-status at: + /api/v1/expected + /api/v1/plot/barcodes_vs_expected.png +*/ + +function(doc) { + for (lane in doc["lanes"]) { + if (doc["lanes"][lane]["bc_metrics"]["unmatched"]) { + emit([doc["name"].substr(7), lane], doc["lanes"][lane]["bc_metrics"]["unmatched"]); + }; + }; +}; diff --git a/StatusDB_views/flowcells/lanes/unmatched.reduce.js b/StatusDB_views/flowcells/lanes/unmatched.reduce.js new file mode 100644 index 0000000..a105062 --- /dev/null +++ b/StatusDB_views/flowcells/lanes/unmatched.reduce.js @@ -0,0 +1 @@ +_sum diff --git a/StatusDB_views/flowcells/lims/summary.map.js b/StatusDB_views/flowcells/lims/summary.map.js new file mode 100644 index 0000000..092167e --- /dev/null +++ b/StatusDB_views/flowcells/lims/summary.map.js @@ -0,0 +1,9 @@ +function(doc) { + if (doc.hasOwnProperty('lims_data')){ + data={}; + data['step_id']=doc.lims_data.step_id; + data['container_id']=doc.lims_data.container_id; + data['container_name']=doc.lims_data.container_name; + emit(doc.name, data); +} +} \ No newline at end of file diff --git a/StatusDB_views/flowcells/names/Barcode_lane_stat.map.js b/StatusDB_views/flowcells/names/Barcode_lane_stat.map.js new file mode 100644 index 0000000..013e8c4 --- /dev/null +++ b/StatusDB_views/flowcells/names/Barcode_lane_stat.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["name"],doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"] ); +} diff --git a/StatusDB_views/flowcells/names/id_to_name.map.js b/StatusDB_views/flowcells/names/id_to_name.map.js new file mode 100644 index 0000000..cdc11c8 --- /dev/null +++ b/StatusDB_views/flowcells/names/id_to_name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["_id"], doc["name"]); +} diff --git a/StatusDB_views/flowcells/names/name.map.js b/StatusDB_views/flowcells/names/name.map.js new file mode 100644 index 0000000..f113de1 --- /dev/null +++ b/StatusDB_views/flowcells/names/name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["name"], null); +} diff --git a/StatusDB_views/flowcells/names/name.reduce.js b/StatusDB_views/flowcells/names/name.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/flowcells/names/name.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/flowcells/names/project_ids_list.map.js b/StatusDB_views/flowcells/names/project_ids_list.map.js new file mode 100644 index 0000000..98ac5be --- /dev/null +++ b/StatusDB_views/flowcells/names/project_ids_list.map.js @@ -0,0 +1,8 @@ +function(doc) { + var proj_in_fc = {} + for (sample in doc["samplesheet_csv"]){ + var proj_id = doc["samplesheet_csv"][sample]["SampleID"].split("_")[0] + proj_in_fc[proj_id] = true + } + emit(doc["name"], Object.keys(proj_in_fc)) +} diff --git a/StatusDB_views/flowcells/reads/per_lane.map.js b/StatusDB_views/flowcells/reads/per_lane.map.js new file mode 100644 index 0000000..b5bc270 --- /dev/null +++ b/StatusDB_views/flowcells/reads/per_lane.map.js @@ -0,0 +1,14 @@ +/** + * reads/per_lane + */ +function(doc) { + var lanes = doc["illumina"]["run_summary"]; + for (l in lanes) { + var reads = doc["illumina"]["run_summary"][l]["Clusters PF R1"]; + var mode = doc["RunParameters"]["RunMode"]; + if(mode == null && doc["RunParameters"]["SampleSheetFolder"].indexOf("MiSeq") != -1) { + mode = "MiSeq"; + } + emit([mode, doc["RunInfo"]["Id"], l],reads); + } +} diff --git a/StatusDB_views/flowcells/samples/demultiplex.map.js b/StatusDB_views/flowcells/samples/demultiplex.map.js new file mode 100644 index 0000000..048b688 --- /dev/null +++ b/StatusDB_views/flowcells/samples/demultiplex.map.js @@ -0,0 +1,11 @@ +function(doc) { + var stats = doc["illumina"]["Demultiplex_Stats"]["Barcode_lane_statistics"]; + for (sample in stats) { + var stat = Object(); + stat["sample"] = stats[sample]; + stat["instrument"] = doc["RunInfo"]["Instrument"]; + stat["setup"] = doc["RunInfo"]["Reads"]; + + emit([doc["name"], stat["sample"]["Lane"], stat["sample"]["Index"]], stat); + }; +}; diff --git a/StatusDB_views/flowcells/samples/lane_clusters.map.js b/StatusDB_views/flowcells/samples/lane_clusters.map.js new file mode 100644 index 0000000..2fbc1e8 --- /dev/null +++ b/StatusDB_views/flowcells/samples/lane_clusters.map.js @@ -0,0 +1,23 @@ +function(doc) { + var key=''; + var vk = ''; + var obj={}; + var cl=0; + if ('illumina' in doc && 'Demultiplex_Stats' in doc['illumina'] && 'Barcode_lane_statistics' in doc['illumina']['Demultiplex_Stats']){ + for (barcode in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics']){ + key=doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Sample ID']; + if (key.indexOf("Sample_")!= -1){ + key=key.substr(7); + } + vk=doc['RunInfo']['Id']+':'+doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Lane']; + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['# Reads'].replace(/,/g,'')); + q30=parseFloat(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['% of >= Q30 Bases (PF)']); + obj={fcp: vk,cl : cl,q30 : q30}; + + if (['', 'Undetermined', 'unknown'].indexOf(key)== -1){ + emit(key, obj); + } + } + } + +} \ No newline at end of file diff --git a/StatusDB_views/flowcells/time/dates.map.js b/StatusDB_views/flowcells/time/dates.map.js new file mode 100644 index 0000000..cd57d51 --- /dev/null +++ b/StatusDB_views/flowcells/time/dates.map.js @@ -0,0 +1,5 @@ +function(doc) { + var date_name = doc["name"].split("_"); + var d = date_name[0]; + emit([d.substr(0,2), d.substr(2,2), d.substr(4,2)], doc["name"]); +} diff --git a/StatusDB_views/flowcells/time/dates.reduce.js b/StatusDB_views/flowcells/time/dates.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/flowcells/time/dates.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/flowcells/time/last_updated.map.js b/StatusDB_views/flowcells/time/last_updated.map.js new file mode 100644 index 0000000..56bc678 --- /dev/null +++ b/StatusDB_views/flowcells/time/last_updated.map.js @@ -0,0 +1,8 @@ +/* + Used by genomics-status at: + /api/v1/last_updated +*/ + +function(doc) { + emit(doc['modification_time'], doc['name']); +} diff --git a/StatusDB_views/gs_users/authorized/api_users.map.js b/StatusDB_views/gs_users/authorized/api_users.map.js new file mode 100644 index 0000000..32a5140 --- /dev/null +++ b/StatusDB_views/gs_users/authorized/api_users.map.js @@ -0,0 +1,4 @@ +function (doc) { + if(doc["web_user"]===false) + emit(doc["key"]["key_id"], doc["key"]); +} \ No newline at end of file diff --git a/StatusDB_views/gs_users/authorized/info.map.js b/StatusDB_views/gs_users/authorized/info.map.js new file mode 100644 index 0000000..7978bd0 --- /dev/null +++ b/StatusDB_views/gs_users/authorized/info.map.js @@ -0,0 +1,13 @@ +/* This view is the authorative source for user roles + in genomics-status */ + +function(doc) { + if (doc["username"]!='genstat-defaults') { + summary = {}; + summary['name'] = doc['name'] + summary['initials'] = doc["initials"]; + summary['roles'] = doc["roles"]; + summary['teams'] = doc["teams"]; + emit(doc["username"], summary); + } +} \ No newline at end of file diff --git a/StatusDB_views/gs_users/authorized/users.map.js b/StatusDB_views/gs_users/authorized/users.map.js new file mode 100644 index 0000000..d0f0f8a --- /dev/null +++ b/StatusDB_views/gs_users/authorized/users.map.js @@ -0,0 +1,6 @@ +/* This view is the authorative source for login + credentials to genomics-status */ + +function(doc) { + emit(doc["username"], doc["_id"]); +} diff --git a/StatusDB_views/instrument_logs/time/last_week.map.js b/StatusDB_views/instrument_logs/time/last_week.map.js new file mode 100644 index 0000000..f354b39 --- /dev/null +++ b/StatusDB_views/instrument_logs/time/last_week.map.js @@ -0,0 +1,8 @@ +function(doc) { + var now=new Date(); + var then=new Date(doc.timestamp); + var days_diff=(now-then)/1000/60/60/24; + if (days_diff<7){ + emit(doc.timestamp, doc); + } +} \ No newline at end of file diff --git a/StatusDB_views/instrument_logs/time/timestamp.map.js b/StatusDB_views/instrument_logs/time/timestamp.map.js new file mode 100644 index 0000000..a5a69ae --- /dev/null +++ b/StatusDB_views/instrument_logs/time/timestamp.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.timestamp, doc); +} \ No newline at end of file diff --git a/StatusDB_views/instruments/info/id_to_name.map.js b/StatusDB_views/instruments/info/id_to_name.map.js new file mode 100644 index 0000000..5c30761 --- /dev/null +++ b/StatusDB_views/instruments/info/id_to_name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.serial_number, doc.name); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/dashboard/week_instr_bp.map.js b/StatusDB_views/nanopore_runs/dashboard/week_instr_bp.map.js new file mode 100644 index 0000000..27f651d --- /dev/null +++ b/StatusDB_views/nanopore_runs/dashboard/week_instr_bp.map.js @@ -0,0 +1,47 @@ +function(doc) { + var prev_monday=null; + var seqtype=null; + var yd=0; + var key= []; + + run_path = doc['run_path'] + path_parts = run_path.split("/") + run_name = path_parts[path_parts.length - 1] + // Some ids iclude the '20' century and some do not + var d_str = run_name.split("_")[0].slice(-6); + + var run_date=new Date(parseInt('20' + d_str.slice(0,2)), parseInt(d_str.slice(2,4),10)-1, parseInt(d_str.slice(4,6),10)); + + + var dw = run_date.getDay(); + if (dw===0){ + prev_monday=new Date(run_date.getFullYear(), run_date.getMonth(), (run_date.getDate()-6)); + }else{ + prev_monday=new Date(run_date.getFullYear(), run_date.getMonth(), (run_date.getDate() - run_date.getDay() + 1)); + } + + d_str=prev_monday.getDate().toString(); + + if (prev_monday.getDate()<10){ + d_str = "0"+d_str; + } + var m_str=(prev_monday.getMonth() + 1).toString(); + if (prev_monday.getMonth() + 1 < 10){ + m_str = "0"+m_str; + } + var prev_monday_str=prev_monday.getFullYear().toString() + "-" + m_str + "-" + d_str; + + seqtype = doc.protocol_run_info.device.device_type; + seqtype_translation = {'PROMETHION': 'PromethION', 'MINION': 'MinION'} + if (seqtype in seqtype_translation) { + seqtype = seqtype_translation[seqtype]; + } + + key=[prev_monday_str, seqtype]; + acquisition = doc.acquisitions[doc.acquisitions.length - 1] + yd_passed=parseInt(acquisition.acquisition_run_info.yield_summary.basecalled_pass_bases.replace(/,/g,'')); + yd_failed=parseInt(acquisition.acquisition_run_info.yield_summary.basecalled_fail_bases.replace(/,/g,'')); + + yd = yd_passed + yd_failed; + emit(key, yd); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/dashboard/week_instr_bp.reduce.js b/StatusDB_views/nanopore_runs/dashboard/week_instr_bp.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/nanopore_runs/dashboard/week_instr_bp.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/info/all_stats.map.js b/StatusDB_views/nanopore_runs/info/all_stats.map.js new file mode 100644 index 0000000..c9dcf8a --- /dev/null +++ b/StatusDB_views/nanopore_runs/info/all_stats.map.js @@ -0,0 +1,81 @@ +function(doc) { + + function last(list) { + len = list.length + return list[len - 1]; + } + + // Fetch key + run_name = last(doc['run_path'].split("/")) + + // Start building val dict + var all_stats = new Object(); + all_stats["TACA_run_path"] = doc['run_path'] + all_stats["TACA_run_status"] = doc['run_status'] + + // If the MinKNOW .json report has been appended to the db entry + if (doc.hasOwnProperty('protocol_run_info')) { + // Specification of projects and samples + all_stats['experiment_name'] = doc['protocol_run_info']['user_info']['protocol_group_id']; // Should correspond to project ID by convention + all_stats['sample_name'] = doc['protocol_run_info']['user_info']['sample_id']; // Should correspond to sample or pool ID by convention + + // Hardware + if (doc['host']['product_name'] == "PromethION 24" ) { + // PromethION + all_stats['instrument'] = doc['host']['product_name']; + all_stats['position'] = doc['protocol_run_info']['device']['device_id']; + } else if (doc['host']['product_name'] === "" ){ + // MinION + all_stats['instrument'] = doc['protocol_run_info']['device']['device_id']; + } + all_stats['flow_cell_type'] = doc['protocol_run_info']['meta_info']['tags']['flow cell']['string_value']; + all_stats['flow_cell_id'] = doc['protocol_run_info']['user_info']['user_specified_flow_cell_id']; + all_stats['prep_kit'] = doc['protocol_run_info']['meta_info']['tags']['kit']["string_value"]; + + args = doc['protocol_run_info']['args'] + if (args.indexOf('--barcoding' != -1)) { + bc_kit_str = args[args.indexOf('--barcoding')+1] + all_stats["barcoding_kit"] = bc_kit_str.split('\"')[1] + } + + // Run metadata + all_stats["run_id"] = doc['protocol_run_info']['run_id'] + all_stats['start_date'] = doc['protocol_run_info']['start_time'].split("T")[0]; + all_stats['end_date'] = doc['protocol_run_info']['end_time'].split("T")[0]; + + // Dangerously assume (may need fixing) that last acquisition is the correct one, i.e.: + // "acquisition_run_info" --> "config_summary" --> "purpose" : "SEQUENCING" + last_acquisition = last(doc['acquisitions']) + + // Read counts + yield_summary = last_acquisition['acquisition_run_info']['yield_summary'] + all_stats["read_count"] = yield_summary['read_count'] + all_stats["basecalled_pass_read_count"] = yield_summary['basecalled_pass_read_count'] + all_stats["basecalled_fail_read_count"] = yield_summary['basecalled_fail_read_count'] + + // Base yield + last_snapshot = last(last_acquisition["acquisition_output"][0]["plot"][0]["snapshots"][0]["snapshots"])["yield_summary"] + + all_stats["basecalled_pass_bases"] = last_snapshot["basecalled_pass_bases"] + all_stats["basecalled_fail_bases"] = last_snapshot["basecalled_fail_bases"] + + // N50 + last_read_lengths = last(last_acquisition["read_length_histogram"]) + if (last_read_lengths && + last_read_lengths["plot"] && + last_read_lengths["plot"]["histogram_data"] && + last_read_lengths["plot"]["histogram_data"][0]) { + all_stats["n50"] = last_read_lengths["plot"]["histogram_data"][0]["n50"]; + } else { + all_stats["n50"] = ""; + } + + } + + all_stats["pore_count_history"] = doc["pore_count_history"]; + all_stats["lims"] = doc["lims"]; + all_stats["pore_activity"] = doc["pore_activity"]; + + emit(run_name, all_stats); + +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/info/args.map.js b/StatusDB_views/nanopore_runs/info/args.map.js new file mode 100644 index 0000000..91860fd --- /dev/null +++ b/StatusDB_views/nanopore_runs/info/args.map.js @@ -0,0 +1,16 @@ +function (doc) { + + function last(list) { + len = list.length + return list[len - 1]; + } + + // Fetch key + run_path = doc['run_path'] + run_name = last(run_path.split("/")) + + // Fetch all cmd arguments for safe-keeping + args = doc['protocol_run_info']['args'] + +emit(run_name, args); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/info/barcodes.map.js b/StatusDB_views/nanopore_runs/info/barcodes.map.js new file mode 100644 index 0000000..c32ecaf --- /dev/null +++ b/StatusDB_views/nanopore_runs/info/barcodes.map.js @@ -0,0 +1,45 @@ +function(doc) { + + function last(list) { + len = list.length + return list[len - 1]; + } + + // Fetch key + run_path = doc['run_path'] + run_name = last(run_path.split("/")) + + // FETCH DATA + + var last_acquisition = last(doc['acquisitions']) + + for (var output_type in last_acquisition["acquisition_output"]) { + if (last_acquisition["acquisition_output"][output_type]["type"] == "SplitByBarcode") { + var bcs = last_acquisition["acquisition_output"][output_type]["plot"][0]["snapshots"] + } + } + + var bc_info = new Object({}); + + i = doc['protocol_run_info']['args'].indexOf('--barcoding') + if (i != -1) { + for (var bc in bcs) { + + bc_name = bcs[bc]["filtering"][0]["barcode_name"] + last_snapshot = last(bcs[bc]["snapshots"])["yield_summary"] + + bc_info[bc_name] = { + "barcode_alias" : bcs[bc]["filtering"][0]["barcode_alias"], + "read_count": last_snapshot["read_count"], + "basecalled_pass_read_count": last_snapshot["basecalled_pass_read_count"], + "basecalled_fail_read_count":last_snapshot["basecalled_fail_read_count"], + "basecalled_pass_bases": last_snapshot["basecalled_pass_bases"], + "basecalled_fail_bases": last_snapshot["basecalled_fail_bases"] + } + } + } else { + bc_info = null + } + + emit(run_name, bc_info); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/info/lims.map.js b/StatusDB_views/nanopore_runs/info/lims.map.js new file mode 100644 index 0000000..64571fd --- /dev/null +++ b/StatusDB_views/nanopore_runs/info/lims.map.js @@ -0,0 +1,13 @@ +function (doc) { + + function last(list) { + len = list.length + return list[len - 1]; + } + + // Fetch key + run_path = doc['run_path'] + run_name = last(run_path.split("/")) + + emit(run_name, doc.lims); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/info/mux_scans.map.js b/StatusDB_views/nanopore_runs/info/mux_scans.map.js new file mode 100644 index 0000000..cf68146 --- /dev/null +++ b/StatusDB_views/nanopore_runs/info/mux_scans.map.js @@ -0,0 +1,29 @@ +function (doc) { + + function last(list) { + var len = list.length; + return list[len - 1]; + } + + // Fetch key + var run_path = doc['run_path']; + var run_name = last(run_path.split("/")); + + // Fetch value + var user_messages = doc["user_messages"]; + + var mux_scans = []; + + for (var i = 0; i < user_messages.length; i++) { + var user_message = user_messages[i]; + if (user_message["identifier"] == "mux_scan_result" || user_message["identifier"] == "channel_scan_result") { + mux_scans.push({ + "num_pores": user_message["extra_data"]["num_pores"], + "total_pores": user_message["extra_data"]["total_pores"], + "time": user_message["time"] + }); + } + } + + emit(run_name, mux_scans); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/info/pore_count_history.map.js b/StatusDB_views/nanopore_runs/info/pore_count_history.map.js new file mode 100644 index 0000000..939f439 --- /dev/null +++ b/StatusDB_views/nanopore_runs/info/pore_count_history.map.js @@ -0,0 +1,13 @@ +function (doc) { + + function last(list) { + len = list.length + return list[len - 1]; + } + + // Fetch key + run_path = doc['run_path'] + run_name = last(run_path.split("/")) + + emit(run_name, doc.pore_count_history); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/names/name.map.js b/StatusDB_views/nanopore_runs/names/name.map.js new file mode 100644 index 0000000..821acfb --- /dev/null +++ b/StatusDB_views/nanopore_runs/names/name.map.js @@ -0,0 +1,15 @@ +// Very simple, robust view to navigate in CouchDB + +function(doc) { + + function last(list) { + len = list.length + return list[len - 1]; + } + + // Fetch key + run_path = doc['run_path'] + run_name = last(run_path.split("/")) + + emit(run_name, null); +} \ No newline at end of file diff --git a/StatusDB_views/nanopore_runs/names/project_ids_list.map.js b/StatusDB_views/nanopore_runs/names/project_ids_list.map.js new file mode 100644 index 0000000..c9c7716 --- /dev/null +++ b/StatusDB_views/nanopore_runs/names/project_ids_list.map.js @@ -0,0 +1,38 @@ +function (doc) { + + // Function to match and extract project ID + function extractProjectId(str) { + const match = str.match(/(p|P)\d+/); + return match ? match[0] : null; + } + + // Fetch key + var project_ids = []; + var p_id = null; + const run_path = doc['run_path']; + const run_name = run_path.split("/")[2]; + if('lims' in doc && 'loading' in doc['lims'] && 'sample_data' in doc['lims']['loading'][0]){ + doc['lims']['loading'][0]['sample_data'].forEach(function(sample) { + if (project_ids.indexOf(sample['project_id']) === -1) { + project_ids.push(sample['project_id']) + } + }) + } + // Fallback conditions for older ONT FCs + else if(doc['run_status']=='ongoing' || doc['run_status']=='interrupted'){ + const experiment_name = run_path.split("/")[0]; + const sample_name = run_path.split("/")[1]; + p_id = extractProjectId(experiment_name) || extractProjectId(sample_name) + } + else{ + const group_id = doc['protocol_run_info']['user_info']['protocol_group_id']; // Should correspond to project ID by convention + const sample_id = doc['protocol_run_info']['user_info']['sample_id']; + p_id = extractProjectId(group_id) || extractProjectId(sample_id) + } + + if(p_id){ + project_ids.push(p_id) + } + + emit(run_name, project_ids); +} \ No newline at end of file diff --git a/StatusDB_views/people_assignments/current/assignments.map.js b/StatusDB_views/people_assignments/current/assignments.map.js new file mode 100644 index 0000000..854e8f4 --- /dev/null +++ b/StatusDB_views/people_assignments/current/assignments.map.js @@ -0,0 +1,15 @@ +function (doc) { + var currentPeople = []; + for (var personId in doc.people) { + var assignments = doc.people[personId]; + if (Array.isArray(assignments) && assignments.length > 0) { + const lastAssignment = assignments[assignments.length - 1]; + + // If the last assignment is not removed, add the person ID to the result + if (lastAssignment && lastAssignment.removed === false) { + currentPeople.push(personId); + } + } + } + emit(doc._id, currentPeople); +} \ No newline at end of file diff --git a/StatusDB_views/pricing_exchange_rates/entire_document/by_date.map.js b/StatusDB_views/pricing_exchange_rates/entire_document/by_date.map.js new file mode 100644 index 0000000..779b0b1 --- /dev/null +++ b/StatusDB_views/pricing_exchange_rates/entire_document/by_date.map.js @@ -0,0 +1,6 @@ +/* Used by genomics-status at /api/v1/pricing_exchange_rates */ + +function(doc) { + date = doc['Issued at'].substring(0, 10); + emit(date, doc); +} diff --git a/StatusDB_views/project_creation_forms/by_creation_date/not_retired.map.js b/StatusDB_views/project_creation_forms/by_creation_date/not_retired.map.js new file mode 100644 index 0000000..03aa1ef --- /dev/null +++ b/StatusDB_views/project_creation_forms/by_creation_date/not_retired.map.js @@ -0,0 +1,5 @@ +function (doc) { + if (doc.status != 'retired') { + emit([doc.status, doc.created]); + } +} \ No newline at end of file diff --git a/StatusDB_views/project_creation_forms/by_creation_date/valid.map.js b/StatusDB_views/project_creation_forms/by_creation_date/valid.map.js new file mode 100644 index 0000000..05cd194 --- /dev/null +++ b/StatusDB_views/project_creation_forms/by_creation_date/valid.map.js @@ -0,0 +1,5 @@ +function (doc) { + if (doc.status == 'valid') { + emit(doc.created); + } +} \ No newline at end of file diff --git a/StatusDB_views/project_creation_forms/summary/all.map.js b/StatusDB_views/project_creation_forms/summary/all.map.js new file mode 100644 index 0000000..765c3f9 --- /dev/null +++ b/StatusDB_views/project_creation_forms/summary/all.map.js @@ -0,0 +1,10 @@ +function (doc) { + var summary = {}; + // Copy all keys from doc to summary except 'json_schema' and 'form_groups' + for (var key in doc) { + if (key !== 'json_schema' && key !== 'form_groups') { + summary[key] = doc[key]; + } + } + emit([doc.status, doc.created], summary); +} \ No newline at end of file diff --git a/StatusDB_views/projects/date/creation_time_v.map.js b/StatusDB_views/projects/date/creation_time_v.map.js new file mode 100644 index 0000000..17209b5 --- /dev/null +++ b/StatusDB_views/projects/date/creation_time_v.map.js @@ -0,0 +1,9 @@ +function(doc) { + if (doc["creation_time"]) { + var d = doc["creation_time"]; + var yy = d.substr(2,2) + var mm = d.substr(5,2) + var dd = d.substr(8,2) + emit([yy, mm, dd]); + } +} diff --git a/StatusDB_views/projects/date/creation_time_v.reduce.js b/StatusDB_views/projects/date/creation_time_v.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/date/creation_time_v.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/date/m_bp_delivered.map.js b/StatusDB_views/projects/date/m_bp_delivered.map.js new file mode 100644 index 0000000..784928a --- /dev/null +++ b/StatusDB_views/projects/date/m_bp_delivered.map.js @@ -0,0 +1,19 @@ +/* + Used by genomics-status at: + /api/v1/delivered_monthly, + /api/v1/delivered_monthly.png, + /api/v1/delivered_quarterly, + /api/v1/delivered_quarterly.png +*/ + +function(doc) { + for (s in doc["samples"]) { + var m_reads = +doc["samples"][s]["m_reads_sequenced"] + var ds = 0 + ds = doc["creation_time"].split("T")[0].split("-") + qq = ((+ds[1]-1)/3|0)+1 + if(m_reads){ + emit([+ds[0], qq, +ds[1], +ds[2]], m_reads * 2 * 101) + } + } +} diff --git a/StatusDB_views/projects/date/m_bp_delivered.reduce.js b/StatusDB_views/projects/date/m_bp_delivered.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/date/m_bp_delivered.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/dates_and_load_per_sample.map.js b/StatusDB_views/projects/genomics-dashboard/dates_and_load_per_sample.map.js new file mode 100644 index 0000000..ae41b44 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/dates_and_load_per_sample.map.js @@ -0,0 +1,155 @@ +function(doc) { + var type = doc["details"]["type"]; + // Only output production documents + //if(type != "Production") { exit; } + + // Get sequencing platform and application for stratification + var sequencing_platform = doc["details"]["sequencing_platform"]; + var application = doc["application"]; + + // Calculate lane load per sample + var proj_lanes = doc["details"]["sequence_units_ordered_(lanes)"]; + var num_samples = doc.no_of_samples; + var lanes_per_sample = proj_lanes/num_samples; + + + // Find arrival date (if present) + var open_date = "0000-00-00"; + if (doc["open_date"] > open_date) { + open_date = doc["open_date"]; + //if(open_date < "2013-07-01") { exit; } // this filter should not be used + } + // Find all samples sequenced (if present) + var ass = doc["project_summary"]["all_samples_sequenced"]; + + // Find all raw data delivered (if present) + var all_raw_data_delivered = "0000-00-00"; + if (doc.details["all_raw_data_delivered"] > all_raw_data_delivered) { + all_raw_data_delivered = doc.details["all_raw_data_delivered"]; + } + + // close date + var close_date = "0000-00-00"; + if (doc["close_date"] > close_date) { + close_date = doc["close_date"]; + } + + // Find aborted date (if present) + var aborted_date = "0000-00-00"; + if (doc.details["aborted"] > aborted_date) { + aborted_date = doc.details["aborted"]; + } + + // go through each sample + for (sample in doc["samples"]){ + + // Find Rec ctrl start + var initial_qc_start = "0000-00-00"; + if(doc["samples"][sample]["first_initial_qc_start_date"] > initial_qc_start) { + initial_qc_start = doc["samples"][sample]["first_initial_qc_start_date"]; + } + + // library prep start date + // NEW temp way to get lib prep start + // This bit of code to be transferred to production server + var lib_prep_start = "0000-00-00"; + if(doc["samples"][sample]["first_prep_start_date"]) { + lib_prep_start = doc["samples"][sample]["first_prep_start_date"]; + } + + // final validation date for Library QC + var final_validation = "0000-00-00"; + // sequence start date + var sequence_start_date = "9999-99-99"; + // final sequence date + var final_sequence_date = "0000-00-00"; + + // Find queue date (if present) + var queued = "0000-00-00"; + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"]; + } + + // go through each lib prep for sample + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep] + + // This is the lib prep finish date before QC starts. Should not be used as final_validation + //if(LP.prep_finished_date) { + // final_validation = LP.prep_finished_date + //} + + // capture earliest lib prep start if not set at sample/first_prep_start_date + // done above at sample level. + // + if(LP["prep_start_date"]) { + if (lib_prep_start == "0000-00-00") { + lib_prep_start = LP["prep_start_date"]; + } else if (LP["prep_start_date"] final_validation) { + final_validation = lib_val_fin; + } + } + + + // Find sequence start date & final sequence date by looking at the first sequence start date & the last sequencing_finish_date + // sequence_start_date initialized at sample level + // final_sequence_date initialized at sample level + for (sample_run_metrics in LP["sample_run_metrics"]) { + // sequence start date + if(sequence_start_date > LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"]) { + sequence_start_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"]; + } + + // sequence end date + if (final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"]) { + final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"]; + //} else if (final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_run_QC_finished"]) { // some older(?) projects only have info on seq_run_QC_finished + // final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_run_QC_finished"]; + } + } // sequence + + } // library prep + + // sample status + var status = doc["samples"][sample]["details"]["status_(manual)"]; + if(!status) { status = null; } + + // in the case final_sequence_date has not been set, and all samples sequenced date is available + if(final_sequence_date == "0000-00-00" && ass != null) { + final_sequence_date = ass; + } + + if (sequence_start_date == "9999-99-99") { sequence_start_date = "0000-00-00"; } + //NEW! Emit what we have all variables should be set before so will be ok at emit + //if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object(); + KPI["Arrival date"] = open_date; + KPI["Rec ctrl start"] = initial_qc_start; + KPI["Queue date"] = queued; + KPI["Lib prep start"] = lib_prep_start; + KPI["QC library finished"] = final_validation; + KPI["Sequencing start"] = sequence_start_date; + KPI["All samples sequenced"] = final_sequence_date; + KPI["All raw data delivered"] = all_raw_data_delivered; + KPI["Close date"] = close_date; + KPI["Aborted date"] = aborted_date; + KPI["Samples"] = 1; + KPI["Lanes"] = lanes_per_sample; + KPI["Status"] = status; + + emit([doc["project_id"], type, application, sequencing_platform, sample], KPI); + + } // sample + +} \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/dates_and_load_per_sample.reduce.js b/StatusDB_views/projects/genomics-dashboard/dates_and_load_per_sample.reduce.js new file mode 100644 index 0000000..2891f21 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/dates_and_load_per_sample.reduce.js @@ -0,0 +1,57 @@ +/** + * Reduce function - shouldn't really be needed + */ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "Rec ctrl start": "0000-00-00", + "Lib prep start": "0000-00-00", + "QC library finished": "0000-00-00", + "Sequencing start": "9999-99-99", + "All samples sequenced": "0000-00-00", + "Close date": "0000-00-00", + "Samples": null, + "Lanes": null + } + + res: for (var k in result) { + for (var i = 0; i < values.length; i++) { + if (k == "Samples" || k == "Lanes") { // add up the values for samples and lanes when reducing + result[k]+= values[i][k]; + continue; + } + if (k == "Sequencing start") { + if(values[i][k] == "0000-00-00") { + result[k] = "0000-00-00"; + } else if (values[i][k] < result[k]) { + result[k] = values[i][k] + } + continue; + } + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00"; + continue res; + } + } + } + //for (var i = 0; i < values.length; i++) { + // for (k in result) { + // if (k == "Samples" || k == "Lanes") { // add up the values for samples and lanes when reducing + // result[k]+= values[i][k]; + // continue; + // } + // if (values[i][k] > result[k]){ + // result[k] = values[i][k] + // } + // else if (values[i][k] == "0000-00-00") { + // // We use the date 0000-00-00 to indicate unfinished process + // result[k] = "0000-00-00" + // } + // } + //} + + return result +} diff --git a/StatusDB_views/projects/genomics-dashboard/open_application_count_projects.map.js b/StatusDB_views/projects/genomics-dashboard/open_application_count_projects.map.js new file mode 100644 index 0000000..e9383b3 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/open_application_count_projects.map.js @@ -0,0 +1,17 @@ +function(doc) { + + if ('details' in doc && 'queued' in doc.details && !('close_date' in doc) && !('isFinishedLib' in doc)){ + var my_application=doc.details.application.toLowerCase(); + if (doc.details.type == 'Application') { + my_application = 'application'; + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=my_application; + emit(key, 1); + } +} diff --git a/StatusDB_views/projects/genomics-dashboard/open_application_count_projects.reduce.js b/StatusDB_views/projects/genomics-dashboard/open_application_count_projects.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/open_application_count_projects.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/open_application_count_samples.map.js b/StatusDB_views/projects/genomics-dashboard/open_application_count_samples.map.js new file mode 100644 index 0000000..2965b42 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/open_application_count_samples.map.js @@ -0,0 +1,14 @@ +function(doc) { + if ('queued' in doc.details && !('close_date' in doc)){ + var my_application=doc.details.application.toLowerCase(); + if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=my_application; + emit(key, Object.keys(doc.samples).length); + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/open_application_count_samples.reduce.js b/StatusDB_views/projects/genomics-dashboard/open_application_count_samples.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/open_application_count_samples.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/open_application_count_seq_projects.map.js b/StatusDB_views/projects/genomics-dashboard/open_application_count_seq_projects.map.js new file mode 100644 index 0000000..c33a45d --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/open_application_count_seq_projects.map.js @@ -0,0 +1,17 @@ +function(doc) { + + if ('details' in doc && 'queued' in doc.details && !('close_date' in doc) && ('isFinishedLib' in doc)){ + var my_application=doc.details.application.toLowerCase(); + if (doc.details.type == 'Application') { + my_application = 'application' + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=my_application; + emit(key, 1); + } +} diff --git a/StatusDB_views/projects/genomics-dashboard/open_application_count_seq_projects.reduce.js b/StatusDB_views/projects/genomics-dashboard/open_application_count_seq_projects.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/open_application_count_seq_projects.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/genomics-dashboard/year_affiliation_count_projects.map.js b/StatusDB_views/projects/genomics-dashboard/year_affiliation_count_projects.map.js new file mode 100644 index 0000000..1fb80a0 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_affiliation_count_projects.map.js @@ -0,0 +1,8 @@ +function(doc) { + var my_affiliation=doc.affiliation.toLowerCase(); + if (my_affiliation == 'slu-uppsala' || my_affiliation == 'slu-umea' || my_affiliation == 'slu-alnarp'){ + my_affiliation = 'slu'; + } + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], my_affiliation]; + emit(key, 1); +} \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_affiliation_count_projects.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_affiliation_count_projects.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_affiliation_count_projects.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_application_count.map.js b/StatusDB_views/projects/genomics-dashboard/year_application_count.map.js new file mode 100644 index 0000000..86cd6be --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_application_count.map.js @@ -0,0 +1,16 @@ +function(doc) { + var my_application=doc.details.application.toLowerCase(); + if (doc.details.sample_type!='Finished Library' && !doc.hasOwnProperty('isFinishedLib')) { + if (doc.details.type == 'Application') { + my_application = 'application'; + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], my_application] + emit(key, Object.keys(doc.samples).length); + } +} diff --git a/StatusDB_views/projects/genomics-dashboard/year_application_count.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_application_count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_application_count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_application_count_samples.map.js b/StatusDB_views/projects/genomics-dashboard/year_application_count_samples.map.js new file mode 100644 index 0000000..86cd6be --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_application_count_samples.map.js @@ -0,0 +1,16 @@ +function(doc) { + var my_application=doc.details.application.toLowerCase(); + if (doc.details.sample_type!='Finished Library' && !doc.hasOwnProperty('isFinishedLib')) { + if (doc.details.type == 'Application') { + my_application = 'application'; + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], my_application] + emit(key, Object.keys(doc.samples).length); + } +} diff --git a/StatusDB_views/projects/genomics-dashboard/year_application_count_samples.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_application_count_samples.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_application_count_samples.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_deliverytime_count_projects.map.js b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_count_projects.map.js new file mode 100644 index 0000000..6cf4fc4 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_count_projects.map.js @@ -0,0 +1,24 @@ +function(doc) { + if (doc.details.type == 'Production' && 'close_date' in doc && !('aborted' in doc.project_summary)){ + var q_date=new Date(doc.details.queued); + var d_date=new Date(doc.close_date); + if ('all_raw_data_delivered' in doc.details){ + d_date=new Date(doc.details.all_raw_data_delivered); + }else if ('all_raw_data_delivered' in doc.project_summary){ + d_date=new Date(doc.project_summary.all_raw_data_delivered); + } + var w_diff=(d_date - q_date)/1000/60/60/24/7; + var subkey="unknown"; + if (w_diff<6){ + subkey="0-6 w"; + }else if (w_diff<12){ + subkey="6-12 w"; + }else if (w_diff<24){ + subkey="12-24 w"; + }else{ + subkey="24+ w"; + } + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], subkey]; + emit(key, 1); + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_deliverytime_count_projects.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_count_projects.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_count_projects.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_deliverytime_median_by_application.map.js b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_median_by_application.map.js new file mode 100644 index 0000000..3486665 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_median_by_application.map.js @@ -0,0 +1,25 @@ +function(doc) { + if (doc.details.type == 'Production' && 'close_date' in doc && !('aborted' in doc.project_summary)){ + var my_application = doc.details.application.toLowerCase(); + if (doc.details.sample_type=='Finished Library' || 'isFinishedLib' in doc) { + my_application = "finished library" + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + + var q_date=new Date(doc.details.queued); + var d_date=new Date(doc.close_date); + if ('all_raw_data_delivered' in doc.details){ + d_date=new Date(doc.details.all_raw_data_delivered); + }else if ('all_raw_data_delivered' in doc.project_summary){ + d_date=new Date(doc.project_summary.all_raw_data_delivered); + } + var w_diff=(d_date - q_date)/1000/60/60/24; + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], my_application]; + emit(key, w_diff); + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/genomics-dashboard/year_deliverytime_median_by_application.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_median_by_application.reduce.js new file mode 100644 index 0000000..06a831d --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_deliverytime_median_by_application.reduce.js @@ -0,0 +1,8 @@ +function(keys, values) { + values.sort( function(a,b) {return a - b;} ); + var half = Math.floor(values.length/2); + if(values.length % 2) + return values[half]; + else + return (values[half-1] + values[half]) / 2.0; +} diff --git a/StatusDB_views/projects/genomics-dashboard/year_seq_application_count.map.js b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count.map.js new file mode 100644 index 0000000..2ebce5f --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count.map.js @@ -0,0 +1,16 @@ +function(doc) { + var my_application=doc.details.application.toLowerCase(); + if (doc.details.sample_type=='Finished Library' || 'isFinishedLib' in doc) { + if (doc.details.type == 'Application') { + my_application = 'application'; + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], my_application] + emit(key, 1); + } +} diff --git a/StatusDB_views/projects/genomics-dashboard/year_seq_application_count.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/genomics-dashboard/year_seq_application_count_samples.map.js b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count_samples.map.js new file mode 100644 index 0000000..723a835 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count_samples.map.js @@ -0,0 +1,16 @@ +function(doc) { + var my_application=doc.details.application.toLowerCase(); + if (doc.details.sample_type=='Finished Library' || 'isFinishedLib' in doc) { + if (doc.details.type == 'Application') { + my_application = 'application'; + }else if (my_application == 'rna-seq (mrna)' || my_application == 'rna-seq (total rna)' || my_application == 'rna-seq (ribozero)'){ + my_application='rna-seq'; + }else if (my_application == 'wg re-seq (ign)'){ + my_application='wg re-seq'; + }else if(my_application == 'mirna-seq'){ + my_application='rna-seq smallrna'; + } + var key=[doc.details.queued.split('-')[0]+"-"+doc.details.queued.split('-')[1], my_application] + emit(key, Object.keys(doc.samples).length); + } +} diff --git a/StatusDB_views/projects/genomics-dashboard/year_seq_application_count_samples.reduce.js b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count_samples.reduce.js new file mode 100644 index 0000000..a105062 --- /dev/null +++ b/StatusDB_views/projects/genomics-dashboard/year_seq_application_count_samples.reduce.js @@ -0,0 +1 @@ +_sum diff --git a/StatusDB_views/projects/invoicing/spec_generated_not_sent.js b/StatusDB_views/projects/invoicing/spec_generated_not_sent.js new file mode 100644 index 0000000..d7532a2 --- /dev/null +++ b/StatusDB_views/projects/invoicing/spec_generated_not_sent.js @@ -0,0 +1,13 @@ +function (doc) { + if(doc.hasOwnProperty('invoice_spec_generated') && doc['invoice_spec_generated']!=='No invoicing'){ + if(!doc.hasOwnProperty('invoice_spec_downloaded')){ + result = {}; + //Leaving as placeholder, since agreement_doc_id might be needed in the future + result["agreement_doc_id"] = ""; + result["invoice_spec_generated"] = doc['invoice_spec_generated']; + result["project_name"] = doc["project_name"]; + result["project_status"] = doc["status_fields"]["status"]; + emit(doc['project_id'], result); + } + } +} diff --git a/StatusDB_views/projects/invoicing/spec_sent.js b/StatusDB_views/projects/invoicing/spec_sent.js new file mode 100644 index 0000000..848aadf --- /dev/null +++ b/StatusDB_views/projects/invoicing/spec_sent.js @@ -0,0 +1,8 @@ +function (doc) { + if(doc.hasOwnProperty('invoice_spec_generated') && doc['invoice_spec_generated']!=='No invoicing'){ + if(doc.hasOwnProperty('invoice_spec_downloaded')){ + downloaded_date = new Date(doc["invoice_spec_downloaded"]).toISOString().split('T')[0]; + emit(downloaded_date, doc['project_id']); + } + } +} diff --git a/StatusDB_views/projects/kpi_external/KPI1.map.js b/StatusDB_views/projects/kpi_external/KPI1.map.js new file mode 100644 index 0000000..2bf40d9 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI1.map.js @@ -0,0 +1,26 @@ +function(doc) { + if(doc["source"] != "lims") { + exit; + } + var date; + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + run = "F"; + //var date = "0000-00-00"; + for (prep in s["library_prep"]){ + if (s["library_prep"][prep]["sample_run_metrics"]){ + run = "T"; + // 2013-09-24 NJ: Take the dilution_and_pooling_start_date + // as date instead of open_date + for (runid in s["library_prep"][prep]["sample_run_metrics"]) { + var newdate = s["library_prep"][prep]["sample_run_metrics"][runid]["dillution_and_pooling_start_date"]; + if(date == undefined || newdate < date) { date = newdate; } + } + } +} + if (run == "T"){ +// emit([doc["open_date"],doc["application"],s["scilife_name"]],s["incoming_QC_status"]) + emit([date,doc["application"],s["scilife_name"]],s["incoming_QC_status"]) + } + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI1.reduce.js b/StatusDB_views/projects/kpi_external/KPI1.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI1.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI1_1.map.js b/StatusDB_views/projects/kpi_external/KPI1_1.map.js new file mode 100644 index 0000000..d01239b --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI1_1.map.js @@ -0,0 +1,15 @@ +function(doc) { +if (doc['source']=="lims") { +samples={} + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + run = "F"; + for (prep in s["library_prep"]){ + if (s["library_prep"][prep]["sample_run_metrics"]){ run = "T"} +} + samples[s["scilife_name"]] = [s["incoming_QC_status"],run] + } +emit([doc["open_date"],doc["project_name"],doc["application"]],samples) +} + +} \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI1_1.reduce.js b/StatusDB_views/projects/kpi_external/KPI1_1.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI1_1.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI2.map.js b/StatusDB_views/projects/kpi_external/KPI2.map.js new file mode 100644 index 0000000..f94f52a --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI2.map.js @@ -0,0 +1,14 @@ +function(doc) { + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + for (prep in s["library_prep"]){ + date = null; + for (libval in s["library_prep"][prep]["library_validation"]){ + date = s["library_prep"][prep]["library_validation"][libval]['start_date']; + } + if (s["library_prep"][prep]["workset_setup"]){ + emit([s["library_prep"][prep]["workset_setup"], doc["application"],date,s["scilife_name"]],s["library_prep"][prep]['prep_status']); + } + } + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI2.reduce.js b/StatusDB_views/projects/kpi_external/KPI2.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI2.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI3.map.js b/StatusDB_views/projects/kpi_external/KPI3.map.js new file mode 100644 index 0000000..231d553 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI3.map.js @@ -0,0 +1,14 @@ +function(doc) { +if (doc['source']=='lims') { +for (sample in doc["samples"]) { +s = doc["samples"][sample]; +for (prep in s["library_prep"]){ +date = null +for ( run in s["library_prep"][prep]["sample_run_metrics"]){ date = s["library_prep"][prep]["sample_run_metrics"][run]['sequencing_run_QC_finished']} +} +if (s['details']["lanes_requested"]) { +emit([date, doc['project_name'],s["scilife_name"]],[s["details"]["lanes_requested"],s['details']["pooling"],s['m_reads_sequenced']]) +} +} +} +} \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI3.reduce.js b/StatusDB_views/projects/kpi_external/KPI3.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI3.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/KPI3_1.map.js b/StatusDB_views/projects/kpi_external/KPI3_1.map.js new file mode 100644 index 0000000..817e0af --- /dev/null +++ b/StatusDB_views/projects/kpi_external/KPI3_1.map.js @@ -0,0 +1,24 @@ +function(doc) { + if(doc["details"]["type"] != "Production") {exit;} + + var pf = doc["details"]["sequencing_platform"]; + var lanes = doc["details"]["sequence_units_ordered_(lanes)"]; + var samples = doc["no_of_samples"]; + var ordered = 0; + if(pf.indexOf("MiSeq") != -1) { + ordered = lanes * 10; // 10 million/lane for MiSeq + } else if (pf.indexOf("High Output") != -1) { + ordered = lanes * 143; // 143 million/lane for High Output + } else if (pf.indexOf("Rapid") != -1) { + ordered = lanes * 114; // 114 million/lane for Rapid + } + + var delivered = 0; + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + delivered += parseFloat(s['m_reads_sequenced']); + } + var fraction = delivered / ordered; + + emit([doc["sequencing_finished"],doc["project_name"]], [pf, lanes, ordered, samples, delivered, fraction ]); +} \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/applications_projects.map.js b/StatusDB_views/projects/kpi_external/applications_projects.map.js new file mode 100644 index 0000000..393ced3 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/applications_projects.map.js @@ -0,0 +1,13 @@ +function(doc) { + if(doc["source"] == "lims" && doc["details"]["type"] == "Production") { + /* skip some bad apples */ + if(doc["application"] == null) { exit; } + if(doc["application"].indexOf("bogus") != -1) { exit; } + + var od = doc["open_date"]; + var ad = doc["details"]["aborted"]; + if (od == ad) { exit; } // omit aborted projects that were never opened + /* emit application & project id */ + emit(doc["application"], [doc["project_id"], od]); + } +} diff --git a/StatusDB_views/projects/kpi_external/applications_projects.reduce.js b/StatusDB_views/projects/kpi_external/applications_projects.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/applications_projects.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/applications_samples.map.js b/StatusDB_views/projects/kpi_external/applications_samples.map.js new file mode 100644 index 0000000..c2d66a5 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/applications_samples.map.js @@ -0,0 +1,15 @@ +function(doc) { + if(doc["source"] == "lims" && doc["details"]["type"] == "Production") { + /* skip some bad apples */ + if(doc["application"] == null) { exit; } + if(doc["application"].indexOf("bogus") != -1) { exit; } + + var od = doc["open_date"]; + var ad = doc["details"]["aborted"]; + if (od == ad) { exit; } // omit aborted projects that were never opened + + + no_of_samples = +doc["no_of_samples"] || 0 + emit(doc["application"], [no_of_samples, od]); + } +} diff --git a/StatusDB_views/projects/kpi_external/date_affiliation.map.js b/StatusDB_views/projects/kpi_external/date_affiliation.map.js new file mode 100644 index 0000000..29bf844 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/date_affiliation.map.js @@ -0,0 +1,12 @@ +function(doc) { + if(doc["details"]["type"] != "Production") { exit; } + if(doc["source"] != "lims") { exit; } + if(doc["application"] == null) { exit; } + if(doc["application"].indexOf("bogus") != -1) { exit; } + + var od = doc["open_date"]; + if (od == null) { exit; } + var ad = doc["details"]["aborted"]; + if (od == ad) { exit; } // omit aborted projects that were never opened + emit([od,doc["affiliation"]], doc["project_id"]); +} diff --git a/StatusDB_views/projects/kpi_external/projects.map.js b/StatusDB_views/projects/kpi_external/projects.map.js new file mode 100644 index 0000000..b4e2346 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/projects.map.js @@ -0,0 +1,59 @@ +/* + * kpi_external/projects + * Map function + */ + +function(doc) { + + var queued = "0000-00-00"; + var close = "0000-00-00"; + var day = 1000*60*60*24; + + var dayDiff = function (date1, date2) { + var diff = Math.ceil((date2.getTime()-date1.getTime())/(day)); + return diff; + } + + var production = (doc["details"]["type"] == "Production"); + if(production) { + if (doc["details"]["queued"]) { + queued = doc["details"]["queued"]; + } + if (doc["close_date"]) { + close = doc["close_date"]; + } + + var bin = null; + var today = new Date(); + var diff; + //var unit = "week"; + var unit = "w"; + + if(doc["details"]["queued"] && doc["close_date"]) { + var qD = new Date(queued); + var cD = new Date(close); + diff = dayDiff(qD, cD); + //diff = Math.ceil( (cD.getTime()-qD.getTime()) / day); + //if(diff <= 4 * 7) { + if(diff <= 6 * 7) { + //bin = "0-4 weeks"; + bin = "0-6 " + unit; + //} else if (diff <= 8 * 7) { + // bin = "4-8 weeks"; + } else if (diff <= 12 * 7) { + //bin = "8-12 weeks"; + bin = "6-12 " + unit; + } else if (diff <= 24 * 7) { + bin = "12-24 " + unit; + } else if (diff <= 52 * 7) { + bin = "24-52 " + unit; + } + } + var KPI = Object(); + KPI["Queue date"] = queued; + KPI["Close date"] = close; + KPI["Total time"] = diff; + //emit([ bin, doc["project_name"] ], KPI); + emit([ bin, doc["project_id"] ], KPI); + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/kpi_external/projects.reduce.js b/StatusDB_views/projects/kpi_external/projects.reduce.js new file mode 100644 index 0000000..ba01d16 --- /dev/null +++ b/StatusDB_views/projects/kpi_external/projects.reduce.js @@ -0,0 +1,7 @@ +function(keys, values, rereduce) { + if (rereduce) { + return sum(values); + } else { + return values.length; + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/names/id_to_name.map.js b/StatusDB_views/projects/names/id_to_name.map.js new file mode 100644 index 0000000..ed3dcc7 --- /dev/null +++ b/StatusDB_views/projects/names/id_to_name.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc["_id"], doc["project_name"]);} diff --git a/StatusDB_views/projects/names/name.map.js b/StatusDB_views/projects/names/name.map.js new file mode 100644 index 0000000..1adaed4 --- /dev/null +++ b/StatusDB_views/projects/names/name.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc["project_name"], null);} diff --git a/StatusDB_views/projects/order_portal/ProjectID_to_PortalID.js b/StatusDB_views/projects/order_portal/ProjectID_to_PortalID.js new file mode 100644 index 0000000..f743eeb --- /dev/null +++ b/StatusDB_views/projects/order_portal/ProjectID_to_PortalID.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.project_id, doc.details.portal_id) +} diff --git a/StatusDB_views/projects/order_portal/ProjectID_to_PortalID.map.js b/StatusDB_views/projects/order_portal/ProjectID_to_PortalID.map.js new file mode 100644 index 0000000..df8c87e --- /dev/null +++ b/StatusDB_views/projects/order_portal/ProjectID_to_PortalID.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.project_id, doc.details.portal_id) +} \ No newline at end of file diff --git a/StatusDB_views/projects/process_flow/KPI.map.js b/StatusDB_views/projects/process_flow/KPI.map.js new file mode 100644 index 0000000..a58c404 --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI.map.js @@ -0,0 +1,96 @@ +function(doc) { + // Only output production documents + if(doc["details"]["type"] != "Production") { exit; } + + + // Get sequencing platform for stratification + var sequencing_platform = doc["details"]["sequencing_platform"] + + // Find arrival date (if present) + var open_date = "0000-00-00" + if (doc["open_date"] > open_date) { + open_date = doc["open_date"] + } + // NJ 2013-10-22 + // Added close date. This is date is emitted further down in the code. + // Also added to Reduce Function ----> + var close_date = "0000-00-00" + if (doc["close_date"] > close_date) { + close_date = doc["close_date"] + } + for (sample in doc["samples"]){ + // Find queue date (if present) + var queued = "0000-00-00" + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"] + } + + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep] + + // Find QC library finish date by looking at the final library validation. + var final_validation = "0000-00-00" + for (lv in LP["library_validation"]) { + var lib_val_fin = LP["library_validation"][lv]["finish_date"] + if (lib_val_fin > final_validation) { + final_validation = lib_val_fin + } + } + + // Find the time a sample is sequenced at by looking at sample runs + // sequencing _start_ date. This is confusing, but it is how Maya + // specified it. + //var final_sequence_date = "0000-00-00" + //for (sample_run_metrics in LP["sample_run_metrics"]) { + // final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"] + //} + +      // NJ 2013-08-23: updated original code above to work with new  +      // key "sequencing_finish_date"  + // NJ 2013-11-06: corrected code to get the latest seq finished date +      var final_sequence_date = "0000-00-00" +      for (sample_run_metrics in LP["sample_run_metrics"]) { + //final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] + var tmp_fin_seq = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] + if(tmp_fin_seq > final_sequence_date) { final_sequence_date = tmp_fin_seq; } +      } + + + // Collect dates to a KPI object + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = final_validation + KPI["All samples sequenced"] = final_sequence_date + KPI["Close date"] = close_date; + + emit([sequencing_platform, doc["project_name"], doc["project_id"], sample, library_prep], KPI) + } + + // If no library preps have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + KPI["Close date"] = close_date; + + emit([sequencing_platform, doc["project_name"], doc["project_id"], sample, null], KPI) + } + } + + // If no samples have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("samples" in doc)) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + KPI["Close date"] = close_date; + + emit([sequencing_platform, doc["project_name"], doc["project_id"], null, null], KPI) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/process_flow/KPI.reduce.js b/StatusDB_views/projects/process_flow/KPI.reduce.js new file mode 100644 index 0000000..96b4ef6 --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI.reduce.js @@ -0,0 +1,22 @@ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "QC library finished": "0000-00-00", + "All samples sequenced": "0000-00-00", + "Close date": "0000-00-00"} + + for (k in result) { + for (var i = 0; i < values.length; i++) { + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } + else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00" + break; + } + } + } + + return result +} \ No newline at end of file diff --git a/StatusDB_views/projects/process_flow/KPI_appl_pf_dates_sampl_lanes.map.js b/StatusDB_views/projects/process_flow/KPI_appl_pf_dates_sampl_lanes.map.js new file mode 100644 index 0000000..c9b2312 --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI_appl_pf_dates_sampl_lanes.map.js @@ -0,0 +1,112 @@ +function(doc) { + var type = doc["details"]["type"]; + // Only output production documents + //if(type != "Production") { exit; } + + // Get sequencing platform and application for stratification + var sequencing_platform = doc["details"]["sequencing_platform"]; + var application = doc["application"]; + + // Calculate lane load per sample + var proj_lanes = doc["details"]["sequence_units_ordered_(lanes)"]; + var num_samples = doc.no_of_samples; + var lanes_per_sample = proj_lanes/num_samples; + + + // Find arrival date (if present) + var open_date = "0000-00-00"; + if (doc["open_date"] > open_date) { + open_date = doc["open_date"]; + if(open_date < "2013-07-01") { exit; } + } + + // close date + var close_date = "0000-00-00"; + if (doc["close_date"] > close_date) { + close_date = doc["close_date"]; + } + + // go through each sample + for (sample in doc["samples"]){ + // library prep start date + // NEW temp way to get lib prep start + // This bit of code to be transferred to production server + var lib_prep_start = "0000-00-00"; + if(doc["samples"][sample]["first_prep_start_date"]) { + lib_prep_start = doc["samples"][sample]["first_prep_start_date"]; + } + + // final validation date for Library QC + var final_validation = "0000-00-00"; + // sequence start date + var sequence_start_date = "9999-99-99"; + // final sequence date + var final_sequence_date = "0000-00-00"; + + // Find queue date (if present) + var queued = "0000-00-00"; + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"]; + } + + // go through each lib prep for sample + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep] + if(LP.prep_finished_date) { + final_validation = LP.prep_finished_date + } + // capture earliest lib prep start + // NOW DONE above at sample level. + // This bit of code should be commented out on production server + //if(LP["prep_start_date"]) { + // if (lib_prep_start == "0000-00-00") { + // lib_prep_start = LP["prep_start_date"]; + // } else if (LP["prep_start_date"] final_validation) { + // final_validation = lib_val_fin; + // } + //} + + + // Find sequence start date & final sequence date by looking at the first sequence start date & the last sequencing_finish_date + // sequence_start_date initialized at sample level + // final_sequence_date initialized at sample level + for (sample_run_metrics in LP["sample_run_metrics"]) { + if(sequence_start_date > LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"]) { + sequence_start_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"]; + } + if(final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"]) { + final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"]; + } + } // sequence + + } // library prep + + if (sequence_start_date == "9999-99-99") { sequence_start_date = "0000-00-00"; } + //NEW! Emit what we have all variables should be set before so will be ok at emit + //if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object(); + KPI["Arrival date"] = open_date; + KPI["Queue date"] = queued; + KPI["Lib prep start"] = lib_prep_start; + KPI["QC library finished"] = final_validation; + KPI["Sequencing start"] = sequence_start_date; + KPI["All samples sequenced"] = final_sequence_date; + KPI["Close date"] = close_date; + KPI["Samples"] = 1; + KPI["Lanes"] = lanes_per_sample; + +// emit([doc["project_id"], doc["project_name"], application, sequencing_platform, sample], KPI); + emit([doc["project_id"], type, application, sequencing_platform, sample], KPI); + + } // sample + +} diff --git a/StatusDB_views/projects/process_flow/KPI_appl_pf_dates_sampl_lanes.reduce.js b/StatusDB_views/projects/process_flow/KPI_appl_pf_dates_sampl_lanes.reduce.js new file mode 100644 index 0000000..aea906d --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI_appl_pf_dates_sampl_lanes.reduce.js @@ -0,0 +1,56 @@ +/** + * Reduce function - shouldn't really be needed + */ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "Lib prep start": "0000-00-00", + "QC library finished": "0000-00-00", + "Sequencing start": "9999-99-99", + "All samples sequenced": "0000-00-00", + "Close date": "0000-00-00", + "Samples": null, + "Lanes": null + } + + res: for (var k in result) { + for (var i = 0; i < values.length; i++) { + if (k == "Samples" || k == "Lanes") { // add up the values for samples and lanes when reducing + result[k]+= values[i][k]; + continue; + } + if (k == "Sequencing start") { + if(values[i][k] == "0000-00-00") { + result[k] = "0000-00-00"; + } else if (values[i][k] < result[k]) { + result[k] = values[i][k] + } + continue; + } + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00"; + continue res; + } + } + } + //for (var i = 0; i < values.length; i++) { + // for (k in result) { + // if (k == "Samples" || k == "Lanes") { // add up the values for samples and lanes when reducing + // result[k]+= values[i][k]; + // continue; + // } + // if (values[i][k] > result[k]){ + // result[k] = values[i][k] + // } + // else if (values[i][k] == "0000-00-00") { + // // We use the date 0000-00-00 to indicate unfinished process + // result[k] = "0000-00-00" + // } + // } + //} + + return result +} \ No newline at end of file diff --git a/StatusDB_views/projects/process_flow/KPI_applications.map.js b/StatusDB_views/projects/process_flow/KPI_applications.map.js new file mode 100644 index 0000000..5674e9f --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI_applications.map.js @@ -0,0 +1,97 @@ +function(doc) { + // Only output production documents + if(doc["details"]["type"] != "Production") { exit; } + + // Get sequencing platform for stratification + var application = doc["application"] + + + // Find arrival date (if present) + var open_date = "0000-00-00" + if (doc["open_date"] > open_date) { + open_date = doc["open_date"] + } + // NJ 2013-10-22 + // Added close date. This is date is emitted further down in the code. + // Also added to Reduce Function ----> + var close_date = "0000-00-00" + if (doc["close_date"] > close_date) { + close_date = doc["close_date"] + } + for (sample in doc["samples"]){ + // Find queue date (if present) + var queued = "0000-00-00" + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"] + } + + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep] + + // Find QC library finish date by looking at the final library validation. + var final_validation = "0000-00-00" + for (lv in LP["library_validation"]) { + var lib_val_fin = LP["library_validation"][lv]["finish_date"] + if (lib_val_fin > final_validation) { + final_validation = lib_val_fin + } + } + + // Find the time a sample is sequenced at by looking at sample runs + // sequencing _start_ date. This is confusing, but it is how Maya + // specified it. + //var final_sequence_date = "0000-00-00" + //for (sample_run_metrics in LP["sample_run_metrics"]) { + // final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"] + //} + + // NJ 2013-08-23: updated original code above to work with new + // key "sequencing_finish_date" + // NJ 2013-11-06: corrected code to get the latest seq finished date + var final_sequence_date = "0000-00-00" + for (sample_run_metrics in LP["sample_run_metrics"]) { + //final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] + var tmp_fin_seq = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] + if(tmp_fin_seq > final_sequence_date) { final_sequence_date = tmp_fin_seq; } + + } + + + // Collect dates to a KPI object + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = final_validation + KPI["All samples sequenced"] = final_sequence_date + KPI["Close date"] = close_date; + + emit([application, doc["project_name"], doc["project_id"], sample, library_prep], KPI) + } + + // If no library preps have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + KPI["Close date"] = close_date; + + emit([application, doc["project_name"], doc["project_id"], sample, null], KPI) + } + } + + // If no samples have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("samples" in doc)) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + KPI["Close date"] = close_date; + + emit([application, doc["project_name"], doc["project_id"], null, null], KPI) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/process_flow/KPI_applications.reduce.js b/StatusDB_views/projects/process_flow/KPI_applications.reduce.js new file mode 100644 index 0000000..fccabbf --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI_applications.reduce.js @@ -0,0 +1,21 @@ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "QC library finished": "0000-00-00", + "All samples sequenced": "0000-00-00", + "Close date": "0000-00-00"} + for (k in result) { + for (var i = 0; i < values.length; i++) { + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } + else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00" + break; + } + } + } + + return result +} diff --git a/StatusDB_views/projects/process_flow/KPI_applications_test.map.js b/StatusDB_views/projects/process_flow/KPI_applications_test.map.js new file mode 100644 index 0000000..436e688 --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI_applications_test.map.js @@ -0,0 +1,88 @@ +function(doc) { + // Only output production documents + if(doc["details"]["type"] != "Production") { exit; } + + // Get sequencing platform for stratification + var application = doc["application"] + + + // Find arrival date (if present) + var open_date = "0000-00-00" + if (doc["open_date"] > open_date) { + open_date = doc["open_date"] + } + + for (sample in doc["samples"]){ + // Find queue date (if present) + var queued = "0000-00-00" + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"] + } + + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep]; + + // Find QC library finish date by looking at the final library validation. + var final_validation = "0000-00-00"; + if(LP["prep_status"] == "FAILED") { + final_validation = "0000-00-00"; + } else { + for (lv in LP["library_validation"]) { + var lib_val_fin = LP["library_validation"][lv]["finish_date"] + if (lib_val_fin > final_validation) { + final_validation = lib_val_fin + } + } + } + + // Find the time a sample is sequenced at by looking at sample runs + // sequencing _start_ date. This is confusing, but it is how Maya + // specified it. + //var final_sequence_date = "0000-00-00" + //for (sample_run_metrics in LP["sample_run_metrics"]) { + // final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"] + //} + + // NJ 2013-08-23: updated original code above to work with new + // key "sequencing_finish_date" + var final_sequence_date = "0000-00-00" + for (sample_run_metrics in LP["sample_run_metrics"]) { + final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] + } + + + // Collect dates to a KPI object + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = final_validation + KPI["All samples sequenced"] = final_sequence_date + + emit([application, doc["project_name"], sample, library_prep], KPI) + } + + // If no library preps have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + + emit([application, doc["project_name"], sample, null], KPI) + } + } + + // If no samples have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("samples" in doc)) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + + emit([application, doc["project_name"], null, null], KPI) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/process_flow/KPI_applications_test.reduce.js b/StatusDB_views/projects/process_flow/KPI_applications_test.reduce.js new file mode 100644 index 0000000..470bb42 --- /dev/null +++ b/StatusDB_views/projects/process_flow/KPI_applications_test.reduce.js @@ -0,0 +1,30 @@ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "QC library finished": "0000-00-00", + "All samples sequenced": "0000-00-00"} + var unfinished = []; + for (var i = 0; i < values.length; i++) { + for (k in result) { + if (values[i][k] === "0000-00-00"){ + unfinished.push(k); + } + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } + else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00"; + } + } + } +    for (k in unfinished) { + var k2 = parseInt(k); + if(k2 != NaN) { continue;} +// if (typeof k === 'number') {continue;} +// if (typeof k == 'number') {continue;} +// if (k == 0 || k == 1) {continue;} +      result[k] = "0000-00-00"; +    } + return result; +} \ No newline at end of file diff --git a/StatusDB_views/projects/project/applications.map.js b/StatusDB_views/projects/project/applications.map.js new file mode 100644 index 0000000..aaff163 --- /dev/null +++ b/StatusDB_views/projects/project/applications.map.js @@ -0,0 +1,8 @@ +/* + Used by genomics-status at: + /api/v1/application/:id +*/ + +function(doc) { + emit(doc["application"], doc["project_id"]); +} diff --git a/StatusDB_views/projects/project/applications.reduce.js b/StatusDB_views/projects/project/applications.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/project/applications.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/project/caliper_links.map.js b/StatusDB_views/projects/project/caliper_links.map.js new file mode 100644 index 0000000..2244be0 --- /dev/null +++ b/StatusDB_views/projects/project/caliper_links.map.js @@ -0,0 +1,23 @@ +function (doc) { + data={}; + for (sample in doc.samples){ + data[sample]={} + if (doc.samples[sample].hasOwnProperty('initial_qc') && doc.samples[sample].initial_qc.hasOwnProperty('caliper_image')){ + data[sample]["initial_qc"]=doc.samples[sample].initial_qc.caliper_image; + } + if (doc.samples[sample].hasOwnProperty('library_prep')){ + for(libprep in doc.samples[sample].library_prep){ + if(doc.samples[sample].library_prep[libprep].hasOwnProperty('library_validation')){ + for (libvalart in doc.samples[sample].library_prep[libprep].library_validation){ + if (doc.samples[sample].library_prep[libprep].library_validation[libvalart].hasOwnProperty('caliper_image')){ + data[sample]['libval'+libprep]=doc.samples[sample].library_prep[libprep].library_validation[libvalart].caliper_image; + + } + } + } + } + } + } + emit(doc.project_id , data); + } + diff --git a/StatusDB_views/projects/project/controls.map.js b/StatusDB_views/projects/project/controls.map.js new file mode 100644 index 0000000..6b0f266 --- /dev/null +++ b/StatusDB_views/projects/project/controls.map.js @@ -0,0 +1,48 @@ +// view for all control projects +// to be used by the GenStat page for controls + +function (doc) { + const re_positive_control = /p.ositive*/i; + const re_negative_control = /n.egative*/i; + + if(doc["details"]["type"] === "Control") { + if (re_positive_control.test(doc["project_name"])) { + control_project = "positive control";} + else if (re_negative_control.test(doc["project_name"])) { + control_project = "negative control";} + + summary = {}; + for (var sample in doc["samples"]) { + details = doc["samples"][sample]; + if (doc["samples"][sample].hasOwnProperty('library_prep')) { + sample_lib_prep_details = {}; + for (var lib_prep in details["library_prep"]){ + lib_prep_details = {}; + lib_prep_details["customer_name"] = details["customer_name"]; + lib_prep_details["status_manual"] = details["details"]["status_(manual)"]; + lib_prep_details["passed_sequencing_qc"] = details["details"]["passed_sequencing_qc"]; + lib_prep_details["app_qc"] = details["details"]["app_qc"]; + lib_prep_details["workset_name"] = details["library_prep"][lib_prep]["workset_name"]; + lib_prep_details["workset_id"] = details["library_prep"][lib_prep]["workset_setup"]; + lib_prep_details["prep_status"] = details["library_prep"][lib_prep]["prep_status"]; + if(details["library_prep"][lib_prep].hasOwnProperty("sequenced_fc")){ + lib_prep_details["sequenced_fc"] = details["library_prep"][lib_prep]["sequenced_fc"]; + } else { + lib_prep_details["sequenced_fc"] = "not sequenced"; + } + sample_lib_prep_details[lib_prep_details["workset_id"]] = lib_prep_details; + } + summary[sample] = sample_lib_prep_details; + } + else { + lib_prep_details = {}; + lib_prep_details["customer_name"] = details["customer_name"]; + lib_prep_details["status_manual"] = details["details"]["status_(manual)"]; + lib_prep_details["passed_sequencing_qc"] = details["details"]["passed_sequencing_qc"]; + lib_prep_details["app_qc"] = details["details"]["app_qc"]; + summary[sample] = {"no_workset": lib_prep_details}; + } + } + emit([control_project, doc["project_id"]], summary); + } +} diff --git a/StatusDB_views/projects/project/dailyread_dates.map.js b/StatusDB_views/projects/project/dailyread_dates.map.js new file mode 100644 index 0000000..d8c6c9f --- /dev/null +++ b/StatusDB_views/projects/project/dailyread_dates.map.js @@ -0,0 +1,119 @@ + +function(doc) { + if(doc.details.hasOwnProperty('portal_id') && ("contract_sent" in doc["details"])){ + var summary = {}; + var orderer = null; + var portal_id = null; + var close_date = "XXXX-XX-XX"; + if ("close_date" in doc) { + close_date = doc["close_date"]; + } else if (!(("source" in doc) && (doc["source"] == "lims"))) { + // Gdocs - better be closed by now (>2023) + close_date = "1111-11-11"; + } + + if ("order_details" in doc) { + orderer = doc["order_details"]["owner"]["email"] + portal_id = doc["order_details"]["identifier"] + } + summary["orderer"] = orderer + summary["portal_id"] = portal_id + summary["order_year"] = "" + + summary["project_id"] = doc.project_id; + summary["project_name"] = doc.project_name; + summary["proj_dates"] = {} + //From details + var date = null; + const dates_arr = [["samples_received", "Samples Received"], ["queued", "Reception Control Finished"], ["all_samples_sequenced", "All Samples Sequenced"], + ["all_raw_data_delivered", "All Raw Data Delivered"]]; + + dates_arr.forEach(function (item, index) { + date = item[0] in doc["details"] ? doc["details"][item[0]]: ""; + if (date!==""){ + if(date in summary["proj_dates"]){ + summary["proj_dates"][date].push(item[1]); + } + else{ + summary["proj_dates"][date] = [item[1]]; + } + } + }); + + if("contract_sent" in doc["details"]){ + summary["order_year"] = doc["details"]["contract_sent"].split("-")[0] + } + + //Status + summary["status"] = doc["status_fields"]["status"]; + + //Summary Dates + var first_initial_qc_start_date = "9999-99-99"; + var sequencing_start_date = "9999-99-99"; + var qc_library_finished = "0000-00-00"; + var library_prep_start = "9999-99-99"; + + for (var sample in doc["samples"]) { + // Find first library prep start (1st) + if ("first_prep_start_date" in doc["samples"][sample]){ + if (library_prep_start > doc["samples"][sample]["first_prep_start_date"]) { + library_prep_start = doc["samples"][sample]["first_prep_start_date"]; + } + } + + //Sequencing QC + if (doc["samples"][sample].hasOwnProperty('library_prep')) { + var latest_seq="0"; + for (var lib in doc["samples"][sample]['library_prep']){ + var lib_prep_doc = doc["samples"][sample]['library_prep'][lib]; + if (lib_prep_doc.hasOwnProperty('sample_run_metrics')){ + for (var runid in lib_prep_doc['sample_run_metrics']) { + var run_metric_doc = lib_prep_doc['sample_run_metrics'][runid]; + // Find sequencing start date + if (sequencing_start_date > run_metric_doc["sequencing_start_date"]) { + sequencing_start_date = run_metric_doc["sequencing_start_date"]; + } + } + } + // Find last QC library finished + for (var lib_val in lib_prep_doc["library_validation"]) { + var lib_val_doc = lib_prep_doc["library_validation"][lib_val]; + if (qc_library_finished < lib_val_doc["finish_date"]) { + qc_library_finished = lib_val_doc["finish_date"]; + } + } + // Find first library prep start (2nd) + if ("prep_start_date" in lib_prep_doc){ + if (library_prep_start > lib_prep_doc["prep_start_date"]) { + library_prep_start = lib_prep_doc["prep_start_date"]; + } + } + } + } + + // Find first initial QC start date + if ("initial_qc" in doc["samples"][sample]) { + if (first_initial_qc_start_date > doc["samples"][sample]["initial_qc"]["start_date"]) { + first_initial_qc_start_date = doc["samples"][sample]["initial_qc"]["start_date"]; + } + } else if ("first_initial_qc_start_date" in doc["samples"][sample]) { + if (first_initial_qc_start_date > doc["samples"][sample]["first_initial_qc_start_date"]) { + first_initial_qc_start_date = doc["samples"][sample]["first_initial_qc_start_date"]; + } + } + } + + // Omit dates if not set + if (qc_library_finished != "0000-00-00") { + if(qc_library_finished in summary["proj_dates"]){ + summary["proj_dates"][qc_library_finished].push("Library QC Finished"); + } + else{ + summary["proj_dates"][qc_library_finished] = ["Library QC Finished"]; + } + } + + emit([close_date, summary["project_id"]], summary); + } + } + \ No newline at end of file diff --git a/StatusDB_views/projects/project/date_applications.map.js b/StatusDB_views/projects/project/date_applications.map.js new file mode 100644 index 0000000..885ad6e --- /dev/null +++ b/StatusDB_views/projects/project/date_applications.map.js @@ -0,0 +1,11 @@ +/* + Used by genomics-status at: + /api/v1/applications + /api/v1/applications.png +*/ + +function(doc) { + var od = doc["open_date"]; + emit([od,doc["application"]], doc["project_id"]); +} + diff --git a/StatusDB_views/projects/project/date_samples_applications.map.js b/StatusDB_views/projects/project/date_samples_applications.map.js new file mode 100644 index 0000000..a02055f --- /dev/null +++ b/StatusDB_views/projects/project/date_samples_applications.map.js @@ -0,0 +1,12 @@ +/* + Used by genomics-status at: + /api/v1/samples_applications, + /api/v1/samples_applications.png +*/ + +function(doc) { + no_of_samples = +doc["no_of_samples"] || 0 + var od = doc["open_date"]; + emit([od,doc["application"]], no_of_samples); +} + diff --git a/StatusDB_views/projects/project/details_count.map.js b/StatusDB_views/projects/project/details_count.map.js new file mode 100644 index 0000000..c4077b3 --- /dev/null +++ b/StatusDB_views/projects/project/details_count.map.js @@ -0,0 +1,33 @@ +/* A view to count values for most keys in project details and output it per year. Useful to check most common values and how they change over time. */ + +function (doc) { + var creation_time = doc['creation_time']; + var creation_year = creation_time.slice(0, 4); + + // Regular expression to match YYYY-MM-DD format + var dateRegex = /^\d{4}-\d{2}-\d{2}$/; + + // Array of detail_key values to skip + var skipKeys = ['project_comment', 'running_notes', 'customer_project_description', + 'agreement_cost', 'customer_project_reference', 'ethics_permit_number', + 'invoice_reference', 'links', 'portal_id', 'reads_min']; + + + var otherKeys = ['project_name']; + + for (var detail_key in doc['details']) { + var detail_value = doc['details'][detail_key]; + + // Check if detail_key is not in the skipKeys array and detail_value does not match the date format + if (skipKeys.indexOf(detail_key) === -1 && !dateRegex.test(detail_value)) { + emit([detail_key, creation_year, detail_value]); + } + } + for (var other_key_index in otherKeys) { + var other_key = otherKeys[other_key_index]; + if (doc.hasOwnProperty(other_key)) { + var other_value = doc[other_key]; + emit([other_key, creation_year, other_value]); + } + } +} diff --git a/StatusDB_views/projects/project/details_count.reduce.js b/StatusDB_views/projects/project/details_count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/project/details_count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/project/frag_an_links.map.js b/StatusDB_views/projects/project/frag_an_links.map.js new file mode 100644 index 0000000..873660b --- /dev/null +++ b/StatusDB_views/projects/project/frag_an_links.map.js @@ -0,0 +1,23 @@ +function (doc) { + data={}; + for (sample in doc.samples){ + data[sample]={} + if (doc.samples[sample].hasOwnProperty('initial_qc') && doc.samples[sample].initial_qc.hasOwnProperty('frag_an_image')){ + data[sample]["initial_qc"]=doc.samples[sample].initial_qc.frag_an_image; + } + if (doc.samples[sample].hasOwnProperty('library_prep')){ + for(libprep in doc.samples[sample].library_prep){ + if(doc.samples[sample].library_prep[libprep].hasOwnProperty('library_validation')){ + for (libvalart in doc.samples[sample].library_prep[libprep].library_validation){ + if (doc.samples[sample].library_prep[libprep].library_validation[libvalart].hasOwnProperty('frag_an_image')){ + data[sample]['libval'+libprep]=doc.samples[sample].library_prep[libprep].library_validation[libvalart].frag_an_image; + + } + } + } + } + } + } + emit(doc.project_id , data); + } + diff --git a/StatusDB_views/projects/project/id_name_dates.map.js b/StatusDB_views/projects/project/id_name_dates.map.js new file mode 100644 index 0000000..8a77653 --- /dev/null +++ b/StatusDB_views/projects/project/id_name_dates.map.js @@ -0,0 +1,41 @@ +/** +* +* View: id_name_dates +* +* To be used by: script to populate Production application meetings Trello boards +* +*/ + +function(doc) { + order_date = "0000-00-00"; + open_date = "0000-00-00"; + queue_date = "0000-00-00"; + close_date = "0000-00-00"; + if (doc.details.order_received) { + order_date = doc.details.order_received; + } + if (doc["open_date"]) { + open_date = doc["open_date"] + } + if (doc.details.queued) { + queue_date = doc.details.queued; + } + if (doc["close_date"]) { + close_date = doc["close_date"] + } + emit( + doc.project_id, + { + "project_name": doc.project_name, + "portal_id": doc.details.portal_id, + "type": doc.details.type, + "application": doc.application, + "lib_prep": doc.details.library_construction_method, + "platform": doc.details.sequencing_platform, + "order_date": order_date, + "open_date": open_date, + "queue_date": queue_date, + "close_date": close_date, + "no_of_samples": doc.no_of_samples, + }); +} \ No newline at end of file diff --git a/StatusDB_views/projects/project/lib_const_meth.map.js b/StatusDB_views/projects/project/lib_const_meth.map.js new file mode 100644 index 0000000..334ca5f --- /dev/null +++ b/StatusDB_views/projects/project/lib_const_meth.map.js @@ -0,0 +1,8 @@ +/* + Used by genomics-status at: + /project/([^/]*) +*/ + +function(doc) { + emit(doc.project_id, doc["details"]["library_construction_method"]); +} \ No newline at end of file diff --git a/StatusDB_views/projects/project/project_dates.map.js b/StatusDB_views/projects/project/project_dates.map.js new file mode 100644 index 0000000..9babc11 --- /dev/null +++ b/StatusDB_views/projects/project/project_dates.map.js @@ -0,0 +1,27 @@ +/** +* +* View: project_dates +* +* Used by: pm report closed-projects +* +*/ + +function(doc) { + open_date = "0000-00-00" + close_date = "0000-00-00" + aborted = "0000-00-00" + if (doc["open_date"]) { + open_date = doc["open_date"] + } + if (doc["close_date"]) { + close_date = doc["close_date"] + } + if (doc["details"] && doc["details"]["aborted"]) { + aborted = doc["details"]["aborted"] + } + emit(doc["project_name"], { + "open_date": open_date, + "close_date": close_date, + "aborted": aborted + }); +} diff --git a/StatusDB_views/projects/project/project_id.map.js b/StatusDB_views/projects/project/project_id.map.js new file mode 100644 index 0000000..c001626 --- /dev/null +++ b/StatusDB_views/projects/project/project_id.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc.project_id, doc._id)} diff --git a/StatusDB_views/projects/project/project_name.map.js b/StatusDB_views/projects/project/project_name.map.js new file mode 100644 index 0000000..d0d024d --- /dev/null +++ b/StatusDB_views/projects/project/project_name.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc.project_name, doc._id)} diff --git a/StatusDB_views/projects/project/sample_list.map.js b/StatusDB_views/projects/project/sample_list.map.js new file mode 100644 index 0000000..f793fca --- /dev/null +++ b/StatusDB_views/projects/project/sample_list.map.js @@ -0,0 +1,17 @@ +function(doc) { + samples = []; + for (sample in doc["samples"]) { + s = doc["samples"][sample] + if (s["scilife_name"]) { + samples.push(s["scilife_name"]) + } + else if (s["customer_name"]) { + samples.push(s["customer_name"]) + } + else { + samples.push(sample) + } + } + emit(doc["project_id"], samples); +} + diff --git a/StatusDB_views/projects/project/samples.map.js b/StatusDB_views/projects/project/samples.map.js new file mode 100644 index 0000000..c15e477 --- /dev/null +++ b/StatusDB_views/projects/project/samples.map.js @@ -0,0 +1,16 @@ +/* + Used by genomics-status at: + /api/v1/projects/:id +*/ + +function(doc) { + //Patching samples reads_min + if ("reads_min" in doc.details){ + for(sample in doc["samples"]){ + if (! ('reads_min' in doc.samples[sample].details)){ + doc.samples[sample].details['reads_min']=doc.details['reads_min']; + } + } + } + emit(doc["project_id"], doc["samples"]) +} diff --git a/StatusDB_views/projects/project/samples_applications.map.js b/StatusDB_views/projects/project/samples_applications.map.js new file mode 100644 index 0000000..1c125b0 --- /dev/null +++ b/StatusDB_views/projects/project/samples_applications.map.js @@ -0,0 +1,4 @@ +function(doc) { + no_of_samples = +doc["no_of_samples"] || 0 + emit(doc["application"], no_of_samples); +} diff --git a/StatusDB_views/projects/project/samples_applications.reduce.js b/StatusDB_views/projects/project/samples_applications.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/project/samples_applications.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/project/staged_files_sum.map.js b/StatusDB_views/projects/project/staged_files_sum.map.js new file mode 100644 index 0000000..186170c --- /dev/null +++ b/StatusDB_views/projects/project/staged_files_sum.map.js @@ -0,0 +1,22 @@ +function(doc) { + result = {}; + if (doc.staged_files) { + filesize_sum = 0; + for (var sample_id in doc.staged_files) { + for (var file_name in doc.staged_files[sample_id]) { + filesize_sum += doc.staged_files[sample_id][file_name]['size_in_bytes']; + } + } + result['filesize_in_bytes'] = filesize_sum; + result['project_name'] = doc.project_name; + result['close_date'] = doc['close_date']; + result['application'] = doc['application']; + result['sequencing_platform'] = doc['details']['sequencing_platform']; + result['type'] = doc['details']['type']; + result['sample_type'] = doc['details']['sample_type']; + result['best_practice_bioinformatics'] = doc['details']['best_practice_bioinformatics']; + result['delivery_type'] = doc['delivery_type']; + result['reference_genome'] = doc['reference_genome']; + emit(doc.project_id, result); + } +} diff --git a/StatusDB_views/projects/project/status_lanes_ordered.map.js b/StatusDB_views/projects/project/status_lanes_ordered.map.js new file mode 100644 index 0000000..49f486c --- /dev/null +++ b/StatusDB_views/projects/project/status_lanes_ordered.map.js @@ -0,0 +1,25 @@ +/* Should usually be used with the _sum reduce function */ +function(doc) { + if (!("details" in doc)) { + doc["details"] = {"flowcell": "NA", "sequencing_platform": "NA", "sequence_units_ordered_(lanes)": 0} + } + + var flowcell = ""; + if (!("flowcell" in doc["details"]) || doc["details"]["flowcell"] === ""){ + flowcell = "NA"; + } else { + flowcell = doc["details"]["flowcell"]; + } + + var lanes_ordered = 0; + if ("sequence_units_ordered_(lanes)" in doc["details"]){ + lanes_ordered = doc["details"]["sequence_units_ordered_(lanes)"]; + } + + var platform = "NA"; + if ("sequencing_platform" in doc["details"]){ + platform = doc["details"]["sequencing_platform"]; + } + + emit([doc["status_fields"]["status"].toLowerCase(), platform, flowcell, doc["project_id"]], lanes_ordered); +} \ No newline at end of file diff --git a/StatusDB_views/projects/project/summary.map.js b/StatusDB_views/projects/project/summary.map.js new file mode 100644 index 0000000..984c033 --- /dev/null +++ b/StatusDB_views/projects/project/summary.map.js @@ -0,0 +1,192 @@ +/* +Used by genomics-status at: + /api/v1/projects, + /api/v1/project_fields, + /api/v1/project_summary/:id +*/ + +// Used for the project list at http://genomics-status.scilifelab.se/projects + +var inc = function(prop, def) { + if (prop == undefined) { + prop = def; + } + else { + prop += def; + } + return prop; +} + +var key_count = function(obj) { + var n_keys = 0; + for (key in obj) { + n_keys++; + } + return n_keys +} + +function(doc) { + var summary = Object(); + + // final_number_of_samples emitted only if 'status_(manual)' is set for all + var final_number_of_samples = 0; + var is_final = true; + if (doc["samples"] == undefined) {is_final = false;} + + // Temporary objects for counting purposes + var lib_repreps = Object(); + var pools = Object(); + var lanes = Object(); + var progress = Object(); // possible keys: "Aborted", "In Progress", "Finished" + +summary["passed_samples"]=0; + for (sample in doc["samples"]) { + var seen=false; + //Sequencing QC + if (doc["samples"][sample].hasOwnProperty('library_prep')){ + var latest_seq="0"; + for(lib in doc["samples"][sample]['library_prep']){ + if (doc["samples"][sample]['library_prep'][lib].hasOwnProperty('sample_run_metrics')){ + for(runid in doc["samples"][sample]['library_prep'][lib]['sample_run_metrics']){ + if (doc["samples"][sample]['library_prep'][lib]['sample_run_metrics'][runid]["sequencing_start_date"]> latest_seq){ + latest_seq=doc["samples"][sample]['library_prep'][lib]['sample_run_metrics'][runid]["sequencing_start_date"]; + if (doc["samples"][sample]['library_prep'][lib]['sample_run_metrics'][runid]['seq_qc_flag'] == "PASSED" && !seen){ + summary["passed_samples"]=summary["passed_samples"]+1; + seen=true; + } + } + } + } + } + } + + + // samples > [sample] > details + if ("details" in doc["samples"][sample]){ + + // final_number_of_samples + var status = doc["samples"][sample]["details"]["status_(manual)"]; + if (status !== "Aborted"){ + final_number_of_samples += 1; + }; + if (status !== undefined){ + summary[status] = inc(summary[status],1) + } + else { + is_final = false; + } + + // passed_initial_qc + var initial_qc = doc["samples"][sample]["details"]["passed_initial_qc"]; + if (initial_qc == "True") { + progress["passed_initial_qc"] = inc(progress["passed_initial_qc"], 1); + } + else if (initial_qc == "False") { + progress["passed_initial_qc"] = inc(progress["passed_initial_qc"], 0); + } + + // samples > [sample] > library_prep + var lib_qc = undefined; + for (prep in doc["samples"][sample]["library_prep"]) { + if (prep !== 'A') {lib_repreps[prep] = 1;} + // [library_prep] > sample_run_metrics + for (lane in doc["samples"][sample]["library_prep"][prep]["sample_run_metrics"]) { + lanes[lane.split("_").slice(0,3).join("_")] = 1; + } + + prep_status = doc["samples"][sample]["library_prep"][prep]["prep_status"]; + if (prep_status == "PASSED") { + lib_qc = inc(lib_qc,1); + } + else if (prep_status == "FAILED") { + lib_qc = inc(lib_qc,0); + } + } + + // Library QC + if (lib_qc !== undefined) { + progress["passed_library_qc"] = inc(progress["passed_library_qc"], Math.min(1,lib_qc)); + } + + // number_of_pools + if (doc["samples"][sample]["details"]["pooling"] !== undefined) { + pools[doc["samples"][sample]["details"]["pooling"]] = 1; + } + } + } + + // X/Y passed QC + if (is_final) { + if (progress["passed_library_qc"] !== undefined) { + summary["passed_library_qc"] = String(progress["passed_library_qc"]) + "/" + String(final_number_of_samples) + " P"; + } + if (progress["passed_initial_qc"] !== undefined) { + summary["passed_initial_qc"] = String(progress["passed_initial_qc"]) + "/" + String(final_number_of_samples) + " P"; + } + if (summary["passed_samples"] !== undefined) { + summary["passed_seq_qc"] = String(summary["passed_samples"]) + "/" + String(final_number_of_samples) + " P" + } + } + + // Count objects, emit only if count !== 0 + summary["library_repreps"] = key_count(lib_repreps) || undefined; + summary["number_of_pools"] = key_count(pools) || undefined; + summary["lanes_sequenced"] = key_count(lanes) || undefined; + + /* Details will contain all project level udfs */ + summary["details"] = doc["details"]; + /* Project summary will contain all temporary process/project level udfs */ + summary["project_summary"] = doc["project_summary"]; + summary["project_summary_links"] = doc["project_summary_links"]; + summary["application"] = doc["application"]; + summary["no_samples"] = doc["no_of_samples"]; + summary["ordered_reads"] = doc["min_m_reads_per_sample_ordered"]; + summary["open_date"] = doc["open_date"]; + summary["project_name"] = doc["project_name"]; + summary["affiliation"] = doc["affiliation"]; + summary["order_details"] = doc["order_details"]; + summary["delivery_projects"] = doc["delivery_projects"]; + summary["modification_time"] = doc["modification_time"]; + summary["priority"] = doc["priority"]; + //Check for PI contact information + if ("contact" in doc) { + summary["contact"] = doc["contact"]; + } + + if ("source" in doc) { + summary["source"] = doc["source"]; + } + else { + summary["source"] = "gdocs"; + } + + if (is_final) { + summary["final_number_of_samples"] = final_number_of_samples; + } + + summary["reference_genome"] = doc["reference_genome"] + summary["customer_reference"] = doc["customer_reference"] + if ("uppnex_id" in doc){ + summary["delivery_type"] = doc["uppnex_id"] + } + else if("delivery_type" in doc) { + summary["delivery_type"] = doc["delivery_type"] + } + summary["uppnex_id"] = doc["uppnex_id"] + summary["close_date"] = doc["close_date"] + + if (doc.hasOwnProperty("escalations") && doc.escalations.length >0){ + summary["pending_reviews"]=doc.escalations; + } + if(doc.hasOwnProperty("invoice_spec_downloaded")){ + summary["invoice_spec_downloaded"] = doc["invoice_spec_downloaded"]; + } + if(doc.hasOwnProperty("invoice_spec_generated")){ + summary["invoice_spec_generated"] = doc["invoice_spec_generated"]; + } + if ((summary["source"] == "lims") && (!("close_date" in doc))){ + emit(["open", doc["project_id"]], summary); + } else { + emit(["closed", doc["project_id"]], summary); + } +} diff --git a/StatusDB_views/projects/project/summary_dates.map.js b/StatusDB_views/projects/project/summary_dates.map.js new file mode 100644 index 0000000..eb891ef --- /dev/null +++ b/StatusDB_views/projects/project/summary_dates.map.js @@ -0,0 +1,63 @@ +/* Used by genomics-status at + /api/v1/projects + /api/v1/project_fields + /api/v1/project_summary/:id + */ + +function(doc) { + /* Emit once per library prep to enable reduce */ + for (sample in doc["samples"]) { + var emit_summary = Object(); + /* Find first initial QC start date */ + var first_initial_qc_start_date = "9999-99-99"; + if ("initial_qc" in doc["samples"][sample]){ + first_initial_qc_start_date = doc["samples"][sample]["initial_qc"]["start_date"] + } + else if ("first_initial_qc_start_date" in doc["samples"][sample]){ + first_initial_qc_start_date = doc["samples"][sample]["first_initial_qc_start_date"] + } + if ("first_prep_start_date" in doc["samples"][sample]){ + emit_summary["library_prep_start"] = doc["samples"][sample]["first_prep_start_date"]; + } + if ("library_prep" in doc["samples"][sample]) { + for (lib_prep in doc["samples"][sample]["library_prep"]) { + var lib_prep_doc = doc["samples"][sample]["library_prep"][lib_prep]; + + /* Find first sequencing start */ + var sequencing_start_date = "9999-99-99"; + for (sample_run_metric in lib_prep_doc["sample_run_metrics"]) { + var run_metric_doc = lib_prep_doc["sample_run_metrics"][sample_run_metric]; + if (sequencing_start_date > run_metric_doc["sequencing_start_date"]) { + sequencing_start_date = run_metric_doc["sequencing_start_date"]; + } + } + + /* Find last QC library finished */ + var qc_library_finished = "0000-00-00" + for (lib_val in lib_prep_doc["library_validation"]) { + var lib_val_doc = lib_prep_doc["library_validation"][lib_val]; + if (qc_library_finished < lib_val_doc["finish_date"]) { + qc_library_finished = lib_val_doc["finish_date"]; + } + } + if ("prep_start_date" in lib_prep_doc){ + emit_summary["library_prep_start"] = lib_prep_doc["prep_start_date"]; + } + if (!(sequencing_start_date == "9999-99-99")) { + emit_summary["sequencing_start_date"] = sequencing_start_date; + } + if (!(qc_library_finished == "0000-00-00")) { + emit_summary["qc_library_finished"] = qc_library_finished + } + if (!(first_initial_qc_start_date == "9999-99-99")) { + emit_summary["first_initial_qc_start_date"] = first_initial_qc_start_date + } + emit([doc["project_id"]], emit_summary); + } + } + else if (!(first_initial_qc_start_date == "9999-99-99")){ + emit_summary["first_initial_qc_start_date"] = first_initial_qc_start_date; + emit([doc["project_id"]], emit_summary); + } + } +} diff --git a/StatusDB_views/projects/project/summary_dates.reduce.js b/StatusDB_views/projects/project/summary_dates.reduce.js new file mode 100644 index 0000000..811c256 --- /dev/null +++ b/StatusDB_views/projects/project/summary_dates.reduce.js @@ -0,0 +1,60 @@ +function(keys, values, rereduce){ + /* Any parameter except those explicitly mentioned here should be the same for all values */ + var result = Object(); + + result["library_prep_start"] = "9999-99-99"; + result["qc_library_finished"] = "0000-00-00"; + result["sequencing_start_date"] = "9999-99-99"; + result["first_initial_qc_start_date"] = "9999-99-99"; + + /* FIRST library prep start date */ + for (var i = 0; i < values.length; i++) { + if ("library_prep_start" in values[i]) { + if (result["library_prep_start"] > values[i]["library_prep_start"]){ + result["library_prep_start"] = values[i]["library_prep_start"]; + } + } + } + + /* LAST QC library finishd date */ + for (var i = 0; i < values.length; i++) { + if ("qc_library_finished" in values[i]) { + if (result["qc_library_finished"] < values[i]["qc_library_finished"]){ + result["qc_library_finished"] = values[i]["qc_library_finished"]; + } + } + } + + /* FIRST sequencing start date */ + for (var i = 0; i < values.length; i++) { + if ("sequencing_start_date" in values[i]) { + if (result["sequencing_start_date"] > values[i]["sequencing_start_date"]){ + result["sequencing_start_date"] = values[i]["sequencing_start_date"]; + } + } + } + + /* FIRST first_initial_qc_start_date */ + for (var i = 0; i < values.length; i++) { + if ("first_initial_qc_start_date" in values[i]) { + if (result["first_initial_qc_start_date"] > values[i]["first_initial_qc_start_date"]){ + result["first_initial_qc_start_date"] = values[i]["first_initial_qc_start_date"]; + } + } + } + + /* if no values are found */ + if (result["library_prep_start"] == "9999-99-99") { + delete result["library_prep_start"]; + } + if (result["qc_library_finished"] == "0000-00-00") { + delete result["qc_library_finished"]; + } + if (result["sequencing_start_date"] == "9999-99-99") { + delete result["sequencing_start_date"]; + } + if (result["first_initial_qc_start_date"] == "9999-99-99") { + delete result["first_initial_qc_start_date"]; + } + return result +} diff --git a/StatusDB_views/projects/project/summary_develop.map.js b/StatusDB_views/projects/project/summary_develop.map.js new file mode 100644 index 0000000..66ee09d --- /dev/null +++ b/StatusDB_views/projects/project/summary_develop.map.js @@ -0,0 +1,62 @@ +/* + Used by genomics-status at: + /api/v1/projects, + /api/v1/project_fields, + /api/v1/project_summary/:id +*/ + +// Used for the project list at http://genomics-status.scilifelab.se/projects + +function(doc) { + var passed_samples = 0; + var final_number_of_samples = 0; + for (sample in doc["samples"]) { + if (doc["samples"][sample]["status"] === "P") { + if (sample !== "Unexpectedbarcode") { + passed_samples++; + }; + }; + if ("details" in doc["samples"][sample]){ + if (doc["samples"][sample]["details"]["status_(manual)"] !== "Aborted"){ + final_number_of_samples++; + }; + }; + }; + + var summary = Object(); + + /* Details will contain all project level udfs */ + summary["details"] = doc["details"]; + /* Project summary will contain all temporary process/project level udfs */ + summary["project_summary"] = doc["project_summary"]; + summary["application"] = doc["application"]; + summary["no_samples"] = doc["no_of_samples"]; + summary["final_number_of_samples"] = final_number_of_samples; + summary["ordered_reads"] = doc["min_m_reads_per_sample_ordered"]; + summary["project_name"] = doc["project_name"] + summary["open_date"] = doc["open_date"]; + summary["project_name"] = doc["project_name"]; + //Check for PI contact information + if ("contact" in doc) { + summary["contact"] = doc["contact"]; + } + + if ("source" in doc) { + summary["source"] = doc["source"]; + } + else { + summary["source"] = "gdocs"; + } + + summary["passed_samples"] = passed_samples + summary["reference_genome"] = doc["reference_genome"] + summary["customer_reference"] = doc["customer_reference"] + summary["uppnex_id"] = doc["uppnex_id"] + summary["close_date"] = doc["close_date"] + + if ((summary["source"] == "lims") && (!("close_date" in doc))){ + emit(["open", doc["project_id"]], summary); + } else { + emit(["closed", doc["project_id"]], summary); + } +} diff --git a/StatusDB_views/projects/project/summary_status.map.js b/StatusDB_views/projects/project/summary_status.map.js new file mode 100644 index 0000000..696c529 --- /dev/null +++ b/StatusDB_views/projects/project/summary_status.map.js @@ -0,0 +1,255 @@ +/* +Used by genomics-status at: + /api/v1/projects, +*/ + +// Used for the project list at http://genomics-status.scilifelab.se/projects +var inc = function (prop, def) { + if (prop === undefined) { + prop = def; + } else { + prop += def; + } + return prop; +}; + +var key_count = function (obj) { + var n_keys = 0; + for (var key in obj) { + n_keys++; + } + return n_keys; +}; + +function(doc) { + var summary = {}; + // final_number_of_samples emitted only if 'status_(manual)' is set for all + var final_number_of_samples = 0; + var is_final = true; + if (doc["samples"] === undefined) { + is_final = false; + } + + // Temporary objects for counting purposes + var lib_repreps = {}; + var pools = {}; + var lanes = {}; + var progress = {}; // possible keys: "Aborted", "In Progress", "Finished" + + + // Dates + var first_initial_qc_start_date = "9999-99-99"; + var sequencing_start_date = "9999-99-99"; + var qc_library_finished = "0000-00-00"; + var library_prep_start = "9999-99-99"; + + summary["passed_samples"]=0; + for (var sample in doc["samples"]) { + var seen=false; + + // Find first library prep start (1st) + if ("first_prep_start_date" in doc["samples"][sample]){ + if (library_prep_start > doc["samples"][sample]["first_prep_start_date"]) { + library_prep_start = doc["samples"][sample]["first_prep_start_date"]; + } + } + + //Sequencing QC + if (doc["samples"][sample].hasOwnProperty('library_prep')) { + var latest_seq="0"; + for (var lib in doc["samples"][sample]['library_prep']){ + var lib_prep_doc = doc["samples"][sample]['library_prep'][lib]; + if (lib_prep_doc.hasOwnProperty('sample_run_metrics')){ + for (var runid in lib_prep_doc['sample_run_metrics']) { + var run_metric_doc = lib_prep_doc['sample_run_metrics'][runid]; + + // counting passed samples + if (run_metric_doc["sequencing_start_date"]> latest_seq) { + latest_seq=run_metric_doc["sequencing_start_date"]; + if (run_metric_doc['seq_qc_flag'] == "PASSED" && !seen) { + summary["passed_samples"] += 1; + seen=true; + } + } + + // Find sequencing start date + if (sequencing_start_date > run_metric_doc["sequencing_start_date"]) { + sequencing_start_date = run_metric_doc["sequencing_start_date"]; + } + } + } + // Find last QC library finished + for (var lib_val in lib_prep_doc["library_validation"]) { + var lib_val_doc = lib_prep_doc["library_validation"][lib_val]; + if (qc_library_finished < lib_val_doc["finish_date"]) { + qc_library_finished = lib_val_doc["finish_date"]; + } + } + // Find first library prep start (2nd) + if ("prep_start_date" in lib_prep_doc){ + if (library_prep_start > lib_prep_doc["prep_start_date"]) { + library_prep_start = lib_prep_doc["prep_start_date"]; + } + } + } + } + + // Find first initial QC start date + if ("initial_qc" in doc["samples"][sample]) { + if (first_initial_qc_start_date > doc["samples"][sample]["initial_qc"]["start_date"]) { + first_initial_qc_start_date = doc["samples"][sample]["initial_qc"]["start_date"]; + } + } else if ("first_initial_qc_start_date" in doc["samples"][sample]) { + if (first_initial_qc_start_date > doc["samples"][sample]["first_initial_qc_start_date"]) { + first_initial_qc_start_date = doc["samples"][sample]["first_initial_qc_start_date"]; + } + } + + + // samples > [sample] > details + if ("details" in doc["samples"][sample]){ + + // final_number_of_samples + var status = doc["samples"][sample]["details"]["status_(manual)"]; + if (status !== "Aborted"){ + final_number_of_samples += 1; + }; + if (status !== undefined){ + summary[status] = inc(summary[status],1) + } else { + is_final = false; + } + + // passed_initial_qc + var initial_qc = doc["samples"][sample]["details"]["passed_initial_qc"]; + if (initial_qc == "True") { + progress["passed_initial_qc"] = inc(progress["passed_initial_qc"], 1); + } else if (initial_qc == "False") { + progress["passed_initial_qc"] = inc(progress["passed_initial_qc"], 0); + } + + // samples > [sample] > library_prep + var lib_qc = undefined; + for (var prep in doc["samples"][sample]["library_prep"]) { + if (prep !== 'A') { + lib_repreps[prep] = 1; + } + // [library_prep] > sample_run_metrics + for (lane in doc["samples"][sample]["library_prep"][prep]["sample_run_metrics"]) { + lanes[lane.split("_").slice(0,3).join("_")] = 1; + } + + prep_status = doc["samples"][sample]["library_prep"][prep]["prep_status"]; + if (prep_status == "PASSED") { + lib_qc = inc(lib_qc,1); + } else if (prep_status == "FAILED") { + lib_qc = inc(lib_qc,0); + } + } + + // Library QC + if (lib_qc !== undefined) { + progress["passed_library_qc"] = inc(progress["passed_library_qc"], Math.min(1,lib_qc)); + } + + // number_of_pools + if (doc["samples"][sample]["details"]["pooling"] !== undefined) { + pools[doc["samples"][sample]["details"]["pooling"]] = 1; + } + } + } + + // X/Y passed QC + if (is_final) { + if (progress["passed_library_qc"] !== undefined) { + summary["passed_library_qc"] = String(progress["passed_library_qc"]) + "/" + String(final_number_of_samples) + " P"; + } + if (progress["passed_initial_qc"] !== undefined) { + summary["passed_initial_qc"] = String(progress["passed_initial_qc"]) + "/" + String(final_number_of_samples) + " P"; + } + if (summary["passed_samples"] !== undefined) { + summary["passed_seq_qc"] = String(summary["passed_samples"]) + "/" + String(final_number_of_samples) + " P" + } + } + + summary["summary_dates"] = Object() + // Omit dates if not set + if (library_prep_start != "9999-99-99") { + summary["summary_dates"]["library_prep_start"] = library_prep_start + } + if (qc_library_finished != "0000-00-00") { + summary["summary_dates"]["qc_library_finished"] = qc_library_finished + } + if (sequencing_start_date != "9999-99-99") { + summary["summary_dates"]["sequencing_start_date"] = sequencing_start_date + } + if (first_initial_qc_start_date != "9999-99-99") { + summary["summary_dates"]["first_initial_qc_start_date"] = first_initial_qc_start_date + } + + // Count objects, emit only if count !== 0 + summary["library_repreps"] = key_count(lib_repreps) || undefined; + summary["number_of_pools"] = key_count(pools) || undefined; + summary["lanes_sequenced"] = key_count(lanes) || undefined; + + /* Details will contain all project level udfs */ + summary["details"] = doc["details"]; + + /* Status fields */ + summary["status_fields"] = doc["status_fields"]; + + /* Project summary will contain all temporary process/project level udfs */ + summary["project_summary"] = doc["project_summary"]; + summary["application"] = doc["application"]; + summary["no_samples"] = doc["no_of_samples"]; + summary["ordered_reads"] = doc["min_m_reads_per_sample_ordered"]; + summary["open_date"] = doc["open_date"]; + summary["project_name"] = doc["project_name"]; + summary["affiliation"] = doc["affiliation"]; + summary["order_details"] = doc["order_details"]; + summary["delivery_projects"] = doc["delivery_projects"]; + summary["priority"] = doc["priority"]; + //Check for PI contact information + if ("contact" in doc) { + summary["contact"] = doc["contact"]; + } + + if ("source" in doc) { + summary["source"] = doc["source"]; + } else { + summary["source"] = "gdocs"; + } + + if (is_final) { + summary["final_number_of_samples"] = final_number_of_samples; + } + + summary["reference_genome"] = doc["reference_genome"] + summary["customer_reference"] = doc["customer_reference"] + if ("uppnex_id" in doc){ + summary["delivery_type"] = doc["uppnex_id"] + } else if("delivery_type" in doc) { + summary["delivery_type"] = doc["delivery_type"] + } + summary["uppnex_id"] = doc["uppnex_id"] + summary["close_date"] = doc["close_date"] + + if ("invoice_spec_generated" in doc){ + var date_string = 'No invoicing' + if (doc["invoice_spec_generated"]!=='No invoicing'){ + var date = new Date(doc["invoice_spec_generated"]) + date_string = date.toISOString().slice(0,10) + ', ' + date.toISOString().slice(11,19) + } + summary["invoice_spec_generated"] = date_string + } + if ("invoice_spec_downloaded" in doc){ + var date = new Date(doc["invoice_spec_downloaded"]) + summary["invoice_spec_downloaded"] = date.toISOString().slice(0,10) + } + + if (doc.hasOwnProperty("escalations") && doc.escalations.length >0){ + summary["pending_reviews"]=doc.escalations; + } + + emit([doc["status_fields"]["status"].toLowerCase(), doc["project_id"]], summary); +} diff --git a/StatusDB_views/projects/project/summary_with_sources.map.js b/StatusDB_views/projects/project/summary_with_sources.map.js new file mode 100644 index 0000000..7bf1a93 --- /dev/null +++ b/StatusDB_views/projects/project/summary_with_sources.map.js @@ -0,0 +1,215 @@ +/* +Used by genomics-status at: + /api/v1/projects, + /api/v1/project_fields, + /api/v1/project_summary/:id +*/ + +// Used for the project cards at http://genomics-status.scilifelab.se/project_cards + +var inc = function(prop, def) { + if (prop == undefined) { + prop = def; + } + else { + prop += def; + } + return prop; +} + +var key_count = function(obj) { + var n_keys = 0; + for (key in obj) { + n_keys++; + } + return n_keys +} + +function(doc) { + var summary = Object(); + summary["field_sources"] = Object(); + + // final_number_of_samples emitted only if 'status_(manual)' is set for all + var final_number_of_samples = 0; + var aborted_samples = 0; + var is_final = true; + if (doc["samples"] == undefined) {is_final = false;} + + // Temporary objects for counting purposes + var lib_repreps = Object(); + var pools = Object(); + var lanes = Object(); + var progress = Object(); // possible keys: "Aborted", "In Progress", "Finished" + + summary["passed_samples"]=0; + summary["field_sources"]["passed_samples"] = "Samples with seq_qc_flag == 'PASSED' from LIMS, calculated on StatusDB view project/summary.map.js" + + + for (sample in doc["samples"]) { + var seen=false; + //Sequencing QC + if (doc["samples"][sample].hasOwnProperty('library_prep')){ + var latest_seq="0"; + for(lib in doc["samples"][sample]['library_prep']){ + if (doc["samples"][sample]['library_prep'][lib].hasOwnProperty('sample_run_metrics')){ + for(runid in doc["samples"][sample]['library_prep'][lib]['sample_run_metrics']){ + if (doc["samples"][sample]['library_prep'][lib]['sample_run_metrics'][runid]["sequencing_start_date"]> latest_seq){ + latest_seq=doc["samples"][sample]['library_prep'][lib]['sample_run_metrics'][runid]["sequencing_start_date"]; + if (doc["samples"][sample]['library_prep'][lib]['sample_run_metrics'][runid]['seq_qc_flag'] == "PASSED" && !seen){ + summary["passed_samples"]=inc(summary["passed_samples"], 1); + seen=true; + } + } + } + } + } + } + + + // samples > [sample] > details + if ("details" in doc["samples"][sample]){ + + // final_number_of_samples + var status = doc["samples"][sample]["details"]["status_(manual)"]; + if (status !== "Aborted"){ + final_number_of_samples += 1; + } else { + aborted_samples = inc(aborted_samples,1); + } + if (status !== undefined){ + summary[status] = inc(summary[status],1) + summary["field_sources"][status] = "Samples with status_(manual) == '"+status+"' from LIMS project summary, calculated on StatusDB view project/summary.map.js" + } + else { + is_final = false; + } + + // passed_initial_qc + var initial_qc = doc["samples"][sample]["details"]["passed_initial_qc"]; + if (initial_qc == "True") { + progress["passed_initial_qc"] = inc(progress["passed_initial_qc"], 1); + } + else if (initial_qc == "False") { + progress["passed_initial_qc"] = inc(progress["passed_initial_qc"], 0); + } + + // samples > [sample] > library_prep + var lib_qc = undefined; + for (prep in doc["samples"][sample]["library_prep"]) { + if (prep !== 'A') { + lib_repreps[prep] = 1; + } + // [library_prep] > sample_run_metrics + for (lane in doc["samples"][sample]["library_prep"][prep]["sample_run_metrics"]) { + lanes[lane.split("_").slice(0,3).join("_")] = 1; + } + + prep_status = doc["samples"][sample]["library_prep"][prep]["prep_status"]; + if (prep_status == "PASSED") { + lib_qc = inc(lib_qc,1); + } + else if (prep_status == "FAILED") { + lib_qc = inc(lib_qc,0); + } + } + + // Library QC + if (lib_qc !== undefined) { + progress["passed_library_qc"] = inc(progress["passed_library_qc"], Math.min(1,lib_qc)); + } + + // number_of_pools + if (doc["samples"][sample]["details"]["pooling"] !== undefined) { + pools[doc["samples"][sample]["details"]["pooling"]] = 1; + } + } + } // End of sample loop + + + summary["field_sources"]["passed_library_qc"] = "Samples with at least one library preparation with prep_status PASSED in LIMS. If 'NA', either no library prep has prep_status set, or 'status_(manual)' is missing for some sample. Calculated on StatusDB view project/summary.map.js" + summary["field_sources"]["passed_initial_qc"] = "Samples with passed_initial_qc == 'True' from LIMS. If 'NA', either no initial qc is registered, or 'status_(manual) is missing for some sample. Calculated on StatusDB view project/summary.map.js" + summary["field_sources"]["passed_seq_qc"] = "Samples with at least one seq_qc_flag == 'PASSED' from LIMS. If 'NA', either no sample has seq_qc_flag set, or 'status_(manual) is missing for some sample. Calculated on StatusDB view project/summary.map.js" + summary["passed_library_qc"] = 'NA' + summary["passed_initial_qc"] = 'NA' + summary["passed_seq_qc"] = 'NA' + // X/Y passed QC + if (is_final) { + if (progress["passed_library_qc"] !== undefined) { + summary["passed_library_qc"] = String(progress["passed_library_qc"]) ; + } + if (progress["passed_initial_qc"] !== undefined) { + summary["passed_initial_qc"] = String(progress["passed_initial_qc"]); + } + if (summary["passed_samples"] !== undefined) { + summary["passed_seq_qc"] = String(summary["passed_samples"]); + } + } + + // Count objects, emit only if count !== 0 + summary["library_repreps"] = key_count(lib_repreps) || undefined; + summary["number_of_pools"] = key_count(pools) || undefined; + summary["lanes_sequenced"] = key_count(lanes) || undefined; + + /* Details will contain all project level udfs */ + summary["details"] = doc["details"]; + /* Project summary will contain all temporary process/project level udfs */ + summary["project_summary"] = doc["project_summary"]; + summary["application"] = doc["application"]; + summary["no_samples"] = doc["no_of_samples"]; + summary["field_sources"]["no_samples"] = "Total number of samples in LIMS, calculated on LIMS2DB" + summary["ordered_reads"] = doc["min_m_reads_per_sample_ordered"]; + summary["field_sources"]["ordered_reads"] = "Minimum number of reads per sample ordered (probably from LIMS)" + summary["open_date"] = doc["open_date"]; + summary["project_name"] = doc["project_name"]; + summary["affiliation"] = doc["affiliation"]; + summary["order_details"] = doc["order_details"]; + summary["delivery_projects"] = doc["delivery_projects"]; + summary["modification_time"] = doc["modification_time"]; + summary["priority"] = doc["priority"]; + //Check for PI contact information + if ("contact" in doc) { + summary["contact"] = doc["contact"]; + } + + if ("source" in doc) { + summary["source"] = doc["source"]; + } + else { + summary["source"] = "gdocs"; + } + + summary["field_sources"]["final_number_of_samples"] = "Number of samples in LIMS project summary that are not aborted. If 'NA', some sample is missing 'status_(manual)' in project summary. Calculated on StatusDB view project/summary.map.js" + summary['final_number_of_samples'] = 'NA'; + if (is_final) { + summary["final_number_of_samples"] = final_number_of_samples; + } + summary["field_sources"]["aborted_samples"] = "Number of samples in LIMS project summary that are aborted. If 'NA', some sample is missing 'status_(manual)' in project summary. Calculated on StatusDB view project/summary.map.js" + summary['aborted_samples'] = 'NA'; + summary["aborted_samples"] = aborted_samples; + + summary["reference_genome"] = doc["reference_genome"] + summary["customer_reference"] = doc["customer_reference"] + if ("uppnex_id" in doc){ + summary["delivery_type"] = doc["uppnex_id"] + } + else if("delivery_type" in doc) { + summary["delivery_type"] = doc["delivery_type"] + } + summary["uppnex_id"] = doc["uppnex_id"] + summary["close_date"] = doc["close_date"] + + if (doc.hasOwnProperty("escalations") && doc.escalations.length >0){ + summary["pending_reviews"]=doc.escalations; + } + if(doc.hasOwnProperty("invoice_spec_downloaded")){ + summary["invoice_spec_downloaded"] = doc["invoice_spec_downloaded"]; + } + + summary["status"] = doc["status_fields"]["status"]; + + if ((summary["source"] == "lims") && (!("close_date" in doc))){ + emit(["open", doc["project_id"]], summary); + } else { + emit(["closed", doc["project_id"]], summary); + } +} diff --git a/StatusDB_views/projects/projects/appl_proj_sample_preps.map.js b/StatusDB_views/projects/projects/appl_proj_sample_preps.map.js new file mode 100644 index 0000000..d9d5de6 --- /dev/null +++ b/StatusDB_views/projects/projects/appl_proj_sample_preps.map.js @@ -0,0 +1,17 @@ +function(doc) { +if (doc['source']=="lims") { + samples={} + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + samples[s["scilife_name"]]={} + for (prep in s["library_prep"]) { + samples[s["scilife_name"]][prep]=s["library_prep"][prep]["prep_status"] +} +} + +emit([doc["application"],doc["project_name"]],samples) + + +} + +} diff --git a/StatusDB_views/projects/projects/date_proj_sample_firstInitQcDate.map.js b/StatusDB_views/projects/projects/date_proj_sample_firstInitQcDate.map.js new file mode 100644 index 0000000..2c6e9f1 --- /dev/null +++ b/StatusDB_views/projects/projects/date_proj_sample_firstInitQcDate.map.js @@ -0,0 +1,11 @@ +function(doc) { +if (doc['source']=="lims") { +samples={} + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + samples[s["scilife_name"]] = s["first_initial_qc_start_date"] + } +emit([doc["application"],doc["open_date"],doc["project_name"]],samples) +} + +} diff --git a/StatusDB_views/projects/projects/date_proj_sample_firstInitQcDate.reduce.js b/StatusDB_views/projects/projects/date_proj_sample_firstInitQcDate.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/projects/date_proj_sample_firstInitQcDate.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/projects/date_proj_sample_status.map.js b/StatusDB_views/projects/projects/date_proj_sample_status.map.js new file mode 100644 index 0000000..90d8c40 --- /dev/null +++ b/StatusDB_views/projects/projects/date_proj_sample_status.map.js @@ -0,0 +1,11 @@ +function(doc) { +if (doc['source']=="lims") { +samples={} + for (sample in doc["samples"]) { + s = doc["samples"][sample]; + samples[s["scilife_name"]] = [s["reads_requested_(millions)"],s["status"]] + } +emit([doc["open_date"],doc["project_name"],doc["application"]],samples) +} + +} diff --git a/StatusDB_views/projects/projects/date_proj_sample_status.reduce.js b/StatusDB_views/projects/projects/date_proj_sample_status.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/projects/date_proj_sample_status.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/projects/id_to_name.map.js b/StatusDB_views/projects/projects/id_to_name.map.js new file mode 100644 index 0000000..a1736e6 --- /dev/null +++ b/StatusDB_views/projects/projects/id_to_name.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc["project_id"], doc["project_name"]); +} diff --git a/StatusDB_views/projects/projects/lims_followed.map.js b/StatusDB_views/projects/projects/lims_followed.map.js new file mode 100644 index 0000000..d33bd02 --- /dev/null +++ b/StatusDB_views/projects/projects/lims_followed.map.js @@ -0,0 +1,13 @@ +function(doc) { + if ('open_date' in doc){ + ar=doc['open_date'].split('-'); + + var open_date = new Date(ar[0], ar[1], ar[2]); + var cutoff = new Date(2013,07,01); + if (open_date > cutoff){ + emit(doc.project_id, doc._id); + + } + + } + } \ No newline at end of file diff --git a/StatusDB_views/projects/projects/name_to_id.map.js b/StatusDB_views/projects/projects/name_to_id.map.js new file mode 100644 index 0000000..af04808 --- /dev/null +++ b/StatusDB_views/projects/projects/name_to_id.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.project_name, doc.project_id) +} diff --git a/StatusDB_views/projects/projects/name_to_id_cust_ref.map.js b/StatusDB_views/projects/projects/name_to_id_cust_ref.map.js new file mode 100644 index 0000000..c481022 --- /dev/null +++ b/StatusDB_views/projects/projects/name_to_id_cust_ref.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['project_name'], [doc['project_id'], doc.details['customer_project_reference'], doc.details["portal_id"]]) +} diff --git a/StatusDB_views/projects/projects/open_date2project_name.map.js b/StatusDB_views/projects/projects/open_date2project_name.map.js new file mode 100644 index 0000000..46da5be --- /dev/null +++ b/StatusDB_views/projects/projects/open_date2project_name.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc["open_date"], doc["project_name"]);} diff --git a/StatusDB_views/projects/projects/open_date2project_name_application.map.js b/StatusDB_views/projects/projects/open_date2project_name_application.map.js new file mode 100644 index 0000000..da8a8a0 --- /dev/null +++ b/StatusDB_views/projects/projects/open_date2project_name_application.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc["open_date"], [doc["project_name"],doc["application"]]);} diff --git a/StatusDB_views/projects/projects/proj2status_(manual).map.js b/StatusDB_views/projects/projects/proj2status_(manual).map.js new file mode 100644 index 0000000..cf488ed --- /dev/null +++ b/StatusDB_views/projects/projects/proj2status_(manual).map.js @@ -0,0 +1,6 @@ +function(doc) { + for (sample in doc["samples"]) { + var status = doc["samples"][sample]["details"]["status_(manual)"]; + if(status) { emit([doc.project_id, sample], status);} + } +} diff --git a/StatusDB_views/projects/projects/project_name.map.js b/StatusDB_views/projects/projects/project_name.map.js new file mode 100644 index 0000000..d0d024d --- /dev/null +++ b/StatusDB_views/projects/projects/project_name.map.js @@ -0,0 +1 @@ +function(doc) {emit(doc.project_name, doc._id)} diff --git a/StatusDB_views/projects/samples/customer_names.map.js b/StatusDB_views/projects/samples/customer_names.map.js new file mode 100644 index 0000000..5755e91 --- /dev/null +++ b/StatusDB_views/projects/samples/customer_names.map.js @@ -0,0 +1,8 @@ +function(doc) { + var obj={}; + for (var sa in doc.samples){ + obj[sa] = doc.samples[sa].details.customer_name; + } + emit(doc.project_id, obj); + emit(doc.project_name, obj); +} \ No newline at end of file diff --git a/StatusDB_views/projects/samples/info.map.js b/StatusDB_views/projects/samples/info.map.js new file mode 100644 index 0000000..cbfe49b --- /dev/null +++ b/StatusDB_views/projects/samples/info.map.js @@ -0,0 +1,15 @@ +/* + Used by genomics-status at: + /api/v1/sample_info/:id +*/ + +function(doc) { + for (s in doc["samples"]) { + var info = Object() + info["status"] = doc["samples"][s]["status"] + info["ordered_m_reads"] = doc["min_m_reads_per_sample_ordered"] + info["sequenced_m_reads"] = +doc["samples"][s]["m_reads_sequenced"] + emit(s, info) + } +} + diff --git a/StatusDB_views/projects/samples/library_prep_dates.map.js b/StatusDB_views/projects/samples/library_prep_dates.map.js new file mode 100644 index 0000000..d7c35e6 --- /dev/null +++ b/StatusDB_views/projects/samples/library_prep_dates.map.js @@ -0,0 +1,10 @@ +function(doc) { + for (sample in doc["samples"]) { + for (prep in doc["samples"][sample]["library_prep"]) { + library_validation = doc["samples"][sample]["library_prep"][prep]["library_validation"] + for (lv in library_validation) { + l=library_validation[lv] + emit([sample, prep], l)} + } + } +} diff --git a/StatusDB_views/projects/samples/library_prep_dates.reduce.js b/StatusDB_views/projects/samples/library_prep_dates.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/projects/samples/library_prep_dates.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/projects/samples/library_preps.map.js b/StatusDB_views/projects/samples/library_preps.map.js new file mode 100644 index 0000000..0314bb8 --- /dev/null +++ b/StatusDB_views/projects/samples/library_preps.map.js @@ -0,0 +1,12 @@ +function(doc) { + for (sample in doc["samples"]) { + for (prep in doc["samples"][sample]["library_prep"]) { + run_metrics = doc["samples"][sample]["library_prep"][prep]["sample_run_metrics"] + for (rm in run_metrics) { + break + } + date = rm.split("_")[1] + emit([parseInt("20" + date[0] + date[1]), prep], sample) + } + } +} diff --git a/StatusDB_views/projects/samples/library_preps.reduce.js b/StatusDB_views/projects/samples/library_preps.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/samples/library_preps.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/samples/rec_ctrl_view.map.js b/StatusDB_views/projects/samples/rec_ctrl_view.map.js new file mode 100644 index 0000000..33dc362 --- /dev/null +++ b/StatusDB_views/projects/samples/rec_ctrl_view.map.js @@ -0,0 +1,44 @@ +function(doc) { + sdata={}; + for(s_key in doc['samples']){ + sample=doc['samples'][s_key] + if ("initial_plate_id" in sample){ + if (!(sample["initial_plate_id"] in sdata)){ + sdata[sample["initial_plate_id"]]={}; + } + + if ("well_location" in sample){ + sdata[sample["initial_plate_id"]][sample["well_location"]]={}; + sdata[sample["initial_plate_id"]][sample["well_location"]]["sample_name"]=s_key; + } + if ("details" in sample){ + sdata[sample["initial_plate_id"]][sample["well_location"]]['customer_name']=sample["customer_name"]; + } + if ("details" in sample){ + sdata[sample["initial_plate_id"]][sample["well_location"]]['details']=sample["details"]; + } + if ("initial_qc" in sample){ + sdata[sample["initial_plate_id"]][sample["well_location"]]['initial_qc']=sample["initial_qc"]; + } + } + } + for (plate in sdata){ + x_axis=[]; + y_axis=[]; + for (well_location in sdata[plate]){ + y=well_location.charAt(0); + if (y_axis.indexOf(y) == -1){ + y_axis.push(y); + } + x=well_location.charAt(2); + if (x_axis.indexOf(x) == -1){ + x_axis.push(x); + } + } + x_axis.sort(); + y_axis.sort(); + sdata[plate]['y_axis']=y_axis; + sdata[plate]['x_axis']=x_axis; + } + emit(doc.project_id, sdata); +} diff --git a/StatusDB_views/projects/samples/sample_project_name.map.js b/StatusDB_views/projects/samples/sample_project_name.map.js new file mode 100644 index 0000000..2d489ac --- /dev/null +++ b/StatusDB_views/projects/samples/sample_project_name.map.js @@ -0,0 +1,5 @@ +function(doc) { + for (sample in doc["samples"]) { + emit([sample], doc["project_name"]) + } +} diff --git a/StatusDB_views/projects/samples/sample_project_name.reduce.js b/StatusDB_views/projects/samples/sample_project_name.reduce.js new file mode 100644 index 0000000..c866cd7 --- /dev/null +++ b/StatusDB_views/projects/samples/sample_project_name.reduce.js @@ -0,0 +1 @@ +_count diff --git a/StatusDB_views/projects/test/KPI.map.js b/StatusDB_views/projects/test/KPI.map.js new file mode 100644 index 0000000..9dc42e0 --- /dev/null +++ b/StatusDB_views/projects/test/KPI.map.js @@ -0,0 +1,84 @@ +function(doc) { + // Only output production documents + if(doc["details"]["type"] != "Production") { exit; } + + + // Get sequencing platform for stratification + var sequencing_platform = doc["details"]["sequencing_platform"] + + // Find arrival date (if present) + var open_date = "0000-00-00" + if (doc["open_date"] > open_date) { + open_date = doc["open_date"] + } + + for (sample in doc["samples"]){ + // Find queue date (if present) + var queued = "0000-00-00" + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"] + } + + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep] + + // Find QC library finish date by looking at the final library validation. + var final_validation = "0000-00-00" + for (lv in LP["library_validation"]) { + var lib_val_fin = LP["library_validation"][lv]["finish_date"] + if (lib_val_fin > final_validation) { + final_validation = lib_val_fin + } + } + + // Find the time a sample is sequenced at by looking at sample runs + // sequencing _start_ date. This is confusing, but it is how Maya + // specified it. + //var final_sequence_date = "0000-00-00" + //for (sample_run_metrics in LP["sample_run_metrics"]) { + // final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"] + //} + +      // NJ 2013-08-23: updated original code above to work with new  +      // key "sequencing_finish_date"  +      var final_sequence_date = "0000-00-00" +      for (sample_run_metrics in LP["sample_run_metrics"]) { +        final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] +      } + + + // Collect dates to a KPI object + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = final_validation + KPI["All samples sequenced"] = final_sequence_date + + emit([sequencing_platform, doc["project_name"], doc["project_id"], sample, library_prep], KPI) + } + + // If no library preps have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + + emit([sequencing_platform, doc["project_name"], doc["project_id"], sample, null], KPI) + } + } + + // If no samples have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("samples" in doc)) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + + emit([sequencing_platform, doc["project_name"], doc["project_id"], null, null], KPI) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/KPI.reduce.js b/StatusDB_views/projects/test/KPI.reduce.js new file mode 100644 index 0000000..2c3b7b5 --- /dev/null +++ b/StatusDB_views/projects/test/KPI.reduce.js @@ -0,0 +1,20 @@ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "QC library finished": "0000-00-00", + "All samples sequenced": "0000-00-00"} + + for (var i = 0; i < values.length; i++) { + for (k in result) { + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } + else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00" + } + } + } + + return result +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/KPI_applications.map.js b/StatusDB_views/projects/test/KPI_applications.map.js new file mode 100644 index 0000000..31e6b25 --- /dev/null +++ b/StatusDB_views/projects/test/KPI_applications.map.js @@ -0,0 +1,84 @@ +function(doc) { + // Only output production documents + if(doc["details"]["type"] != "Production") { exit; } + + // Get sequencing platform for stratification + var application = doc["application"] + + + // Find arrival date (if present) + var open_date = "0000-00-00" + if (doc["open_date"] > open_date) { + open_date = doc["open_date"] + } + + for (sample in doc["samples"]){ + // Find queue date (if present) + var queued = "0000-00-00" + if (doc["details"]["queued"] > queued) { + queued = doc["details"]["queued"] + } + + for (library_prep in doc["samples"][sample]["library_prep"]) { + var LP = doc["samples"][sample]["library_prep"][library_prep] + + // Find QC library finish date by looking at the final library validation. + var final_validation = "0000-00-00" + for (lv in LP["library_validation"]) { + var lib_val_fin = LP["library_validation"][lv]["finish_date"] + if (lib_val_fin > final_validation) { + final_validation = lib_val_fin + } + } + + // Find the time a sample is sequenced at by looking at sample runs + // sequencing _start_ date. This is confusing, but it is how Maya + // specified it. + //var final_sequence_date = "0000-00-00" + //for (sample_run_metrics in LP["sample_run_metrics"]) { + // final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"] + //} + + // NJ 2013-08-23: updated original code above to work with new + // key "sequencing_finish_date" + var final_sequence_date = "0000-00-00" + for (sample_run_metrics in LP["sample_run_metrics"]) { + final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"] + } + + + // Collect dates to a KPI object + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = final_validation + KPI["All samples sequenced"] = final_sequence_date + + emit([application, doc["project_name"], doc["project_id"], sample, library_prep], KPI) + } + + // If no library preps have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("library_prep" in doc["samples"][sample])) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + + emit([application, doc["project_name"], doc["project_id"], sample, null], KPI) + } + } + + // If no samples have been entered to the project, set all library prep + // and sample sequencing dates to "0000-00-00" + if (!("samples" in doc)) { + var KPI = Object() + KPI["Arrival date"] = open_date + KPI["Queue date"] = queued + KPI["QC library finished"] = "0000-00-00" + KPI["All samples sequenced"] = "0000-00-00" + + emit([application, doc["project_name"], doc["project_id"], null, null], KPI) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/KPI_applications.reduce.js b/StatusDB_views/projects/test/KPI_applications.reduce.js new file mode 100644 index 0000000..2c3b7b5 --- /dev/null +++ b/StatusDB_views/projects/test/KPI_applications.reduce.js @@ -0,0 +1,20 @@ +function(keys, values, rereduce){ + var result = {"Arrival date": "0000-00-00", + "Queue date": "0000-00-00", + "QC library finished": "0000-00-00", + "All samples sequenced": "0000-00-00"} + + for (var i = 0; i < values.length; i++) { + for (k in result) { + if (values[i][k] > result[k]){ + result[k] = values[i][k] + } + else if (values[i][k] == "0000-00-00") { + // We use the date 0000-00-00 to indicate unfinished process + result[k] = "0000-00-00" + } + } + } + + return result +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/appl_setup_lanes.map.js b/StatusDB_views/projects/test/appl_setup_lanes.map.js new file mode 100644 index 0000000..97b5398 --- /dev/null +++ b/StatusDB_views/projects/test/appl_setup_lanes.map.js @@ -0,0 +1,13 @@ +function(doc) { + if(doc["source"] != "lims") { exit; } + if(doc["open_date"] < "2013-07-01") { exit; } + if(doc["application"] == "bogus1") { exit; } + if(doc["application"] == null) { exit; } + emit([ + doc["details"]["type"], + doc["details"]["sequencing_platform"], + doc["application"] + ], + doc["details"]["sequence_units_ordered_(lanes)"] + ); +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/appl_setup_lanes.reduce.js b/StatusDB_views/projects/test/appl_setup_lanes.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/test/appl_setup_lanes.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/test/appl_setup_samples.map.js b/StatusDB_views/projects/test/appl_setup_samples.map.js new file mode 100644 index 0000000..18e13e2 --- /dev/null +++ b/StatusDB_views/projects/test/appl_setup_samples.map.js @@ -0,0 +1,16 @@ +function(doc) { + if(doc["source"] != "lims") { exit; } + if(doc["open_date"] < "2013-07-01") { exit; } + if(doc["application"] == "bogus1") { exit; } + if(doc["application"] == null) { exit; } + var samples = doc["samples"]; + var numS = 0; + for(s in samples) { numS++; } + emit([ + doc["details"]["type"], + doc["details"]["sequencing_platform"], + doc["application"] + ], + numS + ); +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/appl_setup_samples.reduce.js b/StatusDB_views/projects/test/appl_setup_samples.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/test/appl_setup_samples.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/test/contact_mail.map.js b/StatusDB_views/projects/test/contact_mail.map.js new file mode 100644 index 0000000..0795c64 --- /dev/null +++ b/StatusDB_views/projects/test/contact_mail.map.js @@ -0,0 +1,7 @@ +function(doc) { + var o = doc['order_details']['fields']['project_lab_email']; + var c = doc['contact']; + var count = 0; + if(o == c) { count=1; } + emit(doc['project_id'], count); +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/contact_mail.reduce.js b/StatusDB_views/projects/test/contact_mail.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/test/contact_mail.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/test/date_proj2numLanes.map.js b/StatusDB_views/projects/test/date_proj2numLanes.map.js new file mode 100644 index 0000000..97ed9ee --- /dev/null +++ b/StatusDB_views/projects/test/date_proj2numLanes.map.js @@ -0,0 +1,7 @@ +function(doc) { + if(doc.details.type != "Production") { exit; } + var lanes = doc["details"]["sequence_units_ordered_(lanes)"]; + if(lanes != null) { + emit([doc.open_date, doc.project_name], lanes) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/date_proj2numLanes.reduce.js b/StatusDB_views/projects/test/date_proj2numLanes.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/test/date_proj2numLanes.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/test/date_proj2numSamples.map.js b/StatusDB_views/projects/test/date_proj2numSamples.map.js new file mode 100644 index 0000000..b080598 --- /dev/null +++ b/StatusDB_views/projects/test/date_proj2numSamples.map.js @@ -0,0 +1,6 @@ +function(doc) { + if(doc.details.type != "Production") { exit; } + if(doc.no_of_samples != null) { + emit([doc.open_date, doc.project_name], parseInt(doc.no_of_samples)) + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/test/date_proj2numSamples.reduce.js b/StatusDB_views/projects/test/date_proj2numSamples.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/projects/test/date_proj2numSamples.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/projects/test/open_date2proj_source_lims.map.js b/StatusDB_views/projects/test/open_date2proj_source_lims.map.js new file mode 100644 index 0000000..68ec387 --- /dev/null +++ b/StatusDB_views/projects/test/open_date2proj_source_lims.map.js @@ -0,0 +1,8 @@ +function(doc) { + var lims = (doc["source"] == "lims"); + var since_july = (doc["open_date"] >= "2013-07-01"); + var production = (doc["details"]["type"] == "Production"); + if(lims && since_july && production) { + emit(doc["open_date"], [ doc["project_name"], doc["details"]["queued"] ]); + } +}; diff --git a/StatusDB_views/projects/test/project2queueDate_closeDate.map.js b/StatusDB_views/projects/test/project2queueDate_closeDate.map.js new file mode 100644 index 0000000..eacd65b --- /dev/null +++ b/StatusDB_views/projects/test/project2queueDate_closeDate.map.js @@ -0,0 +1,58 @@ +/* + * test/project2queueDate_closeDate + * Map function + */ + +function(doc) { + + var queued = "0000-00-00"; + var close = "0000-00-00"; + var day = 1000*60*60*24; + + var dayDiff = function (date1, date2) { + var diff = Math.ceil((date2.getTime()-date1.getTime())/(day)); + return diff; + } + + var production = (doc["details"]["type"] == "Production"); + if(production) { + if (doc["details"]["queued"]) { + queued = doc["details"]["queued"]; + } + if (doc["close_date"]) { + close = doc["close_date"]; + } + + var bin = null; + var today = new Date(); + var diff; + //var unit = "week"; + var unit = "w"; + + if(doc["details"]["queued"] && doc["close_date"]) { + var qD = new Date(queued); + var cD = new Date(close); + diff = dayDiff(qD, cD); + //diff = Math.ceil( (cD.getTime()-qD.getTime()) / day); + //if(diff <= 4 * 7 * day) { + if(diff <= 6 * 7 * day) { + //bin = "0-4 weeks"; + bin = "0-6 " + unit; + //} else if (diff <= 8 * 7 * day) { + // bin = "4-8 weeks"; + } else if (diff <= 12 * 7 * day) { + //bin = "8-12 weeks"; + bin = "6-12 " + unit; + } else if (diff <= 24 * 7 * day) { + bin = "12-24 " + unit; + } else if (diff <= 52 * 7 * day) { + bin = "24-52 " + unit; + } + } + var KPI = Object(); + KPI["Queue date"] = queued; + KPI["Close date"] = close; + KPI["Total time"] = diff; + emit([ bin, doc["project_name"] ], KPI); + } +} diff --git a/StatusDB_views/projects/test/project2queueDate_closeDate.reduce.js b/StatusDB_views/projects/test/project2queueDate_closeDate.reduce.js new file mode 100644 index 0000000..ba01d16 --- /dev/null +++ b/StatusDB_views/projects/test/project2queueDate_closeDate.reduce.js @@ -0,0 +1,7 @@ +function(keys, values, rereduce) { + if (rereduce) { + return sum(values); + } else { + return values.length; + } +} \ No newline at end of file diff --git a/StatusDB_views/projects/time/last_updated.map.js b/StatusDB_views/projects/time/last_updated.map.js new file mode 100644 index 0000000..f73092d --- /dev/null +++ b/StatusDB_views/projects/time/last_updated.map.js @@ -0,0 +1,8 @@ +/* + Used by genomics-status at: + /api/v1/last_updated +*/ + +function(doc) { + emit(doc['modification_time'], doc['project_id']); +} diff --git a/StatusDB_views/projects/time/time_tracking_delivered.map.js b/StatusDB_views/projects/time/time_tracking_delivered.map.js new file mode 100644 index 0000000..ee8d7ba --- /dev/null +++ b/StatusDB_views/projects/time/time_tracking_delivered.map.js @@ -0,0 +1,73 @@ +function(doc) { + if (doc.details && doc.details.all_raw_data_delivered) { + // Calculate dates from samples data + var library_prep_start = '9999-99-99'; + var qc_library_finished = '0000-00-00'; + var sequencing_start_date = '9999-99-99'; + + if (doc.samples) { + for (var sample in doc.samples) { + // Find first library prep start + if (doc.samples[sample].first_prep_start_date) { + if (library_prep_start > doc.samples[sample].first_prep_start_date) { + library_prep_start = doc.samples[sample].first_prep_start_date; + } + } + + if (doc.samples[sample].library_prep) { + for (var lib in doc.samples[sample].library_prep) { + var lib_prep_doc = doc.samples[sample].library_prep[lib]; + + // Find first library prep start (alternative location) + if (lib_prep_doc.prep_start_date) { + if (library_prep_start > lib_prep_doc.prep_start_date) { + library_prep_start = lib_prep_doc.prep_start_date; + } + } + + // Find last QC library finished + if (lib_prep_doc.library_validation) { + for (var lib_val in lib_prep_doc.library_validation) { + var lib_val_doc = lib_prep_doc.library_validation[lib_val]; + if (lib_val_doc.finish_date && qc_library_finished < lib_val_doc.finish_date) { + qc_library_finished = lib_val_doc.finish_date; + } + } + } + + // Find first sequencing start + if (lib_prep_doc.sample_run_metrics) { + for (var run_metric in lib_prep_doc.sample_run_metrics) { + var run_metric_doc = lib_prep_doc.sample_run_metrics[run_metric]; + if (run_metric_doc.sequencing_start_date && sequencing_start_date > run_metric_doc.sequencing_start_date) { + sequencing_start_date = run_metric_doc.sequencing_start_date; + } + } + } + } + } + } + } + + emit([doc.details.all_raw_data_delivered, doc.project_id], { + // Dates + open_date: doc.open_date, + queued: doc.details.queued, + library_prep_start: library_prep_start != '9999-99-99' ? library_prep_start : undefined, + qc_library_finished: qc_library_finished != '0000-00-00' ? qc_library_finished : undefined, + sequencing_start_date: sequencing_start_date != '9999-99-99' ? sequencing_start_date : undefined, + all_samples_sequenced: doc.details.all_samples_sequenced, + all_raw_data_delivered: doc.details.all_raw_data_delivered, + best_practice_analysis_completed: doc.details.best_practice_analysis_completed, + close_date: doc.close_date, + + // Metadata + project_name: doc.project_name, + application: doc.application, + library_construction_method: doc.details.library_construction_method, + sequencing_platform: doc.details.sequencing_platform, + sequence_units_ordered: doc.details["sequence_units_ordered_(lanes)"], + type: doc.details.type + }); + } +} diff --git a/StatusDB_views/reference/documents/doc_source.map.js b/StatusDB_views/reference/documents/doc_source.map.js new file mode 100644 index 0000000..68594c6 --- /dev/null +++ b/StatusDB_views/reference/documents/doc_source.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["_id"], doc["doc_source"]); +} diff --git a/StatusDB_views/reference/documents/doc_type.map.js b/StatusDB_views/reference/documents/doc_type.map.js new file mode 100644 index 0000000..9492abe --- /dev/null +++ b/StatusDB_views/reference/documents/doc_type.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["_id"], doc["doc_type"]); +} diff --git a/StatusDB_views/reference/documents/entity_types.map.js b/StatusDB_views/reference/documents/entity_types.map.js new file mode 100644 index 0000000..4764206 --- /dev/null +++ b/StatusDB_views/reference/documents/entity_types.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["entity_type"], doc["_id"]); +} diff --git a/StatusDB_views/running_notes/latest_note_previews/flowcell.map.js b/StatusDB_views/running_notes/latest_note_previews/flowcell.map.js new file mode 100644 index 0000000..4bc4069 --- /dev/null +++ b/StatusDB_views/running_notes/latest_note_previews/flowcell.map.js @@ -0,0 +1,24 @@ +/* Returns a preview of the running note, with the note being truncated if it's + longer than a 10000 characters. The truncation is due to data limitations on + the reduce function +*/ + +function (doc) { + var ret_doc = {} + if ("note_type" in doc){ + var note_type = doc["note_type"].split("_")[0]; + if(note_type === "flowcell"){ + var fields = ["parent", "user", "email", "categories", "created_at_utc", "updated_at_utc", "note_type"]; + for(var i in fields){ + ret_doc[fields[i]] = doc[fields[i]]; + } + if(doc['note'].length>3000){ + ret_doc['note'] = doc['note'].substring(0, 3000)+'``` \ntruncated after 3000 chars' + } + else{ + ret_doc['note'] = doc['note'] + } + emit(doc._id.split(":")[0], ret_doc); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_note_previews/flowcell.reduce.js b/StatusDB_views/running_notes/latest_note_previews/flowcell.reduce.js new file mode 100644 index 0000000..bd6906a --- /dev/null +++ b/StatusDB_views/running_notes/latest_note_previews/flowcell.reduce.js @@ -0,0 +1,14 @@ +/* Reduce function to get the latest running note +*/ + +function (keys, values, rereduce) { + var max = '0'; + var max_doc = {} + for(var i = 0; i < values.length; i++){ + if(values[i].created_at_utc>max){ + max = values[i].created_at_utc; + max_doc = values[i]; + } + } + return max_doc + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_note_previews/project.map.js b/StatusDB_views/running_notes/latest_note_previews/project.map.js new file mode 100644 index 0000000..198f40d --- /dev/null +++ b/StatusDB_views/running_notes/latest_note_previews/project.map.js @@ -0,0 +1,23 @@ +/* Returns a preview of the running note, with the note being truncated if it's + longer than a 10000 characters. The truncation is due to data limitations on + the reduce function +*/ + +function (doc) { + var ret_doc = {} + if ("note_type" in doc){ + if(doc["note_type"] == "project"){ + var fields = ["parent", "user", "email", "categories", "created_at_utc", "updated_at_utc", "note_type"]; + for(var i in fields){ + ret_doc[fields[i]] = doc[fields[i]]; + } + if(doc['note'].length>3000){ + ret_doc['note'] = doc['note'].substring(0, 3000)+'``` \ntruncated after 3000 chars' + } + else{ + ret_doc['note'] = doc['note'] + } + emit(doc._id.split(":")[0], ret_doc); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_note_previews/project.reduce.js b/StatusDB_views/running_notes/latest_note_previews/project.reduce.js new file mode 100644 index 0000000..bd6906a --- /dev/null +++ b/StatusDB_views/running_notes/latest_note_previews/project.reduce.js @@ -0,0 +1,14 @@ +/* Reduce function to get the latest running note +*/ + +function (keys, values, rereduce) { + var max = '0'; + var max_doc = {} + for(var i = 0; i < values.length; i++){ + if(values[i].created_at_utc>max){ + max = values[i].created_at_utc; + max_doc = values[i]; + } + } + return max_doc + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_note_previews/workset.map.js b/StatusDB_views/running_notes/latest_note_previews/workset.map.js new file mode 100644 index 0000000..e1877ce --- /dev/null +++ b/StatusDB_views/running_notes/latest_note_previews/workset.map.js @@ -0,0 +1,23 @@ +/* Returns a preview of the running note, with the note being truncated if it's + longer than a 10000 characters. The truncation is due to data limitations on + the reduce function +*/ + +function (doc) { + var ret_doc = {} + if ("note_type" in doc){ + if(doc["note_type"] == "workset"){ + var fields = ["parent", "user", "email", "categories", "created_at_utc", "updated_at_utc", "note_type"]; + for(var i in fields){ + ret_doc[fields[i]] = doc[fields[i]]; + } + if(doc['note'].length>3000){ + ret_doc['note'] = doc['note'].substring(0, 3000)+'``` \ntruncated after 3000 chars' + } + else{ + ret_doc['note'] = doc['note'] + } + emit(doc._id.split(":")[0], ret_doc); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_note_previews/workset.reduce.js b/StatusDB_views/running_notes/latest_note_previews/workset.reduce.js new file mode 100644 index 0000000..bd6906a --- /dev/null +++ b/StatusDB_views/running_notes/latest_note_previews/workset.reduce.js @@ -0,0 +1,14 @@ +/* Reduce function to get the latest running note +*/ + +function (keys, values, rereduce) { + var max = '0'; + var max_doc = {} + for(var i = 0; i < values.length; i++){ + if(values[i].created_at_utc>max){ + max = values[i].created_at_utc; + max_doc = values[i]; + } + } + return max_doc + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_sticky_note_previews/project.map.js b/StatusDB_views/running_notes/latest_sticky_note_previews/project.map.js new file mode 100644 index 0000000..40b0702 --- /dev/null +++ b/StatusDB_views/running_notes/latest_sticky_note_previews/project.map.js @@ -0,0 +1,25 @@ +/* Returns a preview of the running note, with the note being truncated if it's + longer than a 3000 characters. The truncation is due to data limitations on + the reduce function +*/ + +function (doc) { + var ret_doc = {} + if ("note_type" in doc){ + if(doc["note_type"] == "project"){ + if(doc["categories"].indexOf("Sticky")>=0){ + var fields = ["parent", "user", "email", "categories", "created_at_utc", "updated_at_utc", "note_type"]; + for(var i in fields){ + ret_doc[fields[i]] = doc[fields[i]]; + } + if(doc['note'].length>3000){ + ret_doc['note'] = doc['note'].substring(0, 3000)+'``` \ntruncated after 3000 chars' + } + else{ + ret_doc['note'] = doc['note'] + } + emit(doc._id.split(":")[0], ret_doc); + } + } + } + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/latest_sticky_note_previews/project.reduce.js b/StatusDB_views/running_notes/latest_sticky_note_previews/project.reduce.js new file mode 100644 index 0000000..bd6906a --- /dev/null +++ b/StatusDB_views/running_notes/latest_sticky_note_previews/project.reduce.js @@ -0,0 +1,14 @@ +/* Reduce function to get the latest running note +*/ + +function (keys, values, rereduce) { + var max = '0'; + var max_doc = {} + for(var i = 0; i < values.length; i++){ + if(values[i].created_at_utc>max){ + max = values[i].created_at_utc; + max_doc = values[i]; + } + } + return max_doc + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/note_types/invoicing_notes.map.js b/StatusDB_views/running_notes/note_types/invoicing_notes.map.js new file mode 100644 index 0000000..ab025aa --- /dev/null +++ b/StatusDB_views/running_notes/note_types/invoicing_notes.map.js @@ -0,0 +1,16 @@ +/* THIS IS A PARTITIONED QUERY + */ +function (doc) { + if ("categories" in doc){ + if(doc["categories"].indexOf("Invoicing")>=0){ + var note = {}; + note["user"] = doc["user"]; + note["email"] = doc["email"]; + note["categories"] = doc["categories"]; + note["created_at_utc"] = doc["created_at_utc"]; + note["updated_at_utc"] = doc["updated_at_utc"]; + note["note"] = doc["note"]; + emit( doc.created_at_utc, note ); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/running_notes/note_types/sticky_notes.map.js b/StatusDB_views/running_notes/note_types/sticky_notes.map.js new file mode 100644 index 0000000..ab23b0d --- /dev/null +++ b/StatusDB_views/running_notes/note_types/sticky_notes.map.js @@ -0,0 +1,16 @@ +/* THIS IS A PARTITIONED QUERY + */ +function (doc) { + if ("categories" in doc){ + if(doc["categories"].indexOf("Sticky")>=0){ + var note = {}; + note["user"] = doc["user"]; + note["email"] = doc["email"]; + note["categories"] = doc["categories"]; + note["created_at_utc"] = doc["created_at_utc"]; + note["updated_at_utc"] = doc["updated_at_utc"]; + note["note"] = doc["note"]; + emit( doc.created_at_utc, note ); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/sample_requirements/drafts/by_date_and_user.map.js b/StatusDB_views/sample_requirements/drafts/by_date_and_user.map.js new file mode 100644 index 0000000..23c49b7 --- /dev/null +++ b/StatusDB_views/sample_requirements/drafts/by_date_and_user.map.js @@ -0,0 +1,5 @@ +function(doc) { + if ('draft' in doc && doc['draft']) { + emit([doc['issued_at'], doc['issued_by']], doc); + } +} diff --git a/StatusDB_views/sample_requirements/entire_document/by_version.map.js b/StatusDB_views/sample_requirements/entire_document/by_version.map.js new file mode 100644 index 0000000..0e6e981 --- /dev/null +++ b/StatusDB_views/sample_requirements/entire_document/by_version.map.js @@ -0,0 +1,6 @@ +/* Used by genomics-status at /api/v1/sample_requirements */ + +function(doc) { + /* Used to fetch the entire document using the version id */ + emit(doc['Version'], doc); +} diff --git a/StatusDB_views/sample_requirements/entire_document/published_by_version.map.js b/StatusDB_views/sample_requirements/entire_document/published_by_version.map.js new file mode 100644 index 0000000..73dc556 --- /dev/null +++ b/StatusDB_views/sample_requirements/entire_document/published_by_version.map.js @@ -0,0 +1,7 @@ +/* Used by genomics-status at /api/v1/sample_requirements */ + +function (doc) { + if (!doc['Draft']) { + emit(doc['Version'], doc); + } +} diff --git a/StatusDB_views/sample_requirements/valid/by_date.map.js b/StatusDB_views/sample_requirements/valid/by_date.map.js new file mode 100644 index 0000000..9e4a14b --- /dev/null +++ b/StatusDB_views/sample_requirements/valid/by_date.map.js @@ -0,0 +1,5 @@ +function(doc) { + if ('draft' in doc && !doc['draft']) { + emit(doc['issued_at'], doc); + } +} diff --git a/StatusDB_views/sensorpush/entire_document/by_sensor_id_and_date.map.js b/StatusDB_views/sensorpush/entire_document/by_sensor_id_and_date.map.js new file mode 100644 index 0000000..43cf86c --- /dev/null +++ b/StatusDB_views/sensorpush/entire_document/by_sensor_id_and_date.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit([doc['sensor_id'], doc['start_date_midnight']], doc); +} diff --git a/StatusDB_views/sensorpush/sensor_id/by_date.map.js b/StatusDB_views/sensorpush/sensor_id/by_date.map.js new file mode 100644 index 0000000..bf4016d --- /dev/null +++ b/StatusDB_views/sensorpush/sensor_id/by_date.map.js @@ -0,0 +1,3 @@ +function (doc) { + emit(doc['start_date_midnight'], doc['sensor_id']); +} diff --git a/StatusDB_views/sensorpush/sensor_id/by_date.reduce.js b/StatusDB_views/sensorpush/sensor_id/by_date.reduce.js new file mode 100644 index 0000000..fc0292f --- /dev/null +++ b/StatusDB_views/sensorpush/sensor_id/by_date.reduce.js @@ -0,0 +1,19 @@ +function (keys, values, rereduce) { + var unique_sensors = {}; + + if (rereduce) { + // values is an array of arrays from previous reduce steps + for (var i = 0; i < values.length; i++) { + for (var j = 0; j < values[i].length; j++) { + unique_sensors[values[i][j]] = true; + } + } + } else { + // values is an array of sensor_ids from the map function + for (var i = 0; i < values.length; i++) { + unique_sensors[values[i]] = true; + } + } + + return Object.keys(unique_sensors); +} diff --git a/StatusDB_views/server_status/all_docs/by_timestamp.map.js b/StatusDB_views/server_status/all_docs/by_timestamp.map.js new file mode 100644 index 0000000..c6b4624 --- /dev/null +++ b/StatusDB_views/server_status/all_docs/by_timestamp.map.js @@ -0,0 +1,8 @@ +/* + Used by genomics-status + (in status/util.py, MainHandler) + to display server status on the main page +*/ +function(doc) { + emit(doc.time, doc); +} \ No newline at end of file diff --git a/StatusDB_views/server_status/nases/by_timestamp.map.js b/StatusDB_views/server_status/nases/by_timestamp.map.js new file mode 100644 index 0000000..e284d05 --- /dev/null +++ b/StatusDB_views/server_status/nases/by_timestamp.map.js @@ -0,0 +1,9 @@ +/* + Used by genomics-status + (in status/util.py, MainHandler) + to display server status on the main page +*/ +function(doc) { +if (doc.server_type == 'nas') { + emit(doc.time, doc);} +} \ No newline at end of file diff --git a/StatusDB_views/server_status/nases/latest_data.map.js b/StatusDB_views/server_status/nases/latest_data.map.js new file mode 100644 index 0000000..74b3cff --- /dev/null +++ b/StatusDB_views/server_status/nases/latest_data.map.js @@ -0,0 +1,9 @@ +/* + Used by genomics-status + (in status/util.py, MainHandler) + to display server status on the main page +*/ +function(doc) { +if (doc.type == 'nas') { + emit(doc.time, doc);} +} \ No newline at end of file diff --git a/StatusDB_views/server_status/uppmax/by_timestamp.map.js b/StatusDB_views/server_status/uppmax/by_timestamp.map.js new file mode 100644 index 0000000..23cd14f --- /dev/null +++ b/StatusDB_views/server_status/uppmax/by_timestamp.map.js @@ -0,0 +1,9 @@ +/* + Used by genomics-status + (in status/util.py, MainHandler) + to display server status on the main page +*/ +function(doc) { +if (doc.server_type == 'uppmax') { + emit(doc.time, doc);} +} \ No newline at end of file diff --git a/StatusDB_views/suggestion_box/card/id.map.js b/StatusDB_views/suggestion_box/card/id.map.js new file mode 100644 index 0000000..e47a4c5 --- /dev/null +++ b/StatusDB_views/suggestion_box/card/id.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['card_id'], doc['_id']); +} \ No newline at end of file diff --git a/StatusDB_views/suggestion_box/card/unarchived_jira_cards.map.js b/StatusDB_views/suggestion_box/card/unarchived_jira_cards.map.js new file mode 100644 index 0000000..3c35339 --- /dev/null +++ b/StatusDB_views/suggestion_box/card/unarchived_jira_cards.map.js @@ -0,0 +1,7 @@ +function(doc) { + if(doc.hasOwnProperty("source") && doc["source"] === 'jira'){ + if(!doc["archived"]){ + emit(doc['_id'], doc['card_id']); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/suggestion_box/date/info.map.js b/StatusDB_views/suggestion_box/date/info.map.js new file mode 100644 index 0000000..18b5bf1 --- /dev/null +++ b/StatusDB_views/suggestion_box/date/info.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['date'], [doc['name'], doc['url'], doc['archived']]); +} \ No newline at end of file diff --git a/StatusDB_views/suggestion_box/date/title_description.map.js b/StatusDB_views/suggestion_box/date/title_description.map.js new file mode 100644 index 0000000..9a3bf6c --- /dev/null +++ b/StatusDB_views/suggestion_box/date/title_description.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['date'], [doc['name'], doc['url']]); +} \ No newline at end of file diff --git a/StatusDB_views/suggestion_box/date/title_url.map.js b/StatusDB_views/suggestion_box/date/title_url.map.js new file mode 100644 index 0000000..9a3bf6c --- /dev/null +++ b/StatusDB_views/suggestion_box/date/title_url.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['date'], [doc['name'], doc['url']]); +} \ No newline at end of file diff --git a/StatusDB_views/userman/log/doc.map.js b/StatusDB_views/userman/log/doc.map.js new file mode 100644 index 0000000..bc3d11a --- /dev/null +++ b/StatusDB_views/userman/log/doc.map.js @@ -0,0 +1,8 @@ +/* Userman + Index log documents by doc. + Value: timestamp. +*/ +function(doc) { + if (doc.userman_doctype !== 'log') return; + emit(doc.doc, doc.timestamp); +} diff --git a/StatusDB_views/userman/service/name.map.js b/StatusDB_views/userman/service/name.map.js new file mode 100644 index 0000000..554aea8 --- /dev/null +++ b/StatusDB_views/userman/service/name.map.js @@ -0,0 +1,8 @@ +/* Userman + Index service documents by name. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'service') return; + emit(doc.name, null); +} diff --git a/StatusDB_views/userman/service/public.map.js b/StatusDB_views/userman/service/public.map.js new file mode 100644 index 0000000..0e9a2aa --- /dev/null +++ b/StatusDB_views/userman/service/public.map.js @@ -0,0 +1,9 @@ +/* Userman + Index public service documents by name. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'service') return; + if (!doc.public) return; + emit(doc.name, null); +} diff --git a/StatusDB_views/userman/team/leader.map.js b/StatusDB_views/userman/team/leader.map.js new file mode 100644 index 0000000..bc463ff --- /dev/null +++ b/StatusDB_views/userman/team/leader.map.js @@ -0,0 +1,10 @@ +/* Userman + Index team documents by leaders. + Value: name. +*/ +function(doc) { + if (doc.userman_doctype !== 'team') return; + for (var i in doc.leaders) { + emit(doc.leaders[i], doc.name); + } +} diff --git a/StatusDB_views/userman/team/name.map.js b/StatusDB_views/userman/team/name.map.js new file mode 100644 index 0000000..390eea1 --- /dev/null +++ b/StatusDB_views/userman/team/name.map.js @@ -0,0 +1,8 @@ +/* Userman + Index team documents by name. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'team') return; + emit(doc.name, null); +} diff --git a/StatusDB_views/userman/user/blocked.map.js b/StatusDB_views/userman/user/blocked.map.js new file mode 100644 index 0000000..86d17bb --- /dev/null +++ b/StatusDB_views/userman/user/blocked.map.js @@ -0,0 +1,8 @@ +/* Userman + Index user documents that are in status 'blocked'. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + if (doc.status === 'blocked') emit(doc.modified, null); +} diff --git a/StatusDB_views/userman/user/count.map.js b/StatusDB_views/userman/user/count.map.js new file mode 100644 index 0000000..26958ad --- /dev/null +++ b/StatusDB_views/userman/user/count.map.js @@ -0,0 +1,9 @@ +/* Userman + Index user documents by status. + Value: 1. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + if (!doc.status) return; + emit(doc.status, 1); +} diff --git a/StatusDB_views/userman/user/count.reduce.js b/StatusDB_views/userman/user/count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/userman/user/count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/userman/user/email.map.js b/StatusDB_views/userman/user/email.map.js new file mode 100644 index 0000000..b2dd74d --- /dev/null +++ b/StatusDB_views/userman/user/email.map.js @@ -0,0 +1,8 @@ +/* Userman + Index user documents by email. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + emit(doc.email, null); +} diff --git a/StatusDB_views/userman/user/pending.map.js b/StatusDB_views/userman/user/pending.map.js new file mode 100644 index 0000000..8a1e5c6 --- /dev/null +++ b/StatusDB_views/userman/user/pending.map.js @@ -0,0 +1,8 @@ +/* Userman + Index user documents that are in status 'pending'. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + if (doc.status === 'pending') emit(doc.modified, null); +} diff --git a/StatusDB_views/userman/user/role.map.js b/StatusDB_views/userman/user/role.map.js new file mode 100644 index 0000000..8086293 --- /dev/null +++ b/StatusDB_views/userman/user/role.map.js @@ -0,0 +1,8 @@ +/* Userman + Index user documents by role. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + emit(doc.role, null); +} diff --git a/StatusDB_views/userman/user/team.map.js b/StatusDB_views/userman/user/team.map.js new file mode 100644 index 0000000..22c8db6 --- /dev/null +++ b/StatusDB_views/userman/user/team.map.js @@ -0,0 +1,10 @@ +/* Userman + Index user documents by teams. + Value: email. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + for (var i in doc.teams) { + emit(doc.teams[i], doc.email); + } +} diff --git a/StatusDB_views/userman/user/username.map.js b/StatusDB_views/userman/user/username.map.js new file mode 100644 index 0000000..d774cc5 --- /dev/null +++ b/StatusDB_views/userman/user/username.map.js @@ -0,0 +1,8 @@ +/* Userman + Index user documents by username. + Value: null. +*/ +function(doc) { + if (doc.userman_doctype !== 'user') return; + if (doc.username) emit(doc.username, null); +} diff --git a/StatusDB_views/worksets/project/ws_name.map.js b/StatusDB_views/worksets/project/ws_name.map.js new file mode 100644 index 0000000..f783c35 --- /dev/null +++ b/StatusDB_views/worksets/project/ws_name.map.js @@ -0,0 +1,5 @@ +function(doc) { + for (project in doc['projects']){ + emit(project, doc.name); +} +} diff --git a/StatusDB_views/worksets/project/ws_proj.map.js b/StatusDB_views/worksets/project/ws_proj.map.js new file mode 100644 index 0000000..11e13cb --- /dev/null +++ b/StatusDB_views/worksets/project/ws_proj.map.js @@ -0,0 +1,11 @@ +// Used for NGI_dashboards +function(doc) { + for (project in doc['projects']){ + var ws_proj = Object(); + ws_proj[doc.name] = Object(); + ws_proj[doc.name]['samples'] = doc['projects'][project]['samples']; + ws_proj[doc.name]['date_run'] = doc['date_run']; + ws_proj[doc.name]['last_aggregate'] = doc['last_aggregate']; + emit(project, ws_proj); + } +} diff --git a/StatusDB_views/worksets/worksets/controls_project_list.map.js b/StatusDB_views/worksets/worksets/controls_project_list.map.js new file mode 100644 index 0000000..bc5a3ba --- /dev/null +++ b/StatusDB_views/worksets/worksets/controls_project_list.map.js @@ -0,0 +1,18 @@ +// filters out worksets with control projects and returns project names and Project numbers for such worksets + +function(doc) { + ws_projects = {}; + const re_positive_control = /p.ositive*/i; + const re_negative_control = /n.egative*/i; + var is_control = false; + + for (var p in doc.projects){ + ws_projects[doc.projects[p]["name"]] = p; + if(re_positive_control.test(doc.projects[p]["name"]) || re_negative_control.test(doc.projects[p]["name"])){ + is_control = true; + } + } + if(is_control){ + emit([doc.id, doc.name], ws_projects); + } +} diff --git a/StatusDB_views/worksets/worksets/lims_id.map.js b/StatusDB_views/worksets/worksets/lims_id.map.js new file mode 100644 index 0000000..23ab7db --- /dev/null +++ b/StatusDB_views/worksets/worksets/lims_id.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.id, doc); +} diff --git a/StatusDB_views/worksets/worksets/name.map.js b/StatusDB_views/worksets/worksets/name.map.js new file mode 100644 index 0000000..df6347f --- /dev/null +++ b/StatusDB_views/worksets/worksets/name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.name, doc); +} diff --git a/StatusDB_views/worksets/worksets/only_name.map.js b/StatusDB_views/worksets/worksets/only_name.map.js new file mode 100644 index 0000000..7c9d260 --- /dev/null +++ b/StatusDB_views/worksets/worksets/only_name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc.name, null); +} diff --git a/StatusDB_views/worksets/worksets/project_list.js b/StatusDB_views/worksets/worksets/project_list.js new file mode 100644 index 0000000..fdad628 --- /dev/null +++ b/StatusDB_views/worksets/worksets/project_list.js @@ -0,0 +1,10 @@ +function(doc) { + project_list = []; + + for (var p in doc.projects){ + if(p!=='Control'){ + project_list.push(p); + } + } + emit(doc.id, {project_list: project_list, name: doc.name}); +} diff --git a/StatusDB_views/worksets/worksets/summary.map.js b/StatusDB_views/worksets/worksets/summary.map.js new file mode 100644 index 0000000..7a8864e --- /dev/null +++ b/StatusDB_views/worksets/worksets/summary.map.js @@ -0,0 +1,52 @@ +function(doc) { + summary = {}; + summary['projects'] = {}; + summary['technician'] = doc.technician; + summary['date_run'] = doc.date_run; + summary['finish date']=doc['last_aggregate']; + summary['application'] = []; + summary['library_method'] = []; + summary['library_option'] = []; + summary['samples'] = {}; + summary['samples']['total'] = 0; + summary['samples']['passed'] = 0; + summary['samples']['failed'] = 0; + summary['samples']['unknown'] = 0; + summary['id'] = doc['id']; + + for (var p in doc.projects){ + summary['projects'][p] = {}; + summary['projects'][p]['samples_nb']=Object.keys(doc.projects[p].samples).length; + summary['projects'][p]['project_name']=doc.projects[p].name; + if (doc.projects[p].sequencing_setup) { + summary['projects'][p]['sequencing_setup'] = doc.projects[p].sequencing_setup; + } else { + summary['projects'][p]['sequencing_setup'] = '-'; + } + if ("close_date" in doc.projects[p]){ + summary['projects'][p]['status']="Closed"; + }else{ + summary['projects'][p]['status']="Open"; + } + if (doc.projects[p].application && summary['application'].indexOf(doc.projects[p].application) == -1){ + summary['application'][summary['application'].length]=doc.projects[p].application; + } + if (doc.projects[p].library && summary['library_method'].indexOf(doc.projects[p].library) == -1){ + summary['library_method'][summary['library_method'].length]=doc.projects[p].library; + } + if (doc.projects[p].library_option && summary['library_option'].indexOf(doc.projects[p].library_option) == -1){ + summary['library_option'][summary['library_option'].length]=doc.projects[p].library_option; + } + for (var s in doc.projects[p].samples){ + summary['samples']['total']+=1; + if(doc.projects[p].samples[s].library_status == 'PASSED'){ + summary['samples']['passed']+=1; + }else if (doc.projects[p].samples[s].library_status == 'FAILED'){ + summary['samples']['failed']+=1; + }else{ + summary['samples']['unknown']+=1; + } + } + } + emit(doc.name, summary); +} diff --git a/StatusDB_views/x_flowcells/dashboard/week_instr_bp.map.js b/StatusDB_views/x_flowcells/dashboard/week_instr_bp.map.js new file mode 100644 index 0000000..2ab090f --- /dev/null +++ b/StatusDB_views/x_flowcells/dashboard/week_instr_bp.map.js @@ -0,0 +1,47 @@ +function(doc) { + var prev_monday=null; + var seqtype=null; + var yd=0; + var key=new Array(); + + var id_str=doc.RunInfo.Id; + // Some ids iclude the '20' century and some do not + var d_str = id_str.split("_")[0].slice(-6) + var run_date=new Date(parseInt('20' + d_str.slice(0,2)), parseInt(d_str.slice(2,4),10)-1, parseInt(d_str.slice(4,6),10)); + var dw = run_date.getDay(); + if (dw==0){ + prev_monday=new Date(run_date.getFullYear(), run_date.getMonth(), (run_date.getDate()-6)); + }else{ + prev_monday=new Date(run_date.getFullYear(), run_date.getMonth(), (run_date.getDate() - run_date.getDay() + 1)); + } + var d_str=prev_monday.getDate().toString(); + if (prev_monday.getDate()<10){ + d_str = "0"+d_str; + } + var m_str=(prev_monday.getMonth() + 1).toString(); + if (prev_monday.getMonth() + 1 < 10){ + m_str = "0"+m_str; + } + var prev_monday_str=prev_monday.getFullYear().toString() + "-" + m_str + "-" + d_str; + + if (doc.RunInfo.Instrument.indexOf('ST-E') != -1){ + seqtype="HiseqX"; + }else if (doc.RunInfo.Instrument.indexOf('D') != -1){ + seqtype="Hiseq"; + }else if (doc.RunInfo.Instrument.indexOf('M') != -1){ + seqtype="Miseq"; + }else if (doc.RunInfo.Instrument.indexOf('A') != -1){ + seqtype="NovaSeq 6000"; + }else if (doc.RunInfo.Instrument.indexOf('LH') != -1){ + seqtype="NovaSeqXPlus"; + }else if (doc.RunInfo.Instrument.indexOf('N') != -1){ + seqtype="NextSeq"; + }else if (doc.RunInfo.Instrument.indexOf('VH') != -1){ + seqtype="NextSeq 2000"; + }else{ + return ''; + } + var key=[prev_monday_str, seqtype]; + yd=parseInt(doc.illumina.Demultiplex_Stats.Flowcell_stats["Yield (MBases)"].replace(/,/g,'')) * 1000000; + emit(key, yd); +} \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/dashboard/week_instr_bp.reduce.js b/StatusDB_views/x_flowcells/dashboard/week_instr_bp.reduce.js new file mode 100644 index 0000000..79f412b --- /dev/null +++ b/StatusDB_views/x_flowcells/dashboard/week_instr_bp.reduce.js @@ -0,0 +1 @@ +_sum \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/info/id.map.js b/StatusDB_views/x_flowcells/info/id.map.js new file mode 100644 index 0000000..8748f76 --- /dev/null +++ b/StatusDB_views/x_flowcells/info/id.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['RunInfo']['Id'], doc['_id']); +} diff --git a/StatusDB_views/x_flowcells/info/name.map.js b/StatusDB_views/x_flowcells/info/name.map.js new file mode 100644 index 0000000..dbbf1b4 --- /dev/null +++ b/StatusDB_views/x_flowcells/info/name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc['name'], doc); +} \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/info/short_name_to_full_name.map.js b/StatusDB_views/x_flowcells/info/short_name_to_full_name.map.js new file mode 100644 index 0000000..2d97311 --- /dev/null +++ b/StatusDB_views/x_flowcells/info/short_name_to_full_name.map.js @@ -0,0 +1,8 @@ +/* Used by genomics-status at individual flowcell page */ + +function(doc) { + if ('RunInfo' in doc) { + full_name = doc.RunInfo.Id; + emit(doc['name'], full_name); + } +} diff --git a/StatusDB_views/x_flowcells/info/summary.map.js b/StatusDB_views/x_flowcells/info/summary.map.js new file mode 100644 index 0000000..49bef6a --- /dev/null +++ b/StatusDB_views/x_flowcells/info/summary.map.js @@ -0,0 +1,226 @@ +/* + Used by genomics-status at: + /api/v1/flowcell_info, + /api/v1/flowcells +*/ + +function(doc) { + + var summary = new Object(); + summary["startdate"] = doc["RunInfo"]["Date"]; + summary["instrument"] = doc["RunInfo"]["Instrument"]; + summary["flowcell"] = doc["RunInfo"]["Flowcell"]; + summary["run id"] = doc["RunInfo"]["Id"]; + + // Position is first character after first '_' in name + summary["pos"] = doc["name"].split("_")[1][0] + + summary["reads"] = doc["RunInfo"]["Reads"]; + summary["number"] = doc["RunInfo"]["Number"]; + summary["recipe"] = doc["run_setup"]; + summary["lane_info"] = {}; + summary['demultiplexing']='Pending'; + summary["pdc_archived"] = doc["pdc_archived"]; + + if(doc.hasOwnProperty("RunInfo")){ + run_setup = doc.RunInfo.Reads; + run_setup_text = ''; + read_count = 0; + index_count = 0; + longer_read_length = 0; + + run_setup.forEach(function(read){ + run_setup_text += read['NumCycles']; + run_setup_text += 'nt'; + if(read['IsIndexedRead'] === 'N'){ + read_count += 1; + run_setup_text += '(R'; + run_setup_text += read_count.toString(); + if(parseInt(read['NumCycles']) > longer_read_length){ + longer_read_length = parseInt(read['NumCycles']); + } + } + else if(read['IsIndexedRead'] == 'Y'){ + index_count += 1; + run_setup_text += '(I'; + run_setup_text += index_count.toString(); + } + if(run_setup.indexOf(read) === run_setup.length-1) + run_setup_text += ')'; + else + run_setup_text += ')-'; + }); + summary['actual_run_setup'] = run_setup_text; + summary['longer_read_length'] = longer_read_length; + } + + if (doc.hasOwnProperty("RunParameters")){ + if (doc["RunParameters"].hasOwnProperty('Setup')){ + summary["mode"] = doc["RunParameters"]['Setup']["RunMode"]; + summary["type"] = doc['RunParameters']['Setup']['ApplicationName']; + summary["fctype"] = doc['RunParameters']['Setup']['Flowcell']; + summary["appver"] = doc['RunParameters']['Setup']['ApplicationVersion']; + //Miseq + if(doc["RunParameters"].hasOwnProperty('ReagentKitVersion')){ + summary["kitver"]=doc["RunParameters"]['ReagentKitVersion']; + } + }else{ + if (doc["RunParameters"].hasOwnProperty('ApplicationName')){ + summary["type"] = doc['RunParameters']['ApplicationName']; + summary["mode"] = doc["RunParameters"]["RunMode"]; + }else if (doc["RunParameters"].hasOwnProperty('InstrumentType')){ + // NovaSeq X Plus + summary["type"] = doc['RunParameters']['InstrumentType']; + summary["mode"] = doc["RunParameters"]["RecipeName"]; + }else{ + //NovaSeq + summary["type"] = doc['RunParameters']['Application']; + summary["mode"] = doc["RunParameters"]["RfidsInfo"]["FlowCellMode"]; + summary["workflow"] = doc["RunParameters"]["WorkflowType"]; + } + if (doc["RunParameters"].hasOwnProperty('Flowcell')){ + summary["fctype"] = doc['RunParameters']['Flowcell']; + }else{ + summary["fctype"] = doc['RunParameters']['FlowCellName']; + } + summary["fctype"] = doc['RunParameters']['Flowcell']; + summary["appver"] = doc['RunParameters']['ApplicationVersion']; + } + } + + // to define tresholds for number of clusters + summary['run_mode']=''; + + if (doc['RunParameters'].hasOwnProperty('ReagentKitVersion') && doc['RunParameters'].hasOwnProperty('RunParametersVersion') && doc['RunParameters']['RunParametersVersion'].indexOf('MiSeq') != -1) { + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_type') && doc['lims_data']['run_type']!='null') { + summary['run_mode']='MiSeq ' + doc['lims_data']['run_type']; + } + else { + if (doc['RunParameters'].hasOwnProperty('Setup') && doc['RunParameters']['Setup'].hasOwnProperty('SupportMultipleSurfacesInUI') && doc['RunParameters']['Setup'].hasOwnProperty('NumTilesPerSwath')) { + if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='19') { + summary['run_mode']='MiSeq Version3'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='14') { + summary['run_mode']='MiSeq Version2'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='false' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='2') { + summary['run_mode']='MiSeq Version2Nano'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='4') { + summary['run_mode']='MiSeq Version2Micro'; + } + else { + summary['run_mode']='MiSeq null'; + } + } + else { + summary['run_mode']='MiSeq ' + doc['RunParameters']['ReagentKitVersion']; + } + } + } else if (doc['RunParameters'].hasOwnProperty('Chemistry') && doc['RunParameters']['Chemistry'].indexOf('NextSeq')!=-1) { + summary['run_mode']=doc['RunParameters']['Chemistry']; + } else if (doc['RunParameters'].hasOwnProperty('InstrumentType')) { + if (doc['RunParameters'].hasOwnProperty('FlowCellMode') && doc['RunParameters']['InstrumentType'].indexOf('NextSeq 2000')!=-1) { + summary['run_mode']=doc['RunParameters']['InstrumentType'] + ' ' + doc['RunParameters']['FlowCellMode'].match(/P[1,2,3]/)[0]; + } else if (doc['RunParameters']['InstrumentType'].indexOf('NovaSeqXPlus')!=-1) { + // NovaSeq X Plus + summary['run_mode']=doc['RunParameters']['InstrumentType'] + ' ' + doc['RunParameters']['RecipeName'].split(" ")[0]; + } + } else if (doc['RunParameters'].hasOwnProperty('Setup')){ + if (doc['RunParameters']['Setup'].hasOwnProperty('RunMode')){ + // HiSeq + summary['run_mode']=doc['RunParameters']['Setup']['RunMode']; + } else if (doc['RunParameters']['Setup'].hasOwnProperty('Index') && doc['RunParameters']['Setup']['Index'].indexOf('HiSeq X')!=-1) { + summary['run_mode']='HiSeq X'; + } + } else if (doc['RunParameters'].hasOwnProperty('RfidsInfo') && doc['RunParameters']['RfidsInfo'].hasOwnProperty('FlowCellMode')) { + summary['run_mode']='NovaSeq ' + doc['RunParameters']['RfidsInfo']['FlowCellMode']; + } + else { + summary['run_mode']=''; + } + + /*Retrieve information of involved projects*/ + if (doc.hasOwnProperty('samplesheet_csv') && doc.samplesheet_csv.length >0){ + for (index in doc.samplesheet_csv){ + lane = doc.samplesheet_csv[index]['Lane']; + if (doc.samplesheet_csv[index].hasOwnProperty('Sample_Name')){ + pid = doc.samplesheet_csv[index]['Sample_Name'].split('_')[0]; + pname = doc.samplesheet_csv[index]['Sample_Project'].replace(/^(\w+?)_+(\w+)/, "$1.$2"); + } else if (doc.samplesheet_csv[index].hasOwnProperty('SampleName')){ + pid = doc.samplesheet_csv[index]['SampleName'].split('_')[0]; + pname = doc.samplesheet_csv[index]['Project'].replace(/^(\w+?)_+(\w+)/, "$1.$2"); + } else { + continue; + } + + if(!(lane in summary["lane_info"])){ + summary["lane_info"][lane] = {"project_id": [pid], "project_name": [pname]}; + } else if (summary["lane_info"][lane]["project_id"].indexOf(pid) == -1){ + summary["lane_info"][lane]["project_id"].push(pid); + summary["lane_info"][lane]["project_name"].push(pname); + } else{ + continue; + } + } + } + + /*Retrieve information of lane yields and quality*/ + if (doc.hasOwnProperty('illumina') && doc.illumina.hasOwnProperty('Demultiplex_Stats') && doc.illumina['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics')){ + if(doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics') && doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'].length >0){ + summary['demultiplexing']='Done'; + } + if (doc.illumina['Demultiplex_Stats'].hasOwnProperty('Lanes_stats') && doc['illumina']['Demultiplex_Stats']['Lanes_stats'].length > 0){ + for (index in doc.illumina.Demultiplex_Stats.Lanes_stats){ + lane = doc.illumina.Demultiplex_Stats.Lanes_stats[index]['Lane']; + summary["lane_info"][lane]["pf_clusters"] = doc.illumina.Demultiplex_Stats.Lanes_stats[index]["PF Clusters"]; + summary["lane_info"][lane]["q30_bases"] = doc.illumina.Demultiplex_Stats.Lanes_stats[index]["% >= Q30bases"]; + } + } + /*Retrive information of PhiX error rate*/ + if (doc.hasOwnProperty('lims_data') && doc.lims_data.hasOwnProperty('run_summary')){ + for (lane in doc.lims_data.run_summary){ + var er_rate=0; + if (doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R1')){ + er_rate=doc.lims_data.run_summary[lane]['% Error Rate R1']; + } + if (doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R2') && doc.lims_data.run_summary[lane]['% Error Rate R2'] != 0){ + er_rate=(er_rate+doc.lims_data.run_summary[lane]['% Error Rate R2'])/2; + } + summary["lane_info"][lane]["er_rate"] = er_rate; + } + } + + /*yield is in Mb, but is displayed in Gb*/ + summary['yield']=0; + var undetermined={1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0}; + + for(barcode in doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics']){ + if (doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Index'] == 'Undetermined'){ + undetermined[doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Lane']]+=1; + } + intLocalYield=parseInt(doc.illumina['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Yield (Mbases)'].replace(/,/g, "")); + summary['yield']=summary['yield']+intLocalYield; + } + summary['yield']=summary['yield']/1000; + for (lane in undetermined){ + if (undetermined[lane]>1){ + /*if there is more than one undetermined indices, the actual yield is messed up, so we don't display it*/ + summary['yield']=0; + } + } + } + + /*Retrieve running notes*/ + summary['running_notes']=''; + if (doc.hasOwnProperty('lims_data') && doc.lims_data.hasOwnProperty('container_running_notes') && Object.keys(doc['lims_data']['container_running_notes']).length>0){ + summary['running_notes']=doc['lims_data']['container_running_notes']; + } + + // NovaSeq X Plus has more digits in the date, will mess up the sorting if not adjusted + name_arr = doc["name"].split("_") + run_date_original = name_arr[0] + run_date = run_date_original.slice(-6) + modified_name = [run_date, name_arr[1]].join('_') + emit(modified_name, summary); +} diff --git a/StatusDB_views/x_flowcells/info/summary2.map.js b/StatusDB_views/x_flowcells/info/summary2.map.js new file mode 100644 index 0000000..513c9e1 --- /dev/null +++ b/StatusDB_views/x_flowcells/info/summary2.map.js @@ -0,0 +1,188 @@ +/* + Used by genomics-status at: flowcell page +*/ + +function ( doc) { + sum=Object(); + sum['name']=doc['name']; + + if ('RunInfo' in doc) { + sum['instrument'] = doc.RunInfo.Instrument; + sum['short_name'] = doc.RunInfo.Flowcell; + sum['full_name'] = doc.RunInfo.Id; + } + sum['run_setup'] = doc['run_setup']; + + // to define tresholds for number of clusters + sum['run_mode']=''; + if (doc['RunParameters'].hasOwnProperty('ReagentKitVersion') && doc['RunParameters'].hasOwnProperty('RunParametersVersion') && doc['RunParameters']['RunParametersVersion'].indexOf('MiSeq') != -1) { + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_type') && doc['lims_data']['run_type']!='null') { + sum['run_mode']='MiSeq ' + doc['lims_data']['run_type']; + } + else { + if (doc['RunParameters'].hasOwnProperty('Setup') && doc['RunParameters']['Setup'].hasOwnProperty('SupportMultipleSurfacesInUI') && doc['RunParameters']['Setup'].hasOwnProperty('NumTilesPerSwath')) { + if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='19') { + sum['run_mode']='MiSeq Version3'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='14') { + sum['run_mode']='MiSeq Version2'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='false' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='2') { + sum['run_mode']='MiSeq Version2Nano'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='4') { + sum['run_mode']='MiSeq Version2Micro'; + } + else { + sum['run_mode']='MiSeq null'; + } + } + else { + sum['run_mode']='MiSeq ' + doc['RunParameters']['ReagentKitVersion']; + } + } + } else if (doc['RunParameters'].hasOwnProperty('Chemistry') && doc['RunParameters']['Chemistry'].indexOf('NextSeq')!=-1) { + sum['run_mode']=doc['RunParameters']['Chemistry']; + } else if (doc['RunParameters'].hasOwnProperty('InstrumentType') && doc['RunParameters'].hasOwnProperty('FlowCellMode') && doc['RunParameters']['InstrumentType'].indexOf('NextSeq 2000')!=-1) { + sum['run_mode']=doc['RunParameters']['InstrumentType'] + ' ' + doc['RunParameters']['FlowCellMode'].match(/P[1,2,3]/)[0]; + } else if (doc['RunParameters'].hasOwnProperty('Setup')){ + if (doc['RunParameters']['Setup'].hasOwnProperty('RunMode')){ + // HiSeq + sum['run_mode']=doc['RunParameters']['Setup']['RunMode']; + } else if (doc['RunParameters']['Setup'].hasOwnProperty('Index') && doc['RunParameters']['Setup']['Index'].indexOf('HiSeq X')!=-1) { + sum['run_mode']='HiSeq X'; + } + } else { + sum['run_mode']=''; + } + + if (doc['illumina'].hasOwnProperty('Summary')){ + if (doc['illumina']['Summary'].hasOwnProperty('read3')){ + //error rates per read and per lane + sum['err1']=Array(-1,0,0,0,0,0,0,0,0); + sum['err2']=Array(-1,0,0,0,0,0,0,0,0); + sum['err3']=Array(-1,0,0,0,0,0,0,0,0); + for(i=1;i<4;i++){ + for(lane in doc['illumina']['Summary']['read'+i]){ + sum['err'+i][lane]=doc['illumina']['Summary']['read'+i][lane]['ErrRatePhiX']; + } + } + } + } + if (doc['illumina'].hasOwnProperty('Demultiplex_Stats') && doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Lanes_stats')){ + lanedata=Object(); + for (idx in doc['illumina']['Demultiplex_Stats']['Lanes_stats']){ + ld=doc['illumina']['Demultiplex_Stats']['Lanes_stats'][idx]; + if ('Clusters' in ld){ + var cltk = 'Clusters'; + } else if ('PF Clusters' in ld){ + var cltk = "PF Clusters"; + } + Subset=Object(); + Subset['clustersnb']=ld[cltk]; + lane = ld['Lane']; + Subset['yield']=ld['Yield (Mbases)']; + Subset['overthirty']=ld['% >= Q30bases']; + Subset['mqs']=ld['Mean QualityScore']; + Subset['perf']=ld['% Perfectbarcode']; + if (doc.hasOwnProperty('lims_data') && doc.lims_data.run_summary[lane].hasOwnProperty('% phiX')){ + Subset['phix']=doc.lims_data.run_summary[lane]['% phiX']; + } + if (doc.hasOwnProperty('lims_data') && doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R1')){ + var er_rate=doc.lims_data.run_summary[lane]['% Error Rate R1']; + if (doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R2') && doc.lims_data.run_summary[lane]['% Error Rate R2'] != 0){ + er_rate=(er_rate+doc.lims_data.run_summary[lane]['% Error Rate R2'])/2; + } + Subset['er_rate']=er_rate; + } + lanedata[lane]=Subset; + + } + sum['lanedata']=lanedata; + } + if (doc['illumina'].hasOwnProperty('Demultiplex_Stats') && doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics') && doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'].length >0){ + sum['lane']=Object(); + //lanes are arrays of subsets + sum['lane']['1']=Array(); + sum['lane']['2']=Array(); + sum['lane']['3']=Array(); + sum['lane']['4']=Array(); + sum['lane']['5']=Array(); + sum['lane']['6']=Array(); + sum['lane']['7']=Array(); + sum['lane']['8']=Array(); + sum['yields']=Array(-1,0,0,0,0,0,0,0,0); + sum['seq_qc']=Array(-1,0,0,0,0,0,0,0,0); + sum['demuldone']=true; + subsets=[]; + plist=[]; + + for (lane in doc['illumina']['run_summary']){ + sum['seq_qc'][lane]=doc['illumina']['run_summary'][lane]['qc']; + } + + for (sample in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics']){ + id=doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][sample]; + //if(id['Project']==='Undetermined_indices'){ + // continue; + //} + //subsets are sample objects" + if ('Clusters' in id){ + var cstk='Clusters'; + } else if ('PF Clusters' in id){ + var cstk='PF Clusters'; + } else { + //We're doomed + var cstk="ERROR"; + } + Subset=Object(); + Subset['SampleName']=id['Sample']; + Subset['clustersnb']=id[cstk]; + proj_name = id['Project']; + plist.push(proj_name); + Subset['Project']=proj_name; + + lane = id['Lane']; + Subset['lane']=lane; + Subset['yield']=id['Yield (Mbases)']; + sum['yields'][lane]+=parseInt(id['Yield (Mbases)'].replace(/,/g,"")); + Subset['overthirty']=id['% >= Q30bases']; + + Subset['barcode']=id['Barcode sequence']; + Subset['desc']=id['Description']; + + Subset['mqs']=id['Mean QualityScore']; + //THIS NUMBER IS UNRELIABLE, COMPUTE IT INSTEAD + //Subset['lanepc']=id['% of thelane']; + + var clnb=parseInt(id[cstk].replace(/,/g,"")); + var lane_clnb=0; + if("Lanes_stats" in doc["illumina"]["Demultiplex_Stats"]){ + for(idx in doc["illumina"]["Demultiplex_Stats"]["Lanes_stats"]){ + if(doc["illumina"]["Demultiplex_Stats"]["Lanes_stats"][idx]["Lane"] == lane){ + lane_clnb=parseInt(doc["illumina"]["Demultiplex_Stats"]["Lanes_stats"][idx][cstk].replace(/,/g,"")); + } + } + // here we get division by zero + if (lane_clnb==0) { + Subset['lanepc'] = 0; + } else { + Subset['lanepc'] = 100 * (clnb / lane_clnb); + } + } + subsets.push(Subset); + } + for (s in subsets){ + //order by lane + sum['lane'][subsets[s]['lane']].push(subsets[s]); + } + if ('Undetermined' in doc){ + sum['undetermined']=doc["Undetermined"]; + } + //clean duplicates + sum['plist']=plist.filter(function( item, index, inputArray ) { + return inputArray.indexOf(item) == index; + }); + } + emit(doc.name, sum) +} diff --git a/StatusDB_views/x_flowcells/info/summary2_full_id.map.js b/StatusDB_views/x_flowcells/info/summary2_full_id.map.js new file mode 100644 index 0000000..052f93f --- /dev/null +++ b/StatusDB_views/x_flowcells/info/summary2_full_id.map.js @@ -0,0 +1,233 @@ +/* + Used by genomics-status at: flowcell page +*/ + +function ( doc) { + sum=Object(); + sum['name']=doc['name']; + if ('RunInfo' in doc) { + sum['instrument'] = doc.RunInfo.Instrument; + sum['short_name'] = doc.RunInfo.Flowcell; + sum['full_name'] = doc.RunInfo.Id; + run_setup = doc.RunInfo.Reads; + run_setup_text = ''; + read_count = 0; + index_count = 0; + longer_read_length = 0; + + run_setup.forEach(function(read){ + run_setup_text += read['NumCycles']; + run_setup_text += 'nt'; + if(read['IsIndexedRead'] === 'N'){ + read_count += 1; + run_setup_text += '(R'; + run_setup_text += read_count.toString(); + if(parseInt(read['NumCycles']) > longer_read_length){ + longer_read_length = parseInt(read['NumCycles']); + } + } + else if(read['IsIndexedRead'] == 'Y'){ + index_count += 1; + run_setup_text += '(I'; + run_setup_text += index_count.toString(); + } + if(run_setup.indexOf(read) === run_setup.length-1) + run_setup_text += ')'; + else + run_setup_text += ')-'; + }); + sum['actual_run_setup'] = run_setup_text; + sum['longer_read_length'] = longer_read_length; + } + sum['run_setup'] = doc['run_setup']; + + // to define tresholds for number of clusters + sum['run_mode']=''; + + if (doc['RunParameters'].hasOwnProperty('ReagentKitVersion') && doc['RunParameters'].hasOwnProperty('RunParametersVersion') && doc['RunParameters']['RunParametersVersion'].indexOf('MiSeq') != -1) { + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_type') && doc['lims_data']['run_type']!='null') { + sum['run_mode']='MiSeq ' + doc['lims_data']['run_type']; + } + else { + if (doc['RunParameters'].hasOwnProperty('Setup') && doc['RunParameters']['Setup'].hasOwnProperty('SupportMultipleSurfacesInUI') && doc['RunParameters']['Setup'].hasOwnProperty('NumTilesPerSwath')) { + if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='19') { + sum['run_mode']='MiSeq Version3'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='14') { + sum['run_mode']='MiSeq Version2'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='false' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='2') { + sum['run_mode']='MiSeq Version2Nano'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='4') { + sum['run_mode']='MiSeq Version2Micro'; + } + else { + sum['run_mode']='MiSeq null'; + } + } + else { + sum['run_mode']='MiSeq ' + doc['RunParameters']['ReagentKitVersion']; + } + } + } else if (doc['RunParameters'].hasOwnProperty('Chemistry') && doc['RunParameters']['Chemistry'].indexOf('NextSeq')!=-1) { + sum['run_mode']=doc['RunParameters']['Chemistry']; + } else if (doc['RunParameters'].hasOwnProperty('InstrumentType')){ + if (doc['RunParameters'].hasOwnProperty('FlowCellMode') && doc['RunParameters']['InstrumentType'].indexOf('NextSeq 2000')!=-1) { + sum['run_mode']=doc['RunParameters']['InstrumentType'] + ' ' + doc['RunParameters']['FlowCellMode'].match(/P[1,2,3]/)[0]; + } else if (doc['RunParameters']['InstrumentType'].indexOf('NovaSeqXPlus')!=-1) { + sum['run_mode']=doc['RunParameters']['InstrumentType'] + ' ' + doc['RunParameters']['RecipeName'].split(" ")[0]; + } + } else if (doc['RunParameters'].hasOwnProperty('Setup')){ + if (doc['RunParameters']['Setup'].hasOwnProperty('RunMode')){ + // HiSeq + sum['run_mode']=doc['RunParameters']['Setup']['RunMode']; + } else if (doc['RunParameters']['Setup'].hasOwnProperty('Index') && doc['RunParameters']['Setup']['Index'].indexOf('HiSeq X')!=-1) { + sum['run_mode']='HiSeq X'; + } + } else if (doc['RunParameters'].hasOwnProperty('RfidsInfo') && doc['RunParameters']['RfidsInfo'].hasOwnProperty('FlowCellMode')) { + sum['run_mode']='NovaSeq ' + doc['RunParameters']['RfidsInfo']['FlowCellMode']; + } else { + sum['run_mode']=''; + } + + if (doc.hasOwnProperty('illumina')){ + if (doc['illumina'].hasOwnProperty('Summary')){ + if (doc['illumina']['Summary'].hasOwnProperty('read3')){ + //error rates per read and per lane + sum['err1']=Array(-1,0,0,0,0,0,0,0,0); + sum['err2']=Array(-1,0,0,0,0,0,0,0,0); + sum['err3']=Array(-1,0,0,0,0,0,0,0,0); + for(i=1;i<4;i++){ + for(lane in doc['illumina']['Summary']['read'+i]){ + sum['err'+i][lane]=doc['illumina']['Summary']['read'+i][lane]['ErrRatePhiX']; + } + } + } + } + if (doc['illumina'].hasOwnProperty('Demultiplex_Stats') && doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Lanes_stats')){ + lanedata=Object(); + for (idx in doc['illumina']['Demultiplex_Stats']['Lanes_stats']){ + ld=doc['illumina']['Demultiplex_Stats']['Lanes_stats'][idx]; + if ('Clusters' in ld){ + var cltk = 'Clusters'; + } else if ('PF Clusters' in ld){ + var cltk = "PF Clusters"; + } + Subset=Object(); + Subset['clustersnb']=ld[cltk]; + lane = ld['Lane']; + Subset['yield']=ld['Yield (Mbases)']; + Subset['overthirty']=ld['% >= Q30bases']; + Subset['mqs']=ld['Mean QualityScore']; + Subset['perf']=ld['% Perfectbarcode']; + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_summary') && doc.lims_data.run_summary[lane].hasOwnProperty('% phiX')){ + Subset['phix']=doc.lims_data.run_summary[lane]['% phiX']; + } + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_summary') && doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R1')){ + var er_rate=doc.lims_data.run_summary[lane]['% Error Rate R1']; + if (doc.lims_data.run_summary[lane].hasOwnProperty('% Error Rate R2') && doc.lims_data.run_summary[lane]['% Error Rate R2'] != 0){ + er_rate=(er_rate+doc.lims_data.run_summary[lane]['% Error Rate R2'])/2; + } + Subset['er_rate']=er_rate; + } + lanedata[lane]=Subset; + + } + sum['lanedata']=lanedata; + } + if (doc['illumina'].hasOwnProperty('Demultiplex_Stats') && doc['illumina']['Demultiplex_Stats'].hasOwnProperty('Barcode_lane_statistics') && doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'].length >0){ + sum['lane']=Object(); + //lanes are arrays of subsets + sum['lane']['1']=Array(); + sum['lane']['2']=Array(); + sum['lane']['3']=Array(); + sum['lane']['4']=Array(); + sum['lane']['5']=Array(); + sum['lane']['6']=Array(); + sum['lane']['7']=Array(); + sum['lane']['8']=Array(); + sum['yields']=Array(-1,0,0,0,0,0,0,0,0); + sum['seq_qc']=Array(-1,0,0,0,0,0,0,0,0); + sum['demuldone']=true; + subsets=[]; + plist=[]; + pid_list=[]; + + for (lane in doc['illumina']['run_summary']){ + sum['seq_qc'][lane]=doc['illumina']['run_summary'][lane]['qc']; + } + + for (sample in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics']){ + id=doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][sample]; + //if(id['Project']==='Undetermined_indices'){ + // continue; + //} + //subsets are sample objects" + if ('Clusters' in id){ + var cstk='Clusters'; + } else if ('PF Clusters' in id){ + var cstk='PF Clusters'; + } else { + //We're doomed + var cstk="ERROR"; + } + Subset=Object(); + Subset['SampleName']=id['Sample']; + Subset['clustersnb']=id[cstk]; + proj_name = id['Project']; + plist.push(proj_name); + pid=id['Sample'].split('_')[0]; + if (pid !== "Undetermined") { + pid_list.push(pid); + } + Subset['Project']=proj_name; + + lane = id['Lane']; + Subset['lane']=lane; + Subset['yield']=id['Yield (Mbases)']; + sum['yields'][lane]+=parseInt(id['Yield (Mbases)'].replace(/,/g,"")); + Subset['overthirty']=id['% >= Q30bases']; + + Subset['barcode']=id['Barcode sequence']; + Subset['desc']=id['Description']; + + Subset['mqs']=id['Mean QualityScore']; + //THIS NUMBER IS UNRELIABLE, COMPUTE IT INSTEAD + //Subset['lanepc']=id['% of thelane']; + + var clnb=parseInt(id[cstk].replace(/,/g,"")); + var lane_clnb=0; + if("Lanes_stats" in doc["illumina"]["Demultiplex_Stats"]){ + for(idx in doc["illumina"]["Demultiplex_Stats"]["Lanes_stats"]){ + if(doc["illumina"]["Demultiplex_Stats"]["Lanes_stats"][idx]["Lane"] == lane){ + lane_clnb=parseInt(doc["illumina"]["Demultiplex_Stats"]["Lanes_stats"][idx][cstk].replace(/,/g,"")); + } + } + // here we get division by zero + if (lane_clnb==0) { + Subset['lanepc'] = 0; + } else { + Subset['lanepc'] = 100 * (clnb / lane_clnb); + } + } + subsets.push(Subset); + } + for (s in subsets){ + //order by lane + sum['lane'][subsets[s]['lane']].push(subsets[s]); + } + if ('Undetermined' in doc){ + sum['undetermined']=doc["Undetermined"]; + } + //clean duplicates + sum['plist']=plist.filter(function( item, index, inputArray ) { + return inputArray.indexOf(item) == index; + }); + sum['pid_list']=pid_list.filter(function( item, index, inputArray ) { + return inputArray.indexOf(item) == index; + }); + } + } + emit(sum.full_name, sum) +} diff --git a/StatusDB_views/x_flowcells/info/summary2_stats.map.js b/StatusDB_views/x_flowcells/info/summary2_stats.map.js new file mode 100644 index 0000000..306ba97 --- /dev/null +++ b/StatusDB_views/x_flowcells/info/summary2_stats.map.js @@ -0,0 +1,304 @@ +/* + Used by genomics-status at: flowcell page +*/ + +function (doc) { + sum=Object(); + sum['name']=doc['name']; + + if (doc['Json_Stats']) { + sum['short_name'] = doc['Json_Stats']['Flowcell']; + sum['full_name'] = doc['Json_Stats']['RunId']; + if ( doc['Json_Stats']['ConversionResults'][0]['DemuxResults'][0]['ReadMetrics'][1] ){ + sum['two_reads'] = true; + } else { + sum['two_reads'] = false; + } + } + else { + sum['full_name'] = doc.RunInfo.Id; + } + + if ('RunInfo' in doc) { + sum['instrument'] = doc.RunInfo.Instrument; + } + sum['run_setup'] = doc['run_setup']; + + // Defines instrument version, for threholds. + sum['run_mode']=''; + if (doc['RunParameters'].hasOwnProperty('ReagentKitVersion') && doc['RunParameters'].hasOwnProperty('RunParametersVersion') + && doc['RunParameters']['RunParametersVersion'].indexOf('MiSeq') != -1) { + if (doc.hasOwnProperty('lims_data') && doc['lims_data'].hasOwnProperty('run_type') && doc['lims_data']['run_type']!='null') { + sum['run_mode']='MiSeq ' + doc['lims_data']['run_type']; + } + else { + if (doc['RunParameters'].hasOwnProperty('Setup') && doc['RunParameters']['Setup'].hasOwnProperty('SupportMultipleSurfacesInUI') && doc['RunParameters']['Setup'].hasOwnProperty('NumTilesPerSwath')) { + if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='19') { + sum['run_mode']='MiSeq Version3'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='14') { + sum['run_mode']='MiSeq Version2'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='false' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='2') { + sum['run_mode']='MiSeq Version2Nano'; + } + else if (doc['RunParameters']['Setup']['SupportMultipleSurfacesInUI']=='true' && doc['RunParameters']['Setup']['NumTilesPerSwath']=='4') { + sum['run_mode']='MiSeq Version2Micro'; + } + else { + sum['run_mode']='MiSeq null'; + } + } + else { + sum['run_mode']='MiSeq ' + doc['RunParameters']['ReagentKitVersion']; + } + } + } else if (doc['RunParameters'].hasOwnProperty('Chemistry') && doc['RunParameters']['Chemistry'].indexOf('NextSeq')!=-1) { + sum['run_mode']=doc['RunParameters']['Chemistry']; + } else if (doc['RunParameters'].hasOwnProperty('InstrumentType') && doc['RunParameters'].hasOwnProperty('FlowCellMode') && doc['RunParameters']['InstrumentType'].indexOf('NextSeq 2000')!=-1) { + sum['run_mode']=doc['RunParameters']['InstrumentType'] + ' ' + doc['RunParameters']['FlowCellMode'].match(/P[1,2,3]/)[0]; + } else if (doc['RunParameters'].hasOwnProperty('Setup')){ + if (doc['RunParameters']['Setup'].hasOwnProperty('RunMode')){ + // HiSeq 2500 variant + sum['run_mode']=doc['RunParameters']['Setup']['RunMode']; + } else if (doc['RunParameters']['Setup'].hasOwnProperty('Index') + && doc['RunParameters']['Setup']['Index'].indexOf('HiSeq X')!=-1) { + sum['run_mode']='HiSeq X'; + } + } else if (doc['RunParameters'].hasOwnProperty('RfidsInfo') && doc['RunParameters']['RfidsInfo'].hasOwnProperty('FlowCellMode')) { + sum['run_mode']='NovaSeq ' + doc['RunParameters']['RfidsInfo']['FlowCellMode']; + } + else { + sum['run_mode']='UNDEFINED'; + } + + if (doc['illumina']['Summary'] && doc['illumina']['Summary']['read3']){ + //error rates per read and per lane + sum['err1']=Array(-1,0,0,0,0,0,0,0,0); + sum['err2']=Array(-1,0,0,0,0,0,0,0,0); + sum['err3']=Array(-1,0,0,0,0,0,0,0,0); + for(i=1;i<4;i++){ + for(lane in doc['illumina']['Summary']['read'+i]){ + sum['err'+i][lane]=doc['illumina']['Summary']['read'+i][lane]['ErrRatePhiX']; + } + } + } +// Lane level stuff + if (doc['Json_Stats'] && doc['Json_Stats']['ConversionResults']){ + lanedata=Object(); + undetDict=Object(); + for (laneNo in doc['Json_Stats']['ConversionResults']){ + id = doc['Json_Stats']['ConversionResults'][laneNo]; + Subset=Object(); + Subset['clustersnb']=parseInt(id['TotalClustersPF']); + Subset['clustersnb']=Subset['clustersnb'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + lane = id['LaneNumber']; + lanedata[lane]=Subset; + + Subset['exact_yield'] = id['Yield']; + + // Tallies mismatch % + Subset['perf'] = 0; + reads = 0; + for (sample in id['DemuxResults']){ + if ('IndexMetrics' in id['DemuxResults'][sample] ){ + reads = reads + id['DemuxResults'][sample]['NumberReads']; + for (bc in id['DemuxResults'][sample]['IndexMetrics']){ + Subset['perf'] = Subset['perf'] + id['DemuxResults'][sample]['IndexMetrics'][bc]['MismatchCounts'][0]; + + } + } + } + Subset['perf'] = ((Subset['perf']/reads)*100).toFixed(2); + + Subset['yield']=((Subset['exact_yield']/1000000).toFixed(0)).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + + //Subset['percpf']=100*(id['TotalClustersPF']/id['TotalClustersRaw']); + //Subset['percpf']=Subset['perf'].toFixed(2); + + + if (doc['illumina']['Demultiplex_Stats'] && doc['illumina']['Demultiplex_Stats']['Lanes_stats']){ + illid = doc['illumina']['Demultiplex_Stats']['Lanes_stats'][laneNo]; + Subset['overthirty']=illid['% >= Q30bases']; + Subset['mqs']=illid['Mean QualityScore']; + } + + if (doc['lims_data']){ + var er_rate=0; + if (doc['lims_data']['run_summary'][lane + ""]['% phiX']){ + Subset['phix']=doc.lims_data.run_summary[lane + ""]['% phiX'].toFixed(1); + } + if (doc['lims_data']['run_summary'][lane + ""]['% Error Rate R1']){ + er_rate=doc['lims_data']['run_summary'][lane + ""]['% Error Rate R1']; + } + if (doc['lims_data']['run_summary'][lane + ""]['% Error Rate R2']){ + er_rate=(er_rate + doc['lims_data']['run_summary'][lane + ""]['% Error Rate R2'])/2; + } + Subset['er_rate']=er_rate.toFixed(2) + } + + // Attach undetermined indexes + if (doc['Json_Stats']['UnknownBarcodes']){ + undetDict[lane + ""] = doc['Json_Stats']['UnknownBarcodes'][laneNo]['Barcodes']; + sum['undetermined'] = undetDict; + } + + } + sum['lanedata']=lanedata; + subsets.push(Subset); + } + +// See no reason to not always produce this. + sum['lane']=Object(); + //lanes are arrays of subsets + sum['lane']['1']=Array(); + sum['lane']['2']=Array(); + sum['lane']['3']=Array(); + sum['lane']['4']=Array(); + sum['lane']['5']=Array(); + sum['lane']['6']=Array(); + sum['lane']['7']=Array(); + sum['lane']['8']=Array(); + sum['yields']=Array(-1,0,0,0,0,0,0,0,0); + sum['seq_qc']=Array(-1,0,0,0,0,0,0,0,0); + + sum['demuldone']=true; + //Creates empty subset container + subsets=[]; + plist=[]; + + if ( doc['illumina']['run_summary'] ){ + for (lane in doc['illumina']['run_summary']){ + sum['seq_qc'][lane]=doc['illumina']['run_summary'][lane]['qc']; + } + } + + +// Sample specific data + if (doc['Json_Stats'] && doc['Json_Stats']['ConversionResults']){ + for (laneNo in doc['Json_Stats']['ConversionResults']){ + for (sample in doc['Json_Stats']['ConversionResults'][laneNo]['DemuxResults']){ + id=doc['Json_Stats']['ConversionResults'][laneNo]['DemuxResults'][sample]; + Subset=Object(); + Subset['SampleName']=id['SampleName']; + //Add commas, necessary for flowcell.html + Subset['clustersnb']=id['NumberReads'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + lane = doc['Json_Stats']['ConversionResults'][laneNo]['LaneNumber']; + Subset['lane']=lane; + + //Change this to use samplesheet_csv. + //check sample name and lane. Then snag the project and replace first underscore with a dot. + for (sheetsample in doc['samplesheet_csv']){ + if ('SampleName' in doc['samplesheet_csv'][sheetsample]){ + samplename = doc['samplesheet_csv'][sheetsample]['SampleName']; + } else { + samplename = doc['samplesheet_csv'][sheetsample]['Sample_Name']; + } + + if (doc['samplesheet_csv'][sheetsample]['Lane'] == Subset['lane'] && + samplename == Subset['SampleName']){ + + if ('Project' in doc['samplesheet_csv'][sheetsample]){ + proj_name = doc['samplesheet_csv'][sheetsample]['Project']; + } else { + proj_name = doc['samplesheet_csv'][sheetsample]['Sample_Project']; + } + + // Add project radio buttons to flowcell page + plist.push(proj_name); + + //Replace first underscore(s). Done afterwards because fc page is insane. + proj_name = proj_name.replace("__", "."); + if (proj_name.indexOf("_") == 1){ + proj_name = proj_name.replace("_", "."); + } + Subset['Project']=proj_name; + break; + } + } + + //Legacy stuff, unsure about purpose + sum['yields'][lane] += doc['Json_Stats']['ConversionResults'][laneNo]['Yield']; + + Subset['yield']=(id['Yield']/1000000).toFixed(2) + ''; + Subset['yield']=Subset['yield'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + + + Subset['overthirty_r1'] = (100*(id['ReadMetrics'][0]['YieldQ30']/id['ReadMetrics'][0]['Yield'])).toFixed(2); + bcList=[]; + + if ( id['IndexMetrics'] ) { + if ( id['IndexMetrics'][1] ) { + for (index in id['IndexMetrics']){ + bcList.push(id['IndexMetrics'][index]['IndexSequence']); + } + Subset['multi_barcode']=bcList; + } + else { + Subset['barcode']=id['IndexMetrics'][0]['IndexSequence']; + } + } else { + Subset['barcode']="unknown"; + } + //Subset['desc']=id['Description']; Omitting this one, hopefully irrelevant + //Subset['mqs_r1'] = (id['ReadMetrics'][0]['QualityScoreSum']/id['ReadMetrics'][0]['Yield']).toFixed(2); + //Subset['zeromismatchpc'] = (100*id['IndexMetrics']['0']['MismatchCounts']['0']/id['NumberReads']).toFixed(1); + + if ( id['ReadMetrics'][1] ) { + // Q30 reads of R1+R2, divided by yield + Subset['overthirty']=(100*((id['ReadMetrics'][0]['YieldQ30']+id['ReadMetrics'][1]['YieldQ30']))/id['Yield']).toFixed(2); + Subset['overthirty_r2'] = (100*(id['ReadMetrics'][1]['YieldQ30']/id['ReadMetrics'][1]['Yield'])).toFixed(2); + Subset['mqs']=((id['ReadMetrics'][0]['QualityScoreSum']+id['ReadMetrics'][1]['QualityScoreSum'])/id['Yield']).toFixed(1); + Subset['lanepc']=(100*((id['ReadMetrics'][0]['Yield']+id['ReadMetrics'][1]['Yield'])/sum['lanedata'][lane]['exact_yield'])).toFixed(2); + //Subset['mqs_r2'] = (id['ReadMetrics'][1]['QualityScoreSum']/id['ReadMetrics'][1]['Yield']).toFixed(2); + } else { + Subset['overthirty']=((100*id['ReadMetrics'][0]['YieldQ30'])/id['Yield']).toFixed(2); + Subset['mqs']=(id['ReadMetrics'][0]['QualityScoreSum']/id['Yield']).toFixed(1); + Subset['lanepc']=(100*(id['ReadMetrics'][0]['Yield']/sum['lanedata'][lane]['exact_yield'])).toFixed(2); + } + subsets.push(Subset); + } + // Adding undetermined sample + // Could possibly put this as an if case in the loop + if ( doc['Json_Stats']['ConversionResults'][laneNo]['Undetermined'] ){ + und_id=doc['Json_Stats']['ConversionResults'][laneNo]['Undetermined'] + if ( und_id['Yield'] != 0 ){ + Subset=Object(); + Subset['SampleName']='Undetermined'; + Subset['clustersnb']=und_id['NumberReads'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + Subset['Project']="default"; + Subset['barcode']="unknown"; + Subset['lane']=doc['Json_Stats']['ConversionResults'][laneNo]['LaneNumber']; + Subset['yield']=(und_id['Yield']/1000000).toFixed(2) + ''; + Subset['yield']=Subset['yield'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + Subset['overthirty_r1'] = (100*(und_id['ReadMetrics'][0]['YieldQ30']/und_id['ReadMetrics'][0]['Yield'])).toFixed(2); + + if ( und_id['ReadMetrics'][1] ) { + Subset['overthirty']=(100*((und_id['ReadMetrics'][0]['YieldQ30']+und_id['ReadMetrics'][1]['YieldQ30']))/id['Yield']).toFixed(2); + Subset['overthirty_r2'] = (100*(und_id['ReadMetrics'][1]['YieldQ30']/und_id['ReadMetrics'][1]['Yield'])).toFixed(2); + Subset['mqs']=((und_id['ReadMetrics'][0]['QualityScoreSum']+und_id['ReadMetrics'][1]['QualityScoreSum'])/und_id['Yield']).toFixed(1); + Subset['lanepc']=(100*((und_id['ReadMetrics'][0]['Yield']+und_id['ReadMetrics'][1]['Yield'])/sum['lanedata'][lane]['exact_yield'])).toFixed(2); + } else { + Subset['overthirty']=((100*und_id['ReadMetrics'][0]['YieldQ30'])/id['Yield']).toFixed(2); + Subset['mqs']=(und_id['ReadMetrics'][0]['QualityScoreSum']/und_id['Yield']).toFixed(1); + Subset['lanepc']=(100*(und_id['ReadMetrics'][0]['Yield']/sum['lanedata'][lane]['exact_yield'])).toFixed(2); + } + subsets.push(Subset); + } + } + } + } + + //For each subset + for (s in subsets){ + //order by lane + //Push data for subset x to sum['lane']['subset X's laneNo'] + sum['lane'][subsets[s]['lane']].push(subsets[s]); + } + + //clean duplicates + sum['plist']=plist.filter(function( item, index, inputArray ) { + return inputArray.indexOf(item) == index; + }); + emit(sum.full_name, sum) +} diff --git a/StatusDB_views/x_flowcells/lanes/clusters.map.js b/StatusDB_views/x_flowcells/lanes/clusters.map.js new file mode 100644 index 0000000..c1310e4 --- /dev/null +++ b/StatusDB_views/x_flowcells/lanes/clusters.map.js @@ -0,0 +1,21 @@ +function(doc) { + var key=''; + var vk = ''; + var obj={}; + var cl=0; + if ('RunParameters' in doc && 'Setup' in doc['RunParameters'] && 'Flowcell' in doc['RunParameters']['Setup'] && doc['RunParameters']['Setup']['Flowcell'].indexOf('HiSeq X') != -1){ + if ('illumina' in doc && 'Demultiplex_Stats' in doc['illumina'] && 'Lanes_stats' in doc['illumina']['Demultiplex_Stats']){ + for (laneid in doc['illumina']['Demultiplex_Stats']['Lanes_stats']){ + vk=doc['RunInfo']['Id']+':'+doc['illumina']['Demultiplex_Stats']['Lanes_stats'][laneid]['Lane']; + if ('Clusters' in doc['illumina']['Demultiplex_Stats']['Lanes_stats'][laneid]){ + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Lanes_stats'][laneid]['Clusters'].replace(/,/g,'')); + }else if('PF Clusters' in doc['illumina']['Demultiplex_Stats']['Lanes_stats'][laneid]){ + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Lanes_stats'][laneid]['PF Clusters'].replace(/,/g,'')); + } + + emit(vk, cl); + + } + } + } +} \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/names/id_to_name.map.js b/StatusDB_views/x_flowcells/names/id_to_name.map.js new file mode 100644 index 0000000..cdc11c8 --- /dev/null +++ b/StatusDB_views/x_flowcells/names/id_to_name.map.js @@ -0,0 +1,3 @@ +function(doc) { + emit(doc["_id"], doc["name"]); +} diff --git a/StatusDB_views/x_flowcells/names/name.map.js b/StatusDB_views/x_flowcells/names/name.map.js new file mode 100644 index 0000000..e179252 --- /dev/null +++ b/StatusDB_views/x_flowcells/names/name.map.js @@ -0,0 +1,8 @@ +function(doc) { + // NovaSeq X Plus has more digits in the date, will mess up the sorting if not adjusted + name_arr = doc["name"].split("_") + run_date_original = name_arr[0] + run_date = run_date_original.slice(-6) + modified_name = [run_date, name_arr[1]].join('_') + emit(modified_name, null); +} diff --git a/StatusDB_views/x_flowcells/names/project_ids_list.map.js b/StatusDB_views/x_flowcells/names/project_ids_list.map.js new file mode 100644 index 0000000..0cebfac --- /dev/null +++ b/StatusDB_views/x_flowcells/names/project_ids_list.map.js @@ -0,0 +1,17 @@ +function(doc) { + var proj_in_fc = {} + for (sample in doc["samplesheet_csv"]){ + if ("SampleName" in doc["samplesheet_csv"][sample]) { + var proj_id = doc["samplesheet_csv"][sample]["SampleName"].split("_")[0] + } else { + var proj_id = doc["samplesheet_csv"][sample]["Sample_Name"].split("_")[0] + } + proj_in_fc[proj_id] = true + } + // NovaSeq X Plus has more digits in the date, will mess up the sorting if not adjusted + name_arr = doc["name"].split("_") + run_date_original = name_arr[0] + run_date = run_date_original.slice(-6) + modified_name = [run_date, name_arr[1]].join('_') + emit(modified_name, Object.keys(proj_in_fc)) +} diff --git a/StatusDB_views/x_flowcells/plot/count.map.js b/StatusDB_views/x_flowcells/plot/count.map.js new file mode 100644 index 0000000..c32f384 --- /dev/null +++ b/StatusDB_views/x_flowcells/plot/count.map.js @@ -0,0 +1,18 @@ +function(doc) { + var date = doc.RunInfo.Id; + var instrument = doc.RunInfo.Instrument; + var key = [instrument]; + key.push("20"+date.substr(0,2)); + key.push(date.substr(2,2)); + + // Now hell begins + var d = new Date(key[1], key[2]-1, parseInt(date.substr(4,2),10)); + var thursday_of_that_week = d.setDate(d.getDate()-d.getDay()+4); + var first_thursday = new Date(d.getFullYear(), 0, 1+((4 - new Date(d.getFullYear(),0,1).getDay() + 7) % 7)); + var week_nb = 1 + Math.ceil((thursday_of_that_week - first_thursday) / 604800000); + key.push(week_nb); + // end of hell + key.push(date.substr(4,2)); + + emit(key, 1); +} \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/plot/count.reduce.js b/StatusDB_views/x_flowcells/plot/count.reduce.js new file mode 100644 index 0000000..768b109 --- /dev/null +++ b/StatusDB_views/x_flowcells/plot/count.reduce.js @@ -0,0 +1 @@ +_count \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/plot/reads_yield.map.js b/StatusDB_views/x_flowcells/plot/reads_yield.map.js new file mode 100644 index 0000000..82e55ed --- /dev/null +++ b/StatusDB_views/x_flowcells/plot/reads_yield.map.js @@ -0,0 +1,63 @@ +function(doc) { + var key = doc.RunInfo.Id; + data={}; + data['id']=key; + data['instrument']=doc.RunInfo.Instrument; + if (data.instrument.indexOf('M') != -1){ + var ar = doc.RunParameters.ReagentKitVersion.split(" "); + data['cver'] = ar[ar.length-1]; + //Added to fetch the Nano runs, 2 tiles for Nano + data['mode'] = doc.RunParameters.Setup.NumTilesPerSwath; + }else if (data.instrument.indexOf('D') != -1) { + var ar = doc.RunParameters.Setup.Flowcell.split(" "); + data['cver'] = ar[ar.length-1]; + if (doc.RunParameters.Setup.Flowcell.indexOf("Rapid") != -1){ + data['mode'] = "Rapid"; + }else{ + data['mode'] = "HighOutput"; + } + }else if (data.instrument.indexOf('A') != -1) { + //Note: Rethink this. What does mode and chemistry v. really mean? + data['mode'] = doc.RunParameters.RfidsInfo.FlowCellMode; + data['cver'] = doc.RunParameters.RfidsInfo.FlowCellMode; + }else if (data.instrument.indexOf('N') != -1) { + var ar = doc.RunParameters.Chemistry.split(" "); + data['cver'] = ar[ar.length-1]; + if (doc.RunParameters.Chemistry.indexOf("Mid") != -1){ + data['mode'] = "Mid"; + }else{ + data['mode'] = "High"; + } + }else if (data.instrument.indexOf('VH') != -1) { + var ar = doc.RunParameters.FlowCellMode.match(/P[1,2,3]/)[0]; + data['cver'] = "NextSeq 2000" + ' ' + ar; + }else if (data.instrument.indexOf('LH') != -1) { + // NovaSeq X Plus has more digits in the date, will mess up the sorting if not adjusted + key = key.slice(2); + data['mode'] = doc.RunParameters.RecipeName.replace(' Sequencing',''); + data['cver'] = doc.RunParameters.RecipeName.replace(' Sequencing',''); + }else{ + var ar = doc.RunParameters.Setup.Flowcell.split(" "); + data['cver'] = ar[ar.length-1]; + } + + data['total_clusters'] = parseInt(doc.illumina.Demultiplex_Stats.Flowcell_stats['Clusters(PF)'].replace(/,/g,'')); + data['total_yield'] = parseInt(doc.illumina.Demultiplex_Stats.Flowcell_stats['Yield (MBases)'].replace(/,/g,''))*1000000; + data['lanes']=[]; + var onelane=null; + for (lane in doc.illumina.Demultiplex_Stats.Lanes_stats){ + laneobj={}; + onelane=doc.illumina.Demultiplex_Stats.Lanes_stats[lane]; + laneobj['lane']=onelane['Lane']; + laneobj['total_yield']=parseInt(onelane['Yield (Mbases)'].replace(/,/g, ''))*1000000; + laneobj['total_clusters']=parseInt(onelane['PF Clusters'].replace(/,/g, '')); + laneobj['mqs']=parseFloat(onelane['Mean QualityScore']); + laneobj['perfect_match_pc']=parseFloat(onelane['% Perfectbarcode']); + laneobj['one_mismatch_pc']=parseFloat(onelane['% One mismatchbarcode']); + laneobj['overeq_q30_pc']=parseFloat(onelane['% >= Q30bases']); + + data['lanes'].push(laneobj); + } + + emit(key, data); +} diff --git a/StatusDB_views/x_flowcells/projects/fc_lane_ss.map.js b/StatusDB_views/x_flowcells/projects/fc_lane_ss.map.js new file mode 100644 index 0000000..f11d8ef --- /dev/null +++ b/StatusDB_views/x_flowcells/projects/fc_lane_ss.map.js @@ -0,0 +1,10 @@ +function(doc) { + for (row in doc.samplesheet_csv){ + var fc = doc.RunInfo.Id; + var lane = doc.samplesheet_csv[row].Lane; + var pj = doc.samplesheet_csv[row].Sample_Project; + if (pj != null){ + emit([pj, fc,lane], doc.samplesheet_csv[row]); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/projects/projects_lanes.map.js b/StatusDB_views/x_flowcells/projects/projects_lanes.map.js new file mode 100644 index 0000000..3f6fe06 --- /dev/null +++ b/StatusDB_views/x_flowcells/projects/projects_lanes.map.js @@ -0,0 +1,9 @@ +function(doc) { + for (row in doc.samplesheet_csv){ + var value = doc.RunInfo.Id + ":" + doc.samplesheet_csv[row].Lane; + var pj = doc.samplesheet_csv[row].Sample_Project; + if (pj != null){ + emit([pj, value], null); + } + } + } \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/projects/projects_lanes.reduce.js b/StatusDB_views/x_flowcells/projects/projects_lanes.reduce.js new file mode 100644 index 0000000..8e6b0a5 --- /dev/null +++ b/StatusDB_views/x_flowcells/projects/projects_lanes.reduce.js @@ -0,0 +1,3 @@ +function (key, values, rereduce) { + return null +} \ No newline at end of file diff --git a/StatusDB_views/x_flowcells/samples/lane_clusters.map.js b/StatusDB_views/x_flowcells/samples/lane_clusters.map.js new file mode 100644 index 0000000..7c09bca --- /dev/null +++ b/StatusDB_views/x_flowcells/samples/lane_clusters.map.js @@ -0,0 +1,50 @@ +function(doc) { + var key=''; + var vk = ''; + var obj={}; + var cl=0; + var l_seen_once=[]; + var s_seen_once=[]; + var l_seen_twice=[]; + if ('illumina' in doc && 'Demultiplex_Stats' in doc['illumina'] && 'Barcode_lane_statistics' in doc['illumina']['Demultiplex_Stats']){ + for (barcode in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics']){ + key=doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Sample']; + if (key.indexOf("Sample_")!= -1){ + key=key.substr(7); + } + vk=doc['RunInfo']['Id']+':'+doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Lane']; + if ('Clusters' in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]){ + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Clusters'].replace(/,/g,'')); + }else if('PF Clusters' in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]){ + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['PF Clusters'].replace(/,/g,'')); + } + q30=parseFloat(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['% >= Q30bases']); + obj={fcp: vk,cl : cl, q30 : q30}; + + if (['', 'Undetermined', 'unknown'].indexOf(key)== -1){ + if (l_seen_once.indexOf(obj.fcp) != -1){ + l_seen_twice.push(obj.fcp); + }else{ + l_seen_once.push(obj.fcp); + s_seen_once.push(key); + } + emit(key, obj); + } + } + for (barcode in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics']){ + vk=doc['RunInfo']['Id']+':'+doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Lane']; + if (['', 'Undetermined', 'unknown'].indexOf(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Sample']) != -1 && l_seen_once.indexOf(vk) != -1 && l_seen_twice.indexOf(vk)==-1){ + key=s_seen_once[l_seen_once.indexOf(vk)]; + if ('Clusters' in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]){ + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['Clusters'].replace(/,/g,'')); + }else if('PF Clusters' in doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]){ + cl=parseInt(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['PF Clusters'].replace(/,/g,'')); + } + q30=parseFloat(doc['illumina']['Demultiplex_Stats']['Barcode_lane_statistics'][barcode]['% >= Q30bases']); + vk=vk + "_UD"; + obj={fcp: vk,cl : cl, q30 : q30}; + emit(key,obj); + } + } + } +} \ No newline at end of file diff --git a/scripts/init-seed-data.sh b/scripts/init-seed-data.sh index f7e04ec..f0821fd 100644 --- a/scripts/init-seed-data.sh +++ b/scripts/init-seed-data.sh @@ -6,8 +6,12 @@ COUCHDB_HOST="${COUCHDB_HOST:-localhost}" COUCHDB_PORT="${COUCHDB_PORT:-5984}" COUCHDB_USER="${COUCHDB_USER:-admin}" COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-admin}" -SEED_DIR="${SEED_DIR:-/opt/couchdb/seed}" +SEED_DIR="${SEED_DIR:-/opt/couchdb/seed_data}" +DESIGN_DOCS_DIR="${DESIGN_DOCS_DIR:-/opt/couchdb/design_docs_build}" INIT_MARKER="/opt/couchdb/data/.seed_initialized" +SCENARIO="${SCENARIO:-stage}" +VIEWS_CONFIG="${VIEWS_CONFIG:-/opt/couchdb/views_config.yaml}" +VIEWS_DIR="${VIEWS_DIR:-/opt/couchdb/StatusDB_views}" COUCHDB_URL="http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@${COUCHDB_HOST}:${COUCHDB_PORT}" @@ -105,6 +109,7 @@ load_seed_data() { done # Also load any top-level JSON files into a 'statusdb' database (legacy support) + echo "Processing top-level JSON files for 'statusdb'..." local has_toplevel_json=false for json_file in "$SEED_DIR"/*.json; do if [ -f "$json_file" ]; then @@ -119,6 +124,55 @@ load_seed_data() { echo "Seed data loading complete!" } +# Deploy design documents based on scenario +create_design_docs() { + echo "Deploying design documents for scenario: ${SCENARIO}..." + + if [ ! -f "$VIEWS_CONFIG" ]; then + echo "Views config not found: ${VIEWS_CONFIG}" + return 0 + fi + + if [ ! -d "$VIEWS_DIR" ]; then + echo "Views directory not found: ${VIEWS_DIR}" + return 0 + fi + + python3 /opt/couchdb/scripts/validate_views_config.py \ + --build \ + --scenario "$SCENARIO" \ + --config "$VIEWS_CONFIG" \ + --views-dir "$VIEWS_DIR" \ + --design_docs_dir "$DESIGN_DOCS_DIR" + + echo "Design documents deployment complete!" +} + +deploy_design_docs() { + echo "Deploying design documents from ${DESIGN_DOCS_DIR}..." + + if [ ! -d "$DESIGN_DOCS_DIR" ]; then + echo "Design docs directory not found: ${DESIGN_DOCS_DIR}" + return 0 + fi + + for db_dir in "$DESIGN_DOCS_DIR"/*/; do + if [ -d "$db_dir" ]; then + local db_name=$(basename "$db_dir") + echo "Processing design docs for database: ${db_name}" + create_database "$db_name" + + for json_file in "$db_dir"/*.json; do + if [ -f "$json_file" ]; then + load_document "$db_name" "$json_file" + fi + done + fi + done + + echo "Design documents deployment complete!" +} + # Main execution main() { # Check if we've already initialized @@ -129,7 +183,9 @@ main() { wait_for_couchdb create_system_databases + create_design_docs load_seed_data + deploy_design_docs # Create marker file to indicate initialization is complete touch "$INIT_MARKER" diff --git a/scripts/validate_views_config.py b/scripts/validate_views_config.py new file mode 100644 index 0000000..3a377c1 --- /dev/null +++ b/scripts/validate_views_config.py @@ -0,0 +1,206 @@ +import yaml +from pathlib import Path +import argparse +import json +import urllib.request +import urllib.error +from base64 import b64encode + +def scan_views_directory(views_dir): + """Scan the views directory and return a config-like structure.""" + databases = {} + if not views_dir.exists(): + return {"databases": databases} + + for db_path in sorted(views_dir.iterdir()): + if not db_path.is_dir(): + continue + db_name = db_path.name + databases[db_name] = {"design_docs": {}} + for item in sorted(db_path.iterdir()): + if item.is_dir(): + design_doc_name = item.name + databases[db_name]["design_docs"][design_doc_name] = {"views": {}} + for view_file in sorted(item.glob("*.map.js")): + view_name = view_file.stem.replace('.map', '') + reduce_file = item / f"{view_name}.reduce.js" + databases[db_name]["design_docs"][design_doc_name]["views"][view_name] = { + "reduce": reduce_file.exists() + } + elif item.is_dir() and item.name == "_design": + for design_doc_path in sorted(item.iterdir()): + if design_doc_path.is_dir(): + design_doc_name = design_doc_path.name + databases[db_name]["design_docs"][design_doc_name] = {"views": {}} + for view_file in sorted(design_doc_path.glob("*.map.js")): + view_name = view_file.stem.replace(".map", "") + reduce_file = design_doc_path / f"{view_name}.reduce.js" + databases[db_name]["design_docs"][design_doc_name]["views"][view_name] = { + "reduce": reduce_file.exists() + } + return {"databases": databases} + +def load_config(config_path): + """Load the existing config file.""" + if not config_path.exists(): + return {"databases": {}} + with open(config_path, "r") as f: + return yaml.safe_load(f) or {"databases": {}} + +def save_config(config, config_path): + """Save the config to file.""" + with open(config_path, "w") as f: + yaml.dump(config, f, default_flow_style=False, sort_keys=False) + +def compare_and_report(scanned_config, loaded_config): + """Compare scanned and loaded configs, report differences.""" + scanned_dbs = scanned_config.get("databases", {}) + loaded_dbs = loaded_config.get("databases", {}) + all_ok = True + + for db_name in scanned_dbs: + if db_name not in loaded_dbs: + print(f"❌ Database '{db_name}' is in directory but missing from config") + all_ok = False + continue + for doc_name in scanned_dbs[db_name].get("design_docs", {}): + if doc_name not in loaded_dbs[db_name].get("design_docs", {}): + print(f"❌ Design doc '{doc_name}' in '{db_name}' is in directory but missing from config") + all_ok = False + continue + for view_name, view_config in scanned_dbs[db_name]["design_docs"][doc_name].get("views", {}).items(): + if view_name not in loaded_dbs[db_name]["design_docs"][doc_name].get("views", {}): + print(f"❌ View '{view_name}' in '{db_name}/{doc_name}' is in directory but missing from config") + all_ok = False + elif view_config.get("reduce") != loaded_dbs[db_name]["design_docs"][doc_name]["views"][view_name].get("reduce"): + print(f"⚠️ Reduce flag mismatch for '{view_name}' in '{db_name}/{doc_name}'") + + for db_name in loaded_dbs: + if db_name not in scanned_dbs: + print(f"⚠️ Database '{db_name}' is in config but missing from directory") + all_ok = False + continue + for doc_name in loaded_dbs[db_name].get("design_docs", {}): + if doc_name not in scanned_dbs[db_name].get("design_docs", {}): + print(f"⚠️ Design doc '{doc_name}' in '{db_name}' is in config but missing from directory") + all_ok = False + continue + for view_name in loaded_dbs[db_name]["design_docs"][doc_name].get("views", {}): + if view_name not in scanned_dbs[db_name]["design_docs"][doc_name].get("views", {}): + print(f"⚠️ View '{view_name}' in '{db_name}/{doc_name}' is in config but missing from directory") + all_ok = False + + if all_ok: + print("✅ Config is up to date with directory structure") + return all_ok + +def update_config(scanned_config, loaded_config): + """Update the loaded config to match the scanned structure, preserving scenarios.""" + updated_config = {"databases": {}} + for db_name, db_data in scanned_config.get("databases", {}).items(): + updated_config["databases"][db_name] = {"design_docs": {}} + for doc_name, doc_data in db_data.get("design_docs", {}).items(): + updated_config["databases"][db_name]["design_docs"][doc_name] = {"views": {}} + for view_name, view_config in doc_data.get("views", {}).items(): + # Get existing scenarios list, default to ["stage"] + scenarios = loaded_config.get("databases", {}).get(db_name, {}).get("design_docs", {}).get(doc_name, {}).get("views", {}).get(view_name, {}).get("scenarios", ["stage"]) + updated_config["databases"][db_name]["design_docs"][doc_name]["views"][view_name] = { + "reduce": view_config["reduce"], + "scenarios": scenarios + } + return updated_config + +def filter_views_by_scenario(config, scenario): + """Filter views that include the specified scenario.""" + filtered = {"databases": {}} + for db_name, db_data in config.get("databases", {}).items(): + filtered["databases"][db_name] = {"design_docs": {}} + for doc_name, doc_data in db_data.get("design_docs", {}).items(): + views = {} + for view_name, view_config in doc_data.get("views", {}).items(): + if scenario in view_config.get("scenarios", []): + views[view_name] = view_config + if views: + filtered["databases"][db_name]["design_docs"][doc_name] = {"views": views} + if not filtered["databases"][db_name]["design_docs"]: + del filtered["databases"][db_name] + return filtered + +def build_design_doc(db_name, doc_name, views_config, views_dir): + """Build a CouchDB design document from view files.""" + design_doc = { + "_id": f"_design/{doc_name}", + "language": "javascript", + "views": {} + } + + doc_path = views_dir / db_name / doc_name + if not doc_path.exists(): + return None + + for view_name, view_config in views_config.items(): + map_file = doc_path / f"{view_name}.map.js" + if not map_file.exists(): + continue + + design_doc["views"][view_name] = { + "map": map_file.read_text() + } + + if view_config.get("reduce"): + reduce_file = doc_path / f"{view_name}.reduce.js" + if reduce_file.exists(): + design_doc["views"][view_name]["reduce"] = reduce_file.read_text() + + return design_doc if design_doc["views"] else None + +def build_design_docs(config, views_dir, design_docs_dir): + """Build design documents for deployment.""" + design_docs_dir = Path(design_docs_dir) + design_docs_dir.mkdir(parents=True, exist_ok=True) + + for db_name, db_data in config.get("databases", {}).items(): + db_dir = design_docs_dir / db_name + db_dir.mkdir(parents=True, exist_ok=True) + + for doc_name, doc_data in db_data.get("design_docs", {}).items(): + design_doc = build_design_doc(db_name, doc_name, doc_data.get("views", {}), views_dir) + if not design_doc: + continue + + doc_file = db_dir / f"{doc_name}.json" + doc_file.write_text(json.dumps(design_doc, indent=2)) + print(f"✅ Built {db_name}/{doc_name}.json") + + + +def main(): + parser = argparse.ArgumentParser(description="Check or update CouchDB views config based on directory structure.") + parser.add_argument("--config", default="config.yaml", help="Path to config file") + parser.add_argument("--views-dir", default="views", help="Path to views directory") + parser.add_argument("--check", action="store_true", help="Check if config is up to date") + parser.add_argument("--update", action="store_true", help="Update config to match directory structure") + parser.add_argument("--build", action="store_true", help="Build design documents for deployment") + parser.add_argument("--scenario", default="stage", help="Scenario to deploy (default: stage)") + parser.add_argument("--design_docs_dir", default="design_docs_build", help="Directory to build design docs for deployment") + args = parser.parse_args() + + views_dir = Path(args.views_dir) + config_path = Path(args.config) + scanned_config = scan_views_directory(views_dir) + loaded_config = load_config(config_path) + + if args.build: + filtered_config = filter_views_by_scenario(loaded_config, args.scenario) + print(f"Building design documents for scenario: {args.scenario}") + build_design_docs(filtered_config, views_dir, args.design_docs_dir) + elif args.update: + updated_config = update_config(scanned_config, loaded_config) + save_config(updated_config, config_path) + print(f"✅ Config updated to match directory structure. File saved to {config_path}") + compare_and_report(scanned_config, loaded_config) + else: + compare_and_report(scanned_config, loaded_config) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/seed/agreements/_design_project.json b/seed/agreements/_design_project.json deleted file mode 100644 index e674061..0000000 --- a/seed/agreements/_design_project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "_design/project", - "views": { - "project_id": { - "map": "function(doc) { if (doc.project_id) { emit(doc.project_id, doc); } }" - } - } -} diff --git a/seed/example_project.json b/seed/example_project.json deleted file mode 100644 index 3779f3b..0000000 --- a/seed/example_project.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "_id": "project_001", - "type": "project", - "name": "Example Genomics Project", - "project_id": "P12345", - "application": "Whole Genome Sequencing", - "status": "ongoing", - "created": "2025-11-14T10:00:00Z", - "updated": "2025-11-14T10:00:00Z", - "contact": { - "name": "John Doe", - "email": "john.doe@example.com", - "affiliation": "Example University" - }, - "samples": [ - { - "sample_id": "S001", - "sample_name": "Sample_A", - "organism": "Homo sapiens", - "tissue": "blood", - "collection_date": "2025-10-01" - }, - { - "sample_id": "S002", - "sample_name": "Sample_B", - "organism": "Homo sapiens", - "tissue": "tissue", - "collection_date": "2025-10-02" - } - ], - "sequencing_runs": [ - { - "run_id": "RUN001", - "instrument": "NovaSeq 6000", - "date": "2025-11-01", - "lanes": 2, - "read_length": "2x150" - } - ], - "metadata": { - "budget_code": "GRANT-2025-001", - "priority": "normal", - "notes": "Initial test data for StatusDB development" - } -} diff --git a/seed/gs_users/_design_authorized.json b/seed/gs_users/_design_authorized.json deleted file mode 100644 index 1b25cc0..0000000 --- a/seed/gs_users/_design_authorized.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "_id": "_design/authorized", - "views": { - "users": { - "map": "function(doc) { if (doc.email) { emit(doc.email, doc); } }" - }, - "info": { - "map": "function(doc) { if (doc.email) { emit(doc.email, {name: doc.name, initials: doc.initials, roles: doc.roles, teams: doc.teams}); } }" - } - } -} diff --git a/seed/people_assignments/_design_current.json b/seed/people_assignments/_design_current.json deleted file mode 100644 index 14da720..0000000 --- a/seed/people_assignments/_design_current.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "_design/current", - "views": { - "assignments": { - "map": "function(doc) { if (doc.project_id && doc.assigned_to) { emit(doc.project_id, doc.assigned_to); } }" - } - } -} diff --git a/seed/projects/_design_project.json b/seed/projects/_design_project.json deleted file mode 100644 index 67a7ad6..0000000 --- a/seed/projects/_design_project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "_design/project", - "views": { - "summary_status": { - "map": "function(doc) { if (doc.status) { emit([doc.status, doc.project_id], doc); } }" - } - } -} diff --git a/seed/running_notes/_design_latest_note_previews.json b/seed/running_notes/_design_latest_note_previews.json deleted file mode 100644 index 2b140e7..0000000 --- a/seed/running_notes/_design_latest_note_previews.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "_id": "_design/latest_note_previews", - "views": { - "project": { - "map": "function(doc) { if (doc.project_id && doc.created_at_utc) { emit(doc.project_id, {created_at_utc: doc.created_at_utc, note: doc.note}); } }", - "reduce": "_stats" - } - } -} diff --git a/seed/sensorpush/_design_entire_document.json b/seed/sensorpush/_design_entire_document.json deleted file mode 100644 index b3c51da..0000000 --- a/seed/sensorpush/_design_entire_document.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "_design/entire_document", - "views": { - "by_sensor_id_and_date": { - "map": "function(doc) { if (doc.sensor_id && doc.date) { emit([doc.sensor_id, doc.date], doc); } }" - } - } -} diff --git a/seed/sensorpush/_design_sensor_id.json b/seed/sensorpush/_design_sensor_id.json deleted file mode 100644 index fef6c07..0000000 --- a/seed/sensorpush/_design_sensor_id.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "_design/sensor_id", - "views": { - "by_date": { - "map": "function(doc) { if (doc.date && doc.sensor_id) { emit(doc.date, doc.sensor_id); } }" - } - } -} diff --git a/seed/server_status/_design_nases.json b/seed/server_status/_design_nases.json deleted file mode 100644 index 4a07e0c..0000000 --- a/seed/server_status/_design_nases.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "_design/nases", - "views": { - "by_timestamp": { - "map": "function(doc) { if (doc.timestamp) { emit(doc.timestamp, doc); } }" - } - } -} diff --git a/seed/server_status/example_status.json b/seed/server_status/example_status.json deleted file mode 100644 index 7be86ed..0000000 --- a/seed/server_status/example_status.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_id": "status_001", - "timestamp": "2025-12-05T09:00:00Z", - "name": "dev-nas-01", - "status": "ok", - "disk_usage": 50, - "disk_total": 100 -} diff --git a/seed/gs_configs/genstat_defaults.json b/seed_data/gs_configs/genstat_defaults.json similarity index 100% rename from seed/gs_configs/genstat_defaults.json rename to seed_data/gs_configs/genstat_defaults.json diff --git a/seed/gs_configs/gs_teams.json b/seed_data/gs_configs/gs_teams.json similarity index 100% rename from seed/gs_configs/gs_teams.json rename to seed_data/gs_configs/gs_teams.json diff --git a/seed/gs_users/test_admin.json b/seed_data/gs_users/test_admin.json similarity index 100% rename from seed/gs_users/test_admin.json rename to seed_data/gs_users/test_admin.json diff --git a/seed/projects/P12345.json b/seed_data/projects/P12345.json similarity index 100% rename from seed/projects/P12345.json rename to seed_data/projects/P12345.json diff --git a/seed/projects/P12346.json b/seed_data/projects/P12346.json similarity index 100% rename from seed/projects/P12346.json rename to seed_data/projects/P12346.json diff --git a/seed/projects/P12347.json b/seed_data/projects/P12347.json similarity index 100% rename from seed/projects/P12347.json rename to seed_data/projects/P12347.json diff --git a/seed_data/server_status/example_status.json b/seed_data/server_status/example_status.json new file mode 100644 index 0000000..aa747f7 --- /dev/null +++ b/seed_data/server_status/example_status.json @@ -0,0 +1,12 @@ +{ + "disk_size": "28T", + "space_used": "26T", + "space_available": "2T", + "used_percentage": "93%", + "available_percentage": "7%", + "mounted_on": "/data", + "filesystem": "/dev/md127", + "name": "promet.scilifelab.se", + "time": "2023-03-08T11:20:56.430212", + "server_type": "nas" +} diff --git a/views_config.yaml b/views_config.yaml new file mode 100644 index 0000000..0119769 --- /dev/null +++ b/views_config.yaml @@ -0,0 +1,2797 @@ +databases: + agreement_templates: + design_docs: + entire_document: + views: + by_version: + reduce: false + scenarios: + - stage + agreements: + design_docs: + entire_document: + views: + project_id: + reduce: false + scenarios: + - stage + project: + views: + project_id: + reduce: false + scenarios: + - stage + analysis: + design_docs: + multiqc: + views: + full_doc: + reduce: false + scenarios: + - stage + modules: + reduce: false + scenarios: + - stage + names: + views: + id_to_name: + reduce: false + scenarios: + - stage + process_flow: + views: + KPI: + reduce: true + scenarios: + - stage + KPI_applications: + reduce: true + scenarios: + - stage + project: + views: + name2_id: + reduce: false + scenarios: + - stage + name2application: + reduce: false + scenarios: + - stage + name2customer_reference: + reduce: false + scenarios: + - stage + name2no_of_samples: + reduce: false + scenarios: + - stage + name2open_date: + reduce: false + scenarios: + - stage + name2project_id: + reduce: false + scenarios: + - stage + name2reference_genome: + reduce: false + scenarios: + - stage + name2uppnex_id: + reduce: false + scenarios: + - stage + project_id: + reduce: false + scenarios: + - stage + project_name: + reduce: false + scenarios: + - stage + reports: + views: + RNA_report: + reduce: false + scenarios: + - stage + samples: + views: + samp_top3: + reduce: false + scenarios: + - stage + application_categories: + design_docs: + general: + views: + app_cat: + reduce: false + scenarios: + - stage + bioinfo_analysis: + design_docs: + full_doc: + views: + pj_run_lane_sample_to_doc: + reduce: false + scenarios: + - stage + pj_run_to_doc: + reduce: false + scenarios: + - stage + pj_sample_run_lane_to_doc: + reduce: false + scenarios: + - stage + proj_run_lane_to_doc: + reduce: false + scenarios: + - stage + project_to_doc: + reduce: false + scenarios: + - stage + run_id_to_doc: + reduce: false + scenarios: + - stage + general: + views: + incoming_projectids: + reduce: true + scenarios: + - stage + not_ongoing_projectids: + reduce: false + scenarios: + - stage + not_ongoing_runids: + reduce: false + scenarios: + - stage + ongoing_projectids: + reduce: true + scenarios: + - stage + genomics_dashboard: + views: + run_lane_sample_status: + reduce: false + scenarios: + - stage + keys: + views: + pj_run: + reduce: false + scenarios: + - stage + run_id: + reduce: false + scenarios: + - stage + latest_data: + views: + project_id: + reduce: false + scenarios: + - stage + sample_id: + reduce: false + scenarios: + - stage + sample_id_open: + reduce: false + scenarios: + - stage + status: + views: + pj_run: + reduce: false + scenarios: + - stage + biomek_logs: + design_docs: + dates: + views: + timestamp: + reduce: false + scenarios: + - stage + names: + views: + run_finished: + reduce: false + scenarios: + - stage + charon: + design_docs: + filters: + views: {} + internal: + views: + sampleids_to_projectids: + reduce: false + scenarios: + - stage + libprep: + views: + count: + reduce: true + scenarios: + - stage + libprepid: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + log: + views: + doc: + reduce: false + scenarios: + - stage + project: + views: + modified: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + not_done: + reduce: false + scenarios: + - stage + projectid: + reduce: false + scenarios: + - stage + splitname: + reduce: false + scenarios: + - stage + sample: + views: + analyzed_failed: + reduce: false + scenarios: + - stage + count: + reduce: true + scenarios: + - stage + count_delivered: + reduce: true + scenarios: + - stage + count_done: + reduce: true + scenarios: + - stage + done: + reduce: false + scenarios: + - stage + failed: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + not_done: + reduce: false + scenarios: + - stage + running: + reduce: false + scenarios: + - stage + sampleid: + reduce: false + scenarios: + - stage + sequenced: + reduce: true + scenarios: + - stage + summary_count: + reduce: true + scenarios: + - stage + total_coverage: + reduce: true + scenarios: + - stage + seqrun: + views: + count: + reduce: true + scenarios: + - stage + seqrunid: + reduce: false + scenarios: + - stage + test: + views: + test: + reduce: false + scenarios: + - stage + user: + views: + api_token: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + cost_calculator: + design_docs: + entire_document: + views: + by_version: + reduce: false + scenarios: + - stage + published_by_version: + reduce: false + scenarios: + - stage + version_info: + views: {} + cronjobs: + design_docs: + server: + views: + alias: + reduce: false + scenarios: + - stage + demux_configuration: + design_docs: + summary: + views: {} + demux_sample_info: + design_docs: + info: + views: + flowcell_id: + reduce: false + scenarios: + - stage + summary: + views: + date_flowcell_id: + reduce: false + scenarios: + - stage + element_runs: + design_docs: + dashboard: + views: + week_instr_bp: + reduce: true + scenarios: + - stage + info: + views: + id: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + reads_yield: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + summary: + reduce: false + scenarios: + - stage + names: + views: + project_ids_list: + reduce: false + scenarios: + - stage + expected_yields: + design_docs: + yields: + views: + avg_yield: + reduce: false + scenarios: + - stage + min_yield: + reduce: false + scenarios: + - stage + flowcell_status: + design_docs: + events: + views: + all: + reduce: false + scenarios: + - stage + current_status_per_fcid: + reduce: false + scenarios: + - stage + current_status_per_runfolder: + reduce: false + scenarios: + - stage + lookup: + views: + flowcell_id: + reduce: false + scenarios: + - stage + runfolder_id: + reduce: false + scenarios: + - stage + summary: + views: + date_flowcell_id: + reduce: false + scenarios: + - stage + flowcells: + design_docs: + info: + views: + id: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + software_run_mode: + reduce: false + scenarios: + - stage + storage_status: + reduce: false + scenarios: + - stage + summary: + reduce: false + scenarios: + - stage + summary2: + reduce: false + scenarios: + - stage + instr: + views: + unmatched: + reduce: false + scenarios: + - stage + instrument: + views: + bp_yield: + reduce: false + scenarios: + - stage + clusters_raw: + reduce: false + scenarios: + - stage + error_rates: + reduce: false + scenarios: + - stage + unmatched: + reduce: false + scenarios: + - stage + yield: + reduce: false + scenarios: + - stage + lanes: + views: + bp_yield: + reduce: false + scenarios: + - stage + cluster_cont: + reduce: false + scenarios: + - stage + cluster_count: + reduce: false + scenarios: + - stage + clusters: + reduce: false + scenarios: + - stage + date_pf: + reduce: true + scenarios: + - stage + demultiplex: + reduce: false + scenarios: + - stage + err_rate_phix_yield: + reduce: false + scenarios: + - stage + gtq30: + reduce: true + scenarios: + - stage + gtq30_old: + reduce: true + scenarios: + - stage + project_lane_undemultiplex: + reduce: false + scenarios: + - stage + projects: + reduce: false + scenarios: + - stage + qc: + reduce: false + scenarios: + - stage + qtq30_old: + reduce: false + scenarios: + - stage + unmatched: + reduce: true + scenarios: + - stage + lims: + views: + summary: + reduce: false + scenarios: + - stage + names: + views: + Barcode_lane_stat: + reduce: false + scenarios: + - stage + id_to_name: + reduce: false + scenarios: + - stage + name: + reduce: true + scenarios: + - stage + project_ids_list: + reduce: false + scenarios: + - stage + reads: + views: + per_lane: + reduce: false + scenarios: + - stage + samples: + views: + demultiplex: + reduce: false + scenarios: + - stage + lane_clusters: + reduce: false + scenarios: + - stage + time: + views: + dates: + reduce: true + scenarios: + - stage + last_updated: + reduce: false + scenarios: + - stage + gs_users: + design_docs: + authorized: + views: + api_users: + reduce: false + scenarios: + - stage + info: + reduce: false + scenarios: + - stage + users: + reduce: false + scenarios: + - stage + instrument_logs: + design_docs: + time: + views: + last_week: + reduce: false + scenarios: + - stage + timestamp: + reduce: false + scenarios: + - stage + instruments: + design_docs: + info: + views: + id_to_name: + reduce: false + scenarios: + - stage + kpi: + design_docs: + dashboard: + views: + by_time: + reduce: false + scenarios: + - stage + nanopore_runs: + design_docs: + dashboard: + views: + week_instr_bp: + reduce: true + scenarios: + - stage + info: + views: + all_stats: + reduce: false + scenarios: + - stage + args: + reduce: false + scenarios: + - stage + barcodes: + reduce: false + scenarios: + - stage + lims: + reduce: false + scenarios: + - stage + mux_scans: + reduce: false + scenarios: + - stage + pore_count_history: + reduce: false + scenarios: + - stage + names: + views: + name: + reduce: false + scenarios: + - stage + project_ids_list: + reduce: false + scenarios: + - stage + orderportal_compcent: + design_docs: + account: + views: + api_key: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + first_name: + reduce: false + scenarios: + - stage + last_name: + reduce: false + scenarios: + - stage + login: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + university: + reduce: false + scenarios: + - stage + event: + views: + date: + reduce: false + scenarios: + - stage + file: + views: + name: + reduce: false + scenarios: + - stage + form: + views: + disabled: + reduce: false + scenarios: + - stage + enabled: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + group: + views: + invited: + reduce: false + scenarios: + - stage + member: + reduce: false + scenarios: + - stage + modified: + reduce: true + scenarios: + - stage + owner: + reduce: false + scenarios: + - stage + info: + views: + menu: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + log: + views: + account: + reduce: false + scenarios: + - stage + entity: + reduce: false + scenarios: + - stage + login_failure: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + message: + views: + modified: + reduce: false + scenarios: + - stage + recipient: + reduce: true + scenarios: + - stage + unsent: + reduce: false + scenarios: + - stage + meta: + views: + id: + reduce: false + scenarios: + - stage + news: + views: + modified: + reduce: false + scenarios: + - stage + order: + views: + form: + reduce: true + scenarios: + - stage + identifier: + reduce: false + scenarios: + - stage + keyword: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + owner: + reduce: true + scenarios: + - stage + owner_status: + reduce: true + scenarios: + - stage + status: + reduce: true + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + text: + views: + name: + reduce: false + scenarios: + - stage + orderportal_cryoem: + design_docs: + account: + views: + api_key: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + first_name: + reduce: false + scenarios: + - stage + last_name: + reduce: false + scenarios: + - stage + login: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + university: + reduce: false + scenarios: + - stage + event: + views: + date: + reduce: false + scenarios: + - stage + fields: + views: + pi_identifier: + reduce: false + scenarios: + - stage + file: + views: + name: + reduce: false + scenarios: + - stage + form: + views: + disabled: + reduce: false + scenarios: + - stage + enabled: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + group: + views: + invited: + reduce: false + scenarios: + - stage + member: + reduce: false + scenarios: + - stage + modified: + reduce: true + scenarios: + - stage + owner: + reduce: false + scenarios: + - stage + info: + views: + menu: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + log: + views: + account: + reduce: false + scenarios: + - stage + entity: + reduce: false + scenarios: + - stage + login_failure: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + message: + views: + modified: + reduce: false + scenarios: + - stage + recipient: + reduce: true + scenarios: + - stage + unsent: + reduce: false + scenarios: + - stage + meta: + views: + id: + reduce: false + scenarios: + - stage + news: + views: + modified: + reduce: false + scenarios: + - stage + order: + views: + form: + reduce: true + scenarios: + - stage + identifier: + reduce: false + scenarios: + - stage + keyword: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + owner: + reduce: true + scenarios: + - stage + owner_status: + reduce: true + scenarios: + - stage + status: + reduce: true + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + text: + views: + name: + reduce: false + scenarios: + - stage + orderportal_demo: + design_docs: + account: + views: + api_key: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + first_name: + reduce: false + scenarios: + - stage + last_name: + reduce: false + scenarios: + - stage + login: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + university: + reduce: false + scenarios: + - stage + event: + views: + date: + reduce: false + scenarios: + - stage + file: + views: + name: + reduce: false + scenarios: + - stage + form: + views: + disabled: + reduce: false + scenarios: + - stage + enabled: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + group: + views: + invited: + reduce: false + scenarios: + - stage + member: + reduce: false + scenarios: + - stage + modified: + reduce: true + scenarios: + - stage + owner: + reduce: false + scenarios: + - stage + info: + views: + menu: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + log: + views: + account: + reduce: false + scenarios: + - stage + entity: + reduce: false + scenarios: + - stage + login_failure: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + message: + views: + modified: + reduce: false + scenarios: + - stage + recipient: + reduce: true + scenarios: + - stage + unsent: + reduce: false + scenarios: + - stage + meta: + views: + id: + reduce: false + scenarios: + - stage + news: + views: + modified: + reduce: false + scenarios: + - stage + order: + views: + form: + reduce: true + scenarios: + - stage + identifier: + reduce: false + scenarios: + - stage + keyword: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + owner: + reduce: true + scenarios: + - stage + owner_status: + reduce: true + scenarios: + - stage + status: + reduce: true + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + text: + views: + name: + reduce: false + scenarios: + - stage + orderportal_natproj: + design_docs: + account: + views: + api_key: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + first_name: + reduce: false + scenarios: + - stage + last_name: + reduce: false + scenarios: + - stage + login: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + university: + reduce: false + scenarios: + - stage + event: + views: + date: + reduce: false + scenarios: + - stage + file: + views: + name: + reduce: false + scenarios: + - stage + form: + views: + disabled: + reduce: false + scenarios: + - stage + enabled: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + group: + views: + invited: + reduce: false + scenarios: + - stage + member: + reduce: false + scenarios: + - stage + modified: + reduce: true + scenarios: + - stage + owner: + reduce: false + scenarios: + - stage + info: + views: + menu: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + log: + views: + account: + reduce: false + scenarios: + - stage + entity: + reduce: false + scenarios: + - stage + login_failure: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + message: + views: + modified: + reduce: false + scenarios: + - stage + recipient: + reduce: true + scenarios: + - stage + unsent: + reduce: false + scenarios: + - stage + meta: + views: + id: + reduce: false + scenarios: + - stage + news: + views: + modified: + reduce: false + scenarios: + - stage + order: + views: + form: + reduce: true + scenarios: + - stage + identifier: + reduce: false + scenarios: + - stage + keyword: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + owner: + reduce: true + scenarios: + - stage + owner_status: + reduce: true + scenarios: + - stage + status: + reduce: true + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + text: + views: + name: + reduce: false + scenarios: + - stage + orderportal_ngi: + design_docs: + account: + views: + api_key: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + first_name: + reduce: false + scenarios: + - stage + last_name: + reduce: false + scenarios: + - stage + login: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + university: + reduce: false + scenarios: + - stage + event: + views: + date: + reduce: false + scenarios: + - stage + fields: + views: + Owner: + reduce: false + scenarios: + - stage + Status: + reduce: false + scenarios: + - stage + file: + views: + name: + reduce: false + scenarios: + - stage + form: + views: + disabled: + reduce: false + scenarios: + - stage + enabled: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + group: + views: + invited: + reduce: false + scenarios: + - stage + member: + reduce: false + scenarios: + - stage + modified: + reduce: true + scenarios: + - stage + owner: + reduce: false + scenarios: + - stage + info: + views: + menu: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + log: + views: + account: + reduce: false + scenarios: + - stage + entity: + reduce: false + scenarios: + - stage + login_failure: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + message: + views: + modified: + reduce: false + scenarios: + - stage + recipient: + reduce: true + scenarios: + - stage + unsent: + reduce: false + scenarios: + - stage + meta: + views: + id: + reduce: false + scenarios: + - stage + news: + views: + modified: + reduce: false + scenarios: + - stage + order: + views: + form: + reduce: true + scenarios: + - stage + identifier: + reduce: false + scenarios: + - stage + keyword: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + owner: + reduce: true + scenarios: + - stage + owner_status: + reduce: true + scenarios: + - stage + status: + reduce: true + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + taca: + views: + project_id_to_pi_email: + reduce: false + scenarios: + - stage + text: + views: + name: + reduce: false + scenarios: + - stage + orderportal_nmi: + design_docs: + account: + views: + api_key: + reduce: false + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + first_name: + reduce: false + scenarios: + - stage + last_name: + reduce: false + scenarios: + - stage + login: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + status: + reduce: false + scenarios: + - stage + university: + reduce: false + scenarios: + - stage + event: + views: + date: + reduce: false + scenarios: + - stage + file: + views: + name: + reduce: false + scenarios: + - stage + form: + views: + disabled: + reduce: false + scenarios: + - stage + enabled: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + group: + views: + invited: + reduce: false + scenarios: + - stage + member: + reduce: false + scenarios: + - stage + modified: + reduce: true + scenarios: + - stage + owner: + reduce: false + scenarios: + - stage + info: + views: + menu: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + log: + views: + account: + reduce: false + scenarios: + - stage + entity: + reduce: false + scenarios: + - stage + login_failure: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + message: + views: + modified: + reduce: false + scenarios: + - stage + recipient: + reduce: true + scenarios: + - stage + unsent: + reduce: false + scenarios: + - stage + meta: + views: + id: + reduce: false + scenarios: + - stage + news: + views: + modified: + reduce: false + scenarios: + - stage + order: + views: + form: + reduce: true + scenarios: + - stage + identifier: + reduce: false + scenarios: + - stage + keyword: + reduce: false + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + owner: + reduce: true + scenarios: + - stage + owner_status: + reduce: true + scenarios: + - stage + status: + reduce: true + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + text: + views: + name: + reduce: false + scenarios: + - stage + people_assignments: + design_docs: + current: + views: + assignments: + reduce: false + scenarios: + - stage + pricing_exchange_rates: + design_docs: + entire_document: + views: + by_date: + reduce: false + scenarios: + - stage + project_creation_forms: + design_docs: + by_creation_date: + views: + not_retired: + reduce: false + scenarios: + - stage + valid: + reduce: false + scenarios: + - stage + summary: + views: + all: + reduce: false + scenarios: + - stage + projects: + design_docs: + daily_read: + views: {} + date: + views: + creation_time_v: + reduce: true + scenarios: + - stage + m_bp_delivered: + reduce: true + scenarios: + - stage + genomics-dashboard: + views: + dates_and_load_per_sample: + reduce: true + scenarios: + - stage + open_application_count_projects: + reduce: true + scenarios: + - stage + open_application_count_samples: + reduce: true + scenarios: + - stage + open_application_count_seq_projects: + reduce: true + scenarios: + - stage + year_affiliation_count_projects: + reduce: true + scenarios: + - stage + year_application_count: + reduce: true + scenarios: + - stage + year_application_count_samples: + reduce: true + scenarios: + - stage + year_deliverytime_count_projects: + reduce: true + scenarios: + - stage + year_deliverytime_median_by_application: + reduce: true + scenarios: + - stage + year_seq_application_count: + reduce: true + scenarios: + - stage + year_seq_application_count_samples: + reduce: true + scenarios: + - stage + invoicing: + views: {} + kpi_external: + views: + KPI1: + reduce: true + scenarios: + - stage + KPI1_1: + reduce: true + scenarios: + - stage + KPI2: + reduce: true + scenarios: + - stage + KPI3: + reduce: true + scenarios: + - stage + KPI3_1: + reduce: false + scenarios: + - stage + applications_projects: + reduce: true + scenarios: + - stage + applications_samples: + reduce: false + scenarios: + - stage + date_affiliation: + reduce: false + scenarios: + - stage + projects: + reduce: true + scenarios: + - stage + names: + views: + id_to_name: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + order_portal: + views: + ProjectID_to_PortalID: + reduce: false + scenarios: + - stage + process_flow: + views: + KPI: + reduce: true + scenarios: + - stage + KPI_appl_pf_dates_sampl_lanes: + reduce: true + scenarios: + - stage + KPI_applications: + reduce: true + scenarios: + - stage + KPI_applications_test: + reduce: true + scenarios: + - stage + project: + views: + applications: + reduce: true + scenarios: + - stage + caliper_links: + reduce: false + scenarios: + - stage + controls: + reduce: false + scenarios: + - stage + dailyread_dates: + reduce: false + scenarios: + - stage + date_applications: + reduce: false + scenarios: + - stage + date_samples_applications: + reduce: false + scenarios: + - stage + details_count: + reduce: true + scenarios: + - stage + frag_an_links: + reduce: false + scenarios: + - stage + id_name_dates: + reduce: false + scenarios: + - stage + lib_const_meth: + reduce: false + scenarios: + - stage + project_dates: + reduce: false + scenarios: + - stage + project_id: + reduce: false + scenarios: + - stage + project_name: + reduce: false + scenarios: + - stage + sample_list: + reduce: false + scenarios: + - stage + samples: + reduce: false + scenarios: + - stage + samples_applications: + reduce: true + scenarios: + - stage + staged_files_sum: + reduce: false + scenarios: + - stage + status_lanes_ordered: + reduce: false + scenarios: + - stage + summary: + reduce: false + scenarios: + - stage + summary_dates: + reduce: true + scenarios: + - stage + summary_develop: + reduce: false + scenarios: + - stage + summary_status: + reduce: false + scenarios: + - stage + summary_with_sources: + reduce: false + scenarios: + - stage + projects: + views: + appl_proj_sample_preps: + reduce: false + scenarios: + - stage + date_proj_sample_firstInitQcDate: + reduce: true + scenarios: + - stage + date_proj_sample_status: + reduce: true + scenarios: + - stage + id_to_name: + reduce: false + scenarios: + - stage + lims_followed: + reduce: false + scenarios: + - stage + name_to_id: + reduce: false + scenarios: + - stage + name_to_id_cust_ref: + reduce: false + scenarios: + - stage + open_date2project_name: + reduce: false + scenarios: + - stage + open_date2project_name_application: + reduce: false + scenarios: + - stage + proj2status_(manual): + reduce: false + scenarios: + - stage + project_name: + reduce: false + scenarios: + - stage + samples: + views: + customer_names: + reduce: false + scenarios: + - stage + info: + reduce: false + scenarios: + - stage + library_prep_dates: + reduce: true + scenarios: + - stage + library_preps: + reduce: true + scenarios: + - stage + rec_ctrl_view: + reduce: false + scenarios: + - stage + sample_project_name: + reduce: true + scenarios: + - stage + test: + views: + KPI: + reduce: true + scenarios: + - stage + KPI_applications: + reduce: true + scenarios: + - stage + appl_setup_lanes: + reduce: true + scenarios: + - stage + appl_setup_samples: + reduce: true + scenarios: + - stage + contact_mail: + reduce: true + scenarios: + - stage + date_proj2numLanes: + reduce: true + scenarios: + - stage + date_proj2numSamples: + reduce: true + scenarios: + - stage + open_date2proj_source_lims: + reduce: false + scenarios: + - stage + project2queueDate_closeDate: + reduce: true + scenarios: + - stage + time: + views: + last_updated: + reduce: false + scenarios: + - stage + time_tracking_delivered: + reduce: false + scenarios: + - stage + pubrefdb: + design_docs: + publication: + views: + author: + reduce: false + scenarios: + - stage + excluded: + reduce: false + scenarios: + - stage + incomplete: + reduce: false + scenarios: + - stage + journal: + reduce: false + scenarios: + - stage + journals: + reduce: true + scenarios: + - stage + modified: + reduce: false + scenarios: + - stage + published: + reduce: false + scenarios: + - stage + slug: + reduce: false + scenarios: + - stage + tag: + reduce: false + scenarios: + - stage + tags: + reduce: true + scenarios: + - stage + title: + reduce: false + scenarios: + - stage + type: + reduce: false + scenarios: + - stage + xref: + reduce: false + scenarios: + - stage + years: + reduce: true + scenarios: + - stage + reference: + design_docs: + documents: + views: + doc_source: + reduce: false + scenarios: + - stage + doc_type: + reduce: false + scenarios: + - stage + entity_types: + reduce: false + scenarios: + - stage + running_notes: + design_docs: + latest_note_previews: + views: + flowcell: + reduce: true + scenarios: + - stage + project: + reduce: true + scenarios: + - stage + workset: + reduce: true + scenarios: + - stage + latest_sticky_note_previews: + views: + project: + reduce: true + scenarios: + - stage + note_types: + views: + invoicing_notes: + reduce: false + scenarios: + - stage + sticky_notes: + reduce: false + scenarios: + - stage + sample_requirements: + design_docs: + drafts: + views: + by_date_and_user: + reduce: false + scenarios: + - stage + entire_document: + views: + by_version: + reduce: false + scenarios: + - stage + published_by_version: + reduce: false + scenarios: + - stage + valid: + views: + by_date: + reduce: false + scenarios: + - stage + samples: + design_docs: + barcodes: + views: + date_read_counts: + reduce: true + scenarios: + - stage + flowcell: + reduce: true + scenarios: + - stage + flowcell_sample: + reduce: true + scenarios: + - stage + flowcells: + reduce: true + scenarios: + - stage + read_conts: + reduce: true + scenarios: + - stage + read_counts: + reduce: true + scenarios: + - stage + bc_name: + views: + bc_count: + reduce: false + scenarios: + - stage + contamination: + views: + Serch_by_proj_name: + reduce: false + scenarios: + - stage + fastq_scr: + reduce: false + scenarios: + - stage + index96_screen: + reduce: false + scenarios: + - stage + dates: + views: + count: + reduce: true + scenarios: + - stage + flowcell: + views: + name: + reduce: true + scenarios: + - stage + lanes: + views: + count: + reduce: true + scenarios: + - stage + names: + views: + id_to_name: + reduce: false + scenarios: + - stage + id_to_proj: + reduce: false + scenarios: + - stage + id_to_proj_id: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + name_fc: + reduce: true + scenarios: + - stage + name_fc_proj: + reduce: true + scenarios: + - stage + name_proj: + reduce: true + scenarios: + - stage + name_to_id: + reduce: false + scenarios: + - stage + proj_fc_sample: + reduce: false + scenarios: + - stage + runs: + reduce: true + scenarios: + - stage + samplename_run: + reduce: true + scenarios: + - stage + qc: + views: + alignment_summary: + reduce: false + scenarios: + - stage + coverage: + reduce: false + scenarios: + - stage + date_reads_per_qv: + reduce: false + scenarios: + - stage + insert_size_distribution: + reduce: false + scenarios: + - stage + qc_summary: + reduce: false + scenarios: + - stage + reads_per_qv: + reduce: false + scenarios: + - stage + summary: + reduce: true + scenarios: + - stage + sample: + views: + INS_metrics: + reduce: false + scenarios: + - stage + samples: + views: + read_counts: + reduce: true + scenarios: + - stage + time: + views: + checkpoints: + reduce: false + scenarios: + - stage + last_updated: + reduce: false + scenarios: + - stage + sensorpush: + design_docs: + entire_document: + views: + by_sensor_id_and_date: + reduce: false + scenarios: + - stage + sensor_id: + views: + by_date: + reduce: true + scenarios: + - stage + server_status: + design_docs: + all_docs: + views: + by_timestamp: + reduce: false + scenarios: + - stage + nases: + views: + by_timestamp: + reduce: false + scenarios: + - stage + latest_data: + reduce: false + scenarios: + - stage + uppmax: + views: + by_timestamp: + reduce: false + scenarios: + - stage + suggestion_box: + design_docs: + card: + views: + id: + reduce: false + scenarios: + - stage + unarchived_jira_cards: + reduce: false + scenarios: + - stage + date: + views: + info: + reduce: false + scenarios: + - stage + title_description: + reduce: false + scenarios: + - stage + title_url: + reduce: false + scenarios: + - stage + taca_flowcells: + design_docs: + run: + views: + id_status: + reduce: false + scenarios: + - stage + status: + views: + archived: + reduce: false + scenarios: + - stage + archiving: + reduce: false + scenarios: + - stage + sequencing: + reduce: false + scenarios: + - stage + uppmax: + design_docs: + status: + views: + project_cpu_usage_over_time: + reduce: false + scenarios: + - stage + project_quota_usage_over_time: + reduce: false + scenarios: + - stage + projects: + reduce: true + scenarios: + - stage + time: + views: + last_updated: + reduce: false + scenarios: + - stage + last_updated_full_doc: + reduce: false + scenarios: + - stage + userman: + design_docs: + log: + views: + doc: + reduce: false + scenarios: + - stage + service: + views: + name: + reduce: false + scenarios: + - stage + public: + reduce: false + scenarios: + - stage + team: + views: + leader: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + user: + views: + blocked: + reduce: false + scenarios: + - stage + count: + reduce: true + scenarios: + - stage + email: + reduce: false + scenarios: + - stage + pending: + reduce: false + scenarios: + - stage + role: + reduce: false + scenarios: + - stage + team: + reduce: false + scenarios: + - stage + username: + reduce: false + scenarios: + - stage + worksets: + design_docs: + project: + views: + ws_name: + reduce: false + scenarios: + - stage + ws_proj: + reduce: false + scenarios: + - stage + worksets: + views: + controls_project_list: + reduce: false + scenarios: + - stage + lims_id: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + only_name: + reduce: false + scenarios: + - stage + summary: + reduce: false + scenarios: + - stage + x_flowcells: + design_docs: + dashboard: + views: + week_instr_bp: + reduce: true + scenarios: + - stage + info: + views: + id: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + short_name_to_full_name: + reduce: false + scenarios: + - stage + summary: + reduce: false + scenarios: + - stage + summary2: + reduce: false + scenarios: + - stage + summary2_full_id: + reduce: false + scenarios: + - stage + summary2_stats: + reduce: false + scenarios: + - stage + lanes: + views: + clusters: + reduce: false + scenarios: + - stage + names: + views: + id_to_name: + reduce: false + scenarios: + - stage + name: + reduce: false + scenarios: + - stage + project_ids_list: + reduce: false + scenarios: + - stage + plot: + views: + count: + reduce: true + scenarios: + - stage + reads_yield: + reduce: false + scenarios: + - stage + projects: + views: + fc_lane_ss: + reduce: false + scenarios: + - stage + projects_lanes: + reduce: true + scenarios: + - stage + samples: + views: + lane_clusters: + reduce: false + scenarios: + - stage