在MongoDB中使用不同的关系定义3个模式(多对多,一对多......)

时间:2015-12-02 13:03:53

标签: node.js mongodb mongoose nosql

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

userSchema, questionSchema, listingSchema

三者之间的关系如下:

每个列表都有很多与之相关的问题(每个列表都有相同的问题) 每个用户 都可以在多个商家信息中回答许多问题 很多用户都会回答每个问题

我试图围绕定义这些模式之间的正确关系(主要是因为_id = 100用户在_id = 5的商家信息中使用_id = 3回答了问题,我如何以最有效的方式更新所有这些?)。

到目前为止,我已定义:

questionSchema:

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

userSchema:

var userSchema = new Schema({

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

并且listSchema:

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数据库中做得好?我的定义有意义吗?有没有更好的方法来描述这些模式之间的关系?

任何帮助都非常赞赏!

2 个答案:

答案 0 :(得分:1)

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
}

然后,你也可以放松ApartmentsAndQuestions.questions_id和$查询问题数据。它取决于你。

答案 1 :(得分:0)

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

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>>>返回一些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"
}