The following is an example of a simple and minimal college database that uses two-way relationships
{
"students": {
"-SL3Cs0KFvDMQLIYZEzv": {
"name": "Godric Gryffindor",
"id": "900130309",
"courses": {
"potions": true,
"charms": true,
"transfiguration": true,
}
},
"-SL3ws2KvZQLTYMqzSas": {
"name": "Salazar Slytherin",
"id": "900132319",
"courses": {
"potions": true,
"herbs": true,
"muggleStudies": true,
}
},
"-SL3ns2OtARSTUMywqWt": { ... },
// More students here
},
"courses": {
"potions": {
"code": "CHEM305",
"enrolledStudents": {
"-SL3Cs0KFvDMQLIYZEzv": true, // Godric Gryffindor
"-SL3ws2KvZQLTYMqzSas": true, // Salazar Slytherin
// More students
}
},
"muggleStuddies": {
"code": "SOC215",
"enrolledStudents": {
"-SL3ws2KvZQLTYMqzSas": true, // Salazar Slytherin
"-SL3ns2OtARSTUMywqWt": true, // Some other student
// More students
}
},
// More courses
}
}
Note that each student has a list of courses and each course has a list of enrolled students.
Redundancy is not always a bad approach. It's true that it costs storage space and having to deal with multiple entries' updating when deleting or editing a duplicated node; however, in some scenarios where data is not updated often, having two-way relationships could ease the fetching/writing process significantly.
In most scenarios where an SQL-like query seems needed, inverting the data and creating two-way relationships is usually the solution.
Consider an application using the database above that requires the ability to:
If the database structure had been one-directional, it would incredibly slower to scan or query for one of the two requirements above. In some scenarios, redundancy makes frequent operations faster and much more efficient which, on the long run, makes the duplications' cost negligible.