docs(backend): How to create & run data migrations

This commit is contained in:
roschaefer 2020-01-19 17:51:27 +01:00
parent b063847849
commit ce664040c6
5 changed files with 32 additions and 142 deletions

View File

@ -111,6 +111,38 @@ $ yarn run db:reset
{% endtab %}
{% endtabs %}
### Data migrations
Although Neo4J is schema-less,you might find yourself in a situation in which
you have to migrate your data e.g. because your data modeling has changed.
{% tabs %}
{% tab title="Docker" %}
Generate a data migration file:
```bash
$ docker-compose exec backend yarn run db:migrate:create your_data_migration
# Edit the file in ./src/db/migrations/
```
To run the migration:
```bash
$ docker-compose exec backend yarn run db:migrate up
```
{% endtab %}
{% tab title="Without Docker" %}
Generate a data migration file:
```bash
$ yarn run db:migrate:create your_data_migration
# Edit the file in ./src/db/migrations/
```
To run the migration:
```bash
$ yarn run db:migrate up
```
{% endtab %}
{% endtabs %}
# Testing
**Beware**: We have no multiple database setup at the moment. We clean the

View File

@ -36,20 +36,6 @@ Then make sure to allow Apoc procedures by adding the following line to your Neo
```
dbms.security.procedures.unrestricted=apoc.*
```
### Database Indices and Constraints
If you have `cypher-shell` available with your local installation of neo4j you
can run:
```bash
# in folder neo4j/
$ cp .env.template .env
$ ./db_setup.sh
```
Otherwise, if you don't have `cypher-shell` available, copy the cypher
statements [from the `db_setup.sh` script](https://github.com/Human-Connection/Human-Connection/blob/master/neo4j/db_setup.sh) and paste the scripts into your
[database browser frontend](http://localhost:7474).
### Alternatives

View File

@ -1,55 +0,0 @@
#!/usr/bin/env bash
ENV_FILE=$(dirname "$0")/.env
[[ -f "$ENV_FILE" ]] && source "$ENV_FILE"
if [ -z "$NEO4J_USERNAME" ] || [ -z "$NEO4J_PASSWORD" ]; then
echo "Please set NEO4J_USERNAME and NEO4J_PASSWORD environment variables."
echo "Database manipulation is not possible without connecting to the database."
echo "E.g. you could \`cp .env.template .env\` unless you run the script in a docker container"
fi
until echo 'RETURN "Connection successful" as info;' | cypher-shell
do
echo "Connecting to neo4j failed, trying again..."
sleep 1
done
echo "
// convert old DISABLED to new REVIEWED-Report-BELONGS_TO structure
MATCH (moderator:User)-[disabled:DISABLED]->(disabledResource)
WHERE disabledResource:User OR disabledResource:Comment OR disabledResource:Post
DELETE disabled
CREATE (moderator)-[review:REVIEWED]->(report:Report)-[:BELONGS_TO]->(disabledResource)
SET review.createdAt = toString(datetime()), review.updatedAt = review.createdAt, review.disable = true
SET report.id = randomUUID(), report.createdAt = toString(datetime()), report.updatedAt = report.createdAt, report.rule = 'latestReviewUpdatedAtRules', report.closed = false
// if disabledResource has no filed report, then create a moderators default filed report
WITH moderator, disabledResource, report
OPTIONAL MATCH (disabledResourceReporter:User)-[existingFiledReport:FILED]->(disabledResource)
FOREACH(disabledResource IN CASE WHEN existingFiledReport IS NULL THEN [1] ELSE [] END |
CREATE (moderator)-[addModeratorReport:FILED]->(report)
SET addModeratorReport.createdAt = toString(datetime()), addModeratorReport.reasonCategory = 'other', addModeratorReport.reasonDescription = 'Old DISABLED relations didn't enforce mandatory reporting !!! Created automatically to ensure database consistency! Creation date is when the database manipulation happened.'
)
FOREACH(disabledResource IN CASE WHEN existingFiledReport IS NOT NULL THEN [1] ELSE [] END |
CREATE (disabledResourceReporter)-[moveModeratorReport:FILED]->(report)
SET moveModeratorReport = existingFiledReport
DELETE existingFiledReport
)
RETURN disabledResource {.id};
" | cypher-shell
echo "
// for FILED resources without DISABLED relation which are handled above, create new FILED-Report-BELONGS_TO structure
MATCH (reporter:User)-[oldReport:REPORTED]->(notDisabledResource)
WHERE notDisabledResource:User OR notDisabledResource:Comment OR notDisabledResource:Post
MERGE (report:Report)-[:BELONGS_TO]->(notDisabledResource)
ON CREATE SET report.id = randomUUID(), report.createdAt = toString(datetime()), report.updatedAt = report.createdAt, report.rule = 'latestReviewUpdatedAtRules', report.closed = false
CREATE (reporter)-[filed:FILED]->(report)
SET report = oldReport
DELETE oldReport
RETURN notDisabledResource {.id};
" | cypher-shell

View File

@ -1,22 +0,0 @@
#!/usr/bin/env bash
if [ -z "$NEO4J_USERNAME" ] || [ -z "$NEO4J_PASSWORD" ]; then
echo "Please set NEO4J_USERNAME and NEO4J_PASSWORD environment variables."
echo "Database manipulation is not possible without connecting to the database."
echo "E.g. you could \`cp .env.template .env\` unless you run the script in a docker container"
fi
until echo 'RETURN "Connection successful" as info;' | cypher-shell
do
echo "Connecting to neo4j failed, trying again..."
sleep 1
done
echo "
CALL apoc.periodic.iterate('
CALL apoc.load.csv("out.csv") yield map as row return row
','
MATCH (post:Post) where post.image = row.image
set post.imageAspectRatio = row.aspectRatio
', {batchSize:10000, iterateList:true, parallel:true});
" | cypher-shell

View File

@ -1,51 +0,0 @@
#!/usr/bin/env bash
ENV_FILE=$(dirname "$0")/.env
[[ -f "$ENV_FILE" ]] && source "$ENV_FILE"
if [ -z "$NEO4J_USERNAME" ] || [ -z "$NEO4J_PASSWORD" ]; then
echo "Please set NEO4J_USERNAME and NEO4J_PASSWORD environment variables."
echo "Database manipulation is not possible without connecting to the database."
echo "E.g. you could \`cp .env.template .env\` unless you run the script in a docker container"
fi
until echo 'RETURN "Connection successful" as info;' | cypher-shell
do
echo "Connecting to neo4j failed, trying again..."
sleep 1
done
echo "
:begin
MATCH(user)-[reported:REPORTED]->(resource)
WITH reported, resource, COLLECT(user) as users
MERGE(report:Report)-[:BELONGS_TO]->(resource)
SET report.id = randomUUID(), report.createdAt = toString(datetime()), report.updatedAt = report.createdAt, report.rule = 'latestReviewUpdatedAtRules', report.closed = false
WITH report, users, reported
UNWIND users as user
MERGE (user)-[filed:FILED]->(report)
SET filed = reported
DELETE reported;
MATCH(moderator)-[disabled:DISABLED]->(resource)
MATCH(report:Report)-[:BELONGS_TO]->(resource)
WITH disabled, resource, COLLECT(moderator) as moderators, report
DELETE disabled
WITH report, moderators, disabled
UNWIND moderators as moderator
MERGE (moderator)-[review:REVIEWED {disable: true}]->(report)
SET review.createdAt = toString(datetime()), review.updatedAt = review.createdAt, review.disable = true;
MATCH(moderator)-[disabled:DISABLED]->(resource)
WITH disabled, resource, COLLECT(moderator) as moderators
MERGE(report:Report)-[:BELONGS_TO]->(resource)
SET report.id = randomUUID(), report.createdAt = toString(datetime()), report.updatedAt = report.createdAt, report.rule = 'latestReviewUpdatedAtRules', report.closed = false
DELETE disabled
WITH report, moderators, disabled
UNWIND moderators as moderator
MERGE(moderator)-[filed:FILED]->(report)
SET filed.createdAt = toString(datetime()), filed.reasonCategory = 'other', filed.reasonDescription = 'Old DISABLED relations didn\'t enforce mandatory reporting !!! Created automatically to ensure database consistency! Creation date is when the database manipulation happened.'
MERGE (moderator)-[review:REVIEWED {disable: true}]->(report)
SET review.createdAt = toString(datetime()), review.updatedAt = review.createdAt, review.disable = true;
:commit
" | cypher-shell