在 MongoDB 中定义 3 个具有不同关系(多对多、一对多...)的模式

Defining 3 schemas in MongoDB with different relations (many-to-many, one-to-many...)

我的应用程序中有 3 个不同的模式:

userSchema, questionSchema, listingSchema

三者的关系如下:

每个 listing 都有许多与之相关的问题(每个 listing 的问题相同)。
每个用户可以回答多个列表中的许多问题。
每个 问题 都会在许多列表中得到许多用户的回答。

我正在努力定义这些模式之间的正确关系(主要是因为诸如“_id = 100 的用户在 [=17] 的列表中回答了 _id = 5 的问题之类的问题=] ,如何以最有效的方式更新所有这些?)。

到目前为止我已经定义了:

问题架构:

var questionSchema = new Schema({
    description:  String
});

用户架构:

var userSchema = new Schema({

    local            : {
        email        : String,
        password     : String,
        name         : String
    },
    ApartmentsAndQuestions: [{
        apartmentID: String,
        questionID: [String] /* one apartment -> multiple questions */
    }]
});

和列表架构:

var listingSchema = new Schema({
     street          : String,
    buildingNumber  : Number,
    apartmentNumber : Number,
    type            : String,
    floor           : Number,
    outOfFloors     : Number,
    numberOfRooms   : Number,
    size            : Number,
    renovated       : Boolean,
    elevator        : Boolean,
    airConditioning : Boolean,
    balcony         : Boolean,
    price           : Number,
    description     : String,
    flagCount       : Number,
    pictures        : [imageSchema]
    owner           : [userSchema]

    UsersAndQuestions: [{
            userID: String,
            questionID: [String] /* one user -> multiple questions asked possible */
    }]
});

问题:我的NoSQL数据库如何做好?我的定义有意义吗?有没有更好的方法来描述这些模式之间的关系?

任何帮助都将 非常感谢

MongoDB 3.2+ 解决方案

在评论中添加提及,您可以使用新的$lookup来避免嵌入大量数据。就像 SQL LEFT JOIN:

让我们添加一些数据,与您的匹配:

db.questionSchema.insert({ _id: 1, description: "My description 1" });
db.questionSchema.insert({ _id: 2, description: "My description 2" });
db.questionSchema.insert({ _id: 3, description: "My description 3" });
db.questionSchema.insert({ _id: 4, description: "My description 4" });

db.userSchema.insert({ _id: 1, email: "my@email1.com", ApartmentsAndQuestions: [] });
db.userSchema.insert({ _id: 2, email: "my@email2.com", ApartmentsAndQuestions: [] });

db.listingSchema.insert({ _id: "A", UsersAndQuestions: [] })
db.listingSchema.insert({ _id: "B", UsersAndQuestions: [] })

// Add some questions
db.userSchema.update({ _id: 1 }, { $addToSet: { ApartmentsAndQuestions: { apartment_id: 1, question_id: [1] } } })
db.userSchema.update({ _id: 1, "ApartmentsAndQuestions.apartment_id": 1 }, { $addToSet: { "ApartmentsAndQuestions.$.question_id": 3 } })

db.userSchema.update({ _id: 2 }, { $addToSet: { ApartmentsAndQuestions: { apartment_id: 2, question_id: [1,2] } } })
db.userSchema.update({ _id: 2, "ApartmentsAndQuestions.apartment_id": 2 }, { $addToSet: { "ApartmentsAndQuestions.$.question_id": 4 } })

db.listingSchema.update({ _id: "A" }, { $addToSet: { UsersAndQuestions: { user_id: 1, question_id: [1] } } })

通过常规查找,您将得到以下结果:

test> db.listingSchema.find()
{
  "_id": "B",
  "UsersAndQuestions": [ ]
}
{
  "_id": "A",
  "UsersAndQuestions": [
    {
      "user_id": 1,
      "question_id": [
        1
      ]
    }
  ]
}

然后,让我们$lookup:

db.listingSchema.aggregate([
    {
        $unwind: "$UsersAndQuestions"
    }
    ,{
        $lookup:
        {
            from: "userSchema",
            localField: "UsersAndQuestions.user_id",
            foreignField: "_id",
            as: "fetched_user"
        }
    }
    ,{
        $unwind: "$UsersAndQuestions.question_id"
    }
    ,{
        $lookup:
        {
            from: "questionSchema",
            localField: "UsersAndQuestions.question_id",
            foreignField: "_id",
            as: "fetched_question"
        }
    }
])

你得到:

{
  "waitedMS": NumberLong("0"),
  "result": [
    {
      "_id": "A",
      "UsersAndQuestions": {
        "user_id": 1,
        "question_id": 1
      },
      "fetched_user": [
        {
          "_id": 1,
          "email": "my@email1.com",
          "ApartmentsAndQuestions": [
            {
              "apartment_id": 1,
              "question_id": [
                1,
                3
              ]
            }
          ]
        }
      ],
      "fetched_question": [
        {
          "_id": 1,
          "description": "My description 1"
        }
      ]
    }
  ],
  "ok": 1
}

然后,您也可以 $unwind ApartmentsAndQuestions.questions_id 和 $lookup 查询数据。由你决定。

您需要按如下方式定义架构:

var userSchema = mongoose.Schema({

    local            : {
        email        : String,
            password     : String,
            name             : String
    },
    /* every entry in the array is an apartment ID and the questionsIDs (array) of the questions that the user ALREADY answered in that *specific* apartment */
    ApartmentsAndQuestions: [{
        apartmentID : String,
        questionsIDs: [String]
    }]
});

并且:

var listingSchema = new Schema({
     street          : String,
     buildingNumber  : Number,
     apartmentNumber : Number,
     type            : String,
     floor           : Number,
     outOfFloors     : Number,
     numberOfRooms   : Number,
     size            : Number,
     renovated       : Boolean,
     elevator        : Boolean,
     airConditioning : Boolean,
     balcony         : Boolean,
     price           : Number,
     description     : String,
     flagCount       : Number,
     ownerID         : String,
     /* every entry in the array is a userID and the questionsIDs (array) of the questions that the user ALREADY answered in that *specific* apartment */
     UsersAndQuestions: [{
        userID: String,
        questionID: [String]
    }],
    /* every image has a count of how many times the users answered YES or NO on it */
    imagesAndCount: [{
        imageID: String,
        count: Number
    }]
});

然后你基本上可以按照以下行做一些事情:

var someuser = db.users.find()[2] // get some user

someuser._id >>> 其中 returns 一些 ObjectId("56472a83bd9fa764158d0cb6") 然后:db.users.find({_id: ObjectId("56472a83bd9fa764158d0cb6")}) >>> which will return someuser (with all the fields that are defined in the User schema)

然后:db.listings.insert({"street" : "SomeStreet", "buildingNumber" : 33, "apartmentNumber" : 63, "beds": 3, "owner" : "56472a83bd9fa764158d0cb6"})

列表将如下所示:
现在列表如下所示:

{
    "_id": {
        "$oid": "566c220abcda51a9eef08576"
    },
    "street": "SomeStreet",
    "buildingNumber": 33,
    "apartmentNumber": 63,
    "beds": 3,
    "owner": "56472a83bd9fa764158d0cb6"
}